diff --git a/.github/workflows/_cleanup.yml b/.github/workflows/_cleanup.yml
new file mode 100644
index 000000000..85113cf5c
--- /dev/null
+++ b/.github/workflows/_cleanup.yml
@@ -0,0 +1,24 @@
+name: cleanup
+
+on:
+ workflow_call:
+ inputs:
+ when:
+ description: "When to clean up (before/after)"
+ required: false
+ default: "before"
+ type: string
+
+jobs:
+ free-disk:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Free up disk space (${{ inputs.when }})
+ run: |
+ echo "Before cleanup:"
+ df -h
+ sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/share/boost
+ sudo apt clean
+ sudo rm -rf ~/.cache/pip /tmp/* /var/tmp/*
+ echo "After cleanup:"
+ df -h
diff --git a/.github/workflows/install.yml b/.github/workflows/install.yml
index 8541dbee2..af1d9d8f1 100644
--- a/.github/workflows/install.yml
+++ b/.github/workflows/install.yml
@@ -5,22 +5,34 @@ on:
pull_request:
jobs:
+ pre-commit:
+ name: pre-commit
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Setup Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.11"
+
+ - name: Run pre-commit on all files
+ uses: pre-commit/action@v3.0.1
+ with:
+ extra_args: --all-files --show-diff-on-failure
+
test:
name: test ${{ matrix.py }} - ${{ matrix.os }} - ${{ matrix.env }}
+ needs: pre-commit
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
- os:
- - ubuntu-latest
- - macos-latest
- py:
- - "3.11"
- - "3.10"
- - "3.9"
- env:
- - pip
- - conda
+ os: [ubuntu-latest, macos-latest]
+ py: ["3.11", "3.10"]
+ env: ["pip"]
+
steps:
- name: Checkout code
uses: actions/checkout@v3
@@ -40,8 +52,31 @@ jobs:
with:
python-version: ${{ matrix.py }}
+ - name: Check disk space (before cleanup)
+ if: runner.os == 'Linux'
+ run: df -h
+
+ - name: Free up disk space (Linux only)
+ if: runner.os == 'Linux'
+ run: |
+ echo "Before cleanup:"
+ df -h
+ sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
+ sudo apt-get clean
+ sudo rm -rf ~/.cache/pip /tmp/* /var/tmp/*
+ echo "After cleanup:"
+ df -h
+
- name: Upgrade pip
run: python -m pip install -U pip
+ - name: Check disk space (before install)
+ if: runner.os == 'Linux'
+ run: df -h
+
- name: Install pufferlib
run: pip install -e .
+
+ - name: Check disk space (after install)
+ if: runner.os == 'Linux'
+ run: df -h
diff --git a/.github/workflows/perf-ci.yml b/.github/workflows/perf-ci.yml
new file mode 100644
index 000000000..fd6f76553
--- /dev/null
+++ b/.github/workflows/perf-ci.yml
@@ -0,0 +1,43 @@
+name: perf-ci
+
+on:
+ pull_request:
+ branches: [ main ]
+
+jobs:
+ test-performance:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Setup Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.11"
+
+ - name: Check disk space (before cleanup)
+ run: df -h
+
+ - name: Free up disk space
+ run: |
+ echo "Before cleanup:"
+ df -h
+ sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
+ sudo apt-get clean
+ sudo rm -rf ~/.cache/pip /tmp/* /var/tmp/*
+ echo "After cleanup:"
+ df -h
+ - name: Install dependencies
+ run: |
+ sudo apt update && sudo apt install -y build-essential
+ python -m pip install -U pip
+ python -m pip install -e .
+ python setup.py build_ext --inplace --force
+ - name: Check disk space (after install)
+ run: df -h
+
+ - name: Test simulator performance
+ run: python tests/test_simulator_perf.py
+ timeout-minutes: 20
diff --git a/.github/workflows/render-ci.yml b/.github/workflows/render-ci.yml
new file mode 100644
index 000000000..9634af71d
--- /dev/null
+++ b/.github/workflows/render-ci.yml
@@ -0,0 +1,59 @@
+name: render-ci
+
+on:
+ pull_request:
+ branches: [ main ]
+ push:
+ branches: [ main ]
+
+jobs:
+ test-render:
+ name: test-render - ubuntu-latest
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Setup Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.11"
+
+ - name: Check disk space (before cleanup)
+ run: df -h
+
+ - name: Free up disk space
+ run: |
+ echo "Before cleanup:"
+ df -h
+ sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
+ sudo apt-get clean
+ sudo rm -rf ~/.cache/pip /tmp/* /var/tmp/*
+ echo "After cleanup:"
+ df -h
+
+ - name: Install system dependencies for headless rendering
+ run: |
+ sudo apt update
+ sudo apt install -y ffmpeg xvfb build-essential
+
+ - name: Upgrade pip
+ run: python -m pip install -U pip
+
+ - name: Install pufferlib
+ run: |
+ pip install -e .[cpu] --no-cache-dir
+ env:
+ TMPDIR: ${{ runner.temp }}/build
+ PIP_NO_CACHE_DIR: 1
+
+ - name: Compile C extensions
+ run: python setup.py build_ext --inplace --force
+
+ - name: Check disk space (after install)
+ run: df -h
+
+ - name: Run render test
+ run: python tests/test_drive_render.py
+ timeout-minutes: 15
diff --git a/.github/workflows/train-ci.yml b/.github/workflows/train-ci.yml
new file mode 100644
index 000000000..bd5b37776
--- /dev/null
+++ b/.github/workflows/train-ci.yml
@@ -0,0 +1,48 @@
+name: train-ci
+
+on:
+ pull_request:
+ branches: [ main ]
+ push:
+ branches: [ main ]
+
+jobs:
+ test-training:
+ name: test-training
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Setup Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: "3.11"
+
+ - name: Check disk space (before cleanup)
+ run: df -h
+
+ - name: Free up disk space
+ run: |
+ echo "Before cleanup:"
+ df -h
+ sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
+ sudo apt-get clean
+ sudo rm -rf ~/.cache/pip /tmp/* /var/tmp/*
+ echo "After cleanup:"
+ df -h
+
+ - name: Install dependencies
+ run: |
+ sudo apt update && sudo apt install -y build-essential
+ python -m pip install -U pip
+ pip install -e .
+ python setup.py build_ext --inplace --force
+
+ - name: Check disk space (after install)
+ run: df -h
+
+ - name: Test training
+ run: python tests/test_drive_train.py
+ timeout-minutes: 20
diff --git a/.gitignore b/.gitignore
index b579f3dd0..808b54b25 100644
--- a/.gitignore
+++ b/.gitignore
@@ -161,6 +161,7 @@ wandb/
.neptune/
raylib*/
box2d*/
+inih*/
# Temp Impulse Wars files
pufferlib/ocean/impulse_wars/*-debug/
@@ -168,3 +169,27 @@ pufferlib/ocean/impulse_wars/*-release/
pufferlib/ocean/impulse_wars/debug-*/
pufferlib/ocean/impulse_wars/release-*/
pufferlib/ocean/impulse_wars/benchmark/
+
+
+# Ignore data files
+data/
+pufferlib/resources/drive/binaries/
+
+# But keep map_000.bin for the training test
+!pufferlib/resources/drive/binaries/map_000.bin
+
+# Compiled drive binary in root
+/drive
+/visualize
+# But allow drive directories
+!*/drive/
+*.exe
+*.out
+*.app
+artifacts/
+pufferlib/resources/drive/output_agent.gif pufferlib/resources/drive/output.gif pufferlib/resources/drive/output_topdown.gif
+
+# Local artifacts and outputs
+artifacts/
+# Local drive renders
+pufferlib/resources/drive/output*.gif
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 000000000..df89de29e
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,23 @@
+# See https://pre-commit.com for more information
+# See https://pre-commit.com/hooks.html for more hooks
+repos:
+# Pre-commit hooks for Python and Jupyter notebooks
+- repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v6.0.0
+ hooks:
+ - id: trailing-whitespace
+ - id: end-of-file-fixer
+# Ruff for Python linting and formatting
+- repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: v0.12.12
+ hooks:
+ # - id: ruff
+ # args: [ --fix ]
+ - id: ruff-format
+# Cleaning Jupyter notebooks
+- repo: https://github.com/srstevenson/nb-clean
+ rev: 4.0.1
+ hooks:
+ - id: nb-clean
+ args:
+ - --remove-empty-cells
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 000000000..576130d05
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,7 @@
+# Agent Instructions
+
+## Git Workflow
+
+- **Never push directly to `main`, `2.0`, or `3.0` branches**
+- Always create a feature branch and open a Pull Request for changes to these branches
+- PRs allow for code review and CI checks before merging
diff --git a/MANIFEST.in b/MANIFEST.in
index 14b53eb75..7f6f85bab 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -13,7 +13,7 @@ include raylib-5.5_linux_amd64/lib/libraylib.a
include raylib-5.5_macos/lib/libraylib.a
include box2d-linux-amd64/libbox2d.a
recursive-exclude box2d-web *
-recursive-exclude raylib-5.5_webassembly *
+recursive-exclude raylib-5.5_webassembly *
recursive-exclude pufferlib/ocean/impulse_wars/debug* *
recursive-exclude pufferlib/ocean/impulse_wars/release* *
recursive-exclude box2d* *
diff --git a/README.md b/README.md
index dc1bfaa81..4cadf675a 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,137 @@
-
+# PufferDrive
-[](https://badge.fury.io/py/pufferlib)
-
-
-[](https://discord.gg/spT4huaGYV)
-[](https://twitter.com/jsuarez5341)
-PufferLib is the reinforcement learning library I wish existed during my PhD. It started as a compatibility layer to make working with complex environments a breeze. Now, it's a high-performance toolkit for research and industry with optimized parallel simulation, environments that run and train at 1M+ steps/second, and tons of quality of life improvements for practitioners. All our tools are free and open source. We also offer priority service for companies, startups, and labs!
+## Installation
-
+Clone the repo
+```bash
+https://github.com/Emerge-Lab/PufferDrive.git
+```
-All of our documentation is hosted at [puffer.ai](https://puffer.ai "PufferLib Documentation"). @jsuarez5341 on [Discord](https://discord.gg/puffer) for support -- post here before opening issues. We're always looking for new contributors, too!
+Make a venv (`uv venv`), activate the venv
+```
+source .venv/bin/activate
+```
-## Star to puff up the project!
+Inside the venv, install the dependencies
+```
+uv pip install -e .
+```
-
-
-
-
-
-
-
+Compile the C code
+```
+python setup.py build_ext --inplace --force
+```
+
+To test your setup, you can run
+```
+puffer train puffer_drive
+```
+See also the [puffer docs](https://puffer.ai/docs.html).
+
+
+## Quick start
+
+Start a training run
+```
+puffer train puffer_drive
+```
+
+## Dataset
+
+
+Downloading and using data
+
+### Data preparation
+
+To train with PufferDrive, you need to convert JSON files to map binaries. Run the following command with the path to your data folder:
+
+```bash
+python pufferlib/ocean/drive/drive.py
+```
+
+### Downloading Waymo Data
+
+You can download the WOMD data from Hugging Face in two versions:
+
+- **Mini Dataset**: [GPUDrive_mini](https://huggingface.co/datasets/EMERGE-lab/GPUDrive_mini) contains 1,000 training files and 300 test/validation files
+- **Full Dataset**: [GPUDrive](https://huggingface.co/datasets/EMERGE-lab/GPUDrive) contains 100,000 unique scenes
+
+**Note**: Replace 'GPUDrive_mini' with 'GPUDrive' in your download commands if you want to use the full dataset.
+
+### Additional Data Sources
+
+For more training data compatible with PufferDrive, see [ScenarioMax](https://github.com/valeoai/ScenarioMax). The GPUDrive data format is fully compatible with PufferDrive.
+
+
+
+## Visualizer
+
+
+Dependencies and usage
+
+## Headless server setup
+
+Run the Raylib visualizer on a headless server and export as .mp4. This will rollout the pre-trained policy in the env.
+
+### Install dependencies
+
+```bash
+sudo apt update
+sudo apt install ffmpeg xvfb
+```
+
+For HPC (There are no root privileges), so install into the conda environment
+```bash
+conda install -c conda-forge xorg-x11-server-xvfb-cos6-x86_64
+conda install -c conda-forge ffmpeg
+```
+
+- `ffmpeg`: Video processing and conversion
+- `xvfb`: Virtual display for headless environments
+
+### Build and run
+
+1. Build the application:
+```bash
+bash scripts/build_ocean.sh visualize local
+```
+
+2. Run with virtual display:
+```bash
+xvfb-run -s "-screen 0 1280x720x24" ./visualize
+```
+
+The `-s` flag sets up a virtual screen at 1280x720 resolution with 24-bit color depth.
+
+---
+
+> To force a rebuild, you can delete the cached compiled executable binary using `rm ./visualize`.
+
+---
+
+
+
+
+## Benchmarks
+
+### Distributional realism
+
+We provide a PufferDrive implementation of the [Waymo Open Sim Agents Challenge (WOSAC)](https://waymo.com/open/challenges/2025/sim-agents/) for fast, easy evaluation of how well your trained agent matches distributional properties of human behavior. See details [here](https://github.com/Emerge-Lab/PufferDrive/main/pufferlib/ocean/benchmark).
+
+WOSAC evaluation with random policy:
+```bash
+puffer eval puffer_drive --eval.wosac-realism-eval True
+```
+
+WOSAC evaluation with your checkpoint (must be .pt file):
+```bash
+puffer eval puffer_drive --eval.wosac-realism-eval True --load-model-path .pt
+```
+
+### Human-compatibility
+
+You may be interested in how compatible your agent is with human partners. For this purpose, we support an eval where your policy only controls the self-driving car (SDC). The rest of the agents in the scene are stepped using the logs. While it is not a perfect eval since the human partners here are static, it will still give you a sense of how closely aligned your agent's behavior is to how people drive. You can run it like this:
+```bash
+puffer eval puffer_drive --eval.human-replay-eval True --load-model-path .pt
+```
diff --git a/data_utils/carla/carla/Town01_0.json b/data_utils/carla/carla/Town01_0.json
new file mode 100644
index 000000000..21b0fbec4
--- /dev/null
+++ b/data_utils/carla/carla/Town01_0.json
@@ -0,0 +1,107229 @@
+{
+ "name": "Town01",
+ "scenario_id": "N0KHWCZZgZhX",
+ "objects": [
+ {
+ "position": [
+ {
+ "x": 92.37733991874609,
+ "y": -48.26687711506169,
+ "z": 1.0
+ },
+ {
+ "x": 92.37727862621773,
+ "y": -47.863670458684396,
+ "z": 1.0
+ },
+ {
+ "x": 92.37720201055727,
+ "y": -47.359662138212784,
+ "z": 1.0
+ },
+ {
+ "x": 92.37711007176472,
+ "y": -46.75485215364684,
+ "z": 1.0
+ },
+ {
+ "x": 92.37704877923635,
+ "y": -46.35164549726926,
+ "z": 1.0
+ },
+ {
+ "x": 92.37701813297217,
+ "y": -46.15004216908089,
+ "z": 1.0
+ },
+ {
+ "x": 92.37694183367158,
+ "y": -45.648114989838035,
+ "z": 1.0
+ },
+ {
+ "x": 92.37688083639642,
+ "y": -45.24685062665783,
+ "z": 1.0
+ },
+ {
+ "x": 92.3767893404837,
+ "y": -44.644954081888244,
+ "z": 1.0
+ },
+ {
+ "x": 92.37669784457097,
+ "y": -44.04305753711837,
+ "z": 1.0
+ },
+ {
+ "x": 92.37663684729581,
+ "y": -43.64179317393818,
+ "z": 1.0
+ },
+ {
+ "x": 92.37654535138309,
+ "y": -43.039896629168595,
+ "z": 1.0
+ },
+ {
+ "x": 92.37645385547036,
+ "y": -42.43800008439872,
+ "z": 1.0
+ },
+ {
+ "x": 92.3763928581952,
+ "y": -42.036735721218534,
+ "z": 1.0
+ },
+ {
+ "x": 92.37630136228248,
+ "y": -41.434839176448946,
+ "z": 1.0
+ },
+ {
+ "x": 92.37622511568853,
+ "y": -40.93325872247377,
+ "z": 1.0
+ },
+ {
+ "x": 92.37616411841337,
+ "y": -40.53199435929386,
+ "z": 1.0
+ },
+ {
+ "x": 92.37607262250064,
+ "y": -39.93009781452399,
+ "z": 1.0
+ },
+ {
+ "x": 92.3760116252255,
+ "y": -39.52883345134437,
+ "z": 1.0
+ },
+ {
+ "x": 92.37592012931276,
+ "y": -38.92693690657421,
+ "z": 1.0
+ },
+ {
+ "x": 92.37585913203762,
+ "y": -38.52567254339458,
+ "z": 1.0
+ },
+ {
+ "x": 92.37578288544367,
+ "y": -38.02409208941941,
+ "z": 1.0
+ },
+ {
+ "x": 92.37572188816851,
+ "y": -37.62282772623949,
+ "z": 1.0
+ },
+ {
+ "x": 92.37563039225579,
+ "y": -37.02093118146962,
+ "z": 1.0
+ },
+ {
+ "x": 92.37555414566185,
+ "y": -36.51935072749474,
+ "z": 1.0
+ },
+ {
+ "x": 92.3754931483867,
+ "y": -36.11808636431482,
+ "z": 1.0
+ },
+ {
+ "x": 92.37541690179276,
+ "y": -35.61650591034021,
+ "z": 1.0
+ },
+ {
+ "x": 92.37532540588003,
+ "y": -35.01460936557035,
+ "z": 1.0
+ },
+ {
+ "x": 92.37526440860488,
+ "y": -34.61334500239043,
+ "z": 1.0
+ },
+ {
+ "x": 92.37518816201093,
+ "y": -34.11176454841525,
+ "z": 1.0
+ },
+ {
+ "x": 92.37512716473579,
+ "y": -33.71050018523563,
+ "z": 1.0
+ },
+ {
+ "x": 92.37505091814184,
+ "y": -33.20891973126045,
+ "z": 1.0
+ },
+ {
+ "x": 92.37495942222911,
+ "y": -32.60702318649058,
+ "z": 1.0
+ },
+ {
+ "x": 92.37488317563518,
+ "y": -32.10544273251598,
+ "z": 1.0
+ },
+ {
+ "x": 92.37482217836002,
+ "y": -31.704178369336063,
+ "z": 1.0
+ },
+ {
+ "x": 92.37474593176607,
+ "y": -31.202597915360887,
+ "z": 1.0
+ },
+ {
+ "x": 92.37466968517214,
+ "y": -30.701017461385998,
+ "z": 1.0
+ },
+ {
+ "x": 92.37460868789698,
+ "y": -30.299753098206086,
+ "z": 1.0
+ },
+ {
+ "x": 92.37453244130305,
+ "y": -29.798172644231478,
+ "z": 1.0
+ },
+ {
+ "x": 92.37447144402789,
+ "y": -29.39690828105128,
+ "z": 1.0
+ },
+ {
+ "x": 92.37437994811516,
+ "y": -28.795011736281694,
+ "z": 1.0
+ },
+ {
+ "x": 92.37430370152121,
+ "y": -28.29343128230652,
+ "z": 1.0
+ },
+ {
+ "x": 92.37421220560849,
+ "y": -27.691534737536653,
+ "z": 1.0
+ },
+ {
+ "x": 92.37415120833333,
+ "y": -27.29027037435674,
+ "z": 1.0
+ },
+ {
+ "x": 92.3740749617394,
+ "y": -26.788689920381852,
+ "z": 1.0
+ },
+ {
+ "x": 92.37398346582667,
+ "y": -26.18679337561198,
+ "z": 1.0
+ },
+ {
+ "x": 92.37390721923272,
+ "y": -25.685212921637092,
+ "z": 1.0
+ },
+ {
+ "x": 92.37384622195758,
+ "y": -25.28394855845746,
+ "z": 1.0
+ },
+ {
+ "x": 92.37376997536363,
+ "y": -24.782368104482284,
+ "z": 1.0
+ },
+ {
+ "x": 92.37370897808847,
+ "y": -24.381103741302372,
+ "z": 1.0
+ },
+ {
+ "x": 92.37364798081333,
+ "y": -23.97983937812274,
+ "z": 1.0
+ },
+ {
+ "x": 92.37355648490059,
+ "y": -23.377942833352595,
+ "z": 1.0
+ },
+ {
+ "x": 92.37349548762545,
+ "y": -22.976678470172963,
+ "z": 1.0
+ },
+ {
+ "x": 92.37340399171272,
+ "y": -22.37478192540309,
+ "z": 1.0
+ },
+ {
+ "x": 92.37334299443756,
+ "y": -21.9735175622229,
+ "z": 1.0
+ },
+ {
+ "x": 92.37325149852484,
+ "y": -21.371621017453307,
+ "z": 1.0
+ },
+ {
+ "x": 92.37317525193089,
+ "y": -20.87004056347814,
+ "z": 1.0
+ },
+ {
+ "x": 92.37308375601816,
+ "y": -20.268144018708266,
+ "z": 1.0
+ },
+ {
+ "x": 92.37299226010543,
+ "y": -19.6662474739384,
+ "z": 1.0
+ },
+ {
+ "x": 92.3729007641927,
+ "y": -19.06435092916853,
+ "z": 1.0
+ },
+ {
+ "x": 92.37283976691755,
+ "y": -18.66308656598862,
+ "z": 1.0
+ },
+ {
+ "x": 92.37274827100482,
+ "y": -18.06119002121876,
+ "z": 1.0
+ },
+ {
+ "x": 92.37267202441087,
+ "y": -17.55960956724387,
+ "z": 1.0
+ },
+ {
+ "x": 92.37258052849815,
+ "y": -16.957713022474007,
+ "z": 1.0
+ },
+ {
+ "x": 92.372519531223,
+ "y": -16.556448659294382,
+ "z": 1.0
+ },
+ {
+ "x": 92.37244328462906,
+ "y": -16.054868205319213,
+ "z": 1.0
+ },
+ {
+ "x": 92.37236703803512,
+ "y": -15.553287751344609,
+ "z": 1.0
+ },
+ {
+ "x": 92.37230604075997,
+ "y": -15.152023388164416,
+ "z": 1.0
+ },
+ {
+ "x": 92.37224504348481,
+ "y": -14.750759024984504,
+ "z": 1.0
+ },
+ {
+ "x": 92.37218404620965,
+ "y": -14.349494661804595,
+ "z": 1.0
+ },
+ {
+ "x": 92.37210779961572,
+ "y": -13.847914207829707,
+ "z": 1.0
+ },
+ {
+ "x": 92.37204680234056,
+ "y": -13.446649844649794,
+ "z": 1.0
+ },
+ {
+ "x": 92.3719858050654,
+ "y": -13.045385481469882,
+ "z": 1.0
+ },
+ {
+ "x": 92.37189430915268,
+ "y": -12.443488936700017,
+ "z": 1.0
+ },
+ {
+ "x": 92.37180281323995,
+ "y": -11.841592391930153,
+ "z": 1.0
+ },
+ {
+ "x": 92.37172656664602,
+ "y": -11.340011937955548,
+ "z": 1.0
+ },
+ {
+ "x": 92.37171131732723,
+ "y": -11.239695847160288,
+ "z": 1.0
+ },
+ {
+ "x": 92.37165010369664,
+ "y": -10.837008211690133,
+ "z": 1.0
+ },
+ {
+ "x": 92.37157358665839,
+ "y": -10.333648667352328,
+ "z": 1.0
+ },
+ {
+ "x": 92.37149706962015,
+ "y": -9.830289123014808,
+ "z": 1.0
+ },
+ {
+ "x": 92.37142055258188,
+ "y": -9.326929578676726,
+ "z": 1.0
+ },
+ {
+ "x": 92.37135933895128,
+ "y": -8.924241943206486,
+ "z": 1.0
+ },
+ {
+ "x": 92.37128282191303,
+ "y": -8.420882398868397,
+ "z": 1.0
+ },
+ {
+ "x": 92.38387847983404,
+ "y": -7.926753944901536,
+ "z": 1.0
+ },
+ {
+ "x": 92.41037157599465,
+ "y": -7.620861084595008,
+ "z": 1.0
+ },
+ {
+ "x": 92.45147026774205,
+ "y": -7.316185300747591,
+ "z": 1.0
+ },
+ {
+ "x": 92.50702318936625,
+ "y": -7.013812440974701,
+ "z": 1.0
+ },
+ {
+ "x": 92.59659554589444,
+ "y": -6.640127905133789,
+ "z": 1.0
+ },
+ {
+ "x": 92.68416038829855,
+ "y": -6.345430981750049,
+ "z": 1.0
+ },
+ {
+ "x": 92.8415494737095,
+ "y": -5.9120333829588265,
+ "z": 1.0
+ },
+ {
+ "x": 93.02946380436408,
+ "y": -5.490972509787698,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 1,
+ "heading": [
+ 1.5541722980230424,
+ 1.5709483394834673,
+ 1.570948339483483,
+ 1.5709483394834929,
+ 1.5709483394834955,
+ 1.5709483394834909,
+ 1.570948339483491,
+ 1.5709483394834989,
+ 1.5709483394834896,
+ 1.570948339483485,
+ 1.5709483394834896,
+ 1.5709483394834896,
+ 1.570948339483485,
+ 1.5709483394834896,
+ 1.5709483394834896,
+ 1.5709483394834933,
+ 1.5709483394835004,
+ 1.5709483394834896,
+ 1.5709483394834753,
+ 1.5709483394834896,
+ 1.5709483394834896,
+ 1.570948339483485,
+ 1.5709483394835004,
+ 1.5709483394834896,
+ 1.5709483394834804,
+ 1.570948339483485,
+ 1.570948339483485,
+ 1.5709483394834804,
+ 1.5709483394834896,
+ 1.5709483394835004,
+ 1.570948339483485,
+ 1.570948339483485,
+ 1.5709483394834933,
+ 1.5709483394834804,
+ 1.570948339483485,
+ 1.5709483394835004,
+ 1.5709483394834896,
+ 1.570948339483485,
+ 1.570948339483485,
+ 1.570948339483485,
+ 1.5709483394834896,
+ 1.5709483394834933,
+ 1.5709483394834933,
+ 1.5709483394834896,
+ 1.570948339483485,
+ 1.5709483394834804,
+ 1.5709483394834933,
+ 1.570948339483485,
+ 1.570948339483485,
+ 1.5709483394835004,
+ 1.570948339483479,
+ 1.5709483394834896,
+ 1.5709483394834896,
+ 1.5709483394834753,
+ 1.5709483394834896,
+ 1.5709483394834896,
+ 1.5709483394834933,
+ 1.5709483394834933,
+ 1.570948339483485,
+ 1.570948339483485,
+ 1.5709483394834896,
+ 1.5709483394834896,
+ 1.5709483394834933,
+ 1.5709483394834933,
+ 1.5709483394834753,
+ 1.570948339483485,
+ 1.5709483394834896,
+ 1.570948339483485,
+ 1.5709483394834967,
+ 1.5709483394834967,
+ 1.570948339483485,
+ 1.570948339483485,
+ 1.5709483394834967,
+ 1.5709483394834896,
+ 1.570948339483485,
+ 1.5709483394834804,
+ 1.570948339483485,
+ 1.5709483394834682,
+ 1.570948339483472,
+ 1.5709483394834736,
+ 1.5709483394834878,
+ 1.5709483394835033,
+ 1.5709483394834878,
+ 1.5582463175408183,
+ 1.5219755106522177,
+ 1.4605422460017705,
+ 1.4129059797025108,
+ 1.3593412115275172,
+ 1.3117280718770892,
+ 1.2462600242857522,
+ 1.1867436228401171
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -0.00061292528357626,
+ "y": 4.032066563772929
+ },
+ {
+ "x": -0.0013790818881886935,
+ "y": 9.072149768489055
+ },
+ {
+ "x": -0.001685544530118932,
+ "y": 11.08818305037559
+ },
+ {
+ "x": -0.001532313209224867,
+ "y": 10.080166409435236
+ },
+ {
+ "x": -0.0009193879255064985,
+ "y": 6.048099845659465
+ },
+ {
+ "x": -0.001069455647666473,
+ "y": 7.035305074312248
+ },
+ {
+ "x": -0.00137296575744017,
+ "y": 9.03191542423059
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079497912
+ },
+ {
+ "x": -0.0018299182545433723,
+ "y": 12.037930895394595
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079500612
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.0018299182545433723,
+ "y": 12.037930895394595
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079500612
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.001677425066759497,
+ "y": 11.034769987447675
+ },
+ {
+ "x": -0.0013724386910496378,
+ "y": 9.028448171550849
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.0015249318786914046,
+ "y": 10.031609079494928
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079497912
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171548007
+ },
+ {
+ "x": -0.0013724386910496378,
+ "y": 9.028448171550849
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079497912
+ },
+ {
+ "x": -0.0016774250666173884,
+ "y": 11.034769987447532
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171548007
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171545307
+ },
+ {
+ "x": -0.0016774250666173884,
+ "y": 11.03476998744469
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.0013724386910496378,
+ "y": 9.028448171550991
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171548007
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171548007
+ },
+ {
+ "x": -0.001677425066759497,
+ "y": 11.034769987450517
+ },
+ {
+ "x": -0.0016774250666173884,
+ "y": 11.03476998744469
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171545165
+ },
+ {
+ "x": -0.0013724386910496378,
+ "y": 9.028448171550956
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079500647
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171548007
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.0284481715452
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171548042
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949784
+ },
+ {
+ "x": -0.001677425066759497,
+ "y": 11.034769987447604
+ },
+ {
+ "x": -0.001677425066759497,
+ "y": 11.03476998745041
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079497805
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171548007
+ },
+ {
+ "x": -0.0016774250666173884,
+ "y": 11.034769987447604
+ },
+ {
+ "x": -0.001677425066759497,
+ "y": 11.034769987447604
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.0284481715452
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171548078
+ },
+ {
+ "x": -0.0013724386910496378,
+ "y": 9.028448171550885
+ },
+ {
+ "x": -0.0012199455029815454,
+ "y": 8.025287263595438
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.0015249318786914046,
+ "y": 10.031609079495034
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079500647
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949784
+ },
+ {
+ "x": -0.001677425066759497,
+ "y": 11.034769987447604
+ },
+ {
+ "x": -0.001677425066759497,
+ "y": 11.03476998745041
+ },
+ {
+ "x": -0.0018299182545433723,
+ "y": 12.037930895397366
+ },
+ {
+ "x": -0.0018299182545433723,
+ "y": 12.037930895397366
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079497805
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079497699
+ },
+ {
+ "x": -0.001677425066759497,
+ "y": 11.034769987447497
+ },
+ {
+ "x": -0.001677425066759497,
+ "y": 11.034769987447532
+ },
+ {
+ "x": -0.0015249318786914046,
+ "y": 10.031609079494892
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171547936
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079497734
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171547971
+ },
+ {
+ "x": -0.001219945503123654,
+ "y": 8.02528726360105
+ },
+ {
+ "x": -0.001219945503123654,
+ "y": 8.025287263598209
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171547971
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171548007
+ },
+ {
+ "x": -0.001219945503123654,
+ "y": 8.025287263598244
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.0018299182545433723,
+ "y": 12.037930895397295
+ },
+ {
+ "x": -0.0016774250666173884,
+ "y": 11.03476998744469
+ },
+ {
+ "x": -0.0009149591272716862,
+ "y": 6.018965447698648
+ },
+ {
+ "x": -0.0007646294938012943,
+ "y": 5.0300372626541545
+ },
+ {
+ "x": -0.0013773066883970841,
+ "y": 9.060471798079597
+ },
+ {
+ "x": -0.0015303407649014389,
+ "y": 10.067190886753252
+ },
+ {
+ "x": -0.0015303407650435474,
+ "y": 10.067190886756023
+ },
+ {
+ "x": -0.0013773066886813012,
+ "y": 9.06047179808322
+ },
+ {
+ "x": -0.0013773066885391927,
+ "y": 9.060471798083292
+ },
+ {
+ "x": 0.1251914088275896,
+ "y": 9.974879983049494
+ },
+ {
+ "x": 0.3908875408161805,
+ "y": 8.000213142733887
+ },
+ {
+ "x": 0.6759178790801457,
+ "y": 6.105686441539451
+ },
+ {
+ "x": 0.9665161337160555,
+ "y": 6.070486436203071
+ },
+ {
+ "x": 1.4512527815239196,
+ "y": 6.760573956138023
+ },
+ {
+ "x": 1.7713719893230007,
+ "y": 6.683814592246522
+ },
+ {
+ "x": 2.44953927815061,
+ "y": 7.280945221749624
+ },
+ {
+ "x": 3.453034160655335,
+ "y": 8.544584719623511
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 93.02946380436408,
+ "y": -5.490972509787698,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 88.39124251873497,
+ "y": -139.72401945159578,
+ "z": 1.0
+ },
+ {
+ "x": 88.3913191036827,
+ "y": -140.22782573152114,
+ "z": 1.0
+ },
+ {
+ "x": 88.39141100561999,
+ "y": -140.83239326743148,
+ "z": 1.0
+ },
+ {
+ "x": 88.3914875905677,
+ "y": -141.33619954735684,
+ "z": 1.0
+ },
+ {
+ "x": 88.39156417551544,
+ "y": -141.84000582728214,
+ "z": 1.0
+ },
+ {
+ "x": 88.39156417551544,
+ "y": -141.84000582728214,
+ "z": 1.0
+ },
+ {
+ "x": 88.39162514892526,
+ "y": -142.2411131951493,
+ "z": 1.0
+ },
+ {
+ "x": 88.39168607725401,
+ "y": -142.6419240013292,
+ "z": 1.0
+ },
+ {
+ "x": 88.39176223766492,
+ "y": -143.14293750905404,
+ "z": 1.0
+ },
+ {
+ "x": 88.39185363015802,
+ "y": -143.74415371832356,
+ "z": 1.0
+ },
+ {
+ "x": 88.39191455848675,
+ "y": -144.14496452450373,
+ "z": 1.0
+ },
+ {
+ "x": 88.3919754868155,
+ "y": -144.54577533068306,
+ "z": 1.0
+ },
+ {
+ "x": 88.39203641514422,
+ "y": -144.94658613686346,
+ "z": 1.0
+ },
+ {
+ "x": 88.39209734347294,
+ "y": -145.34739694304335,
+ "z": 1.0
+ },
+ {
+ "x": 88.39217350388387,
+ "y": -145.84841045076791,
+ "z": 1.0
+ },
+ {
+ "x": 88.3922344322126,
+ "y": -146.2492212569481,
+ "z": 1.0
+ },
+ {
+ "x": 88.39229536054133,
+ "y": -146.65003206312798,
+ "z": 1.0
+ },
+ {
+ "x": 88.39235628887006,
+ "y": -147.05084286930781,
+ "z": 1.0
+ },
+ {
+ "x": 88.3924172171988,
+ "y": -147.4516536754877,
+ "z": 1.0
+ },
+ {
+ "x": 88.39249337760971,
+ "y": -147.95266718321255,
+ "z": 1.0
+ },
+ {
+ "x": 88.39258477010281,
+ "y": -148.55388339248236,
+ "z": 1.0
+ },
+ {
+ "x": 88.39266093051373,
+ "y": -149.0548969002072,
+ "z": 1.0
+ },
+ {
+ "x": 88.39273709092465,
+ "y": -149.55591040793178,
+ "z": 1.0
+ },
+ {
+ "x": 88.39281325133557,
+ "y": -150.05692391565663,
+ "z": 1.0
+ },
+ {
+ "x": 88.3928741796643,
+ "y": -150.45773472183646,
+ "z": 1.0
+ },
+ {
+ "x": 88.39293510799303,
+ "y": -150.85854552801663,
+ "z": 1.0
+ },
+ {
+ "x": 88.39299603632178,
+ "y": -151.25935633419624,
+ "z": 1.0
+ },
+ {
+ "x": 88.39308742881487,
+ "y": -151.86057254346605,
+ "z": 1.0
+ },
+ {
+ "x": 88.39316358922578,
+ "y": -152.36158605119118,
+ "z": 1.0
+ },
+ {
+ "x": 88.39322451755451,
+ "y": -152.76239685737107,
+ "z": 1.0
+ },
+ {
+ "x": 88.39328544588325,
+ "y": -153.16320766355062,
+ "z": 1.0
+ },
+ {
+ "x": 88.39337683837634,
+ "y": -153.76442387282077,
+ "z": 1.0
+ },
+ {
+ "x": 88.39346823086944,
+ "y": -154.36564008209058,
+ "z": 1.0
+ },
+ {
+ "x": 88.39352915919818,
+ "y": -154.7664508882704,
+ "z": 1.0
+ },
+ {
+ "x": 88.39362055169128,
+ "y": -155.36766709754022,
+ "z": 1.0
+ },
+ {
+ "x": 88.39371194418439,
+ "y": -155.9688833068098,
+ "z": 1.0
+ },
+ {
+ "x": 88.3937881045953,
+ "y": -156.4698968145346,
+ "z": 1.0
+ },
+ {
+ "x": 88.39386426500621,
+ "y": -156.97091032225944,
+ "z": 1.0
+ },
+ {
+ "x": 88.39392519333495,
+ "y": -157.37172112843933,
+ "z": 1.0
+ },
+ {
+ "x": 88.39401658582806,
+ "y": -157.97293733770914,
+ "z": 1.0
+ },
+ {
+ "x": 88.39409274623897,
+ "y": -158.47395084543427,
+ "z": 1.0
+ },
+ {
+ "x": 88.39418413873207,
+ "y": -159.0751670547038,
+ "z": 1.0
+ },
+ {
+ "x": 88.39426029914299,
+ "y": -159.57618056242865,
+ "z": 1.0
+ },
+ {
+ "x": 88.3943364595539,
+ "y": -160.0771940701535,
+ "z": 1.0
+ },
+ {
+ "x": 88.39439738788263,
+ "y": -160.4780048763334,
+ "z": 1.0
+ },
+ {
+ "x": 88.39445831621137,
+ "y": -160.87881568251328,
+ "z": 1.0
+ },
+ {
+ "x": 88.39454970870446,
+ "y": -161.48003189178337,
+ "z": 1.0
+ },
+ {
+ "x": 88.39462586911537,
+ "y": -161.98104539950816,
+ "z": 1.0
+ },
+ {
+ "x": 88.39471726160848,
+ "y": -162.58226160877803,
+ "z": 1.0
+ },
+ {
+ "x": 88.39480865410158,
+ "y": -163.18347781804755,
+ "z": 1.0
+ },
+ {
+ "x": 88.39490004659467,
+ "y": -163.78469402731764,
+ "z": 1.0
+ },
+ {
+ "x": 88.3949609749234,
+ "y": -164.18550483349753,
+ "z": 1.0
+ },
+ {
+ "x": 88.39502190325214,
+ "y": -164.58631563967737,
+ "z": 1.0
+ },
+ {
+ "x": 88.39509806366306,
+ "y": -165.08732914740222,
+ "z": 1.0
+ },
+ {
+ "x": 88.39517422407398,
+ "y": -165.58834265512678,
+ "z": 1.0
+ },
+ {
+ "x": 88.3952503844849,
+ "y": -166.0893561628519,
+ "z": 1.0
+ },
+ {
+ "x": 88.39532654489581,
+ "y": -166.59036967057676,
+ "z": 1.0
+ },
+ {
+ "x": 88.39540270530674,
+ "y": -167.09138317830133,
+ "z": 1.0
+ },
+ {
+ "x": 88.39547886571765,
+ "y": -167.59239668602618,
+ "z": 1.0
+ },
+ {
+ "x": 88.39555502612856,
+ "y": -168.09341019375103,
+ "z": 1.0
+ },
+ {
+ "x": 88.39563118653948,
+ "y": -168.59442370147616,
+ "z": 1.0
+ },
+ {
+ "x": 88.39570734695039,
+ "y": -169.09543720920095,
+ "z": 1.0
+ },
+ {
+ "x": 88.39579873944349,
+ "y": -169.69665341847082,
+ "z": 1.0
+ },
+ {
+ "x": 88.3958748998544,
+ "y": -170.19766692619567,
+ "z": 1.0
+ },
+ {
+ "x": 88.39595106026533,
+ "y": -170.69868043392017,
+ "z": 1.0
+ },
+ {
+ "x": 88.39602722067625,
+ "y": -171.1996939416453,
+ "z": 1.0
+ },
+ {
+ "x": 88.39611861316935,
+ "y": -171.80091015091483,
+ "z": 1.0
+ },
+ {
+ "x": 88.39619477358026,
+ "y": -172.30192365863996,
+ "z": 1.0
+ },
+ {
+ "x": 88.39625570190898,
+ "y": -172.70273446481986,
+ "z": 1.0
+ },
+ {
+ "x": 88.39634709440209,
+ "y": -173.30395067408966,
+ "z": 1.0
+ },
+ {
+ "x": 88.39643848689519,
+ "y": -173.9051668833592,
+ "z": 1.0
+ },
+ {
+ "x": 88.39651464730612,
+ "y": -174.40618039108404,
+ "z": 1.0
+ },
+ {
+ "x": 88.39657557563484,
+ "y": -174.80699119726415,
+ "z": 1.0
+ },
+ {
+ "x": 88.39665173604575,
+ "y": -175.308004704989,
+ "z": 1.0
+ },
+ {
+ "x": 88.39671266437449,
+ "y": -175.70881551116884,
+ "z": 1.0
+ },
+ {
+ "x": 88.3968040568676,
+ "y": -176.31003172043836,
+ "z": 1.0
+ },
+ {
+ "x": 88.39688021727851,
+ "y": -176.8110452281632,
+ "z": 1.0
+ },
+ {
+ "x": 88.39695637768943,
+ "y": -177.312058735888,
+ "z": 1.0
+ },
+ {
+ "x": 88.39701730601816,
+ "y": -177.71286954206818,
+ "z": 1.0
+ },
+ {
+ "x": 88.39710869851126,
+ "y": -178.3140857513377,
+ "z": 1.0
+ },
+ {
+ "x": 88.39720009100436,
+ "y": -178.91530196060745,
+ "z": 1.0
+ },
+ {
+ "x": 88.39729148349745,
+ "y": -179.51651816987754,
+ "z": 1.0
+ },
+ {
+ "x": 88.39738287599056,
+ "y": -180.11773437914735,
+ "z": 1.0
+ },
+ {
+ "x": 88.3974438043193,
+ "y": -180.5185451853269,
+ "z": 1.0
+ },
+ {
+ "x": 88.39750473264803,
+ "y": -180.9193559915068,
+ "z": 1.0
+ },
+ {
+ "x": 88.39756566097675,
+ "y": -181.3201667976869,
+ "z": 1.0
+ },
+ {
+ "x": 88.39764182138767,
+ "y": -181.82118030541176,
+ "z": 1.0
+ },
+ {
+ "x": 88.39770274971642,
+ "y": -182.2219911115913,
+ "z": 1.0
+ },
+ {
+ "x": 88.39776367804514,
+ "y": -182.62280191777148,
+ "z": 1.0
+ },
+ {
+ "x": 88.39782460637387,
+ "y": -183.02361272395103,
+ "z": 1.0
+ },
+ {
+ "x": 88.3979007667848,
+ "y": -183.5246262316756,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 2,
+ "heading": [
+ -1.5706443141063071,
+ -1.5706443141062971,
+ -1.5706443141062971,
+ -1.57064431410631,
+ -1.5706443141063113,
+ -1.5706443141062971,
+ -1.5706443141064466,
+ -1.5706443141063546,
+ -1.5706443141062902,
+ -1.5706443141063045,
+ -1.5706443141063122,
+ -1.570644314106298,
+ -1.570644314106298,
+ -1.5706443141063335,
+ -1.570644314106306,
+ -1.5706443141062902,
+ -1.5706443141063158,
+ -1.5706443141063158,
+ -1.570644314106298,
+ -1.570644314106306,
+ -1.5706443141063045,
+ -1.5706443141063045,
+ -1.570644314106298,
+ -1.570644314106298,
+ -1.570644314106306,
+ -1.5706443141063158,
+ -1.570644314106298,
+ -1.570644314106298,
+ -1.5706443141063176,
+ -1.570644314106306,
+ -1.570644314106298,
+ -1.5706443141063122,
+ -1.57064431410631,
+ -1.570644314106298,
+ -1.570644314106298,
+ -1.570644314106298,
+ -1.5706443141063045,
+ -1.5706443141063122,
+ -1.570644314106306,
+ -1.570644314106298,
+ -1.5706443141063047,
+ -1.5706443141063045,
+ -1.5706443141063045,
+ -1.5706443141063122,
+ -1.570644314106306,
+ -1.570644314106298,
+ -1.5706443141063122,
+ -1.5706443141063176,
+ -1.5706443141063045,
+ -1.570644314106298,
+ -1.57064431410631,
+ -1.5706443141063122,
+ -1.570644314106298,
+ -1.570644314106306,
+ -1.570644314106298,
+ -1.570644314106298,
+ -1.5706443141063122,
+ -1.570644314106298,
+ -1.570644314106298,
+ -1.5706443141063122,
+ -1.5706443141063122,
+ -1.5706443141063122,
+ -1.5706443141063045,
+ -1.5706443141063045,
+ -1.570644314106298,
+ -1.570644314106298,
+ -1.5706443141063045,
+ -1.5706443141063045,
+ -1.5706443141063218,
+ -1.5706443141063122,
+ -1.570644314106298,
+ -1.5706443141062916,
+ -1.570644314106306,
+ -1.5706443141063218,
+ -1.570644314106306,
+ -1.570644314106298,
+ -1.5706443141063045,
+ -1.570644314106298,
+ -1.570644314106306,
+ -1.5706443141063122,
+ -1.570644314106298,
+ -1.57064431410631,
+ -1.57064431410631,
+ -1.570644314106298,
+ -1.570644314106298,
+ -1.5706443141063158,
+ -1.5706443141063218,
+ -1.5706443141062902,
+ -1.570644314106298,
+ -1.5706443141063158,
+ -1.57064431410629
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": 0.0007658494773465918,
+ "y": -5.0380627992535665
+ },
+ {
+ "x": 0.001684868850162502,
+ "y": -11.08373815835705
+ },
+ {
+ "x": 0.0016848688500203934,
+ "y": -11.08373815835705
+ },
+ {
+ "x": 0.001531698954551075,
+ "y": -10.076125598506565
+ },
+ {
+ "x": 0.0007658494773465918,
+ "y": -5.038062799252998
+ },
+ {
+ "x": 0.0006097340981625621,
+ "y": -4.011073678671551
+ },
+ {
+ "x": 0.001219017385665211,
+ "y": -8.019181740470458
+ },
+ {
+ "x": 0.0013708873966322699,
+ "y": -9.0182431390474
+ },
+ {
+ "x": 0.0016755290401704315,
+ "y": -11.022297169943727
+ },
+ {
+ "x": 0.0015232082182592421,
+ "y": -10.020270154496984
+ },
+ {
+ "x": 0.0012185665747210805,
+ "y": -8.016216123594972
+ },
+ {
+ "x": 0.0012185665747210805,
+ "y": -8.016216123597246
+ },
+ {
+ "x": 0.0012185665744368634,
+ "y": -8.01621612360293
+ },
+ {
+ "x": 0.0013708873964901613,
+ "y": -9.018243139044557
+ },
+ {
+ "x": 0.0013708873966322699,
+ "y": -9.0182431390474
+ },
+ {
+ "x": 0.001218566574578972,
+ "y": -8.016216123600657
+ },
+ {
+ "x": 0.001218566574578972,
+ "y": -8.016216123597246
+ },
+ {
+ "x": 0.0012185665747210805,
+ "y": -8.016216123597246
+ },
+ {
+ "x": 0.0013708873964901613,
+ "y": -9.0182431390474
+ },
+ {
+ "x": 0.0016755290401704315,
+ "y": -11.022297169946569
+ },
+ {
+ "x": 0.0016755290401704315,
+ "y": -11.022297169946569
+ },
+ {
+ "x": 0.0015232082184013507,
+ "y": -10.020270154494142
+ },
+ {
+ "x": 0.0015232082184013507,
+ "y": -10.020270154494142
+ },
+ {
+ "x": 0.0013708873964901613,
+ "y": -9.018243139046831
+ },
+ {
+ "x": 0.001218566574578972,
+ "y": -8.016216123600088
+ },
+ {
+ "x": 0.0012185665747210805,
+ "y": -8.016216123597815
+ },
+ {
+ "x": 0.0015232082184013507,
+ "y": -10.020270154494142
+ },
+ {
+ "x": 0.001675529040028323,
+ "y": -11.022297169949411
+ },
+ {
+ "x": 0.0013708873964901613,
+ "y": -9.018243139050242
+ },
+ {
+ "x": 0.0012185665747210805,
+ "y": -8.016216123594404
+ },
+ {
+ "x": 0.0015232082182592421,
+ "y": -10.020270154496984
+ },
+ {
+ "x": 0.0018278498619395123,
+ "y": -12.024324185399564
+ },
+ {
+ "x": 0.0015232082184013507,
+ "y": -10.020270154496416
+ },
+ {
+ "x": 0.0015232082184013507,
+ "y": -10.020270154496416
+ },
+ {
+ "x": 0.0018278498620816208,
+ "y": -12.02432418539388
+ },
+ {
+ "x": 0.0016755290401704315,
+ "y": -11.022297169943727
+ },
+ {
+ "x": 0.0015232082182592421,
+ "y": -10.020270154496416
+ },
+ {
+ "x": 0.0013708873964901613,
+ "y": -9.0182431390474
+ },
+ {
+ "x": 0.0015232082184013507,
+ "y": -10.020270154496984
+ },
+ {
+ "x": 0.0016755290401704315,
+ "y": -11.022297169949411
+ },
+ {
+ "x": 0.0016755290401704315,
+ "y": -11.022297169946569
+ },
+ {
+ "x": 0.0016755290401704315,
+ "y": -11.022297169943727
+ },
+ {
+ "x": 0.0015232082182592421,
+ "y": -10.020270154496984
+ },
+ {
+ "x": 0.0013708873964901613,
+ "y": -9.0182431390474
+ },
+ {
+ "x": 0.0012185665747210805,
+ "y": -8.016216123597815
+ },
+ {
+ "x": 0.0015232082182592421,
+ "y": -10.020270154499826
+ },
+ {
+ "x": 0.001675529040028323,
+ "y": -11.022297169948843
+ },
+ {
+ "x": 0.0016755290401704315,
+ "y": -11.022297169946569
+ },
+ {
+ "x": 0.0018278498620816208,
+ "y": -12.02432418539388
+ },
+ {
+ "x": 0.0018278498619395123,
+ "y": -12.024324185396154
+ },
+ {
+ "x": 0.0015232082182592421,
+ "y": -10.020270154499826
+ },
+ {
+ "x": 0.0012185665747210805,
+ "y": -8.016216123597246
+ },
+ {
+ "x": 0.0013708873964901613,
+ "y": -9.018243139046831
+ },
+ {
+ "x": 0.0015232082184013507,
+ "y": -10.020270154494142
+ },
+ {
+ "x": 0.0015232082184013507,
+ "y": -10.020270154496984
+ },
+ {
+ "x": 0.0015232082182592421,
+ "y": -10.020270154499826
+ },
+ {
+ "x": 0.0015232082184013507,
+ "y": -10.020270154494142
+ },
+ {
+ "x": 0.0015232082184013507,
+ "y": -10.020270154494142
+ },
+ {
+ "x": 0.0015232082182592421,
+ "y": -10.020270154496984
+ },
+ {
+ "x": 0.0015232082182592421,
+ "y": -10.020270154499826
+ },
+ {
+ "x": 0.0015232082182592421,
+ "y": -10.020270154499258
+ },
+ {
+ "x": 0.0016755290401704315,
+ "y": -11.022297169946569
+ },
+ {
+ "x": 0.0016755290401704315,
+ "y": -11.022297169947137
+ },
+ {
+ "x": 0.0015232082184013507,
+ "y": -10.020270154493574
+ },
+ {
+ "x": 0.0015232082184013507,
+ "y": -10.020270154496416
+ },
+ {
+ "x": 0.0016755290401704315,
+ "y": -11.022297169946569
+ },
+ {
+ "x": 0.0016755290401704315,
+ "y": -11.022297169946569
+ },
+ {
+ "x": 0.0013708873963480528,
+ "y": -9.018243139050242
+ },
+ {
+ "x": 0.0015232082182592421,
+ "y": -10.020270154496984
+ },
+ {
+ "x": 0.0018278498620816208,
+ "y": -12.024324185393311
+ },
+ {
+ "x": 0.00167552904031254,
+ "y": -11.022297169943727
+ },
+ {
+ "x": 0.0013708873964901613,
+ "y": -9.018243139049673
+ },
+ {
+ "x": 0.0013708873963480528,
+ "y": -9.018243139049673
+ },
+ {
+ "x": 0.0013708873964901613,
+ "y": -9.018243139046831
+ },
+ {
+ "x": 0.0015232082184013507,
+ "y": -10.020270154493574
+ },
+ {
+ "x": 0.0016755290401704315,
+ "y": -11.022297169943727
+ },
+ {
+ "x": 0.0015232082184013507,
+ "y": -10.020270154496416
+ },
+ {
+ "x": 0.0013708873964901613,
+ "y": -9.018243139049673
+ },
+ {
+ "x": 0.0015232082182592421,
+ "y": -10.020270154496984
+ },
+ {
+ "x": 0.0018278498620816208,
+ "y": -12.024324185392743
+ },
+ {
+ "x": 0.0018278498619395123,
+ "y": -12.024324185398427
+ },
+ {
+ "x": 0.0018278498619395123,
+ "y": -12.024324185398996
+ },
+ {
+ "x": 0.0015232082184013507,
+ "y": -10.020270154493574
+ },
+ {
+ "x": 0.0012185665747210805,
+ "y": -8.016216123594404
+ },
+ {
+ "x": 0.001218566574578972,
+ "y": -8.016216123600088
+ },
+ {
+ "x": 0.0013708873963480528,
+ "y": -9.018243139049673
+ },
+ {
+ "x": 0.0013708873966322699,
+ "y": -9.018243139043989
+ },
+ {
+ "x": 0.0012185665747210805,
+ "y": -8.016216123597246
+ },
+ {
+ "x": 0.001218566574578972,
+ "y": -8.016216123597246
+ },
+ {
+ "x": 0.0013708873966322699,
+ "y": -9.018243139041147
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 88.3979007667848,
+ "y": -183.5246262316756,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 92.17738470449606,
+ "y": -5.543033931552639,
+ "z": 1.0
+ },
+ {
+ "x": 92.02893835203474,
+ "y": -4.9254451369259495,
+ "z": 1.0
+ },
+ {
+ "x": 91.83953272702882,
+ "y": -4.319165007001053,
+ "z": 1.0
+ },
+ {
+ "x": 91.55938507168747,
+ "y": -3.6103693432412705,
+ "z": 1.0
+ },
+ {
+ "x": 91.2232886141611,
+ "y": -2.92632261465836,
+ "z": 1.0
+ },
+ {
+ "x": 90.90160151268881,
+ "y": -2.3777725998696635,
+ "z": 1.0
+ },
+ {
+ "x": 90.46849895465499,
+ "y": -1.750514037920517,
+ "z": 1.0
+ },
+ {
+ "x": 89.98654266873672,
+ "y": -1.1600946235224388,
+ "z": 1.0
+ },
+ {
+ "x": 89.54979571361987,
+ "y": -0.6989172678760334,
+ "z": 1.0
+ },
+ {
+ "x": 89.08343174905256,
+ "y": -0.2681208996727509,
+ "z": 1.0
+ },
+ {
+ "x": 88.58937810804395,
+ "y": 0.13059820714422288,
+ "z": 1.0
+ },
+ {
+ "x": 87.96305420654113,
+ "y": 0.5642434078047397,
+ "z": 1.0
+ },
+ {
+ "x": 87.30318887392193,
+ "y": 0.9465681376052837,
+ "z": 1.0
+ },
+ {
+ "x": 86.73196755078408,
+ "y": 1.2236474556272232,
+ "z": 1.0
+ },
+ {
+ "x": 86.0240164078902,
+ "y": 1.5049320036980738,
+ "z": 1.0
+ },
+ {
+ "x": 85.41840054260388,
+ "y": 1.6954362312776485,
+ "z": 1.0
+ },
+ {
+ "x": 84.67690593435475,
+ "y": 1.8700932166469466,
+ "z": 1.0
+ },
+ {
+ "x": 83.923806202719,
+ "y": 1.9848547149246605,
+ "z": 1.0
+ },
+ {
+ "x": 83.41683773555708,
+ "y": 2.027617963707917,
+ "z": 1.0
+ },
+ {
+ "x": 82.90914004207372,
+ "y": 2.043181161697282,
+ "z": 1.0
+ },
+ {
+ "x": 82.48887153292773,
+ "y": 2.0432892540786893,
+ "z": 1.0
+ },
+ {
+ "x": 81.88708783985336,
+ "y": 2.043093126861388,
+ "z": 1.0
+ },
+ {
+ "x": 81.28530414677901,
+ "y": 2.0428969996440856,
+ "z": 1.0
+ },
+ {
+ "x": 80.88411501806277,
+ "y": 2.0427662481658846,
+ "z": 1.0
+ },
+ {
+ "x": 80.38262860716748,
+ "y": 2.042602808818133,
+ "z": 1.0
+ },
+ {
+ "x": 79.88114219627218,
+ "y": 2.0424393694703813,
+ "z": 1.0
+ },
+ {
+ "x": 79.37965578537688,
+ "y": 2.0422759301226296,
+ "z": 1.0
+ },
+ {
+ "x": 78.8789939970618,
+ "y": 2.0421127595274697,
+ "z": 1.0
+ },
+ {
+ "x": 78.37862787552477,
+ "y": 2.0419496852930257,
+ "z": 1.0
+ },
+ {
+ "x": 77.77818852968032,
+ "y": 2.0417539962116917,
+ "z": 1.0
+ },
+ {
+ "x": 77.2778224081433,
+ "y": 2.0415909219772477,
+ "z": 1.0
+ },
+ {
+ "x": 76.77745628660625,
+ "y": 2.0414278477428027,
+ "z": 1.0
+ },
+ {
+ "x": 76.27709016506921,
+ "y": 2.0412647735083587,
+ "z": 1.0
+ },
+ {
+ "x": 75.77672404353218,
+ "y": 2.0411016992739137,
+ "z": 1.0
+ },
+ {
+ "x": 75.37643114630255,
+ "y": 2.0409712398863586,
+ "z": 1.0
+ },
+ {
+ "x": 74.97613824907293,
+ "y": 2.0408407804988027,
+ "z": 1.0
+ },
+ {
+ "x": 74.47577212753589,
+ "y": 2.0406777062643586,
+ "z": 1.0
+ },
+ {
+ "x": 73.97540600599886,
+ "y": 2.0405146320299137,
+ "z": 1.0
+ },
+ {
+ "x": 73.57511310876923,
+ "y": 2.0403841726423577,
+ "z": 1.0
+ },
+ {
+ "x": 73.1748202115396,
+ "y": 2.0402537132548026,
+ "z": 1.0
+ },
+ {
+ "x": 72.67445409000257,
+ "y": 2.0400906390203577,
+ "z": 1.0
+ },
+ {
+ "x": 72.27416119277294,
+ "y": 2.0399601796328026,
+ "z": 1.0
+ },
+ {
+ "x": 71.7737950712359,
+ "y": 2.039797105398358,
+ "z": 1.0
+ },
+ {
+ "x": 71.37350217400628,
+ "y": 2.0396666460108026,
+ "z": 1.0
+ },
+ {
+ "x": 70.87313605246923,
+ "y": 2.0395035717763577,
+ "z": 1.0
+ },
+ {
+ "x": 70.37276993093221,
+ "y": 2.0393404975419136,
+ "z": 1.0
+ },
+ {
+ "x": 69.77233058508776,
+ "y": 2.0391448084605797,
+ "z": 1.0
+ },
+ {
+ "x": 69.17189123924332,
+ "y": 2.0389491193792466,
+ "z": 1.0
+ },
+ {
+ "x": 68.57145189339887,
+ "y": 2.0387534302979127,
+ "z": 1.0
+ },
+ {
+ "x": 67.97101254755444,
+ "y": 2.0385577412165796,
+ "z": 1.0
+ },
+ {
+ "x": 67.4706464260174,
+ "y": 2.0383946669821356,
+ "z": 1.0
+ },
+ {
+ "x": 67.07035352878778,
+ "y": 2.0382642075945796,
+ "z": 1.0
+ },
+ {
+ "x": 66.46991418294333,
+ "y": 2.0380685185132466,
+ "z": 1.0
+ },
+ {
+ "x": 65.9695480614063,
+ "y": 2.0379054442788016,
+ "z": 1.0
+ },
+ {
+ "x": 65.36910871556185,
+ "y": 2.0377097551974686,
+ "z": 1.0
+ },
+ {
+ "x": 64.96881581833222,
+ "y": 2.037579295809913,
+ "z": 1.0
+ },
+ {
+ "x": 64.36837647248778,
+ "y": 2.0373836067285795,
+ "z": 1.0
+ },
+ {
+ "x": 63.96808357525816,
+ "y": 2.0372531473410236,
+ "z": 1.0
+ },
+ {
+ "x": 63.36764422941371,
+ "y": 2.0370574582596905,
+ "z": 1.0
+ },
+ {
+ "x": 62.76720488356926,
+ "y": 2.0368617691783566,
+ "z": 1.0
+ },
+ {
+ "x": 62.36691198633963,
+ "y": 2.0367313097908015,
+ "z": 1.0
+ },
+ {
+ "x": 61.96661908911,
+ "y": 2.0366008504032456,
+ "z": 1.0
+ },
+ {
+ "x": 61.56632619188035,
+ "y": 2.0364703910156896,
+ "z": 1.0
+ },
+ {
+ "x": 61.16603329465072,
+ "y": 2.0363399316281345,
+ "z": 1.0
+ },
+ {
+ "x": 60.665667173113675,
+ "y": 2.0361768573936896,
+ "z": 1.0
+ },
+ {
+ "x": 60.065227827269226,
+ "y": 2.0359811683123565,
+ "z": 1.0
+ },
+ {
+ "x": 59.464788481424776,
+ "y": 2.0357854792310235,
+ "z": 1.0
+ },
+ {
+ "x": 58.964422359887735,
+ "y": 2.0356224049965785,
+ "z": 1.0
+ },
+ {
+ "x": 58.36398301404327,
+ "y": 2.0354267159152455,
+ "z": 1.0
+ },
+ {
+ "x": 57.76354366819882,
+ "y": 2.0352310268339115,
+ "z": 1.0
+ },
+ {
+ "x": 57.26317754666178,
+ "y": 2.0350679525994675,
+ "z": 1.0
+ },
+ {
+ "x": 56.66273820081733,
+ "y": 2.0348722635181336,
+ "z": 1.0
+ },
+ {
+ "x": 56.062298854972866,
+ "y": 2.0346765744368005,
+ "z": 1.0
+ },
+ {
+ "x": 55.66200595774323,
+ "y": 2.0345461150492445,
+ "z": 1.0
+ },
+ {
+ "x": 55.06156661189878,
+ "y": 2.0343504259679115,
+ "z": 1.0
+ },
+ {
+ "x": 54.56120049036174,
+ "y": 2.0341873517334665,
+ "z": 1.0
+ },
+ {
+ "x": 53.96076114451729,
+ "y": 2.0339916626521335,
+ "z": 1.0
+ },
+ {
+ "x": 53.46039502298024,
+ "y": 2.0338285884176894,
+ "z": 1.0
+ },
+ {
+ "x": 53.0601021257506,
+ "y": 2.0336981290301335,
+ "z": 1.0
+ },
+ {
+ "x": 52.65980922852097,
+ "y": 2.0335676696425775,
+ "z": 1.0
+ },
+ {
+ "x": 52.25951633129134,
+ "y": 2.0334372102550224,
+ "z": 1.0
+ },
+ {
+ "x": 51.859223434061704,
+ "y": 2.0333067508674665,
+ "z": 1.0
+ },
+ {
+ "x": 51.258784088217254,
+ "y": 2.0331110617861334,
+ "z": 1.0
+ },
+ {
+ "x": 50.65834474237279,
+ "y": 2.0329153727047995,
+ "z": 1.0
+ },
+ {
+ "x": 50.25805184514316,
+ "y": 2.0327849133172444,
+ "z": 1.0
+ },
+ {
+ "x": 49.65761249929871,
+ "y": 2.0325892242359105,
+ "z": 1.0
+ },
+ {
+ "x": 49.257319602069074,
+ "y": 2.0324587648483554,
+ "z": 1.0
+ },
+ {
+ "x": 48.85702670483944,
+ "y": 2.0323283054607995,
+ "z": 1.0
+ },
+ {
+ "x": 48.25658735899499,
+ "y": 2.0321326163794664,
+ "z": 1.0
+ },
+ {
+ "x": 47.65614801315053,
+ "y": 2.0319369272981325,
+ "z": 1.0
+ },
+ {
+ "x": 47.155781891613486,
+ "y": 2.0317738530636884,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 3,
+ "heading": [
+ -1.8948221592538605,
+ 1.8066858210761172,
+ 1.8401406999963243,
+ 1.913741599788107,
+ 1.9873425501355715,
+ 2.0610054059259815,
+ 2.1414792235087416,
+ 2.215243017273065,
+ 2.2888481200291793,
+ 2.362398683948051,
+ 2.4291969436707634,
+ 2.5026304445853182,
+ 2.5762559620189145,
+ 2.649850799449807,
+ 2.730018525577581,
+ 2.7967754706062085,
+ 2.8768838068652123,
+ 2.950316514123116,
+ 3.017224983051775,
+ 3.0841724570389077,
+ 3.124706477370499,
+ -3.141506518228522,
+ -3.141266743777655,
+ -3.1412667437776545,
+ -3.141266743777655,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776465,
+ -3.141266743777647,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776536,
+ -3.141266743777655,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.141266743777655,
+ -3.1412667437776545,
+ -3.141266743777654,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776554,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.141266743777655,
+ -3.1412667437776545,
+ -3.141266743777654,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.141266743777655,
+ -3.1412667437776536,
+ -3.141266743777655,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.141266743777655,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776554,
+ -3.1412667437776545,
+ -3.1412667437776536,
+ -3.141266743777655,
+ -3.141266743777655,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.141266743777655,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -1.4844635246132043,
+ "y": 6.175887946266894
+ },
+ {
+ "x": -3.378519774672384,
+ "y": 12.23868924551586
+ },
+ {
+ "x": -4.695532803472702,
+ "y": 13.15075793684679
+ },
+ {
+ "x": -6.162441128677187,
+ "y": 13.928423923426928
+ },
+ {
+ "x": -6.5778355899865915,
+ "y": 12.32596743371607
+ },
+ {
+ "x": -7.547896595061161,
+ "y": 11.758085767378429
+ },
+ {
+ "x": -9.15058843952096,
+ "y": 12.176779763472247
+ },
+ {
+ "x": -9.18703241035118,
+ "y": 10.515967700444836
+ },
+ {
+ "x": -9.031109196841527,
+ "y": 8.919737238496879
+ },
+ {
+ "x": -9.604176055759268,
+ "y": 8.295154750202562
+ },
+ {
+ "x": -11.203775425114344,
+ "y": 8.323643074774905
+ },
+ {
+ "x": -12.861892341220198,
+ "y": 8.159699304610607
+ },
+ {
+ "x": -12.310866557570534,
+ "y": 6.5940404782248345
+ },
+ {
+ "x": -12.791724660317243,
+ "y": 5.5836386609279005
+ },
+ {
+ "x": -13.135670081802004,
+ "y": 4.717887756504253
+ },
+ {
+ "x": -13.471104735354515,
+ "y": 3.6516121294887283
+ },
+ {
+ "x": -14.945943398848698,
+ "y": 2.8941848364701195
+ },
+ {
+ "x": -12.600681987976685,
+ "y": 1.575247470609702
+ },
+ {
+ "x": -10.14666160645291,
+ "y": 0.5832644677262144
+ },
+ {
+ "x": -9.279662026293494,
+ "y": 0.15671290370772528
+ },
+ {
+ "x": -10.220522022203511,
+ "y": -0.0008803483589403527
+ },
+ {
+ "x": -12.035673861487197,
+ "y": -0.003922544346037782
+ },
+ {
+ "x": -10.029728217905927,
+ "y": -0.003268786955032965
+ },
+ {
+ "x": -9.026755396115362,
+ "y": -0.002941908259526116
+ },
+ {
+ "x": -10.029728217905927,
+ "y": -0.003268786955032965
+ },
+ {
+ "x": -10.029728217905927,
+ "y": -0.003268786955032965
+ },
+ {
+ "x": -10.021481992103816,
+ "y": -0.0032660994291155987
+ },
+ {
+ "x": -10.010279098521124,
+ "y": -0.0032624482960397216
+ },
+ {
+ "x": -11.008054673814769,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -11.008054673814769,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -10.007322430740686,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -10.007322430740686,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -8.00585794459252,
+ "y": -0.002609187751110298
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -10.007322430740686,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.002935336220009077
+ },
+ {
+ "x": -8.005857944592663,
+ "y": -0.002609187751110298
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -9.006590187666745,
+ "y": -0.0029353362199957544
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200046362
+ },
+ {
+ "x": -10.007322430740686,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -11.008054673814769,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -12.008786916888852,
+ "y": -0.003913781626669888
+ },
+ {
+ "x": -12.008786916888852,
+ "y": -0.003913781626669888
+ },
+ {
+ "x": -12.008786916888852,
+ "y": -0.003913781626669888
+ },
+ {
+ "x": -11.008054673814769,
+ "y": -0.0035876331577711085
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -10.007322430740686,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -11.008054673814769,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -11.008054673814769,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688885652
+ },
+ {
+ "x": -10.007322430740686,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -10.007322430740544,
+ "y": -0.0032614846888945337
+ },
+ {
+ "x": -10.007322430740686,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -12.008786916888994,
+ "y": -0.003913781626669888
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -8.005857944592663,
+ "y": -0.002609187751110298
+ },
+ {
+ "x": -8.005857944592805,
+ "y": -0.0026091877511191797
+ },
+ {
+ "x": -8.005857944592805,
+ "y": -0.002609187751110298
+ },
+ {
+ "x": -9.006590187666745,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -12.008786916888994,
+ "y": -0.003913781626661006
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -11.008054673815053,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -12.008786916889136,
+ "y": -0.003913781626669888
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -12.008786916889136,
+ "y": -0.003913781626669888
+ },
+ {
+ "x": -10.00732243074097,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -11.008054673815053,
+ "y": -0.0035876331577711085
+ },
+ {
+ "x": -9.006590187666887,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -8.005857944592663,
+ "y": -0.0026091877511191797
+ },
+ {
+ "x": -8.005857944592663,
+ "y": -0.002609187751110298
+ },
+ {
+ "x": -8.005857944592663,
+ "y": -0.002609187751110298
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -12.008786916889136,
+ "y": -0.003913781626669888
+ },
+ {
+ "x": -10.00732243074097,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -8.005857944592663,
+ "y": -0.002609187751110298
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -12.008786916889136,
+ "y": -0.003913781626669888
+ },
+ {
+ "x": -11.008054673815053,
+ "y": -0.0035876331577799903
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 47.155781891613486,
+ "y": 2.0317738530636884,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 161.64683250352334,
+ "y": 2.0437492128140557,
+ "z": 1.0
+ },
+ {
+ "x": 161.1442238107338,
+ "y": 2.0438028558703465,
+ "z": 1.0
+ },
+ {
+ "x": 160.64161511794427,
+ "y": 2.0438564989266377,
+ "z": 1.0
+ },
+ {
+ "x": 160.23952816371266,
+ "y": 2.0438994133716704,
+ "z": 1.0
+ },
+ {
+ "x": 159.63639773236523,
+ "y": 2.0439637850392196,
+ "z": 1.0
+ },
+ {
+ "x": 159.13378903957567,
+ "y": 2.0440174280955103,
+ "z": 1.0
+ },
+ {
+ "x": 158.53065860822824,
+ "y": 2.0440817997630596,
+ "z": 1.0
+ },
+ {
+ "x": 157.92752817688083,
+ "y": 2.0441461714306093,
+ "z": 1.0
+ },
+ {
+ "x": 157.5254412226492,
+ "y": 2.0441890858756424,
+ "z": 1.0
+ },
+ {
+ "x": 157.12335426841756,
+ "y": 2.044232000320675,
+ "z": 1.0
+ },
+ {
+ "x": 156.72126731418595,
+ "y": 2.0442749147657078,
+ "z": 1.0
+ },
+ {
+ "x": 156.2186586213964,
+ "y": 2.0443285578219985,
+ "z": 1.0
+ },
+ {
+ "x": 155.8165716671648,
+ "y": 2.044371472267032,
+ "z": 1.0
+ },
+ {
+ "x": 155.41448471293316,
+ "y": 2.0444143867120648,
+ "z": 1.0
+ },
+ {
+ "x": 154.91187602014364,
+ "y": 2.044468029768356,
+ "z": 1.0
+ },
+ {
+ "x": 154.40926732735412,
+ "y": 2.0445216728246467,
+ "z": 1.0
+ },
+ {
+ "x": 153.90665863456456,
+ "y": 2.0445753158809374,
+ "z": 1.0
+ },
+ {
+ "x": 153.50457168033296,
+ "y": 2.044618230325971,
+ "z": 1.0
+ },
+ {
+ "x": 152.90144124898552,
+ "y": 2.0446826019935203,
+ "z": 1.0
+ },
+ {
+ "x": 152.29831081763808,
+ "y": 2.0447469736610695,
+ "z": 1.0
+ },
+ {
+ "x": 151.89622386340645,
+ "y": 2.044789888106102,
+ "z": 1.0
+ },
+ {
+ "x": 151.293093432059,
+ "y": 2.0448542597736514,
+ "z": 1.0
+ },
+ {
+ "x": 150.79048473926946,
+ "y": 2.0449079028299426,
+ "z": 1.0
+ },
+ {
+ "x": 150.18735430792202,
+ "y": 2.044972274497492,
+ "z": 1.0
+ },
+ {
+ "x": 149.6847456151325,
+ "y": 2.045025917553783,
+ "z": 1.0
+ },
+ {
+ "x": 149.28265866090086,
+ "y": 2.0450688319988157,
+ "z": 1.0
+ },
+ {
+ "x": 148.6795282295534,
+ "y": 2.0451332036663645,
+ "z": 1.0
+ },
+ {
+ "x": 148.2774412753218,
+ "y": 2.045176118111398,
+ "z": 1.0
+ },
+ {
+ "x": 147.87535432109016,
+ "y": 2.045219032556431,
+ "z": 1.0
+ },
+ {
+ "x": 147.2722238897427,
+ "y": 2.04528340422398,
+ "z": 1.0
+ },
+ {
+ "x": 146.87013693551108,
+ "y": 2.0453263186690127,
+ "z": 1.0
+ },
+ {
+ "x": 146.36752824272153,
+ "y": 2.045379961725304,
+ "z": 1.0
+ },
+ {
+ "x": 145.9654412884899,
+ "y": 2.0454228761703366,
+ "z": 1.0
+ },
+ {
+ "x": 145.46283259570038,
+ "y": 2.0454765192266278,
+ "z": 1.0
+ },
+ {
+ "x": 145.06074564146874,
+ "y": 2.045519433671661,
+ "z": 1.0
+ },
+ {
+ "x": 144.96022390291083,
+ "y": 2.045530162282919,
+ "z": 1.0
+ },
+ {
+ "x": 144.5595603980998,
+ "y": 2.0455729248042416,
+ "z": 1.0
+ },
+ {
+ "x": 144.05873101708605,
+ "y": 2.045626377955895,
+ "z": 1.0
+ },
+ {
+ "x": 143.55790163607227,
+ "y": 2.045679831107548,
+ "z": 1.0
+ },
+ {
+ "x": 143.15723813126127,
+ "y": 2.0457225936288705,
+ "z": 1.0
+ },
+ {
+ "x": 142.75657462645026,
+ "y": 2.045765356150193,
+ "z": 1.0
+ },
+ {
+ "x": 142.25574524543651,
+ "y": 2.0458188093018466,
+ "z": 1.0
+ },
+ {
+ "x": 141.8550817406255,
+ "y": 2.045861571823169,
+ "z": 1.0
+ },
+ {
+ "x": 141.4544182358145,
+ "y": 2.045904334344492,
+ "z": 1.0
+ },
+ {
+ "x": 140.95358885480073,
+ "y": 2.045957787496145,
+ "z": 1.0
+ },
+ {
+ "x": 140.35259359758422,
+ "y": 2.0460219312781294,
+ "z": 1.0
+ },
+ {
+ "x": 139.85176421657047,
+ "y": 2.0460753844297823,
+ "z": 1.0
+ },
+ {
+ "x": 139.45110071175947,
+ "y": 2.046118146951105,
+ "z": 1.0
+ },
+ {
+ "x": 138.85010545454296,
+ "y": 2.046182290733089,
+ "z": 1.0
+ },
+ {
+ "x": 138.44944194973195,
+ "y": 2.0462250532544117,
+ "z": 1.0
+ },
+ {
+ "x": 138.04877844492094,
+ "y": 2.0462678157757344,
+ "z": 1.0
+ },
+ {
+ "x": 137.44778318770443,
+ "y": 2.046331959557718,
+ "z": 1.0
+ },
+ {
+ "x": 136.9469538066907,
+ "y": 2.0463854127093715,
+ "z": 1.0
+ },
+ {
+ "x": 136.54629030187968,
+ "y": 2.046428175230694,
+ "z": 1.0
+ },
+ {
+ "x": 136.14562679706867,
+ "y": 2.0464709377520167,
+ "z": 1.0
+ },
+ {
+ "x": 135.74496329225767,
+ "y": 2.0465137002733393,
+ "z": 1.0
+ },
+ {
+ "x": 135.34429978744666,
+ "y": 2.046556462794662,
+ "z": 1.0
+ },
+ {
+ "x": 134.94363628263565,
+ "y": 2.0465992253159846,
+ "z": 1.0
+ },
+ {
+ "x": 134.34264102541917,
+ "y": 2.0466633690979688,
+ "z": 1.0
+ },
+ {
+ "x": 133.74164576820266,
+ "y": 2.0467275128799525,
+ "z": 1.0
+ },
+ {
+ "x": 133.34098226339165,
+ "y": 2.046770275401275,
+ "z": 1.0
+ },
+ {
+ "x": 132.8401528823779,
+ "y": 2.0468237285529285,
+ "z": 1.0
+ },
+ {
+ "x": 132.2391576251614,
+ "y": 2.0468878723349127,
+ "z": 1.0
+ },
+ {
+ "x": 131.73832824414762,
+ "y": 2.0469413254865656,
+ "z": 1.0
+ },
+ {
+ "x": 131.23749886313388,
+ "y": 2.046994778638219,
+ "z": 1.0
+ },
+ {
+ "x": 130.73666948212013,
+ "y": 2.0470482317898724,
+ "z": 1.0
+ },
+ {
+ "x": 130.33600597730913,
+ "y": 2.047090994311195,
+ "z": 1.0
+ },
+ {
+ "x": 129.83517659629538,
+ "y": 2.0471444474628484,
+ "z": 1.0
+ },
+ {
+ "x": 129.43451309148438,
+ "y": 2.047187209984171,
+ "z": 1.0
+ },
+ {
+ "x": 129.03384958667337,
+ "y": 2.0472299725054937,
+ "z": 1.0
+ },
+ {
+ "x": 128.5330202056596,
+ "y": 2.0472834256571466,
+ "z": 1.0
+ },
+ {
+ "x": 128.1323567008486,
+ "y": 2.0473261881784692,
+ "z": 1.0
+ },
+ {
+ "x": 127.53136144363208,
+ "y": 2.0473903319604534,
+ "z": 1.0
+ },
+ {
+ "x": 127.13069793882107,
+ "y": 2.047433094481776,
+ "z": 1.0
+ },
+ {
+ "x": 126.73003443401007,
+ "y": 2.0474758570030986,
+ "z": 1.0
+ },
+ {
+ "x": 126.2292050529963,
+ "y": 2.047529310154752,
+ "z": 1.0
+ },
+ {
+ "x": 125.82854154818529,
+ "y": 2.0475720726760747,
+ "z": 1.0
+ },
+ {
+ "x": 125.32771216717153,
+ "y": 2.047625525827728,
+ "z": 1.0
+ },
+ {
+ "x": 124.82688278615777,
+ "y": 2.047678978979381,
+ "z": 1.0
+ },
+ {
+ "x": 124.42621928134676,
+ "y": 2.0477217415007036,
+ "z": 1.0
+ },
+ {
+ "x": 123.82522402413024,
+ "y": 2.047785885282688,
+ "z": 1.0
+ },
+ {
+ "x": 123.22422876691373,
+ "y": 2.0478500290646715,
+ "z": 1.0
+ },
+ {
+ "x": 122.72339938589997,
+ "y": 2.047903482216325,
+ "z": 1.0
+ },
+ {
+ "x": 122.12240412868344,
+ "y": 2.047967625998309,
+ "z": 1.0
+ },
+ {
+ "x": 121.72174062387244,
+ "y": 2.0480103885196317,
+ "z": 1.0
+ },
+ {
+ "x": 121.22091124285868,
+ "y": 2.0480638416712846,
+ "z": 1.0
+ },
+ {
+ "x": 120.61991598564217,
+ "y": 2.048127985453269,
+ "z": 1.0
+ },
+ {
+ "x": 120.21925248083116,
+ "y": 2.0481707479745914,
+ "z": 1.0
+ },
+ {
+ "x": 119.61825722361463,
+ "y": 2.048234891756575,
+ "z": 1.0
+ },
+ {
+ "x": 119.11742784260088,
+ "y": 2.0482883449082285,
+ "z": 1.0
+ },
+ {
+ "x": 118.51643258538436,
+ "y": 2.0483524886902127,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 4,
+ "heading": [
+ 3.1414859243253446,
+ 3.141485924325344,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.141485924325344,
+ 3.141485924325344,
+ 3.1414859243253432,
+ 3.141485924325343,
+ 3.1414859243253437,
+ 3.141485924325344,
+ 3.141485924325344,
+ 3.1414859243253432,
+ 3.141485924325343,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.141485924325344,
+ 3.1414859243253432,
+ 3.141485924325343,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.141485924325344,
+ 3.1414859243253432,
+ 3.141485924325343,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253432,
+ 3.1414859243253432,
+ 3.141485924325344,
+ 3.1414859243253437,
+ 3.141485924325344,
+ 3.141485924325344,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253432,
+ 3.1414859243253437,
+ 3.141485924325344,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.141485924325344,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.141485924325344,
+ 3.1414859243253437,
+ 3.1414859243253432,
+ 3.1414859243253437,
+ 3.141485924325344,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.141485924325344,
+ 3.141485924325344,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.141485924325344,
+ 3.141485924325344,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253432,
+ 3.1414859243253437,
+ 3.141485924325344,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.141485924325344,
+ 3.1414859243253437,
+ 3.1414859243253432
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -5.026086927895506,
+ "y": 0.0005364305629074195
+ },
+ {
+ "x": -10.052173855790727,
+ "y": 0.00107286112581928
+ },
+ {
+ "x": -9.046956470211285,
+ "y": 0.0009655750132386842
+ },
+ {
+ "x": -10.052173855790443,
+ "y": 0.00107286112581928
+ },
+ {
+ "x": -11.057391241369885,
+ "y": 0.0011801472383998757
+ },
+ {
+ "x": -11.057391241369885,
+ "y": 0.0011801472383998757
+ },
+ {
+ "x": -12.062608626948474,
+ "y": 0.0012874333509893532
+ },
+ {
+ "x": -10.052173855790443,
+ "y": 0.0010728611258281617
+ },
+ {
+ "x": -8.041739084632695,
+ "y": 0.0008582889006580885
+ },
+ {
+ "x": -8.041739084632411,
+ "y": 0.0008582889006536476
+ },
+ {
+ "x": -9.046956470211569,
+ "y": 0.0009655750132342433
+ },
+ {
+ "x": -9.046956470211569,
+ "y": 0.0009655750132431251
+ },
+ {
+ "x": -8.041739084632411,
+ "y": 0.0008582889006625294
+ },
+ {
+ "x": -9.046956470211569,
+ "y": 0.0009655750132386842
+ },
+ {
+ "x": -10.052173855790443,
+ "y": 0.00107286112581928
+ },
+ {
+ "x": -10.052173855790727,
+ "y": 0.001072861125814839
+ },
+ {
+ "x": -9.046956470211569,
+ "y": 0.0009655750132431251
+ },
+ {
+ "x": -10.052173855790443,
+ "y": 0.0010728611258281617
+ },
+ {
+ "x": -12.062608626948759,
+ "y": 0.0012874333509849123
+ },
+ {
+ "x": -10.052173855790727,
+ "y": 0.00107286112581928
+ },
+ {
+ "x": -10.052173855790727,
+ "y": 0.00107286112581928
+ },
+ {
+ "x": -11.057391241369885,
+ "y": 0.0011801472384043166
+ },
+ {
+ "x": -11.057391241369885,
+ "y": 0.0011801472384043166
+ },
+ {
+ "x": -11.0573912413696,
+ "y": 0.0011801472384043166
+ },
+ {
+ "x": -9.046956470211569,
+ "y": 0.0009655750132386842
+ },
+ {
+ "x": -10.052173855791011,
+ "y": 0.001072861125814839
+ },
+ {
+ "x": -10.052173855790727,
+ "y": 0.0010728611258237208
+ },
+ {
+ "x": -8.041739084632411,
+ "y": 0.0008582889006625294
+ },
+ {
+ "x": -10.052173855791011,
+ "y": 0.00107286112581928
+ },
+ {
+ "x": -10.052173855790727,
+ "y": 0.00107286112581928
+ },
+ {
+ "x": -9.046956470211569,
+ "y": 0.0009655750132386842
+ },
+ {
+ "x": -9.046956470211853,
+ "y": 0.0009655750132386842
+ },
+ {
+ "x": -9.046956470211569,
+ "y": 0.0009655750132386842
+ },
+ {
+ "x": -9.046956470211569,
+ "y": 0.0009655750132431251
+ },
+ {
+ "x": -5.026086927895506,
+ "y": 0.0005364305629118604
+ },
+ {
+ "x": -5.011852433689512,
+ "y": 0.0005349113258068527
+ },
+ {
+ "x": -9.0149288582478,
+ "y": 0.0009621567297601885
+ },
+ {
+ "x": -10.016587620275175,
+ "y": 0.001069063033063422
+ },
+ {
+ "x": -9.0149288582478,
+ "y": 0.0009621567297557476
+ },
+ {
+ "x": -8.01327009622014,
+ "y": 0.000855250426452514
+ },
+ {
+ "x": -9.014928858247515,
+ "y": 0.0009621567297601885
+ },
+ {
+ "x": -9.014928858247515,
+ "y": 0.0009621567297601885
+ },
+ {
+ "x": -8.01327009622014,
+ "y": 0.000855250426452514
+ },
+ {
+ "x": -9.0149288582478,
+ "y": 0.0009621567297601885
+ },
+ {
+ "x": -11.018246382302834,
+ "y": 0.0011759693363755375
+ },
+ {
+ "x": -11.01824638230255,
+ "y": 0.0011759693363710966
+ },
+ {
+ "x": -9.014928858247515,
+ "y": 0.0009621567297557476
+ },
+ {
+ "x": -10.016587620275175,
+ "y": 0.001069063033067863
+ },
+ {
+ "x": -10.016587620275175,
+ "y": 0.001069063033067863
+ },
+ {
+ "x": -8.01327009622014,
+ "y": 0.000855250426452514
+ },
+ {
+ "x": -10.016587620275175,
+ "y": 0.001069063033063422
+ },
+ {
+ "x": -11.01824638230255,
+ "y": 0.0011759693363710966
+ },
+ {
+ "x": -9.014928858247515,
+ "y": 0.0009621567297601885
+ },
+ {
+ "x": -8.01327009622014,
+ "y": 0.000855250426452514
+ },
+ {
+ "x": -8.01327009622014,
+ "y": 0.000855250426452514
+ },
+ {
+ "x": -8.01327009622014,
+ "y": 0.000855250426452514
+ },
+ {
+ "x": -8.01327009622014,
+ "y": 0.000855250426452514
+ },
+ {
+ "x": -10.01658762027489,
+ "y": 0.001069063033067863
+ },
+ {
+ "x": -12.019905144329925,
+ "y": 0.001282875639678771
+ },
+ {
+ "x": -10.016587620275175,
+ "y": 0.001069063033063422
+ },
+ {
+ "x": -9.014928858247515,
+ "y": 0.0009621567297601885
+ },
+ {
+ "x": -11.01824638230255,
+ "y": 0.0011759693363755375
+ },
+ {
+ "x": -11.018246382302834,
+ "y": 0.0011759693363710966
+ },
+ {
+ "x": -10.016587620275175,
+ "y": 0.001069063033063422
+ },
+ {
+ "x": -10.01658762027489,
+ "y": 0.001069063033067863
+ },
+ {
+ "x": -9.014928858247515,
+ "y": 0.0009621567297601885
+ },
+ {
+ "x": -9.014928858247515,
+ "y": 0.0009621567297601885
+ },
+ {
+ "x": -9.014928858247515,
+ "y": 0.0009621567297601885
+ },
+ {
+ "x": -8.01327009622014,
+ "y": 0.000855250426452514
+ },
+ {
+ "x": -9.0149288582478,
+ "y": 0.0009621567297557476
+ },
+ {
+ "x": -9.0149288582478,
+ "y": 0.0009621567297557476
+ },
+ {
+ "x": -10.016587620275175,
+ "y": 0.001069063033067863
+ },
+ {
+ "x": -10.016587620275175,
+ "y": 0.001069063033067863
+ },
+ {
+ "x": -8.01327009622014,
+ "y": 0.000855250426452514
+ },
+ {
+ "x": -9.014928858247657,
+ "y": 0.0009621567297601885
+ },
+ {
+ "x": -9.0149288582478,
+ "y": 0.0009621567297601885
+ },
+ {
+ "x": -9.0149288582478,
+ "y": 0.0009621567297601885
+ },
+ {
+ "x": -10.016587620275175,
+ "y": 0.001069063033063422
+ },
+ {
+ "x": -9.014928858247657,
+ "y": 0.0009621567297557476
+ },
+ {
+ "x": -10.016587620275317,
+ "y": 0.001069063033067863
+ },
+ {
+ "x": -12.019905144330352,
+ "y": 0.001282875639678771
+ },
+ {
+ "x": -11.018246382302692,
+ "y": 0.0011759693363710966
+ },
+ {
+ "x": -11.018246382302834,
+ "y": 0.0011759693363755375
+ },
+ {
+ "x": -10.016587620275317,
+ "y": 0.001069063033067863
+ },
+ {
+ "x": -9.014928858247657,
+ "y": 0.0009621567297557476
+ },
+ {
+ "x": -11.018246382302692,
+ "y": 0.0011759693363710966
+ },
+ {
+ "x": -10.016587620275175,
+ "y": 0.001069063033067863
+ },
+ {
+ "x": -10.016587620275317,
+ "y": 0.001069063033063422
+ },
+ {
+ "x": -11.018246382302834,
+ "y": 0.0011759693363710966
+ },
+ {
+ "x": -11.018246382302692,
+ "y": 0.0011759693363755375
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 118.51643258538436,
+ "y": 2.0483524886902127,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 166.26698125656839,
+ "y": -59.490756629877396,
+ "z": 1.0
+ },
+ {
+ "x": 166.7687912075939,
+ "y": -59.49069548293693,
+ "z": 1.0
+ },
+ {
+ "x": 167.1702391684144,
+ "y": -59.49064656538455,
+ "z": 1.0
+ },
+ {
+ "x": 167.67052415520067,
+ "y": -59.490585604265235,
+ "z": 1.0
+ },
+ {
+ "x": 168.2708661393441,
+ "y": -59.49051245092204,
+ "z": 1.0
+ },
+ {
+ "x": 168.67109412877318,
+ "y": -59.490463682026586,
+ "z": 1.0
+ },
+ {
+ "x": 169.0713221182021,
+ "y": -59.49041491313112,
+ "z": 1.0
+ },
+ {
+ "x": 169.5716071049883,
+ "y": -59.49035395201179,
+ "z": 1.0
+ },
+ {
+ "x": 170.1719490891316,
+ "y": -59.49028079866859,
+ "z": 1.0
+ },
+ {
+ "x": 170.57217707856051,
+ "y": -59.49023202977314,
+ "z": 1.0
+ },
+ {
+ "x": 171.17251906270394,
+ "y": -59.490158876429945,
+ "z": 1.0
+ },
+ {
+ "x": 171.5727470521329,
+ "y": -59.49011010753449,
+ "z": 1.0
+ },
+ {
+ "x": 171.97297504156188,
+ "y": -59.49006133863902,
+ "z": 1.0
+ },
+ {
+ "x": 172.57331702570542,
+ "y": -59.48998818529584,
+ "z": 1.0
+ },
+ {
+ "x": 173.17365900984873,
+ "y": -59.48991503195265,
+ "z": 1.0
+ },
+ {
+ "x": 173.57388699927765,
+ "y": -59.48986626305718,
+ "z": 1.0
+ },
+ {
+ "x": 174.17422898342107,
+ "y": -59.489793109713986,
+ "z": 1.0
+ },
+ {
+ "x": 174.57445697285004,
+ "y": -59.48974434081853,
+ "z": 1.0
+ },
+ {
+ "x": 174.974684962279,
+ "y": -59.489695571923065,
+ "z": 1.0
+ },
+ {
+ "x": 175.57502694642244,
+ "y": -59.489622418579884,
+ "z": 1.0
+ },
+ {
+ "x": 176.07531193320875,
+ "y": -59.48956145746055,
+ "z": 1.0
+ },
+ {
+ "x": 176.67565391735207,
+ "y": -59.48948830411736,
+ "z": 1.0
+ },
+ {
+ "x": 177.1759389041382,
+ "y": -59.48942734299804,
+ "z": 1.0
+ },
+ {
+ "x": 177.57616689356718,
+ "y": -59.489378574102574,
+ "z": 1.0
+ },
+ {
+ "x": 178.1765088777106,
+ "y": -59.48930542075939,
+ "z": 1.0
+ },
+ {
+ "x": 178.57673686713957,
+ "y": -59.489256651863926,
+ "z": 1.0
+ },
+ {
+ "x": 178.9769648565685,
+ "y": -59.48920788296846,
+ "z": 1.0
+ },
+ {
+ "x": 179.47724984335468,
+ "y": -59.48914692184914,
+ "z": 1.0
+ },
+ {
+ "x": 180.07759182749828,
+ "y": -59.489073768505946,
+ "z": 1.0
+ },
+ {
+ "x": 180.5778768142843,
+ "y": -59.489012807386615,
+ "z": 1.0
+ },
+ {
+ "x": 181.0781618010705,
+ "y": -59.4889518462673,
+ "z": 1.0
+ },
+ {
+ "x": 181.67850378521393,
+ "y": -59.488878692924104,
+ "z": 1.0
+ },
+ {
+ "x": 182.27884576935747,
+ "y": -59.48880553958092,
+ "z": 1.0
+ },
+ {
+ "x": 182.8791877535008,
+ "y": -59.48873238623773,
+ "z": 1.0
+ },
+ {
+ "x": 183.3794727402871,
+ "y": -59.4886714251184,
+ "z": 1.0
+ },
+ {
+ "x": 183.97981472443053,
+ "y": -59.4885982717752,
+ "z": 1.0
+ },
+ {
+ "x": 184.38004271385938,
+ "y": -59.48854950287975,
+ "z": 1.0
+ },
+ {
+ "x": 184.9803846980028,
+ "y": -59.488476349536555,
+ "z": 1.0
+ },
+ {
+ "x": 185.58072668214623,
+ "y": -59.48840319619336,
+ "z": 1.0
+ },
+ {
+ "x": 186.08101166893238,
+ "y": -59.48834223507404,
+ "z": 1.0
+ },
+ {
+ "x": 186.48123965836135,
+ "y": -59.488293466178575,
+ "z": 1.0
+ },
+ {
+ "x": 187.08158164250494,
+ "y": -59.488220312835395,
+ "z": 1.0
+ },
+ {
+ "x": 187.6819236266482,
+ "y": -59.4881471594922,
+ "z": 1.0
+ },
+ {
+ "x": 188.08215161607728,
+ "y": -59.48809839059673,
+ "z": 1.0
+ },
+ {
+ "x": 188.6824936002206,
+ "y": -59.48802523725354,
+ "z": 1.0
+ },
+ {
+ "x": 189.0827215896495,
+ "y": -59.487976468358085,
+ "z": 1.0
+ },
+ {
+ "x": 189.48294957907848,
+ "y": -59.48792769946262,
+ "z": 1.0
+ },
+ {
+ "x": 190.0832915632219,
+ "y": -59.487854546119436,
+ "z": 1.0
+ },
+ {
+ "x": 190.68363354736533,
+ "y": -59.48778139277624,
+ "z": 1.0
+ },
+ {
+ "x": 191.18391853415153,
+ "y": -59.48772043165691,
+ "z": 1.0
+ },
+ {
+ "x": 191.78426051829496,
+ "y": -59.48764727831373,
+ "z": 1.0
+ },
+ {
+ "x": 192.18448850772393,
+ "y": -59.48759850941826,
+ "z": 1.0
+ },
+ {
+ "x": 192.68477349451007,
+ "y": -59.48753754829893,
+ "z": 1.0
+ },
+ {
+ "x": 193.28511547865367,
+ "y": -59.48746439495575,
+ "z": 1.0
+ },
+ {
+ "x": 193.7854004654397,
+ "y": -59.48740343383642,
+ "z": 1.0
+ },
+ {
+ "x": 194.2856854522259,
+ "y": -59.48734247271709,
+ "z": 1.0
+ },
+ {
+ "x": 194.68591344165486,
+ "y": -59.487293703821635,
+ "z": 1.0
+ },
+ {
+ "x": 195.2862554257983,
+ "y": -59.48722055047844,
+ "z": 1.0
+ },
+ {
+ "x": 195.7865404125845,
+ "y": -59.48715958935912,
+ "z": 1.0
+ },
+ {
+ "x": 196.3868823967279,
+ "y": -59.48708643601593,
+ "z": 1.0
+ },
+ {
+ "x": 196.88716738351405,
+ "y": -59.4870254748966,
+ "z": 1.0
+ },
+ {
+ "x": 197.48750936765748,
+ "y": -59.4869523215534,
+ "z": 1.0
+ },
+ {
+ "x": 197.88773735708645,
+ "y": -59.48690355265795,
+ "z": 1.0
+ },
+ {
+ "x": 198.38802234387265,
+ "y": -59.48684259153862,
+ "z": 1.0
+ },
+ {
+ "x": 198.78825033330162,
+ "y": -59.486793822643165,
+ "z": 1.0
+ },
+ {
+ "x": 199.38859231744516,
+ "y": -59.48672066929997,
+ "z": 1.0
+ },
+ {
+ "x": 199.98893430158847,
+ "y": -59.486647515956776,
+ "z": 1.0
+ },
+ {
+ "x": 200.5892762857319,
+ "y": -59.486574362613595,
+ "z": 1.0
+ },
+ {
+ "x": 200.9895042751608,
+ "y": -59.48652559371813,
+ "z": 1.0
+ },
+ {
+ "x": 201.38973226458978,
+ "y": -59.486476824822674,
+ "z": 1.0
+ },
+ {
+ "x": 201.78996025401875,
+ "y": -59.486428055927206,
+ "z": 1.0
+ },
+ {
+ "x": 202.29024524080495,
+ "y": -59.486367094807875,
+ "z": 1.0
+ },
+ {
+ "x": 202.89058722494838,
+ "y": -59.486293941464695,
+ "z": 1.0
+ },
+ {
+ "x": 203.39087221173452,
+ "y": -59.48623298034536,
+ "z": 1.0
+ },
+ {
+ "x": 203.89115719852072,
+ "y": -59.48617201922603,
+ "z": 1.0
+ },
+ {
+ "x": 204.2913851879497,
+ "y": -59.48612325033058,
+ "z": 1.0
+ },
+ {
+ "x": 204.79167017473588,
+ "y": -59.48606228921125,
+ "z": 1.0
+ },
+ {
+ "x": 205.1918981641648,
+ "y": -59.486013520315794,
+ "z": 1.0
+ },
+ {
+ "x": 205.692183150951,
+ "y": -59.48595255919646,
+ "z": 1.0
+ },
+ {
+ "x": 206.09241114037997,
+ "y": -59.48590379030101,
+ "z": 1.0
+ },
+ {
+ "x": 206.49263912980905,
+ "y": -59.48585502140554,
+ "z": 1.0
+ },
+ {
+ "x": 207.09298111395236,
+ "y": -59.48578186806235,
+ "z": 1.0
+ },
+ {
+ "x": 207.6933230980959,
+ "y": -59.485708714719166,
+ "z": 1.0
+ },
+ {
+ "x": 208.29366508223922,
+ "y": -59.48563556137597,
+ "z": 1.0
+ },
+ {
+ "x": 208.79395006902536,
+ "y": -59.48557460025664,
+ "z": 1.0
+ },
+ {
+ "x": 209.19417805845433,
+ "y": -59.48552583136119,
+ "z": 1.0
+ },
+ {
+ "x": 209.79452004259775,
+ "y": -59.48545267801799,
+ "z": 1.0
+ },
+ {
+ "x": 210.29480502938395,
+ "y": -59.485391716898675,
+ "z": 1.0
+ },
+ {
+ "x": 210.89514701352738,
+ "y": -59.48531856355548,
+ "z": 1.0
+ },
+ {
+ "x": 211.4954889976708,
+ "y": -59.485245410212286,
+ "z": 1.0
+ },
+ {
+ "x": 211.995773984457,
+ "y": -59.485184449092955,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 5,
+ "heading": [
+ 0.00012185278518115317,
+ 0.0001218527851825946,
+ 0.00012185278518572584,
+ 0.00012185278517498467,
+ 0.00012185278517614517,
+ 0.00012185278517742751,
+ 0.00012185278518097994,
+ 0.00012185278519480644,
+ 0.00012185278518907564,
+ 0.00012185278517746212,
+ 0.00012185278517744829,
+ 0.00012185278517744136,
+ 0.00012185278518098858,
+ 0.00012185278517742751,
+ 0.00012185278517507654,
+ 0.00012185278519166489,
+ 0.00012185278519165104,
+ 0.00012185278517744136,
+ 0.00012185278518098858,
+ 0.00012185278517744136,
+ 0.00012185278517613887,
+ 0.00012185278518906306,
+ 0.00012185278517617034,
+ 0.0001218527851790256,
+ 0.00012185278517744136,
+ 0.00012185278517744136,
+ 0.00012185278519875069,
+ 0.0001218527851790256,
+ 0.00012185278517613258,
+ 0.00012185278518906306,
+ 0.00012185278517746212,
+ 0.00012185278517615146,
+ 0.000121852785175065,
+ 0.00012185278517507654,
+ 0.00012185278518906306,
+ 0.00012185278518905047,
+ 0.0001218527851774552,
+ 0.0001218527851774552,
+ 0.00012185278518691218,
+ 0.00012185278517615775,
+ 0.0001218527851790256,
+ 0.00012185278517742058,
+ 0.00012185278517507654,
+ 0.00012185278519165104,
+ 0.00012185278519164411,
+ 0.00012185278517746212,
+ 0.00012185278518099724,
+ 0.00012185278517744136,
+ 0.00012185278517507654,
+ 0.00012185278518906306,
+ 0.00012185278517615146,
+ 0.00012185278517744136,
+ 0.00012185278519480644,
+ 0.00012185278517613887,
+ 0.00012185278517615146,
+ 0.00012185278519166489,
+ 0.0001218527851790179,
+ 0.00012185278517744136,
+ 0.00012185278517615146,
+ 0.00012185278517615146,
+ 0.00012185278518906935,
+ 0.00012185278518906935,
+ 0.00012185278517744136,
+ 0.0001218527851790179,
+ 0.0001218527851790179,
+ 0.00012185278517742751,
+ 0.00012185278518691218,
+ 0.00012185278517508807,
+ 0.00012185278517744829,
+ 0.00012185278518099724,
+ 0.00012185278518098858,
+ 0.00012185278519479875,
+ 0.00012185278517615146,
+ 0.00012185278517615775,
+ 0.00012185278519165104,
+ 0.0001218527851790179,
+ 0.0001218527851790179,
+ 0.0001218527851790256,
+ 0.0001218527851790256,
+ 0.0001218527851790179,
+ 0.00012185278518097128,
+ 0.00012185278519164411,
+ 0.00012185278517507654,
+ 0.00012185278517507654,
+ 0.00012185278518908194,
+ 0.0001218527851790256,
+ 0.00012185278517744136,
+ 0.00012185278517615146,
+ 0.00012185278517615146,
+ 0.00012185278518691218,
+ 0.00012185278518906306
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": 5.01809951025507,
+ "y": 0.0006114694046743807
+ },
+ {
+ "x": 9.032579118460262,
+ "y": 0.001100644928442307
+ },
+ {
+ "x": 9.017329476067744,
+ "y": 0.0010987867169376386
+ },
+ {
+ "x": 11.006269709296816,
+ "y": 0.0013411446251154757
+ },
+ {
+ "x": 10.005699735725102,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 8.004559788579968,
+ "y": 0.0009753779092136483
+ },
+ {
+ "x": 9.005129762151114,
+ "y": 0.0010973001479896993
+ },
+ {
+ "x": 11.006269709295111,
+ "y": 0.0013411446252575843
+ },
+ {
+ "x": 10.00569973572226,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 10.005699735723397,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 10.005699735723965,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 8.0045597885794,
+ "y": 0.0009753779092136483
+ },
+ {
+ "x": 10.005699735725102,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 12.00683968286853,
+ "y": 0.0014630668637494182
+ },
+ {
+ "x": 10.00569973572226,
+ "y": 0.0012192223866236418
+ },
+ {
+ "x": 10.005699735723397,
+ "y": 0.0012192223866236418
+ },
+ {
+ "x": 10.005699735723965,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 8.0045597885794,
+ "y": 0.0009753779092136483
+ },
+ {
+ "x": 10.005699735723965,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 11.006269709297385,
+ "y": 0.0013411446251154757
+ },
+ {
+ "x": 11.006269709296248,
+ "y": 0.0013411446252575843
+ },
+ {
+ "x": 11.006269709294543,
+ "y": 0.0013411446251154757
+ },
+ {
+ "x": 9.005129762151114,
+ "y": 0.0010973001478475908
+ },
+ {
+ "x": 10.005699735723965,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 10.005699735723965,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 8.004559788578831,
+ "y": 0.0009753779093557569
+ },
+ {
+ "x": 9.005129762151114,
+ "y": 0.0010973001478475908
+ },
+ {
+ "x": 11.006269709297953,
+ "y": 0.0013411446251154757
+ },
+ {
+ "x": 11.006269709296248,
+ "y": 0.0013411446252575843
+ },
+ {
+ "x": 10.00569973572226,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 11.006269709296248,
+ "y": 0.0013411446251154757
+ },
+ {
+ "x": 12.006839682869668,
+ "y": 0.0014630668637494182
+ },
+ {
+ "x": 12.00683968286853,
+ "y": 0.0014630668637494182
+ },
+ {
+ "x": 11.006269709296248,
+ "y": 0.0013411446252575843
+ },
+ {
+ "x": 11.006269709297385,
+ "y": 0.0013411446252575843
+ },
+ {
+ "x": 10.005699735722828,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 10.005699735722828,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 12.00683968286853,
+ "y": 0.0014630668638915267
+ },
+ {
+ "x": 11.00626970929568,
+ "y": 0.0013411446251154757
+ },
+ {
+ "x": 9.005129762151114,
+ "y": 0.0010973001478475908
+ },
+ {
+ "x": 10.00569973572567,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 12.00683968286853,
+ "y": 0.0014630668637494182
+ },
+ {
+ "x": 10.005699735723397,
+ "y": 0.0012192223866236418
+ },
+ {
+ "x": 10.005699735723965,
+ "y": 0.0012192223866236418
+ },
+ {
+ "x": 10.00569973572226,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 8.004559788578831,
+ "y": 0.0009753779092136483
+ },
+ {
+ "x": 10.005699735723965,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 12.00683968286853,
+ "y": 0.0014630668637494182
+ },
+ {
+ "x": 11.006269709296248,
+ "y": 0.0013411446252575843
+ },
+ {
+ "x": 11.006269709296248,
+ "y": 0.0013411446251154757
+ },
+ {
+ "x": 10.005699735723965,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 9.005129762151114,
+ "y": 0.0010973001479896993
+ },
+ {
+ "x": 11.006269709297385,
+ "y": 0.0013411446251154757
+ },
+ {
+ "x": 11.006269709296248,
+ "y": 0.0013411446251154757
+ },
+ {
+ "x": 10.00569973572226,
+ "y": 0.0012192223866236418
+ },
+ {
+ "x": 9.005129762151682,
+ "y": 0.0010973001478475908
+ },
+ {
+ "x": 10.005699735723965,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 11.006269709296248,
+ "y": 0.0013411446251154757
+ },
+ {
+ "x": 11.006269709296248,
+ "y": 0.0013411446251154757
+ },
+ {
+ "x": 11.00626970929568,
+ "y": 0.0013411446252575843
+ },
+ {
+ "x": 11.00626970929568,
+ "y": 0.0013411446252575843
+ },
+ {
+ "x": 10.005699735723965,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 9.005129762151682,
+ "y": 0.0010973001478475908
+ },
+ {
+ "x": 9.005129762151682,
+ "y": 0.0010973001478475908
+ },
+ {
+ "x": 10.005699735725102,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 12.00683968286853,
+ "y": 0.0014630668638915267
+ },
+ {
+ "x": 12.006839682867394,
+ "y": 0.0014630668637494182
+ },
+ {
+ "x": 10.005699735723397,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 8.004559788578831,
+ "y": 0.0009753779092136483
+ },
+ {
+ "x": 8.0045597885794,
+ "y": 0.0009753779092136483
+ },
+ {
+ "x": 9.005129762151682,
+ "y": 0.0010973001479896993
+ },
+ {
+ "x": 11.006269709296248,
+ "y": 0.0013411446251154757
+ },
+ {
+ "x": 11.00626970929568,
+ "y": 0.0013411446251154757
+ },
+ {
+ "x": 10.005699735723397,
+ "y": 0.0012192223866236418
+ },
+ {
+ "x": 9.005129762151682,
+ "y": 0.0010973001478475908
+ },
+ {
+ "x": 9.005129762151682,
+ "y": 0.0010973001478475908
+ },
+ {
+ "x": 9.005129762151114,
+ "y": 0.0010973001478475908
+ },
+ {
+ "x": 9.005129762151114,
+ "y": 0.0010973001478475908
+ },
+ {
+ "x": 9.005129762151682,
+ "y": 0.0010973001478475908
+ },
+ {
+ "x": 8.004559788580536,
+ "y": 0.0009753779092136483
+ },
+ {
+ "x": 10.005699735723965,
+ "y": 0.0012192223866236418
+ },
+ {
+ "x": 12.00683968286853,
+ "y": 0.0014630668637494182
+ },
+ {
+ "x": 12.00683968286853,
+ "y": 0.0014630668637494182
+ },
+ {
+ "x": 11.006269709294543,
+ "y": 0.0013411446252575843
+ },
+ {
+ "x": 9.005129762151114,
+ "y": 0.0010973001478475908
+ },
+ {
+ "x": 10.005699735723965,
+ "y": 0.0012192223864815332
+ },
+ {
+ "x": 11.006269709296248,
+ "y": 0.0013411446251154757
+ },
+ {
+ "x": 11.006269709296248,
+ "y": 0.0013411446251154757
+ },
+ {
+ "x": 12.00683968286853,
+ "y": 0.0014630668638915267
+ },
+ {
+ "x": 11.006269709296248,
+ "y": 0.0013411446252575843
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 211.995773984457,
+ "y": -59.485184449092955,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 336.87871837455714,
+ "y": -1.9946542982485806,
+ "z": 1.0
+ },
+ {
+ "x": 337.48138495618383,
+ "y": -1.9949744568755592,
+ "z": 1.0
+ },
+ {
+ "x": 338.08405153781047,
+ "y": -1.995294615502536,
+ "z": 1.0
+ },
+ {
+ "x": 338.58627368916603,
+ "y": -1.9955614143583502,
+ "z": 1.0
+ },
+ {
+ "x": 339.0884958405216,
+ "y": -1.995828213214164,
+ "z": 1.0
+ },
+ {
+ "x": 339.49027356160605,
+ "y": -1.9960416522988154,
+ "z": 1.0
+ },
+ {
+ "x": 339.8920512826905,
+ "y": -1.9962550913834662,
+ "z": 1.0
+ },
+ {
+ "x": 340.394273434046,
+ "y": -1.9965218902392805,
+ "z": 1.0
+ },
+ {
+ "x": 340.9969400156727,
+ "y": -1.9968420488662573,
+ "z": 1.0
+ },
+ {
+ "x": 341.4991621670282,
+ "y": -1.997108847722071,
+ "z": 1.0
+ },
+ {
+ "x": 341.90093988811265,
+ "y": -1.9973222868067224,
+ "z": 1.0
+ },
+ {
+ "x": 342.3027176091971,
+ "y": -1.9975357258913733,
+ "z": 1.0
+ },
+ {
+ "x": 342.70449533028153,
+ "y": -1.9977491649760246,
+ "z": 1.0
+ },
+ {
+ "x": 343.106273051366,
+ "y": -1.997962604060676,
+ "z": 1.0
+ },
+ {
+ "x": 343.5080507724504,
+ "y": -1.9981760431453273,
+ "z": 1.0
+ },
+ {
+ "x": 344.1107173540771,
+ "y": -1.998496201772304,
+ "z": 1.0
+ },
+ {
+ "x": 344.6129395054326,
+ "y": -1.9987630006281178,
+ "z": 1.0
+ },
+ {
+ "x": 345.01471722651706,
+ "y": -1.9989764397127692,
+ "z": 1.0
+ },
+ {
+ "x": 345.4164949476015,
+ "y": -1.99918987879742,
+ "z": 1.0
+ },
+ {
+ "x": 346.0191615292282,
+ "y": -1.9995100374243995,
+ "z": 1.0
+ },
+ {
+ "x": 346.42093925031264,
+ "y": -1.9997234765090504,
+ "z": 1.0
+ },
+ {
+ "x": 346.92316140166815,
+ "y": -1.9999902753648646,
+ "z": 1.0
+ },
+ {
+ "x": 347.3249391227526,
+ "y": -2.000203714449516,
+ "z": 1.0
+ },
+ {
+ "x": 347.72671684383704,
+ "y": -2.0004171535341677,
+ "z": 1.0
+ },
+ {
+ "x": 348.2289389951926,
+ "y": -2.000683952389981,
+ "z": 1.0
+ },
+ {
+ "x": 348.82993064592614,
+ "y": -2.0010032212321396,
+ "z": 1.0
+ },
+ {
+ "x": 349.3307570215374,
+ "y": -2.001269278600605,
+ "z": 1.0
+ },
+ {
+ "x": 349.9317486722709,
+ "y": -2.0015885474427635,
+ "z": 1.0
+ },
+ {
+ "x": 350.43257504788215,
+ "y": -2.001854604811229,
+ "z": 1.0
+ },
+ {
+ "x": 350.9334014234934,
+ "y": -2.0021206621796934,
+ "z": 1.0
+ },
+ {
+ "x": 351.53439307422695,
+ "y": -2.002439931021852,
+ "z": 1.0
+ },
+ {
+ "x": 352.13538472496043,
+ "y": -2.0027591998640104,
+ "z": 1.0
+ },
+ {
+ "x": 352.53604582544943,
+ "y": -2.0029720457587827,
+ "z": 1.0
+ },
+ {
+ "x": 353.13703747618297,
+ "y": -2.0032913146009403,
+ "z": 1.0
+ },
+ {
+ "x": 353.537698576672,
+ "y": -2.0035041604957127,
+ "z": 1.0
+ },
+ {
+ "x": 354.13869022740556,
+ "y": -2.003823429337871,
+ "z": 1.0
+ },
+ {
+ "x": 354.53935132789456,
+ "y": -2.0040362752326435,
+ "z": 1.0
+ },
+ {
+ "x": 355.1403429786281,
+ "y": -2.004355544074802,
+ "z": 1.0
+ },
+ {
+ "x": 355.74133462936163,
+ "y": -2.0046748129169596,
+ "z": 1.0
+ },
+ {
+ "x": 356.2421610049729,
+ "y": -2.004940870285425,
+ "z": 1.0
+ },
+ {
+ "x": 356.84315265570643,
+ "y": -2.0052601391275835,
+ "z": 1.0
+ },
+ {
+ "x": 357.3439790313177,
+ "y": -2.005526196496049,
+ "z": 1.0
+ },
+ {
+ "x": 357.74464013180676,
+ "y": -2.0057390423908212,
+ "z": 1.0
+ },
+ {
+ "x": 358.14530123229576,
+ "y": -2.0059518882855927,
+ "z": 1.0
+ },
+ {
+ "x": 358.7462928830293,
+ "y": -2.006271157127751,
+ "z": 1.0
+ },
+ {
+ "x": 359.1469539835183,
+ "y": -2.0064840030225235,
+ "z": 1.0
+ },
+ {
+ "x": 359.74794563425183,
+ "y": -2.006803271864682,
+ "z": 1.0
+ },
+ {
+ "x": 360.34893728498537,
+ "y": -2.0071225407068396,
+ "z": 1.0
+ },
+ {
+ "x": 360.8497636605967,
+ "y": -2.007388598075305,
+ "z": 1.0
+ },
+ {
+ "x": 361.4507553113302,
+ "y": -2.0077078669174635,
+ "z": 1.0
+ },
+ {
+ "x": 361.9515816869415,
+ "y": -2.007973924285929,
+ "z": 1.0
+ },
+ {
+ "x": 362.552573337675,
+ "y": -2.0082931931280865,
+ "z": 1.0
+ },
+ {
+ "x": 363.0533997132863,
+ "y": -2.008559250496552,
+ "z": 1.0
+ },
+ {
+ "x": 363.65439136401983,
+ "y": -2.0088785193387104,
+ "z": 1.0
+ },
+ {
+ "x": 364.1552177396311,
+ "y": -2.009144576707176,
+ "z": 1.0
+ },
+ {
+ "x": 364.65604411524237,
+ "y": -2.0094106340756412,
+ "z": 1.0
+ },
+ {
+ "x": 365.0567052157314,
+ "y": -2.0096234799704127,
+ "z": 1.0
+ },
+ {
+ "x": 365.45736631622043,
+ "y": -2.009836325865185,
+ "z": 1.0
+ },
+ {
+ "x": 365.9581926918317,
+ "y": -2.0101023832336504,
+ "z": 1.0
+ },
+ {
+ "x": 366.35885379232076,
+ "y": -2.0103152291284228,
+ "z": 1.0
+ },
+ {
+ "x": 366.9598454430543,
+ "y": -2.0106344979705812,
+ "z": 1.0
+ },
+ {
+ "x": 367.5608370937878,
+ "y": -2.010953766812739,
+ "z": 1.0
+ },
+ {
+ "x": 368.0616634693991,
+ "y": -2.0112198241812043,
+ "z": 1.0
+ },
+ {
+ "x": 368.6626551201326,
+ "y": -2.0115390930233628,
+ "z": 1.0
+ },
+ {
+ "x": 369.1634814957439,
+ "y": -2.011805150391828,
+ "z": 1.0
+ },
+ {
+ "x": 369.66430787135516,
+ "y": -2.0120712077602927,
+ "z": 1.0
+ },
+ {
+ "x": 370.16513424696643,
+ "y": -2.012337265128758,
+ "z": 1.0
+ },
+ {
+ "x": 370.6659606225777,
+ "y": -2.0126033224972235,
+ "z": 1.0
+ },
+ {
+ "x": 371.16678699818897,
+ "y": -2.012869379865689,
+ "z": 1.0
+ },
+ {
+ "x": 371.66761337380024,
+ "y": -2.0131354372341543,
+ "z": 1.0
+ },
+ {
+ "x": 372.1684397494115,
+ "y": -2.013401494602619,
+ "z": 1.0
+ },
+ {
+ "x": 372.6692661250228,
+ "y": -2.0136675519710843,
+ "z": 1.0
+ },
+ {
+ "x": 373.17009250063404,
+ "y": -2.0139336093395497,
+ "z": 1.0
+ },
+ {
+ "x": 373.6709188762453,
+ "y": -2.014199666708015,
+ "z": 1.0
+ },
+ {
+ "x": 374.1717452518566,
+ "y": -2.0144657240764805,
+ "z": 1.0
+ },
+ {
+ "x": 374.5724063523456,
+ "y": -2.014678569971252,
+ "z": 1.0
+ },
+ {
+ "x": 375.1733980030791,
+ "y": -2.0149978388134104,
+ "z": 1.0
+ },
+ {
+ "x": 375.77438965381265,
+ "y": -2.015317107655569,
+ "z": 1.0
+ },
+ {
+ "x": 376.3753813045462,
+ "y": -2.0156363764977274,
+ "z": 1.0
+ },
+ {
+ "x": 376.7760424050352,
+ "y": -2.015849222392499,
+ "z": 1.0
+ },
+ {
+ "x": 377.27686878064645,
+ "y": -2.0161152797609643,
+ "z": 1.0
+ },
+ {
+ "x": 377.7776951562577,
+ "y": -2.0163813371294297,
+ "z": 1.0
+ },
+ {
+ "x": 378.1783562567467,
+ "y": -2.016594183024202,
+ "z": 1.0
+ },
+ {
+ "x": 378.5790173572357,
+ "y": -2.0168070289189743,
+ "z": 1.0
+ },
+ {
+ "x": 379.079843732847,
+ "y": -2.017073086287439,
+ "z": 1.0
+ },
+ {
+ "x": 379.68083538358053,
+ "y": -2.0173923551295974,
+ "z": 1.0
+ },
+ {
+ "x": 380.28182703431406,
+ "y": -2.017711623971756,
+ "z": 1.0
+ },
+ {
+ "x": 380.8828186850476,
+ "y": -2.0180308928139143,
+ "z": 1.0
+ },
+ {
+ "x": 381.38364506065886,
+ "y": -2.018296950182379,
+ "z": 1.0
+ },
+ {
+ "x": 381.9846367113924,
+ "y": -2.0186162190245374,
+ "z": 1.0
+ },
+ {
+ "x": 382.3852978118814,
+ "y": -2.0188290649193097,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 6,
+ "heading": [
+ -0.0005312366847937874,
+ -0.0005312366847964263,
+ -0.0005312366847949776,
+ -0.0005312366847937787,
+ -0.0005312366847936362,
+ -0.0005312366847934955,
+ -0.0005312366847933196,
+ -0.000531236684793529,
+ -0.0005312366847937787,
+ -0.0005312366847933768,
+ -0.000531236684793529,
+ -0.0005312366847933196,
+ -0.0005312366847933196,
+ -0.0005312366847938724,
+ -0.0005312366847938724,
+ -0.0005312366847936362,
+ -0.0005312366847933768,
+ -0.000531236684793529,
+ -0.0005312366847933196,
+ -0.0005312366847958469,
+ -0.0005312366847958469,
+ -0.000531236684793529,
+ -0.0005312366847940202,
+ -0.000531236684794425,
+ -0.0005312366847934955,
+ -0.0005312366847932849,
+ -0.0005312366847941043,
+ -0.0005312366847941316,
+ -0.0005312366847941316,
+ -0.000531236684793223,
+ -0.0005312366847932982,
+ -0.0005312366847941248,
+ -0.0005312366847941398,
+ -0.000531236684793223,
+ -0.0005312366847931929,
+ -0.0005312366847940795,
+ -0.0005312366847941097,
+ -0.0005312366847941097,
+ -0.0005312366847933607,
+ -0.0005312366847932982,
+ -0.0005312366847941043,
+ -0.0005312366847941043,
+ -0.0005312366847940829,
+ -0.0005312366847929788,
+ -0.000531236684793223,
+ -0.0005312366847941097,
+ -0.0005312366847941097,
+ -0.0005312366847933607,
+ -0.0005312366847932707,
+ -0.0005312366847940768,
+ -0.0005312366847941043,
+ -0.0005312366847932982,
+ -0.0005312366847932982,
+ -0.0005312366847941043,
+ -0.0005312366847941043,
+ -0.0005312366847941097,
+ -0.0005312366847930977,
+ -0.0005312366847929788,
+ -0.0005312366847941164,
+ -0.0005312366847940829,
+ -0.0005312366847940795,
+ -0.0005312366847933607,
+ -0.0005312366847932982,
+ -0.0005312366847941043,
+ -0.0005312366847941043,
+ -0.000531236684793223,
+ -0.000531236684793223,
+ -0.0005312366847941097,
+ -0.0005312366847941097,
+ -0.0005312366847941097,
+ -0.000531236684793223,
+ -0.000531236684793223,
+ -0.0005312366847941097,
+ -0.0005312366847941097,
+ -0.0005312366847941097,
+ -0.0005312366847931312,
+ -0.000531236684793223,
+ -0.0005312366847940997,
+ -0.0005312366847940997,
+ -0.000531236684793223,
+ -0.0005312366847931312,
+ -0.0005312366847941097,
+ -0.0005312366847941164,
+ -0.0005312366847941248,
+ -0.0005312366847931312,
+ -0.0005312366847932982,
+ -0.0005312366847940997,
+ -0.0005312366847940997,
+ -0.0005312366847932982,
+ -0.0005312366847932982,
+ -0.0005312366847941097
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": 6.026665816266927,
+ "y": -0.0032015862697853947
+ },
+ {
+ "x": 12.053331632533286,
+ "y": -0.006403172539553026
+ },
+ {
+ "x": 11.048887329822037,
+ "y": -0.005869574827910284
+ },
+ {
+ "x": 10.044443027111356,
+ "y": -0.005335977116280866
+ },
+ {
+ "x": 9.039998724400107,
+ "y": -0.004802379404651447
+ },
+ {
+ "x": 8.035554421688857,
+ "y": -0.004268781693022028
+ },
+ {
+ "x": 9.039998724399538,
+ "y": -0.004802379404651447
+ },
+ {
+ "x": 11.048887329822037,
+ "y": -0.005869574827910284
+ },
+ {
+ "x": 11.048887329822037,
+ "y": -0.0058695748279058435
+ },
+ {
+ "x": 9.039998724399538,
+ "y": -0.004802379404651447
+ },
+ {
+ "x": 8.035554421688857,
+ "y": -0.004268781693022028
+ },
+ {
+ "x": 8.035554421688857,
+ "y": -0.004268781693022028
+ },
+ {
+ "x": 8.035554421688857,
+ "y": -0.004268781693026469
+ },
+ {
+ "x": 8.035554421688857,
+ "y": -0.004268781693026469
+ },
+ {
+ "x": 10.044443027111356,
+ "y": -0.005335977116280866
+ },
+ {
+ "x": 11.048887329822037,
+ "y": -0.0058695748279058435
+ },
+ {
+ "x": 9.039998724399538,
+ "y": -0.004802379404651447
+ },
+ {
+ "x": 8.035554421688857,
+ "y": -0.004268781693022028
+ },
+ {
+ "x": 10.044443027111356,
+ "y": -0.00533597711630307
+ },
+ {
+ "x": 10.044443027111356,
+ "y": -0.00533597711630307
+ },
+ {
+ "x": 9.039998724399538,
+ "y": -0.004802379404651447
+ },
+ {
+ "x": 9.039998724399538,
+ "y": -0.004802379404655888
+ },
+ {
+ "x": 8.035554421688857,
+ "y": -0.00426878169303091
+ },
+ {
+ "x": 9.039998724400107,
+ "y": -0.004802379404651447
+ },
+ {
+ "x": 11.032138020891011,
+ "y": -0.005860676979718704
+ },
+ {
+ "x": 11.018180263448016,
+ "y": -0.005853262106239043
+ },
+ {
+ "x": 11.018180263447448,
+ "y": -0.005853262106239043
+ },
+ {
+ "x": 11.018180263447448,
+ "y": -0.005853262106239043
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369299339
+ },
+ {
+ "x": 11.018180263448016,
+ "y": -0.0058532621062301615
+ },
+ {
+ "x": 12.019833014670098,
+ "y": -0.006385376843169865
+ },
+ {
+ "x": 10.016527512224798,
+ "y": -0.005321147369308221
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369299339
+ },
+ {
+ "x": 10.016527512225935,
+ "y": -0.005321147369299339
+ },
+ {
+ "x": 10.016527512225935,
+ "y": -0.005321147369308221
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369308221
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369308221
+ },
+ {
+ "x": 12.019833014670667,
+ "y": -0.006385376843160984
+ },
+ {
+ "x": 11.018180263448016,
+ "y": -0.0058532621062301615
+ },
+ {
+ "x": 11.018180263448016,
+ "y": -0.005853262106239043
+ },
+ {
+ "x": 11.018180263448016,
+ "y": -0.005853262106239043
+ },
+ {
+ "x": 9.014874761003284,
+ "y": -0.004789032632377399
+ },
+ {
+ "x": 8.013222009780634,
+ "y": -0.004256917895437695
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369299339
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369308221
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369308221
+ },
+ {
+ "x": 12.019833014670667,
+ "y": -0.006385376843160984
+ },
+ {
+ "x": 11.018180263448585,
+ "y": -0.0058532621062301615
+ },
+ {
+ "x": 11.018180263448585,
+ "y": -0.005853262106239043
+ },
+ {
+ "x": 11.018180263448016,
+ "y": -0.005853262106239043
+ },
+ {
+ "x": 11.018180263448016,
+ "y": -0.0058532621062301615
+ },
+ {
+ "x": 11.018180263448016,
+ "y": -0.0058532621062301615
+ },
+ {
+ "x": 11.018180263448016,
+ "y": -0.005853262106239043
+ },
+ {
+ "x": 11.018180263448016,
+ "y": -0.005853262106239043
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369308221
+ },
+ {
+ "x": 9.014874761003284,
+ "y": -0.004789032632368517
+ },
+ {
+ "x": 8.013222009780634,
+ "y": -0.004256917895437695
+ },
+ {
+ "x": 9.014874761002716,
+ "y": -0.004789032632377399
+ },
+ {
+ "x": 9.014874761003284,
+ "y": -0.004789032632377399
+ },
+ {
+ "x": 10.016527512225935,
+ "y": -0.005321147369308221
+ },
+ {
+ "x": 12.019833014670667,
+ "y": -0.006385376843160984
+ },
+ {
+ "x": 11.018180263448016,
+ "y": -0.0058532621062301615
+ },
+ {
+ "x": 11.018180263448016,
+ "y": -0.005853262106239043
+ },
+ {
+ "x": 11.018180263448016,
+ "y": -0.005853262106239043
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369299339
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369299339
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369308221
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369308221
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369308221
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369299339
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369299339
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369308221
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369308221
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369308221
+ },
+ {
+ "x": 9.014874761002716,
+ "y": -0.004789032632368517
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369299339
+ },
+ {
+ "x": 12.019833014670667,
+ "y": -0.006385376843169865
+ },
+ {
+ "x": 12.019833014670667,
+ "y": -0.006385376843169865
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369299339
+ },
+ {
+ "x": 9.014874761002716,
+ "y": -0.004789032632368517
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369308221
+ },
+ {
+ "x": 9.014874761002716,
+ "y": -0.004789032632377399
+ },
+ {
+ "x": 8.013222009780065,
+ "y": -0.004256917895446577
+ },
+ {
+ "x": 9.014874761002716,
+ "y": -0.004789032632368517
+ },
+ {
+ "x": 11.018180263448016,
+ "y": -0.0058532621062301615
+ },
+ {
+ "x": 12.019833014670667,
+ "y": -0.006385376843169865
+ },
+ {
+ "x": 12.019833014670667,
+ "y": -0.006385376843169865
+ },
+ {
+ "x": 11.018180263448016,
+ "y": -0.0058532621062301615
+ },
+ {
+ "x": 11.018180263448016,
+ "y": -0.0058532621062301615
+ },
+ {
+ "x": 10.016527512225366,
+ "y": -0.005321147369308221
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 382.3852978118814,
+ "y": -2.0188290649193097,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 396.3472344367284,
+ "y": -37.160345373104796,
+ "z": 1.0
+ },
+ {
+ "x": 396.34783460167466,
+ "y": -36.660199843302536,
+ "z": 1.0
+ },
+ {
+ "x": 396.3484347666208,
+ "y": -36.16005431350368,
+ "z": 1.0
+ },
+ {
+ "x": 396.3491549645562,
+ "y": -35.55987967774118,
+ "z": 1.0
+ },
+ {
+ "x": 396.3496350965132,
+ "y": -35.15976325390029,
+ "z": 1.0
+ },
+ {
+ "x": 396.3503552944486,
+ "y": -34.559588618138925,
+ "z": 1.0
+ },
+ {
+ "x": 396.351075492384,
+ "y": -33.959413982377555,
+ "z": 1.0
+ },
+ {
+ "x": 396.351555624341,
+ "y": -33.559297558536606,
+ "z": 1.0
+ },
+ {
+ "x": 396.35203575629794,
+ "y": -33.15918113469572,
+ "z": 1.0
+ },
+ {
+ "x": 396.35251588825486,
+ "y": -32.75906471085483,
+ "z": 1.0
+ },
+ {
+ "x": 396.3531160532011,
+ "y": -32.258919181052505,
+ "z": 1.0
+ },
+ {
+ "x": 396.35359618515804,
+ "y": -31.85880275721275,
+ "z": 1.0
+ },
+ {
+ "x": 396.3543163830934,
+ "y": -31.258628121451384,
+ "z": 1.0
+ },
+ {
+ "x": 396.3550365810288,
+ "y": -30.65845348569116,
+ "z": 1.0
+ },
+ {
+ "x": 396.35551671298583,
+ "y": -30.25833706184913,
+ "z": 1.0
+ },
+ {
+ "x": 396.35599684494275,
+ "y": -29.858220638008184,
+ "z": 1.0
+ },
+ {
+ "x": 396.35671704287813,
+ "y": -29.25804600224796,
+ "z": 1.0
+ },
+ {
+ "x": 396.3574372408136,
+ "y": -28.657871366485452,
+ "z": 1.0
+ },
+ {
+ "x": 396.358157438749,
+ "y": -28.05769673072409,
+ "z": 1.0
+ },
+ {
+ "x": 396.3588776366844,
+ "y": -27.457522094963863,
+ "z": 1.0
+ },
+ {
+ "x": 396.3593577686414,
+ "y": -27.057405671122968,
+ "z": 1.0
+ },
+ {
+ "x": 396.35983790059834,
+ "y": -26.65728924728094,
+ "z": 1.0
+ },
+ {
+ "x": 396.3605580985337,
+ "y": -26.057114611520714,
+ "z": 1.0
+ },
+ {
+ "x": 396.36115826348,
+ "y": -25.556969081718446,
+ "z": 1.0
+ },
+ {
+ "x": 396.3617584284261,
+ "y": -25.05682355191732,
+ "z": 1.0
+ },
+ {
+ "x": 396.3624786263615,
+ "y": -24.456648916155956,
+ "z": 1.0
+ },
+ {
+ "x": 396.36295875831854,
+ "y": -24.056532492315007,
+ "z": 1.0
+ },
+ {
+ "x": 396.3636789562539,
+ "y": -23.456357856552508,
+ "z": 1.0
+ },
+ {
+ "x": 396.3643991541893,
+ "y": -22.856183220793415,
+ "z": 1.0
+ },
+ {
+ "x": 396.36487928614633,
+ "y": -22.456066796951387,
+ "z": 1.0
+ },
+ {
+ "x": 396.36535941810325,
+ "y": -22.055950373110495,
+ "z": 1.0
+ },
+ {
+ "x": 396.36607961603875,
+ "y": -21.45577573734913,
+ "z": 1.0
+ },
+ {
+ "x": 396.36655974799555,
+ "y": -21.055659313509317,
+ "z": 1.0
+ },
+ {
+ "x": 396.3671599129418,
+ "y": -20.555513783707056,
+ "z": 1.0
+ },
+ {
+ "x": 396.3678801108772,
+ "y": -19.95533914794569,
+ "z": 1.0
+ },
+ {
+ "x": 396.3683602428342,
+ "y": -19.555222724104787,
+ "z": 1.0
+ },
+ {
+ "x": 396.36884037479115,
+ "y": -19.155106300262716,
+ "z": 1.0
+ },
+ {
+ "x": 396.36932050674807,
+ "y": -18.754989876424098,
+ "z": 1.0
+ },
+ {
+ "x": 396.36992067169433,
+ "y": -18.25484434662183,
+ "z": 1.0
+ },
+ {
+ "x": 396.3706408696297,
+ "y": -17.654669710860468,
+ "z": 1.0
+ },
+ {
+ "x": 396.37124103457586,
+ "y": -17.15452418105934,
+ "z": 1.0
+ },
+ {
+ "x": 396.37196123251124,
+ "y": -16.55434954529911,
+ "z": 1.0
+ },
+ {
+ "x": 396.37268143044673,
+ "y": -15.954174909536611,
+ "z": 1.0
+ },
+ {
+ "x": 396.37316156240365,
+ "y": -15.55405848569572,
+ "z": 1.0
+ },
+ {
+ "x": 396.3737617273499,
+ "y": -15.053912955894535,
+ "z": 1.0
+ },
+ {
+ "x": 396.3744819252853,
+ "y": -14.453738320133171,
+ "z": 1.0
+ },
+ {
+ "x": 396.3749620572422,
+ "y": -14.053621896292277,
+ "z": 1.0
+ },
+ {
+ "x": 396.3756822551776,
+ "y": -13.453447260530915,
+ "z": 1.0
+ },
+ {
+ "x": 396.3761623871346,
+ "y": -13.053330836690023,
+ "z": 1.0
+ },
+ {
+ "x": 396.37664251909155,
+ "y": -12.653214412849076,
+ "z": 1.0
+ },
+ {
+ "x": 396.3772426840377,
+ "y": -12.153068883047947,
+ "z": 1.0
+ },
+ {
+ "x": 396.37772281599473,
+ "y": -11.752952459207044,
+ "z": 1.0
+ },
+ {
+ "x": 396.37820294795165,
+ "y": -11.352836035366167,
+ "z": 1.0
+ },
+ {
+ "x": 396.37892314588703,
+ "y": -10.7526613996048,
+ "z": 1.0
+ },
+ {
+ "x": 396.3796433438224,
+ "y": -10.152486763844573,
+ "z": 1.0
+ },
+ {
+ "x": 396.3800034427902,
+ "y": -9.852399445962725,
+ "z": 1.0
+ },
+ {
+ "x": 396.38072947083594,
+ "y": -9.24736630647071,
+ "z": 1.0
+ },
+ {
+ "x": 396.38018884440146,
+ "y": -8.827697833519784,
+ "z": 1.0
+ },
+ {
+ "x": 396.3559542057511,
+ "y": -8.213198337464048,
+ "z": 1.0
+ },
+ {
+ "x": 396.31200879560265,
+ "y": -7.723158864023834,
+ "z": 1.0
+ },
+ {
+ "x": 396.20527536482757,
+ "y": -6.992592214704764,
+ "z": 1.0
+ },
+ {
+ "x": 396.0500718257525,
+ "y": -6.271164008187339,
+ "z": 1.0
+ },
+ {
+ "x": 395.8842368704714,
+ "y": -5.678967931305309,
+ "z": 1.0
+ },
+ {
+ "x": 395.6857622060334,
+ "y": -5.096899880584985,
+ "z": 1.0
+ },
+ {
+ "x": 395.455260748745,
+ "y": -4.526756868425108,
+ "z": 1.0
+ },
+ {
+ "x": 395.2482753165647,
+ "y": -4.0804127215268355,
+ "z": 1.0
+ },
+ {
+ "x": 394.9011210530243,
+ "y": -3.4292445540602023,
+ "z": 1.0
+ },
+ {
+ "x": 394.57919369521915,
+ "y": -2.905263665688727,
+ "z": 1.0
+ },
+ {
+ "x": 394.2286560290763,
+ "y": -2.3999741932397383,
+ "z": 1.0
+ },
+ {
+ "x": 393.85059020493986,
+ "y": -1.9149362194119146,
+ "z": 1.0
+ },
+ {
+ "x": 393.4461633242467,
+ "y": -1.4516473413939093,
+ "z": 1.0
+ },
+ {
+ "x": 393.10315414617816,
+ "y": -1.0964914090564002,
+ "z": 1.0
+ },
+ {
+ "x": 392.5556607414593,
+ "y": -0.5917147279677624,
+ "z": 1.0
+ },
+ {
+ "x": 391.97441258430604,
+ "y": -0.12667220556926106,
+ "z": 1.0
+ },
+ {
+ "x": 391.5694707284134,
+ "y": 0.16029339798120468,
+ "z": 1.0
+ },
+ {
+ "x": 391.1515965517793,
+ "y": 0.42807561936125904,
+ "z": 1.0
+ },
+ {
+ "x": 390.6124534574134,
+ "y": 0.7349446250181975,
+ "z": 1.0
+ },
+ {
+ "x": 389.9432649415583,
+ "y": 1.060967210825062,
+ "z": 1.0
+ },
+ {
+ "x": 389.3693148975709,
+ "y": 1.296387251222732,
+ "z": 1.0
+ },
+ {
+ "x": 388.90088974534075,
+ "y": 1.4604024328109124,
+ "z": 1.0
+ },
+ {
+ "x": 388.3054464689899,
+ "y": 1.6344358076569507,
+ "z": 1.0
+ },
+ {
+ "x": 387.82242371460416,
+ "y": 1.748505382053843,
+ "z": 1.0
+ },
+ {
+ "x": 387.3346097798446,
+ "y": 1.8399412798968666,
+ "z": 1.0
+ },
+ {
+ "x": 386.84306450454335,
+ "y": 1.9085448273143313,
+ "z": 1.0
+ },
+ {
+ "x": 386.2250132455845,
+ "y": 1.961968903319451,
+ "z": 1.0
+ },
+ {
+ "x": 385.4980846920273,
+ "y": 1.979517872767351,
+ "z": 1.0
+ },
+ {
+ "x": 384.8934007714826,
+ "y": 1.9798391030788676,
+ "z": 1.0
+ },
+ {
+ "x": 384.59105881121025,
+ "y": 1.979999718234626,
+ "z": 1.0
+ },
+ {
+ "x": 383.9900671604767,
+ "y": 1.9803189870767843,
+ "z": 1.0
+ },
+ {
+ "x": 383.48924078486544,
+ "y": 1.9805850444452497,
+ "z": 1.0
+ },
+ {
+ "x": 383.08857968437644,
+ "y": 1.980797890340022,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 7,
+ "heading": [
+ 1.8979433016187948,
+ 1.5695963467442284,
+ 1.569596346744338,
+ 1.5695963467444518,
+ 1.5695963467443406,
+ 1.5695963467443392,
+ 1.569596346744453,
+ 1.5695963467443395,
+ 1.5695963467443108,
+ 1.569596346744453,
+ 1.5695963467443281,
+ 1.5695963467443268,
+ 1.5695963467444516,
+ 1.5695963467444518,
+ 1.5695963467443392,
+ 1.5695963467443126,
+ 1.5695963467444516,
+ 1.5695963467443583,
+ 1.5695963467443594,
+ 1.5695963467444518,
+ 1.569596346744338,
+ 1.5695963467443126,
+ 1.569596346744453,
+ 1.5695963467443497,
+ 1.5695963467443406,
+ 1.569596346744453,
+ 1.5695963467443395,
+ 1.5695963467443408,
+ 1.5695963467444518,
+ 1.569596346744338,
+ 1.5695963467443126,
+ 1.5695963467443392,
+ 1.5695963467444516,
+ 1.569596346744453,
+ 1.5695963467443508,
+ 1.5695963467443392,
+ 1.5695963467443126,
+ 1.5695963467444514,
+ 1.569596346744325,
+ 1.5695963467443508,
+ 1.569596346744453,
+ 1.5695963467444518,
+ 1.5695963467443583,
+ 1.5695963467443406,
+ 1.5695963467443268,
+ 1.5695963467443497,
+ 1.569596346744453,
+ 1.569596346744453,
+ 1.5695963467443392,
+ 1.569596346744311,
+ 1.569596346744453,
+ 1.5695963467443266,
+ 1.5695963467443108,
+ 1.569596346744453,
+ 1.5695963467444518,
+ 1.5695963467443268,
+ 1.569596346744325,
+ 1.5706153945049763,
+ 1.5947484581231608,
+ 1.6324452626433934,
+ 1.6936208548054112,
+ 1.7492747489820462,
+ 1.8104893934341382,
+ 1.8716255364061702,
+ 1.9272038296191953,
+ 1.9772242945495098,
+ 2.0383604066772216,
+ 2.0883808667884334,
+ 2.1495169833593275,
+ 2.2050952761025653,
+ 2.260673574203252,
+ 2.3108780558633866,
+ 2.373656925855639,
+ 2.4317794339744916,
+ 2.4901149063298034,
+ 2.548388391437845,
+ 2.600834497835706,
+ 2.659107941869012,
+ 2.7173814004965506,
+ 2.775654864224719,
+ 2.8339283163605002,
+ 2.880547077762562,
+ 2.932993183603905,
+ 2.9796119446485148,
+ 3.0320580554517327,
+ 3.0888726955741186,
+ 3.1281734888993147,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.141061416904999
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": 0.006001649462632486,
+ "y": 5.001455298022606
+ },
+ {
+ "x": 0.012003298924128103,
+ "y": 10.002910596011176
+ },
+ {
+ "x": 0.013203628815290358,
+ "y": 11.003201655613566
+ },
+ {
+ "x": 0.012003298924128103,
+ "y": 10.002910596033914
+ },
+ {
+ "x": 0.012003298924128103,
+ "y": 10.002910596022545
+ },
+ {
+ "x": 0.014403958707589481,
+ "y": 12.003492715227324
+ },
+ {
+ "x": 0.012003298924128103,
+ "y": 10.002910596023185
+ },
+ {
+ "x": 0.009602639139529856,
+ "y": 8.002328476818334
+ },
+ {
+ "x": 0.009602639138392988,
+ "y": 8.002328476817766
+ },
+ {
+ "x": 0.01080296903182898,
+ "y": 9.002619536432164
+ },
+ {
+ "x": 0.01080296903182898,
+ "y": 9.002619536420795
+ },
+ {
+ "x": 0.012003298922991235,
+ "y": 10.002910596011212
+ },
+ {
+ "x": 0.014403958707589481,
+ "y": 12.003492715215884
+ },
+ {
+ "x": 0.012003298924128103,
+ "y": 10.002910596022545
+ },
+ {
+ "x": 0.009602639139529856,
+ "y": 8.002328476829774
+ },
+ {
+ "x": 0.012003298922991235,
+ "y": 10.00291059601171
+ },
+ {
+ "x": 0.01440395870872635,
+ "y": 12.003492715227324
+ },
+ {
+ "x": 0.01440395870872635,
+ "y": 12.003492715238693
+ },
+ {
+ "x": 0.014403958707589481,
+ "y": 12.003492715215884
+ },
+ {
+ "x": 0.012003298924128103,
+ "y": 10.002910596011212
+ },
+ {
+ "x": 0.009602639139529856,
+ "y": 8.002328476829241
+ },
+ {
+ "x": 0.012003298922991235,
+ "y": 10.002910596022545
+ },
+ {
+ "x": 0.013203628816427226,
+ "y": 11.003201655624935
+ },
+ {
+ "x": 0.012003298924128103,
+ "y": 10.00291059603395
+ },
+ {
+ "x": 0.013203628815290358,
+ "y": 11.003201655624899
+ },
+ {
+ "x": 0.012003298924128103,
+ "y": 10.002910596023113
+ },
+ {
+ "x": 0.012003298924128103,
+ "y": 10.002910596034482
+ },
+ {
+ "x": 0.014403958707589481,
+ "y": 12.00349271521592
+ },
+ {
+ "x": 0.012003298924128103,
+ "y": 10.002910596011212
+ },
+ {
+ "x": 0.009602639139529856,
+ "y": 8.002328476829206
+ },
+ {
+ "x": 0.012003298924128103,
+ "y": 10.00291059602258
+ },
+ {
+ "x": 0.012003298922991235,
+ "y": 10.00291059601178
+ },
+ {
+ "x": 0.010802969030692111,
+ "y": 9.002619536420724
+ },
+ {
+ "x": 0.013203628816427226,
+ "y": 11.003201655636268
+ },
+ {
+ "x": 0.012003298924128103,
+ "y": 10.002910596022687
+ },
+ {
+ "x": 0.009602639139529856,
+ "y": 8.002328476829739
+ },
+ {
+ "x": 0.009602639138392988,
+ "y": 8.002328476806895
+ },
+ {
+ "x": 0.01080296903182898,
+ "y": 9.002619536408858
+ },
+ {
+ "x": 0.013203628816427226,
+ "y": 11.003201655636303
+ },
+ {
+ "x": 0.013203628815290358,
+ "y": 11.003201655624899
+ },
+ {
+ "x": 0.013203628815290358,
+ "y": 11.003201655613566
+ },
+ {
+ "x": 0.01440395870872635,
+ "y": 12.003492715227289
+ },
+ {
+ "x": 0.012003298924128103,
+ "y": 10.002910596033914
+ },
+ {
+ "x": 0.01080296903182898,
+ "y": 9.00261953642076
+ },
+ {
+ "x": 0.013203628816427226,
+ "y": 11.003201655625485
+ },
+ {
+ "x": 0.012003298922991235,
+ "y": 10.00291059602258
+ },
+ {
+ "x": 0.012003298922991235,
+ "y": 10.002910596022563
+ },
+ {
+ "x": 0.012003298924128103,
+ "y": 10.002910596022545
+ },
+ {
+ "x": 0.009602639139529856,
+ "y": 8.002328476818388
+ },
+ {
+ "x": 0.010802969030692111,
+ "y": 9.00261953642076
+ },
+ {
+ "x": 0.01080296903182898,
+ "y": 9.002619536420315
+ },
+ {
+ "x": 0.009602639139529856,
+ "y": 8.002328476817802
+ },
+ {
+ "x": 0.012003298922991235,
+ "y": 10.002910596022438
+ },
+ {
+ "x": 0.014403958707589481,
+ "y": 12.003492715215938
+ },
+ {
+ "x": 0.01080296903182898,
+ "y": 9.00261953642076
+ },
+ {
+ "x": 0.010861270135364975,
+ "y": 9.051204573738634
+ },
+ {
+ "x": 0.00185401611247471,
+ "y": 10.247016124429411
+ },
+ {
+ "x": -0.2477526508482697,
+ "y": 10.341679690066616
+ },
+ {
+ "x": -0.6818004879880846,
+ "y": 11.0453896949595
+ },
+ {
+ "x": -1.5067884092354689,
+ "y": 12.206061227592837
+ },
+ {
+ "x": -2.6193696985012593,
+ "y": 14.519948558364941
+ },
+ {
+ "x": -3.210384943561735,
+ "y": 13.13624283399455
+ },
+ {
+ "x": -3.6430961971910847,
+ "y": 11.742641276023544
+ },
+ {
+ "x": -4.289761217264072,
+ "y": 11.522110628802018
+ },
+ {
+ "x": -4.374868894687438,
+ "y": 10.164871590581495
+ },
+ {
+ "x": -5.5413969572066435,
+ "y": 10.975123143649052
+ },
+ {
+ "x": -6.690816213455264,
+ "y": 11.751490558381086
+ },
+ {
+ "x": -6.72465023948007,
+ "y": 10.29270360820464
+ },
+ {
+ "x": -7.286034902792835,
+ "y": 9.903274462768122
+ },
+ {
+ "x": -7.824927048296217,
+ "y": 9.483268518458289
+ },
+ {
+ "x": -7.4743605876170705,
+ "y": 8.184448103555143
+ },
+ {
+ "x": -8.905025827874056,
+ "y": 8.599326134261469
+ },
+ {
+ "x": -11.287415618721184,
+ "y": 9.69819203487139
+ },
+ {
+ "x": -9.861900130458707,
+ "y": 7.52008125948967
+ },
+ {
+ "x": -8.228160325267595,
+ "y": 5.5474782493052
+ },
+ {
+ "x": -9.570172710000406,
+ "y": 5.746512270369927
+ },
+ {
+ "x": -12.083316102209665,
+ "y": 6.32891591463803
+ },
+ {
+ "x": -12.43138559842464,
+ "y": 5.6144262620453445
+ },
+ {
+ "x": -10.42375196217563,
+ "y": 3.9943522198585035
+ },
+ {
+ "x": -10.638684285810314,
+ "y": 3.3804855643421883
+ },
+ {
+ "x": -10.784660307365925,
+ "y": 2.8810294924293056
+ },
+ {
+ "x": -9.70836689145301,
+ "y": 2.055054722399159
+ },
+ {
+ "x": -9.793592100608066,
+ "y": 1.600394452604883
+ },
+ {
+ "x": -11.095965342601062,
+ "y": 1.2202762342258433
+ },
+ {
+ "x": -13.449798125160441,
+ "y": 0.7097304545301975
+ },
+ {
+ "x": -13.316124741018598,
+ "y": 0.17870199759416616
+ },
+ {
+ "x": -9.070258808170593,
+ "y": 0.0048184546727503275
+ },
+ {
+ "x": -9.033336110059054,
+ "y": 0.004798839979167635
+ },
+ {
+ "x": -11.018180263448016,
+ "y": 0.005853262106236823
+ },
+ {
+ "x": -9.014874761002716,
+ "y": 0.004789032632377399
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 383.08857968437644,
+ "y": 1.980797890340022,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 92.38854030013255,
+ "y": -121.94744551989223,
+ "z": 1.0
+ },
+ {
+ "x": 92.38846402549676,
+ "y": -121.44568059549218,
+ "z": 1.0
+ },
+ {
+ "x": 92.38840300578813,
+ "y": -121.04426865597216,
+ "z": 1.0
+ },
+ {
+ "x": 92.38834198607951,
+ "y": -120.64285671645214,
+ "z": 1.0
+ },
+ {
+ "x": 92.38828096637087,
+ "y": -120.2414447769321,
+ "z": 1.0
+ },
+ {
+ "x": 92.38821994666225,
+ "y": -119.84003283741208,
+ "z": 1.0
+ },
+ {
+ "x": 92.38821994666225,
+ "y": -119.84003283741208,
+ "z": 1.0
+ },
+ {
+ "x": 92.38815898411413,
+ "y": -119.43899692261479,
+ "z": 1.0
+ },
+ {
+ "x": 92.38808284520091,
+ "y": -118.93812483537857,
+ "z": 1.0
+ },
+ {
+ "x": 92.38799147850507,
+ "y": -118.33707833069512,
+ "z": 1.0
+ },
+ {
+ "x": 92.38790011180922,
+ "y": -117.73603182601165,
+ "z": 1.0
+ },
+ {
+ "x": 92.38780874511338,
+ "y": -117.1349853213282,
+ "z": 1.0
+ },
+ {
+ "x": 92.3877478339828,
+ "y": -116.73428765153922,
+ "z": 1.0
+ },
+ {
+ "x": 92.38768692285224,
+ "y": -116.33358998175025,
+ "z": 1.0
+ },
+ {
+ "x": 92.3875955561564,
+ "y": -115.7325434770668,
+ "z": 1.0
+ },
+ {
+ "x": 92.38753464502582,
+ "y": -115.33184580727782,
+ "z": 1.0
+ },
+ {
+ "x": 92.38747373389526,
+ "y": -114.93114813748885,
+ "z": 1.0
+ },
+ {
+ "x": 92.38741282276469,
+ "y": -114.5304504676996,
+ "z": 1.0
+ },
+ {
+ "x": 92.38732145606885,
+ "y": -113.92940396301641,
+ "z": 1.0
+ },
+ {
+ "x": 92.38726054493829,
+ "y": -113.52870629322744,
+ "z": 1.0
+ },
+ {
+ "x": 92.38718440602507,
+ "y": -113.02783420599124,
+ "z": 1.0
+ },
+ {
+ "x": 92.38709303932922,
+ "y": -112.42678770130777,
+ "z": 1.0
+ },
+ {
+ "x": 92.38700167263336,
+ "y": -111.82574119662432,
+ "z": 1.0
+ },
+ {
+ "x": 92.38692553372016,
+ "y": -111.3248691093881,
+ "z": 1.0
+ },
+ {
+ "x": 92.3868341670243,
+ "y": -110.72382260470464,
+ "z": 1.0
+ },
+ {
+ "x": 92.38677325589374,
+ "y": -110.32312493491567,
+ "z": 1.0
+ },
+ {
+ "x": 92.38671234476318,
+ "y": -109.9224272651267,
+ "z": 1.0
+ },
+ {
+ "x": 92.38662097806733,
+ "y": -109.32138076044323,
+ "z": 1.0
+ },
+ {
+ "x": 92.38652961137149,
+ "y": -108.72033425575978,
+ "z": 1.0
+ },
+ {
+ "x": 92.38643824467563,
+ "y": -108.11928775107631,
+ "z": 1.0
+ },
+ {
+ "x": 92.38637733354507,
+ "y": -107.71859008128735,
+ "z": 1.0
+ },
+ {
+ "x": 92.38628596684921,
+ "y": -107.1175435766039,
+ "z": 1.0
+ },
+ {
+ "x": 92.38620982793601,
+ "y": -106.61667148936768,
+ "z": 1.0
+ },
+ {
+ "x": 92.3861336890228,
+ "y": -106.11579940213146,
+ "z": 1.0
+ },
+ {
+ "x": 92.38604232232696,
+ "y": -105.514752897448,
+ "z": 1.0
+ },
+ {
+ "x": 92.3859509556311,
+ "y": -104.91370639276454,
+ "z": 1.0
+ },
+ {
+ "x": 92.38589004450054,
+ "y": -104.51300872297557,
+ "z": 1.0
+ },
+ {
+ "x": 92.38579867780469,
+ "y": -103.91196221829183,
+ "z": 1.0
+ },
+ {
+ "x": 92.38573776667413,
+ "y": -103.51126454850314,
+ "z": 1.0
+ },
+ {
+ "x": 92.38566162776092,
+ "y": -103.01039246126692,
+ "z": 1.0
+ },
+ {
+ "x": 92.3855854888477,
+ "y": -102.50952037403071,
+ "z": 1.0
+ },
+ {
+ "x": 92.3855093499345,
+ "y": -102.0086482867945,
+ "z": 1.0
+ },
+ {
+ "x": 92.38544843880392,
+ "y": -101.60795061700523,
+ "z": 1.0
+ },
+ {
+ "x": 92.38538752767336,
+ "y": -101.20725294721655,
+ "z": 1.0
+ },
+ {
+ "x": 92.38531138876016,
+ "y": -100.70638085998033,
+ "z": 1.0
+ },
+ {
+ "x": 92.38523524984694,
+ "y": -100.20550877274411,
+ "z": 1.0
+ },
+ {
+ "x": 92.3851438831511,
+ "y": -99.60446226806066,
+ "z": 1.0
+ },
+ {
+ "x": 92.38508297202053,
+ "y": -99.2037645982714,
+ "z": 1.0
+ },
+ {
+ "x": 92.38502206088997,
+ "y": -98.80306692848272,
+ "z": 1.0
+ },
+ {
+ "x": 92.38493069419413,
+ "y": -98.20202042379925,
+ "z": 1.0
+ },
+ {
+ "x": 92.38486978306355,
+ "y": -97.80132275401029,
+ "z": 1.0
+ },
+ {
+ "x": 92.38479364415035,
+ "y": -97.30045066677407,
+ "z": 1.0
+ },
+ {
+ "x": 92.38471750523713,
+ "y": -96.79957857953785,
+ "z": 1.0
+ },
+ {
+ "x": 92.38465659410657,
+ "y": -96.39888090974888,
+ "z": 1.0
+ },
+ {
+ "x": 92.38456522741073,
+ "y": -95.79783440506542,
+ "z": 1.0
+ },
+ {
+ "x": 92.38450431628016,
+ "y": -95.39713673527645,
+ "z": 1.0
+ },
+ {
+ "x": 92.3844434051496,
+ "y": -94.99643906548748,
+ "z": 1.0
+ },
+ {
+ "x": 92.38438249401904,
+ "y": -94.59574139569851,
+ "z": 1.0
+ },
+ {
+ "x": 92.38432158288846,
+ "y": -94.19504372590953,
+ "z": 1.0
+ },
+ {
+ "x": 92.38423021619262,
+ "y": -93.59399722122608,
+ "z": 1.0
+ },
+ {
+ "x": 92.38416930506204,
+ "y": -93.19329955143711,
+ "z": 1.0
+ },
+ {
+ "x": 92.38407793836619,
+ "y": -92.59225304675364,
+ "z": 1.0
+ },
+ {
+ "x": 92.38401702723561,
+ "y": -92.19155537696439,
+ "z": 1.0
+ },
+ {
+ "x": 92.38394088832241,
+ "y": -91.69068328972845,
+ "z": 1.0
+ },
+ {
+ "x": 92.38387997719185,
+ "y": -91.28998561993949,
+ "z": 1.0
+ },
+ {
+ "x": 92.383788610496,
+ "y": -90.68893911525602,
+ "z": 1.0
+ },
+ {
+ "x": 92.3837124715828,
+ "y": -90.1880670280198,
+ "z": 1.0
+ },
+ {
+ "x": 92.38365156045222,
+ "y": -89.78736935823055,
+ "z": 1.0
+ },
+ {
+ "x": 92.38356019375638,
+ "y": -89.18632285354738,
+ "z": 1.0
+ },
+ {
+ "x": 92.38349928262582,
+ "y": -88.7856251837584,
+ "z": 1.0
+ },
+ {
+ "x": 92.38343837149525,
+ "y": -88.38492751396943,
+ "z": 1.0
+ },
+ {
+ "x": 92.38337746036468,
+ "y": -87.98422984418046,
+ "z": 1.0
+ },
+ {
+ "x": 92.38331654923412,
+ "y": -87.5835321743915,
+ "z": 1.0
+ },
+ {
+ "x": 92.38324041032091,
+ "y": -87.08266008715528,
+ "z": 1.0
+ },
+ {
+ "x": 92.38317949919035,
+ "y": -86.68196241736631,
+ "z": 1.0
+ },
+ {
+ "x": 92.38311858805977,
+ "y": -86.28126474757704,
+ "z": 1.0
+ },
+ {
+ "x": 92.38302722136393,
+ "y": -85.68021824289387,
+ "z": 1.0
+ },
+ {
+ "x": 92.38296631023337,
+ "y": -85.2795205731049,
+ "z": 1.0
+ },
+ {
+ "x": 92.38287494353752,
+ "y": -84.67847406842144,
+ "z": 1.0
+ },
+ {
+ "x": 92.38278357684167,
+ "y": -84.07742756373798,
+ "z": 1.0
+ },
+ {
+ "x": 92.3827226657111,
+ "y": -83.676729893949,
+ "z": 1.0
+ },
+ {
+ "x": 92.38263129901524,
+ "y": -83.07568338926527,
+ "z": 1.0
+ },
+ {
+ "x": 92.38255516010203,
+ "y": -82.57481130202933,
+ "z": 1.0
+ },
+ {
+ "x": 92.38246379340619,
+ "y": -81.97376479734588,
+ "z": 1.0
+ },
+ {
+ "x": 92.38240288227561,
+ "y": -81.57306712755661,
+ "z": 1.0
+ },
+ {
+ "x": 92.38232674336241,
+ "y": -81.07219504032068,
+ "z": 1.0
+ },
+ {
+ "x": 92.38225060444921,
+ "y": -80.57132295308448,
+ "z": 1.0
+ },
+ {
+ "x": 92.38218969331864,
+ "y": -80.1706252832955,
+ "z": 1.0
+ },
+ {
+ "x": 92.3820983266228,
+ "y": -79.56957877861204,
+ "z": 1.0
+ },
+ {
+ "x": 92.38203741549222,
+ "y": -79.16888110882307,
+ "z": 1.0
+ },
+ {
+ "x": 92.38194604879638,
+ "y": -78.5678346041396,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 8,
+ "heading": [
+ 1.5709483394834889,
+ 1.5709483394834909,
+ 1.5709483394834847,
+ 1.5709483394834767,
+ 1.5709483394834944,
+ 1.5709483394834944,
+ 1.5709483394834767,
+ 1.5709483394835362,
+ 1.5709483394835178,
+ 1.5709483394834876,
+ 1.5709483394834864,
+ 1.5709483394834864,
+ 1.5709483394834889,
+ 1.5709483394834922,
+ 1.5709483394834747,
+ 1.5709483394834889,
+ 1.5709483394834922,
+ 1.5709483394834922,
+ 1.5709483394834889,
+ 1.5709483394834747,
+ 1.5709483394834904,
+ 1.5709483394835004,
+ 1.5709483394834982,
+ 1.5709483394834876,
+ 1.5709483394834876,
+ 1.5709483394834889,
+ 1.5709483394834747,
+ 1.5709483394834889,
+ 1.5709483394834864,
+ 1.5709483394834864,
+ 1.5709483394834889,
+ 1.5709483394834889,
+ 1.5709483394834876,
+ 1.5709483394834889,
+ 1.5709483394834876,
+ 1.5709483394834864,
+ 1.5709483394834889,
+ 1.5709483394834887,
+ 1.5709483394834889,
+ 1.5709483394834747,
+ 1.5709483394835029,
+ 1.5709483394835029,
+ 1.5709483394834902,
+ 1.5709483394834922,
+ 1.5709483394834747,
+ 1.5709483394834889,
+ 1.5709483394834876,
+ 1.5709483394834887,
+ 1.5709483394834922,
+ 1.5709483394834747,
+ 1.5709483394834889,
+ 1.5709483394834904,
+ 1.5709483394834889,
+ 1.5709483394834904,
+ 1.5709483394834747,
+ 1.5709483394834889,
+ 1.5709483394834922,
+ 1.5709483394834747,
+ 1.5709483394834922,
+ 1.5709483394834889,
+ 1.5709483394834889,
+ 1.5709483394835029,
+ 1.5709483394835029,
+ 1.5709483394834904,
+ 1.5709483394834747,
+ 1.5709483394834889,
+ 1.5709483394834876,
+ 1.5709483394834902,
+ 1.5709483394834889,
+ 1.5709483394834747,
+ 1.5709483394834922,
+ 1.5709483394834922,
+ 1.5709483394834747,
+ 1.5709483394834904,
+ 1.5709483394834904,
+ 1.5709483394834922,
+ 1.5709483394834889,
+ 1.5709483394834747,
+ 1.5709483394834889,
+ 1.5709483394834864,
+ 1.5709483394834889,
+ 1.5709483394835029,
+ 1.5709483394835004,
+ 1.5709483394834876,
+ 1.5709483394834887,
+ 1.5709483394834904,
+ 1.5709483394834747,
+ 1.5709483394834904,
+ 1.5709483394834889,
+ 1.5709483394834889,
+ 1.5709483394834889
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -0.000762746357878541,
+ "y": 5.017649244000495
+ },
+ {
+ "x": -0.0013729434441245303,
+ "y": 9.031768639200664
+ },
+ {
+ "x": -0.0012203941724919787,
+ "y": 8.028238790400337
+ },
+ {
+ "x": -0.0012203941726340872,
+ "y": 8.028238790400621
+ },
+ {
+ "x": -0.0012203941726340872,
+ "y": 8.028238790400621
+ },
+ {
+ "x": -0.0006101970862459893,
+ "y": 4.014119395200169
+ },
+ {
+ "x": -0.0006096254811893687,
+ "y": 4.010359147972906
+ },
+ {
+ "x": -0.0013710146133405487,
+ "y": 9.019080020335082
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.0018273339169638803,
+ "y": 12.020930093669193
+ },
+ {
+ "x": -0.0018273339169638803,
+ "y": 12.020930093669193
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.001218222611356623,
+ "y": 8.01395339577951
+ },
+ {
+ "x": -0.001522778264018143,
+ "y": 10.01744174472421
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.001218222611356623,
+ "y": 8.01395339577951
+ },
+ {
+ "x": -0.001218222611356623,
+ "y": 8.01395339578221
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.001522778264018143,
+ "y": 10.01744174472151
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.015697570251717
+ },
+ {
+ "x": -0.0016750560907041745,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.0018273339171059888,
+ "y": 12.020930093669193
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196843
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0012182226112145145,
+ "y": 8.013953395779367
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0018273339169638803,
+ "y": 12.020930093669193
+ },
+ {
+ "x": -0.0018273339169638803,
+ "y": 12.020930093669193
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.01744174472421
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.0018273339169638803,
+ "y": 12.020930093669193
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744727051
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0013705004376163288,
+ "y": 9.01569757024916
+ },
+ {
+ "x": -0.0015227782643023602,
+ "y": 10.01744174472421
+ },
+ {
+ "x": -0.0015227782643023602,
+ "y": 10.01744174472421
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.015697570254844
+ },
+ {
+ "x": -0.001218222611356623,
+ "y": 8.01395339577951
+ },
+ {
+ "x": -0.0013705004376163288,
+ "y": 9.015697570249017
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744727051
+ },
+ {
+ "x": -0.001218222611356623,
+ "y": 8.013953395779367
+ },
+ {
+ "x": -0.001522778264018143,
+ "y": 10.01744174472151
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.01569757025186
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.01569757025186
+ },
+ {
+ "x": -0.001522778264018143,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.001218222611356623,
+ "y": 8.013953395779367
+ },
+ {
+ "x": -0.0012182226112145145,
+ "y": 8.013953395779367
+ },
+ {
+ "x": -0.001218222611356623,
+ "y": 8.01395339577951
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.01744174472421
+ },
+ {
+ "x": -0.0015227782643023602,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0015227782643023602,
+ "y": 10.017441744727194
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.01569757025186
+ },
+ {
+ "x": -0.0013705004376163288,
+ "y": 9.015697570249017
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196843
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.015697570254702
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.01744174472421
+ },
+ {
+ "x": -0.001522778264018143,
+ "y": 10.01744174472151
+ },
+ {
+ "x": -0.001218222611356623,
+ "y": 8.01395339577951
+ },
+ {
+ "x": -0.001218222611356623,
+ "y": 8.013953395779367
+ },
+ {
+ "x": -0.0012182226112145145,
+ "y": 8.013953395779367
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.01569757025186
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.01569757025186
+ },
+ {
+ "x": -0.001218222611356623,
+ "y": 8.013953395782352
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.001522778264018143,
+ "y": 10.017441744721367
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0018273339169638803,
+ "y": 12.020930093669193
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0015227782643023602,
+ "y": 10.017441744727194
+ },
+ {
+ "x": -0.0016750560907041745,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919193859
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744727194
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.015697570252001
+ },
+ {
+ "x": -0.001522778264018143,
+ "y": 10.017441744721367
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.01569757025186
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.01744174472421
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 92.38194604879638,
+ "y": -78.5678346041396,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 336.1489057852639,
+ "y": -325.05033162122857,
+ "z": 1.0
+ },
+ {
+ "x": 336.5229456022105,
+ "y": -325.67646946787795,
+ "z": 1.0
+ },
+ {
+ "x": 336.7939565516582,
+ "y": -326.0799650034013,
+ "z": 1.0
+ },
+ {
+ "x": 337.15633618498657,
+ "y": -326.5676097729596,
+ "z": 1.0
+ },
+ {
+ "x": 337.5440052274156,
+ "y": -327.03539979664663,
+ "z": 1.0
+ },
+ {
+ "x": 337.9622085454788,
+ "y": -327.4877505784889,
+ "z": 1.0
+ },
+ {
+ "x": 338.3183308810072,
+ "y": -327.8342538022563,
+ "z": 1.0
+ },
+ {
+ "x": 338.8825055067306,
+ "y": -328.3211543814014,
+ "z": 1.0
+ },
+ {
+ "x": 339.378296205565,
+ "y": -328.69520423560505,
+ "z": 1.0
+ },
+ {
+ "x": 340.0013780611089,
+ "y": -329.10403038474396,
+ "z": 1.0
+ },
+ {
+ "x": 340.5418874628223,
+ "y": -329.4099335158296,
+ "z": 1.0
+ },
+ {
+ "x": 340.9871585419557,
+ "y": -329.63124209683366,
+ "z": 1.0
+ },
+ {
+ "x": 341.5575350479918,
+ "y": -329.8773357090277,
+ "z": 1.0
+ },
+ {
+ "x": 342.141456730006,
+ "y": -330.0889067021541,
+ "z": 1.0
+ },
+ {
+ "x": 342.8572627989721,
+ "y": -330.29624980319954,
+ "z": 1.0
+ },
+ {
+ "x": 343.5860716295812,
+ "y": -330.45182618187255,
+ "z": 1.0
+ },
+ {
+ "x": 344.07732448992476,
+ "y": -330.52637956177955,
+ "z": 1.0
+ },
+ {
+ "x": 344.57157639307513,
+ "y": -330.5773955476963,
+ "z": 1.0
+ },
+ {
+ "x": 345.31253722029027,
+ "y": -330.6095350149743,
+ "z": 1.0
+ },
+ {
+ "x": 345.82291093398845,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 346.2243261579756,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 346.6257413819628,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 347.02715660595004,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 347.528925635934,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 347.7296332479276,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 348.1305367405361,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 348.73136320009144,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 349.23205191638755,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 349.73274063268366,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 350.1332916057205,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 350.6339803220166,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 351.0345312950535,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 351.5352200113496,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 351.93577098438647,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 352.33632195742337,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 352.8370106737195,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 353.2375616467564,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 353.6381126197932,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 354.23893907934854,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 354.8397655389039,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 355.24031651194076,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 355.8411429714961,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 356.4419694310514,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 357.0427958906067,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 357.4433468636436,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 357.8438978366805,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 358.44472429623585,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 358.94541301253196,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 359.3459639855688,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 359.9467904451242,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 360.44747916142023,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 360.94816787771634,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 361.44885659401245,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 361.94954531030857,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 362.4502340266047,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 362.9509227429008,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 363.4516114591969,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 364.0524379187522,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 364.45298889178906,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 365.0538153513444,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 365.5545040676405,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 366.0551927839366,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 366.5558815002327,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 367.0565702165288,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 367.65739667608415,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 368.15808539238026,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 368.65877410867637,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 369.1594628249725,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 369.5600137980093,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 369.9605647710462,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 370.3611157440831,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 370.76166671712,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 371.16221769015687,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 371.662906406453,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 372.1635951227491,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 372.6642838390452,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 373.1649725553413,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 373.6656612716374,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 374.26648773119274,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 374.76717644748885,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 375.2678651637849,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 375.768553880081,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 376.36938033963634,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 376.76993131267324,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 377.17048228571014,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 377.571033258747,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 378.17185971830236,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 378.7726861778577,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 379.1732371508945,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 379.5737881239314,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ {
+ "x": 380.17461458348674,
+ "y": -330.6099853515625,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 9,
+ "heading": [
+ -0.11553553829427615,
+ -1.0323083606255987,
+ -1.0111292333148185,
+ -0.9528825726285378,
+ -0.9052479255653736,
+ -0.8515053875159617,
+ -0.8009884773025137,
+ -0.7358901996185394,
+ -0.6821623094798233,
+ -0.6105251199603642,
+ -0.5508274551632518,
+ -0.4911113655175353,
+ -0.4313047534661909,
+ -0.3774745492893383,
+ -0.3117961589325643,
+ -0.24612873318359238,
+ -0.18643105564388768,
+ -0.1267334041301747,
+ -0.067219329230323,
+ -0.026038151534696963,
+ -0.0004939043817662466,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": 3.7403981694660615,
+ "y": -6.261378466493852
+ },
+ {
+ "x": 6.450507663943199,
+ "y": -10.29633382172733
+ },
+ {
+ "x": 6.333905827760873,
+ "y": -8.911403050816489
+ },
+ {
+ "x": 7.500486757573981,
+ "y": -9.554347932453311
+ },
+ {
+ "x": 8.058723604922307,
+ "y": -9.201408055292859
+ },
+ {
+ "x": 7.743256535916316,
+ "y": -7.988540056096554
+ },
+ {
+ "x": 9.20296961251779,
+ "y": -8.334038029125281
+ },
+ {
+ "x": 10.599653245577656,
+ "y": -8.609504333487621
+ },
+ {
+ "x": 11.188725543782994,
+ "y": -7.82876003342551
+ },
+ {
+ "x": 11.635912572572806,
+ "y": -7.147292802245602
+ },
+ {
+ "x": 9.857804808468131,
+ "y": -5.272117120896951
+ },
+ {
+ "x": 10.156475851695177,
+ "y": -4.674021931980974
+ },
+ {
+ "x": 11.542981880502907,
+ "y": -4.576646053204172
+ },
+ {
+ "x": 12.997277509803098,
+ "y": -4.189140941718392
+ },
+ {
+ "x": 14.446148995752424,
+ "y": -3.6291947971847094
+ },
+ {
+ "x": 12.200616909526616,
+ "y": -2.3012975858000573
+ },
+ {
+ "x": 9.85504763493907,
+ "y": -1.2556936582376466
+ },
+ {
+ "x": 12.352127303655038,
+ "y": -0.8315545319476314
+ },
+ {
+ "x": 12.513345409133194,
+ "y": -0.32589803866187594
+ },
+ {
+ "x": 9.11788937685344,
+ "y": -0.004503365881873833
+ },
+ {
+ "x": 8.028304479743724,
+ "y": 0.0
+ },
+ {
+ "x": 8.028304479744293,
+ "y": 0.0
+ },
+ {
+ "x": 9.03184253971176,
+ "y": 0.0
+ },
+ {
+ "x": 7.024766419775688,
+ "y": 0.0
+ },
+ {
+ "x": 6.0161110460211376,
+ "y": 0.0
+ },
+ {
+ "x": 10.017299521638279,
+ "y": 0.0
+ },
+ {
+ "x": 11.015151758514321,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 9.012396893329537,
+ "y": 0.0
+ },
+ {
+ "x": 9.012396893329537,
+ "y": 0.0
+ },
+ {
+ "x": 9.012396893330106,
+ "y": 0.0
+ },
+ {
+ "x": 9.012396893330106,
+ "y": 0.0
+ },
+ {
+ "x": 9.012396893329537,
+ "y": 0.0
+ },
+ {
+ "x": 8.01101946073743,
+ "y": 0.0
+ },
+ {
+ "x": 9.012396893330106,
+ "y": 0.0
+ },
+ {
+ "x": 9.012396893330106,
+ "y": 0.0
+ },
+ {
+ "x": 8.01101946073743,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325921645,
+ "y": 0.0
+ },
+ {
+ "x": 12.016529191106997,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325921645,
+ "y": 0.0
+ },
+ {
+ "x": 12.016529191106429,
+ "y": 0.0
+ },
+ {
+ "x": 12.016529191106429,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 8.011019460737998,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 11.015151758514321,
+ "y": 0.0
+ },
+ {
+ "x": 9.012396893329537,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 11.015151758514321,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325921645,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 11.015151758514321,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325921645,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325921645,
+ "y": 0.0
+ },
+ {
+ "x": 11.015151758514321,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 11.015151758514321,
+ "y": 0.0
+ },
+ {
+ "x": 11.015151758514321,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 9.012396893329537,
+ "y": 0.0
+ },
+ {
+ "x": 8.01101946073743,
+ "y": 0.0
+ },
+ {
+ "x": 8.011019460737998,
+ "y": 0.0
+ },
+ {
+ "x": 8.011019460737998,
+ "y": 0.0
+ },
+ {
+ "x": 8.01101946073743,
+ "y": 0.0
+ },
+ {
+ "x": 9.012396893329537,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 11.015151758514321,
+ "y": 0.0
+ },
+ {
+ "x": 11.015151758514321,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325921645,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325921645,
+ "y": 0.0
+ },
+ {
+ "x": 11.015151758514321,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 8.011019460737998,
+ "y": 0.0
+ },
+ {
+ "x": 8.01101946073743,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ },
+ {
+ "x": 12.016529191106997,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325921645,
+ "y": 0.0
+ },
+ {
+ "x": 8.01101946073743,
+ "y": 0.0
+ },
+ {
+ "x": 10.013774325922213,
+ "y": 0.0
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 380.17461458348674,
+ "y": -330.6099853515625,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 334.75466558785854,
+ "y": -240.4847832109267,
+ "z": 1.0
+ },
+ {
+ "x": 334.7543028798573,
+ "y": -241.0852821771714,
+ "z": 1.0
+ },
+ {
+ "x": 334.75406107452307,
+ "y": -241.48561482133636,
+ "z": 1.0
+ },
+ {
+ "x": 334.75381926918885,
+ "y": -241.88594746550024,
+ "z": 1.0
+ },
+ {
+ "x": 334.75357746385475,
+ "y": -242.28628010966406,
+ "z": 1.0
+ },
+ {
+ "x": 334.75333565852054,
+ "y": -242.68661275382675,
+ "z": 1.0
+ },
+ {
+ "x": 334.7530334018528,
+ "y": -243.18702855903274,
+ "z": 1.0
+ },
+ {
+ "x": 334.75273114518507,
+ "y": -243.68744436423754,
+ "z": 1.0
+ },
+ {
+ "x": 334.7523684371838,
+ "y": -244.28794333048216,
+ "z": 1.0
+ },
+ {
+ "x": 334.75206618051607,
+ "y": -244.7883591356881,
+ "z": 1.0
+ },
+ {
+ "x": 334.75182437518185,
+ "y": -245.18869177985084,
+ "z": 1.0
+ },
+ {
+ "x": 334.7514616671806,
+ "y": -245.78919074609774,
+ "z": 1.0
+ },
+ {
+ "x": 334.75109895917933,
+ "y": -246.3896897123435,
+ "z": 1.0
+ },
+ {
+ "x": 334.7508571538451,
+ "y": -246.7900223565062,
+ "z": 1.0
+ },
+ {
+ "x": 334.7505548971774,
+ "y": -247.2904381617122,
+ "z": 1.0
+ },
+ {
+ "x": 334.7501921891761,
+ "y": -247.89093712795682,
+ "z": 1.0
+ },
+ {
+ "x": 334.7499503838419,
+ "y": -248.29126977212064,
+ "z": 1.0
+ },
+ {
+ "x": 334.74958767584064,
+ "y": -248.89176873836755,
+ "z": 1.0
+ },
+ {
+ "x": 334.7492249678394,
+ "y": -249.49226770461217,
+ "z": 1.0
+ },
+ {
+ "x": 334.74898316250517,
+ "y": -249.89260034877606,
+ "z": 1.0
+ },
+ {
+ "x": 334.74868090583743,
+ "y": -250.39301615398085,
+ "z": 1.0
+ },
+ {
+ "x": 334.7483786491697,
+ "y": -250.89343195918678,
+ "z": 1.0
+ },
+ {
+ "x": 334.74801594116843,
+ "y": -251.4939309254314,
+ "z": 1.0
+ },
+ {
+ "x": 334.74765323316717,
+ "y": -252.09442989167837,
+ "z": 1.0
+ },
+ {
+ "x": 334.74735097649943,
+ "y": -252.59484569688203,
+ "z": 1.0
+ },
+ {
+ "x": 334.74698826849806,
+ "y": -253.19534466312894,
+ "z": 1.0
+ },
+ {
+ "x": 334.7466860118303,
+ "y": -253.69576046833373,
+ "z": 1.0
+ },
+ {
+ "x": 334.7464442064962,
+ "y": -254.0960931124976,
+ "z": 1.0
+ },
+ {
+ "x": 334.7461419498285,
+ "y": -254.5965089177024,
+ "z": 1.0
+ },
+ {
+ "x": 334.7457792418271,
+ "y": -255.19700788394817,
+ "z": 1.0
+ },
+ {
+ "x": 334.74541653382585,
+ "y": -255.7975068501928,
+ "z": 1.0
+ },
+ {
+ "x": 334.7451142771581,
+ "y": -256.2979226553988,
+ "z": 1.0
+ },
+ {
+ "x": 334.7448120204904,
+ "y": -256.79833846060353,
+ "z": 1.0
+ },
+ {
+ "x": 334.74450976382263,
+ "y": -257.2987542658084,
+ "z": 1.0
+ },
+ {
+ "x": 334.7442075071549,
+ "y": -257.7991700710121,
+ "z": 1.0
+ },
+ {
+ "x": 334.7439657018208,
+ "y": -258.199502715177,
+ "z": 1.0
+ },
+ {
+ "x": 334.74366344515306,
+ "y": -258.6999185203807,
+ "z": 1.0
+ },
+ {
+ "x": 334.7433007371517,
+ "y": -259.3004174866277,
+ "z": 1.0
+ },
+ {
+ "x": 334.7430589318175,
+ "y": -259.70075013079145,
+ "z": 1.0
+ },
+ {
+ "x": 334.7428171264834,
+ "y": -260.1010827749542,
+ "z": 1.0
+ },
+ {
+ "x": 334.74251486981564,
+ "y": -260.6014985801602,
+ "z": 1.0
+ },
+ {
+ "x": 334.7421521618144,
+ "y": -261.20199754640475,
+ "z": 1.0
+ },
+ {
+ "x": 334.74184990514664,
+ "y": -261.7024133516096,
+ "z": 1.0
+ },
+ {
+ "x": 334.7415476484789,
+ "y": -262.2028291568156,
+ "z": 1.0
+ },
+ {
+ "x": 334.74118494047764,
+ "y": -262.80332812306017,
+ "z": 1.0
+ },
+ {
+ "x": 334.7409431351434,
+ "y": -263.20366076722405,
+ "z": 1.0
+ },
+ {
+ "x": 334.74058042714205,
+ "y": -263.8041597334709,
+ "z": 1.0
+ },
+ {
+ "x": 334.7402781704744,
+ "y": -264.30457553867575,
+ "z": 1.0
+ },
+ {
+ "x": 334.7400363651402,
+ "y": -264.70490818283963,
+ "z": 1.0
+ },
+ {
+ "x": 334.739794559806,
+ "y": -265.10524082700226,
+ "z": 1.0
+ },
+ {
+ "x": 334.73943185180474,
+ "y": -265.7057397932481,
+ "z": 1.0
+ },
+ {
+ "x": 334.7390691438035,
+ "y": -266.30623875949505,
+ "z": 1.0
+ },
+ {
+ "x": 334.73876688713574,
+ "y": -266.8066545646998,
+ "z": 1.0
+ },
+ {
+ "x": 334.73840417913436,
+ "y": -267.4071535309456,
+ "z": 1.0
+ },
+ {
+ "x": 334.7380414711331,
+ "y": -268.0076524971913,
+ "z": 1.0
+ },
+ {
+ "x": 334.73767876313184,
+ "y": -268.60815146343714,
+ "z": 1.0
+ },
+ {
+ "x": 334.7373160551306,
+ "y": -269.20865042968285,
+ "z": 1.0
+ },
+ {
+ "x": 334.73701379846284,
+ "y": -269.7090662348877,
+ "z": 1.0
+ },
+ {
+ "x": 334.7367719931286,
+ "y": -270.1093988790516,
+ "z": 1.0
+ },
+ {
+ "x": 334.7364697364609,
+ "y": -270.6098146842563,
+ "z": 1.0
+ },
+ {
+ "x": 334.7361070284596,
+ "y": -271.210313650501,
+ "z": 1.0
+ },
+ {
+ "x": 334.7358047717919,
+ "y": -271.710729455707,
+ "z": 1.0
+ },
+ {
+ "x": 334.7355629664578,
+ "y": -272.1110620998696,
+ "z": 1.0
+ },
+ {
+ "x": 334.73526070978994,
+ "y": -272.6114779050756,
+ "z": 1.0
+ },
+ {
+ "x": 334.7349584531222,
+ "y": -273.11189371028047,
+ "z": 1.0
+ },
+ {
+ "x": 334.73459574512094,
+ "y": -273.7123926765262,
+ "z": 1.0
+ },
+ {
+ "x": 334.73435393978684,
+ "y": -274.1127253206889,
+ "z": 1.0
+ },
+ {
+ "x": 334.73411213445263,
+ "y": -274.5130579648528,
+ "z": 1.0
+ },
+ {
+ "x": 334.7338098777849,
+ "y": -275.01347377005754,
+ "z": 1.0
+ },
+ {
+ "x": 334.7335680724507,
+ "y": -275.4138064142214,
+ "z": 1.0
+ },
+ {
+ "x": 334.73332626711647,
+ "y": -275.81413905838644,
+ "z": 1.0
+ },
+ {
+ "x": 334.73308446178225,
+ "y": -276.2144717025502,
+ "z": 1.0
+ },
+ {
+ "x": 334.7327822051145,
+ "y": -276.71488750775507,
+ "z": 1.0
+ },
+ {
+ "x": 334.7324799484468,
+ "y": -277.2153033129599,
+ "z": 1.0
+ },
+ {
+ "x": 334.7321172404455,
+ "y": -277.8158022792056,
+ "z": 1.0
+ },
+ {
+ "x": 334.7318754351114,
+ "y": -278.2161349233684,
+ "z": 1.0
+ },
+ {
+ "x": 334.7316336297772,
+ "y": -278.61646756753225,
+ "z": 1.0
+ },
+ {
+ "x": 334.73133137310947,
+ "y": -279.116883372737,
+ "z": 1.0
+ },
+ {
+ "x": 334.7309686651081,
+ "y": -279.7173823389828,
+ "z": 1.0
+ },
+ {
+ "x": 334.73060595710683,
+ "y": -280.31788130522966,
+ "z": 1.0
+ },
+ {
+ "x": 334.73024324910557,
+ "y": -280.91838027147435,
+ "z": 1.0
+ },
+ {
+ "x": 334.72994099243783,
+ "y": -281.4187960766802,
+ "z": 1.0
+ },
+ {
+ "x": 334.7296387357701,
+ "y": -281.9192118818862,
+ "z": 1.0
+ },
+ {
+ "x": 334.72927602776883,
+ "y": -282.51971084812976,
+ "z": 1.0
+ },
+ {
+ "x": 334.72891331976757,
+ "y": -283.12020981437547,
+ "z": 1.0
+ },
+ {
+ "x": 334.72867151443336,
+ "y": -283.5205424585405,
+ "z": 1.0
+ },
+ {
+ "x": 334.72842970909915,
+ "y": -283.9208751027044,
+ "z": 1.0
+ },
+ {
+ "x": 334.7281274524314,
+ "y": -284.4212909079091,
+ "z": 1.0
+ },
+ {
+ "x": 334.7278856470972,
+ "y": -284.821623552073,
+ "z": 1.0
+ },
+ {
+ "x": 334.72752293909593,
+ "y": -285.4221225183177,
+ "z": 1.0
+ },
+ {
+ "x": 334.7272811337617,
+ "y": -285.8224551624826,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 10,
+ "heading": [
+ -1.5714003377550492,
+ -1.5714003377550179,
+ -1.5714003377550545,
+ -1.5714003377551105,
+ -1.5714003377549692,
+ -1.5714003377549701,
+ -1.5714003377550798,
+ -1.5714003377550538,
+ -1.5714003377550345,
+ -1.5714003377550338,
+ -1.5714003377550798,
+ -1.5714003377550545,
+ -1.571400337755016,
+ -1.5714003377550552,
+ -1.5714003377550798,
+ -1.5714003377550338,
+ -1.5714003377550552,
+ -1.5714003377550538,
+ -1.5714003377550168,
+ -1.5714003377550552,
+ -1.5714003377550798,
+ -1.5714003377550538,
+ -1.5714003377550338,
+ -1.5714003377550168,
+ -1.5714003377550338,
+ -1.571400337755137,
+ -1.5714003377551364,
+ -1.5714003377549535,
+ -1.5714003377549535,
+ -1.571400337755137,
+ -1.571400337755112,
+ -1.5714003377550338,
+ -1.5714003377550538,
+ -1.5714003377550545,
+ -1.5714003377550552,
+ -1.5714003377549537,
+ -1.5714003377549537,
+ -1.571400337755137,
+ -1.5714003377551675,
+ -1.5714003377549701,
+ -1.5714003377549535,
+ -1.5714003377550338,
+ -1.5714003377550345,
+ -1.5714003377550538,
+ -1.5714003377550338,
+ -1.5714003377550552,
+ -1.5714003377551675,
+ -1.5714003377550332,
+ -1.5714003377549535,
+ -1.5714003377551122,
+ -1.5714003377550552,
+ -1.571400337755016,
+ -1.5714003377550332,
+ -1.571400337755137,
+ -1.5714003377551113,
+ -1.5714003377550168,
+ -1.5714003377550168,
+ -1.5714003377550338,
+ -1.5714003377550798,
+ -1.5714003377550798,
+ -1.5714003377550345,
+ -1.5714003377550338,
+ -1.5714003377549537,
+ -1.5714003377550798,
+ -1.5714003377551673,
+ -1.5714003377550338,
+ -1.5714003377549417,
+ -1.5714003377549701,
+ -1.5714003377550798,
+ -1.5714003377550798,
+ -1.5714003377551105,
+ -1.5714003377551105,
+ -1.5714003377550798,
+ -1.5714003377550545,
+ -1.5714003377550338,
+ -1.5714003377549417,
+ -1.5714003377549701,
+ -1.5714003377550798,
+ -1.571400337755137,
+ -1.5714003377551107,
+ -1.5714003377550168,
+ -1.5714003377550338,
+ -1.5714003377550532,
+ -1.5714003377550345,
+ -1.5714003377550179,
+ -1.5714003377550538,
+ -1.5714003377551105,
+ -1.5714003377550798,
+ -1.5714003377550798,
+ -1.5714003377550552,
+ -1.5714003377550545
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -0.003627080012620354,
+ "y": -6.00498966244686
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.00831610409648
+ },
+ {
+ "x": -0.0048361066842517175,
+ "y": -8.006652883288439
+ },
+ {
+ "x": -0.004836106683114849,
+ "y": -8.00665288327707
+ },
+ {
+ "x": -0.004836106683114849,
+ "y": -8.006652883265133
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686775
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104107848
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714494247
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714505616
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686775
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.00831610409648
+ },
+ {
+ "x": -0.007254160025240708,
+ "y": -12.00997932492669
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104084543
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686775
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714506184
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104084543
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.00831610410728
+ },
+ {
+ "x": -0.007254160025240708,
+ "y": -12.00997932491532
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104085111
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686775
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.00831610410728
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714505616
+ },
+ {
+ "x": -0.007254160025240708,
+ "y": -12.00997932491589
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714506184
+ },
+ {
+ "x": -0.006649646691130329,
+ "y": -11.009147714505616
+ },
+ {
+ "x": -0.006649646691130329,
+ "y": -11.009147714516985
+ },
+ {
+ "x": -0.005440620018362097,
+ "y": -9.007484493686775
+ },
+ {
+ "x": -0.005440620018362097,
+ "y": -9.007484493686775
+ },
+ {
+ "x": -0.006649646691130329,
+ "y": -11.009147714505616
+ },
+ {
+ "x": -0.007254160026377576,
+ "y": -12.009979324903952
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714506184
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.00831610410728
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104095911
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.00831610408568
+ },
+ {
+ "x": -0.005440620018362097,
+ "y": -9.007484493686206
+ },
+ {
+ "x": -0.005440620018362097,
+ "y": -9.007484493686206
+ },
+ {
+ "x": -0.006649646691130329,
+ "y": -11.009147714506753
+ },
+ {
+ "x": -0.006045133355883081,
+ "y": -10.00831610410728
+ },
+ {
+ "x": -0.004836106683114849,
+ "y": -8.006652883265133
+ },
+ {
+ "x": -0.005440620018362097,
+ "y": -9.007484493687343
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714505616
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714494247
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104108417
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714505616
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104084543
+ },
+ {
+ "x": -0.006045133355883081,
+ "y": -10.00831610410728
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714516985
+ },
+ {
+ "x": -0.005440620018362097,
+ "y": -9.007484493687343
+ },
+ {
+ "x": -0.0048361066842517175,
+ "y": -8.006652883265133
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104084543
+ },
+ {
+ "x": -0.007254160025240708,
+ "y": -12.009979324927826
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714516985
+ },
+ {
+ "x": -0.006649646691130329,
+ "y": -11.009147714505616
+ },
+ {
+ "x": -0.007254160026377576,
+ "y": -12.00997932491532
+ },
+ {
+ "x": -0.007254160025240708,
+ "y": -12.00997932491532
+ },
+ {
+ "x": -0.007254160025240708,
+ "y": -12.00997932491532
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714505616
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493687343
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686206
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714494247
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714506753
+ },
+ {
+ "x": -0.005440620018362097,
+ "y": -9.007484493686206
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686206
+ },
+ {
+ "x": -0.006045133355883081,
+ "y": -10.008316104108417
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714505616
+ },
+ {
+ "x": -0.006045133353609344,
+ "y": -10.008316104084543
+ },
+ {
+ "x": -0.004836106683114849,
+ "y": -8.00665288326627
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686206
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686206
+ },
+ {
+ "x": -0.0048361066842517175,
+ "y": -8.006652883289007
+ },
+ {
+ "x": -0.0048361066842517175,
+ "y": -8.00665288328787
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686206
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104097048
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714505616
+ },
+ {
+ "x": -0.006045133353609344,
+ "y": -10.008316104084543
+ },
+ {
+ "x": -0.004836106683114849,
+ "y": -8.00665288326627
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686206
+ },
+ {
+ "x": -0.006649646691130329,
+ "y": -11.009147714505616
+ },
+ {
+ "x": -0.007254160026377576,
+ "y": -12.00997932492669
+ },
+ {
+ "x": -0.007254160025240708,
+ "y": -12.00997932491532
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714505616
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104118649
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714495384
+ },
+ {
+ "x": -0.007254160025240708,
+ "y": -12.009979324892583
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.00831610410728
+ },
+ {
+ "x": -0.0048361066842517175,
+ "y": -8.006652883289007
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686206
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686206
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.00831610408568
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104095911
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 334.7272811337617,
+ "y": -285.8224551624826,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 158.0791310994979,
+ "y": -7.179605138451363,
+ "z": 1.0
+ },
+ {
+ "x": 158.11097082453202,
+ "y": -6.804332927747964,
+ "z": 1.0
+ },
+ {
+ "x": 158.15356090357636,
+ "y": -6.506044877657019,
+ "z": 1.0
+ },
+ {
+ "x": 158.24571299169025,
+ "y": -6.06363223592093,
+ "z": 1.0
+ },
+ {
+ "x": 158.37129529979165,
+ "y": -5.629523240288274,
+ "z": 1.0
+ },
+ {
+ "x": 158.52957898435005,
+ "y": -5.206238236024314,
+ "z": 1.0
+ },
+ {
+ "x": 158.68580526464018,
+ "y": -4.863544334243314,
+ "z": 1.0
+ },
+ {
+ "x": 158.82599564588895,
+ "y": -4.597510743033778,
+ "z": 1.0
+ },
+ {
+ "x": 159.02040646680712,
+ "y": -4.274940885637076,
+ "z": 1.0
+ },
+ {
+ "x": 159.19043770232992,
+ "y": -4.026182441576452,
+ "z": 1.0
+ },
+ {
+ "x": 159.3728867448101,
+ "y": -3.7863852726082063,
+ "z": 1.0
+ },
+ {
+ "x": 159.66581715772864,
+ "y": -3.4485299588337934,
+ "z": 1.0
+ },
+ {
+ "x": 159.86664884961996,
+ "y": -3.248066137378774,
+ "z": 1.0
+ },
+ {
+ "x": 160.07906496134046,
+ "y": -3.059920311173475,
+ "z": 1.0
+ },
+ {
+ "x": 160.4177510798241,
+ "y": -2.8022456274618905,
+ "z": 1.0
+ },
+ {
+ "x": 160.77809586609953,
+ "y": -2.575834518513972,
+ "z": 1.0
+ },
+ {
+ "x": 161.09221276714152,
+ "y": -2.4128186939734793,
+ "z": 1.0
+ },
+ {
+ "x": 161.41831692152203,
+ "y": -2.273349780093421,
+ "z": 1.0
+ },
+ {
+ "x": 161.75389318218015,
+ "y": -2.1585414349510534,
+ "z": 1.0
+ },
+ {
+ "x": 162.16646585430743,
+ "y": -2.054208769202902,
+ "z": 1.0
+ },
+ {
+ "x": 162.5867055330603,
+ "y": -1.9871276453476843,
+ "z": 1.0
+ },
+ {
+ "x": 162.94034406743444,
+ "y": -1.960078107492641,
+ "z": 1.0
+ },
+ {
+ "x": 163.44525098561672,
+ "y": -1.9564427538507048,
+ "z": 1.0
+ },
+ {
+ "x": 163.94900597132929,
+ "y": -1.956496519249997,
+ "z": 1.0
+ },
+ {
+ "x": 164.45276095704185,
+ "y": -1.9565502846492888,
+ "z": 1.0
+ },
+ {
+ "x": 165.05726693989692,
+ "y": -1.9566148031284396,
+ "z": 1.0
+ },
+ {
+ "x": 165.66177292275202,
+ "y": -1.95667932160759,
+ "z": 1.0
+ },
+ {
+ "x": 166.06477691132207,
+ "y": -1.9567223339270237,
+ "z": 1.0
+ },
+ {
+ "x": 166.66928289417714,
+ "y": -1.956786852406174,
+ "z": 1.0
+ },
+ {
+ "x": 167.17303787988973,
+ "y": -1.9568406178054727,
+ "z": 1.0
+ },
+ {
+ "x": 167.7775438627448,
+ "y": -1.9569051362846233,
+ "z": 1.0
+ },
+ {
+ "x": 168.07979685417234,
+ "y": -1.9569373955241984,
+ "z": 1.0
+ },
+ {
+ "x": 168.480178046297,
+ "y": -1.9569801279145151,
+ "z": 1.0
+ },
+ {
+ "x": 169.080749834484,
+ "y": -1.9570442264999608,
+ "z": 1.0
+ },
+ {
+ "x": 169.58122632463983,
+ "y": -1.9570976419878323,
+ "z": 1.0
+ },
+ {
+ "x": 170.18179811282684,
+ "y": -1.957161740573278,
+ "z": 1.0
+ },
+ {
+ "x": 170.5821793049515,
+ "y": -1.957204472963575,
+ "z": 1.0
+ },
+ {
+ "x": 171.18275109313848,
+ "y": -1.957268571549021,
+ "z": 1.0
+ },
+ {
+ "x": 171.68322758329433,
+ "y": -1.9573219870368925,
+ "z": 1.0
+ },
+ {
+ "x": 172.08360877541898,
+ "y": -1.9573647194271895,
+ "z": 1.0
+ },
+ {
+ "x": 172.58408526557483,
+ "y": -1.957418134915061,
+ "z": 1.0
+ },
+ {
+ "x": 173.08456175573065,
+ "y": -1.9574715504029325,
+ "z": 1.0
+ },
+ {
+ "x": 173.58503824588647,
+ "y": -1.957524965890804,
+ "z": 1.0
+ },
+ {
+ "x": 174.0855147360423,
+ "y": -1.9575783813786751,
+ "z": 1.0
+ },
+ {
+ "x": 174.48589592816697,
+ "y": -1.9576211137689725,
+ "z": 1.0
+ },
+ {
+ "x": 174.9863724183228,
+ "y": -1.957674529256844,
+ "z": 1.0
+ },
+ {
+ "x": 175.5869442065098,
+ "y": -1.9577386278422897,
+ "z": 1.0
+ },
+ {
+ "x": 175.98732539863445,
+ "y": -1.9577813602325866,
+ "z": 1.0
+ },
+ {
+ "x": 176.58789718682146,
+ "y": -1.9578454588180327,
+ "z": 1.0
+ },
+ {
+ "x": 177.18846897500845,
+ "y": -1.9579095574034784,
+ "z": 1.0
+ },
+ {
+ "x": 177.6889454651643,
+ "y": -1.95796297289135,
+ "z": 1.0
+ },
+ {
+ "x": 178.28951725335128,
+ "y": -1.9580270714767956,
+ "z": 1.0
+ },
+ {
+ "x": 178.7899937435071,
+ "y": -1.958080486964667,
+ "z": 1.0
+ },
+ {
+ "x": 179.3905655316941,
+ "y": -1.9581445855501127,
+ "z": 1.0
+ },
+ {
+ "x": 179.9911373198811,
+ "y": -1.9582086841355584,
+ "z": 1.0
+ },
+ {
+ "x": 180.49161381003694,
+ "y": -1.95826209962343,
+ "z": 1.0
+ },
+ {
+ "x": 181.09218559822392,
+ "y": -1.9583261982088755,
+ "z": 1.0
+ },
+ {
+ "x": 181.69275738641093,
+ "y": -1.9583902967943212,
+ "z": 1.0
+ },
+ {
+ "x": 182.19323387656675,
+ "y": -1.9584437122821927,
+ "z": 1.0
+ },
+ {
+ "x": 182.59361506869143,
+ "y": -1.9584864446724901,
+ "z": 1.0
+ },
+ {
+ "x": 183.19418685687842,
+ "y": -1.9585505432579358,
+ "z": 1.0
+ },
+ {
+ "x": 183.7947586450654,
+ "y": -1.9586146418433814,
+ "z": 1.0
+ },
+ {
+ "x": 184.3953304332524,
+ "y": -1.958678740428827,
+ "z": 1.0
+ },
+ {
+ "x": 184.79571162537707,
+ "y": -1.9587214728191245,
+ "z": 1.0
+ },
+ {
+ "x": 185.2961881155329,
+ "y": -1.9587748883069955,
+ "z": 1.0
+ },
+ {
+ "x": 185.8967599037199,
+ "y": -1.9588389868924416,
+ "z": 1.0
+ },
+ {
+ "x": 186.39723639387574,
+ "y": -1.9588924023803127,
+ "z": 1.0
+ },
+ {
+ "x": 186.7976175860004,
+ "y": -1.95893513477061,
+ "z": 1.0
+ },
+ {
+ "x": 187.39818937418738,
+ "y": -1.9589992333560557,
+ "z": 1.0
+ },
+ {
+ "x": 187.9987611623744,
+ "y": -1.9590633319415014,
+ "z": 1.0
+ },
+ {
+ "x": 188.4992376525302,
+ "y": -1.959116747429373,
+ "z": 1.0
+ },
+ {
+ "x": 189.09980944071722,
+ "y": -1.9591808460148186,
+ "z": 1.0
+ },
+ {
+ "x": 189.50019063284188,
+ "y": -1.959223578405116,
+ "z": 1.0
+ },
+ {
+ "x": 190.0006671229977,
+ "y": -1.9592769938929875,
+ "z": 1.0
+ },
+ {
+ "x": 190.40104831512238,
+ "y": -1.9593197262832844,
+ "z": 1.0
+ },
+ {
+ "x": 190.9015248052782,
+ "y": -1.959373141771156,
+ "z": 1.0
+ },
+ {
+ "x": 191.30190599740286,
+ "y": -1.959415874161453,
+ "z": 1.0
+ },
+ {
+ "x": 191.8023824875587,
+ "y": -1.9594692896493244,
+ "z": 1.0
+ },
+ {
+ "x": 192.30285897771452,
+ "y": -1.959522705137196,
+ "z": 1.0
+ },
+ {
+ "x": 192.80333546787037,
+ "y": -1.9595761206250675,
+ "z": 1.0
+ },
+ {
+ "x": 193.3038119580262,
+ "y": -1.959629536112939,
+ "z": 1.0
+ },
+ {
+ "x": 193.90438374621317,
+ "y": -1.9596936346983846,
+ "z": 1.0
+ },
+ {
+ "x": 194.40486023636902,
+ "y": -1.9597470501862562,
+ "z": 1.0
+ },
+ {
+ "x": 194.90533672652484,
+ "y": -1.9598004656741277,
+ "z": 1.0
+ },
+ {
+ "x": 195.50590851471185,
+ "y": -1.9598645642595733,
+ "z": 1.0
+ },
+ {
+ "x": 195.9062897068365,
+ "y": -1.9599072966498703,
+ "z": 1.0
+ },
+ {
+ "x": 196.50686149502351,
+ "y": -1.9599713952353164,
+ "z": 1.0
+ },
+ {
+ "x": 197.00733798517933,
+ "y": -1.9600248107231875,
+ "z": 1.0
+ },
+ {
+ "x": 197.60790977336632,
+ "y": -1.9600889093086336,
+ "z": 1.0
+ },
+ {
+ "x": 198.00829096549103,
+ "y": -1.9601316416989305,
+ "z": 1.0
+ },
+ {
+ "x": 198.60886275367812,
+ "y": -1.9601957402843762,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 11,
+ "heading": [
+ 0.19935498835074622,
+ 1.4861546924418993,
+ 1.4607407580935998,
+ 1.3908522439327338,
+ 1.3273172116869896,
+ 1.2510751549492403,
+ 1.1811866373806958,
+ 1.1176473528504982,
+ 1.053886187741048,
+ 1.0029846256276123,
+ 0.9458030512447957,
+ 0.8822169386900508,
+ 0.828543390212532,
+ 0.7546814735401104,
+ 0.6801814600203556,
+ 0.6056813147480384,
+ 0.5236280170446252,
+ 0.44138141729989416,
+ 0.3668904708916304,
+ 0.2849404521945748,
+ 0.20299041185484692,
+ 0.12104038438677348,
+ 0.035725349092794956,
+ 0.0035508163599969026,
+ -0.00010672926444951508,
+ -0.00010672926444963529,
+ -0.00010672926444973295,
+ -0.00010672926444951205,
+ -0.00010672926444951508,
+ -0.00010672926445544282,
+ -0.00010672926445564316,
+ -0.00010672926444961302,
+ -0.00010672926447730693,
+ -0.00010672926446900236,
+ -0.00010672926444954181,
+ -0.00010672926444954181,
+ -0.0001067292644492592,
+ -0.0001067292644497059,
+ -0.00010672926444994514,
+ -0.00010672926444940675,
+ -0.00010672926444940675,
+ -0.00010672926444970287,
+ -0.0001067292644497059,
+ -0.0001067292644492592,
+ -0.00010672926444940675,
+ -0.00010672926444990308,
+ -0.00010672926444954181,
+ -0.0001067292644492592,
+ -0.00010672926444970287,
+ -0.00010672926444977732,
+ -0.00010672926444954181,
+ -0.00010672926444954181,
+ -0.00010672926444954457,
+ -0.00010672926444954181,
+ -0.00010672926444940759,
+ -0.00010672926444954181,
+ -0.00010672926444954181,
+ -0.00010672926444940759,
+ -0.00010672926444954181,
+ -0.00010672926444989972,
+ -0.00010672926444970287,
+ -0.00010672926444941012,
+ -0.00010672926444940759,
+ -0.00010672926444970287,
+ -0.00010672926444940675,
+ -0.00010672926444954181,
+ -0.00010672926444954181,
+ -0.00010672926444940675,
+ -0.0001067292644497059,
+ -0.00010672926444940759,
+ -0.00010672926444954181,
+ -0.00010672926444954181,
+ -0.00010672926444970287,
+ -0.00010672926444990308,
+ -0.00010672926444940675,
+ -0.00010672926444940675,
+ -0.00010672926444941012,
+ -0.00010672926444940675,
+ -0.00010672926444970287,
+ -0.00010672926444970287,
+ -0.00010672926444970287,
+ -0.00010672926444954457,
+ -0.00010672926444954181,
+ -0.00010672926444970287,
+ -0.00010672926444954181,
+ -0.0001067292644492592,
+ -0.00010672926444970287,
+ -0.00010672926444954181,
+ -0.00010672926444954457,
+ -0.00010672926444969984,
+ -0.00010672926444924405
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": 0.31839725034103594,
+ "y": 3.7527221070339856
+ },
+ {
+ "x": 0.7442980407844857,
+ "y": 6.735602607943436
+ },
+ {
+ "x": 1.3474216715823673,
+ "y": 7.407006918270342
+ },
+ {
+ "x": 2.177343962152918,
+ "y": 8.765216373687448
+ },
+ {
+ "x": 2.838659926597984,
+ "y": 8.573939998966162
+ },
+ {
+ "x": 3.1450996484852567,
+ "y": 7.659789060449604
+ },
+ {
+ "x": 2.96416661538899,
+ "y": 6.087274929905355
+ },
+ {
+ "x": 3.3460120216693667,
+ "y": 5.886034486062384
+ },
+ {
+ "x": 3.644420564409643,
+ "y": 5.7132830145732605
+ },
+ {
+ "x": 3.5248027800298587,
+ "y": 4.885556130288693
+ },
+ {
+ "x": 4.753794553987234,
+ "y": 5.776524827426588
+ },
+ {
+ "x": 4.937621048098606,
+ "y": 5.383191352294325
+ },
+ {
+ "x": 4.132478036118243,
+ "y": 3.8860964766031847
+ },
+ {
+ "x": 5.511022302041226,
+ "y": 4.458205099168833
+ },
+ {
+ "x": 6.990309047590699,
+ "y": 4.840857926595028
+ },
+ {
+ "x": 6.744616873174323,
+ "y": 3.894269334884113
+ },
+ {
+ "x": 6.402210554225007,
+ "y": 3.0248473842055112
+ },
+ {
+ "x": 6.616804150386315,
+ "y": 2.542772590224258
+ },
+ {
+ "x": 7.4814893278539785,
+ "y": 2.191410108905192
+ },
+ {
+ "x": 8.328123508801468,
+ "y": 1.7141378960336917
+ },
+ {
+ "x": 7.738782131270057,
+ "y": 0.9413066171026085
+ },
+ {
+ "x": 8.585454525564273,
+ "y": 0.30684891496979505
+ },
+ {
+ "x": 10.08661903894847,
+ "y": 0.03581588242643985
+ },
+ {
+ "x": 10.075099714251223,
+ "y": -0.0010753079858405457
+ },
+ {
+ "x": 11.082609685676346,
+ "y": -0.0011828387844259325
+ },
+ {
+ "x": 12.090119657101752,
+ "y": -0.0012903695830113193
+ },
+ {
+ "x": 10.075099714251508,
+ "y": -0.0010753079858405457
+ },
+ {
+ "x": 10.075099714251223,
+ "y": -0.0010753079858405457
+ },
+ {
+ "x": 11.08260968567663,
+ "y": -0.0011828387844903254
+ },
+ {
+ "x": 11.08260968567663,
+ "y": -0.0011828387844925459
+ },
+ {
+ "x": 9.067589742826101,
+ "y": -0.0009677771872573793
+ },
+ {
+ "x": 7.026341835521919,
+ "y": -0.0007499162989188513
+ },
+ {
+ "x": 10.009529803116664,
+ "y": -0.00106830975762362
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 10.009529803116664,
+ "y": -0.0010683097574260003
+ },
+ {
+ "x": 10.00952980311638,
+ "y": -0.0010683097574304412
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.0011751407331761499
+ },
+ {
+ "x": 9.008576822805026,
+ "y": -0.0009614787816847326
+ },
+ {
+ "x": 9.008576822805026,
+ "y": -0.0009614787816847326
+ },
+ {
+ "x": 10.009529803116664,
+ "y": -0.0010683097574304412
+ },
+ {
+ "x": 10.00952980311638,
+ "y": -0.0010683097574304412
+ },
+ {
+ "x": 10.009529803116664,
+ "y": -0.0010683097574260003
+ },
+ {
+ "x": 9.008576822805026,
+ "y": -0.0009614787816847326
+ },
+ {
+ "x": 9.008576822804741,
+ "y": -0.0009614787816891734
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 10.009529803116664,
+ "y": -0.0010683097574260003
+ },
+ {
+ "x": 10.009529803116664,
+ "y": -0.0010683097574304412
+ },
+ {
+ "x": 12.01143576373994,
+ "y": -0.0012819717089174176
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 11.010482783428017,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 12.01143576373994,
+ "y": -0.0012819717089129767
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 12.01143576373994,
+ "y": -0.0012819717089129767
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 9.008576822805026,
+ "y": -0.0009614787816891734
+ },
+ {
+ "x": 10.009529803116664,
+ "y": -0.0010683097574304412
+ },
+ {
+ "x": 12.011435763739655,
+ "y": -0.0012819717089129767
+ },
+ {
+ "x": 12.01143576373994,
+ "y": -0.0012819717089129767
+ },
+ {
+ "x": 10.009529803116664,
+ "y": -0.0010683097574304412
+ },
+ {
+ "x": 9.008576822805026,
+ "y": -0.0009614787816847326
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 9.008576822805026,
+ "y": -0.0009614787816847326
+ },
+ {
+ "x": 10.00952980311638,
+ "y": -0.0010683097574304412
+ },
+ {
+ "x": 12.01143576373994,
+ "y": -0.0012819717089129767
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 10.009529803116664,
+ "y": -0.0010683097574304412
+ },
+ {
+ "x": 9.008576822804741,
+ "y": -0.0009614787816891734
+ },
+ {
+ "x": 9.008576822805026,
+ "y": -0.0009614787816847326
+ },
+ {
+ "x": 9.008576822805026,
+ "y": -0.0009614787816847326
+ },
+ {
+ "x": 9.008576822804741,
+ "y": -0.0009614787816847326
+ },
+ {
+ "x": 9.008576822805026,
+ "y": -0.0009614787816847326
+ },
+ {
+ "x": 10.009529803116664,
+ "y": -0.0010683097574304412
+ },
+ {
+ "x": 10.009529803116664,
+ "y": -0.0010683097574304412
+ },
+ {
+ "x": 10.009529803116664,
+ "y": -0.0010683097574304412
+ },
+ {
+ "x": 11.010482783428017,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 10.009529803116664,
+ "y": -0.0010683097574304412
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 10.009529803116664,
+ "y": -0.0010683097574260003
+ },
+ {
+ "x": 10.009529803116664,
+ "y": -0.0010683097574304412
+ },
+ {
+ "x": 11.010482783428301,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 11.010482783428017,
+ "y": -0.001175140733171709
+ },
+ {
+ "x": 10.009529803116948,
+ "y": -0.0010683097574304412
+ },
+ {
+ "x": 10.009529803118085,
+ "y": -0.0010683097574260003
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 198.60886275367812,
+ "y": -1.9601957402843762,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": -2.0249086705307424,
+ "y": -8.280471528793488,
+ "z": 1.0
+ },
+ {
+ "x": -2.029612009939554,
+ "y": -8.952394399315889,
+ "z": 1.0
+ },
+ {
+ "x": -2.0297671463414297,
+ "y": -9.355128488453571,
+ "z": 1.0
+ },
+ {
+ "x": -2.029922282743306,
+ "y": -9.757862577591254,
+ "z": 1.0
+ },
+ {
+ "x": -2.029999850944244,
+ "y": -9.959229622160095,
+ "z": 1.0
+ },
+ {
+ "x": -2.030231080992902,
+ "y": -10.5595028133723,
+ "z": 1.0
+ },
+ {
+ "x": -2.0304623110415596,
+ "y": -11.159776004584504,
+ "z": 1.0
+ },
+ {
+ "x": -2.0306164644073315,
+ "y": -11.559958132059307,
+ "z": 1.0
+ },
+ {
+ "x": -2.0308476944559883,
+ "y": -12.160231323271512,
+ "z": 1.0
+ },
+ {
+ "x": -2.0310403861632036,
+ "y": -12.660458982615017,
+ "z": 1.0
+ },
+ {
+ "x": -2.031233077870418,
+ "y": -13.16068664195852,
+ "z": 1.0
+ },
+ {
+ "x": -2.03138723123619,
+ "y": -13.560868769433325,
+ "z": 1.0
+ },
+ {
+ "x": -2.0316184612848476,
+ "y": -14.16114196064553,
+ "z": 1.0
+ },
+ {
+ "x": -2.0317726146506194,
+ "y": -14.561324088120333,
+ "z": 1.0
+ },
+ {
+ "x": -2.0319267680163913,
+ "y": -14.961506215595136,
+ "z": 1.0
+ },
+ {
+ "x": -2.032157998065049,
+ "y": -15.561779406807341,
+ "z": 1.0
+ },
+ {
+ "x": -2.032312151430821,
+ "y": -15.961961534282144,
+ "z": 1.0
+ },
+ {
+ "x": -2.032466304796592,
+ "y": -16.36214366175695,
+ "z": 1.0
+ },
+ {
+ "x": -2.0326975348452496,
+ "y": -16.962416852969152,
+ "z": 1.0
+ },
+ {
+ "x": -2.0329287648939074,
+ "y": -17.56269004418136,
+ "z": 1.0
+ },
+ {
+ "x": -2.033159994942565,
+ "y": -18.162963235393562,
+ "z": 1.0
+ },
+ {
+ "x": -2.0333526866497795,
+ "y": -18.66319089473706,
+ "z": 1.0
+ },
+ {
+ "x": -2.033545378356995,
+ "y": -19.16341855408056,
+ "z": 1.0
+ },
+ {
+ "x": -2.033738070064209,
+ "y": -19.66364621342406,
+ "z": 1.0
+ },
+ {
+ "x": -2.0339307617714244,
+ "y": -20.16387387276756,
+ "z": 1.0
+ },
+ {
+ "x": -2.0341619918200813,
+ "y": -20.76414706397976,
+ "z": 1.0
+ },
+ {
+ "x": -2.034393221868739,
+ "y": -21.36442025519196,
+ "z": 1.0
+ },
+ {
+ "x": -2.034624451917397,
+ "y": -21.96469344640416,
+ "z": 1.0
+ },
+ {
+ "x": -2.0348556819660546,
+ "y": -22.56496663761636,
+ "z": 1.0
+ },
+ {
+ "x": -2.0350869120147124,
+ "y": -23.16523982882856,
+ "z": 1.0
+ },
+ {
+ "x": -2.035241065380484,
+ "y": -23.56542195630336,
+ "z": 1.0
+ },
+ {
+ "x": -2.0354337570876986,
+ "y": -24.06564961564686,
+ "z": 1.0
+ },
+ {
+ "x": -2.035626448794913,
+ "y": -24.56587727499036,
+ "z": 1.0
+ },
+ {
+ "x": -2.035780602160685,
+ "y": -24.96605940246516,
+ "z": 1.0
+ },
+ {
+ "x": -2.0359732938679,
+ "y": -25.466287061808657,
+ "z": 1.0
+ },
+ {
+ "x": -2.036204523916558,
+ "y": -26.06656025302086,
+ "z": 1.0
+ },
+ {
+ "x": -2.0364357539652147,
+ "y": -26.666833444233074,
+ "z": 1.0
+ },
+ {
+ "x": -2.03662844567243,
+ "y": -27.167061103576582,
+ "z": 1.0
+ },
+ {
+ "x": -2.036782599038202,
+ "y": -27.567243231051386,
+ "z": 1.0
+ },
+ {
+ "x": -2.0369367524039736,
+ "y": -27.967425358526196,
+ "z": 1.0
+ },
+ {
+ "x": -2.037129444111188,
+ "y": -28.467653017869704,
+ "z": 1.0
+ },
+ {
+ "x": -2.03728359747696,
+ "y": -28.867835145344507,
+ "z": 1.0
+ },
+ {
+ "x": -2.0374377508427317,
+ "y": -29.268017272819318,
+ "z": 1.0
+ },
+ {
+ "x": -2.037630442549946,
+ "y": -29.768244932162826,
+ "z": 1.0
+ },
+ {
+ "x": -2.0378231342571613,
+ "y": -30.268472591506335,
+ "z": 1.0
+ },
+ {
+ "x": -2.0380158259643757,
+ "y": -30.768700250849843,
+ "z": 1.0
+ },
+ {
+ "x": -2.0381699793301475,
+ "y": -31.16888237832465,
+ "z": 1.0
+ },
+ {
+ "x": -2.0383241326959194,
+ "y": -31.569064505799457,
+ "z": 1.0
+ },
+ {
+ "x": -2.038555362744577,
+ "y": -32.16933769701166,
+ "z": 1.0
+ },
+ {
+ "x": -2.038709516110349,
+ "y": -32.56951982448648,
+ "z": 1.0
+ },
+ {
+ "x": -2.038940746159006,
+ "y": -33.16979301569869,
+ "z": 1.0
+ },
+ {
+ "x": -2.039133437866221,
+ "y": -33.670020675042196,
+ "z": 1.0
+ },
+ {
+ "x": -2.0393261295734355,
+ "y": -34.170248334385704,
+ "z": 1.0
+ },
+ {
+ "x": -2.0394802829392074,
+ "y": -34.57043046186051,
+ "z": 1.0
+ },
+ {
+ "x": -2.039634436304979,
+ "y": -34.97061258933532,
+ "z": 1.0
+ },
+ {
+ "x": -2.039865666353637,
+ "y": -35.57088578054753,
+ "z": 1.0
+ },
+ {
+ "x": -2.040019819719409,
+ "y": -35.971067908022334,
+ "z": 1.0
+ },
+ {
+ "x": -2.0401739730851807,
+ "y": -36.37125003549714,
+ "z": 1.0
+ },
+ {
+ "x": -2.0403281264509525,
+ "y": -36.77143216297195,
+ "z": 1.0
+ },
+ {
+ "x": -2.0405593564996094,
+ "y": -37.37170535418416,
+ "z": 1.0
+ },
+ {
+ "x": -2.0407520482068247,
+ "y": -37.871933013527666,
+ "z": 1.0
+ },
+ {
+ "x": -2.0409062015725965,
+ "y": -38.27211514100247,
+ "z": 1.0
+ },
+ {
+ "x": -2.041098893279811,
+ "y": -38.77234280034598,
+ "z": 1.0
+ },
+ {
+ "x": -2.0412915849870252,
+ "y": -39.27257045968949,
+ "z": 1.0
+ },
+ {
+ "x": -2.0414842766942405,
+ "y": -39.772798119033,
+ "z": 1.0
+ },
+ {
+ "x": -2.041676968401455,
+ "y": -40.27302577837651,
+ "z": 1.0
+ },
+ {
+ "x": -2.04186966010867,
+ "y": -40.773253437720015,
+ "z": 1.0
+ },
+ {
+ "x": -2.042100890157327,
+ "y": -41.373526628932225,
+ "z": 1.0
+ },
+ {
+ "x": -2.0422935818645422,
+ "y": -41.873754288275734,
+ "z": 1.0
+ },
+ {
+ "x": -2.042486273571757,
+ "y": -42.37398194761924,
+ "z": 1.0
+ },
+ {
+ "x": -2.042678965278972,
+ "y": -42.87420960696275,
+ "z": 1.0
+ },
+ {
+ "x": -2.0428331186447437,
+ "y": -43.27439173443756,
+ "z": 1.0
+ },
+ {
+ "x": -2.043025810351958,
+ "y": -43.774619393781066,
+ "z": 1.0
+ },
+ {
+ "x": -2.04317996371773,
+ "y": -44.17480152125587,
+ "z": 1.0
+ },
+ {
+ "x": -2.0434111937663877,
+ "y": -44.77507471246808,
+ "z": 1.0
+ },
+ {
+ "x": -2.0436424238150455,
+ "y": -45.37534790368029,
+ "z": 1.0
+ },
+ {
+ "x": -2.0438736538637023,
+ "y": -45.97562109489251,
+ "z": 1.0
+ },
+ {
+ "x": -2.0440278072294746,
+ "y": -46.37580322236731,
+ "z": 1.0
+ },
+ {
+ "x": -2.0441819605952465,
+ "y": -46.775985349842124,
+ "z": 1.0
+ },
+ {
+ "x": -2.044336113961018,
+ "y": -47.17616747731693,
+ "z": 1.0
+ },
+ {
+ "x": -2.0445288056682327,
+ "y": -47.67639513666044,
+ "z": 1.0
+ },
+ {
+ "x": -2.0447214973754475,
+ "y": -48.17662279600395,
+ "z": 1.0
+ },
+ {
+ "x": -2.0449527274241053,
+ "y": -48.77689598721615,
+ "z": 1.0
+ },
+ {
+ "x": -2.045183957472763,
+ "y": -49.37716917842837,
+ "z": 1.0
+ },
+ {
+ "x": -2.0453766491799774,
+ "y": -49.877396837771876,
+ "z": 1.0
+ },
+ {
+ "x": -2.045569340887192,
+ "y": -50.377624497115384,
+ "z": 1.0
+ },
+ {
+ "x": -2.045762032594407,
+ "y": -50.87785215645889,
+ "z": 1.0
+ },
+ {
+ "x": -2.045954724301622,
+ "y": -51.378079815802394,
+ "z": 1.0
+ },
+ {
+ "x": -2.0461474160088358,
+ "y": -51.87830747514591,
+ "z": 1.0
+ },
+ {
+ "x": -2.0463786460574935,
+ "y": -52.47858066635812,
+ "z": 1.0
+ },
+ {
+ "x": -2.0466098761061513,
+ "y": -53.07885385757033,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 12,
+ "heading": [
+ -1.5713009816235572,
+ -1.577796032862566,
+ -1.5753172510457183,
+ -1.5711815347978622,
+ -1.5711815347978622,
+ -1.5711815347978622,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978615,
+ -1.571181534797862,
+ -1.5711815347978624,
+ -1.571181534797862,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978613,
+ -1.5711815347978615,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.571181534797862,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.571181534797862,
+ -1.5711815347978617,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.571181534797862,
+ -1.5711815347978615,
+ -1.571181534797862,
+ -1.5711815347978628,
+ -1.5711815347978628,
+ -1.5711815347978617,
+ -1.571181534797862,
+ -1.5711815347978628,
+ -1.5711815347978624,
+ -1.571181534797862,
+ -1.571181534797862,
+ -1.5711815347978624,
+ -1.571181534797862,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.571181534797862,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978615,
+ -1.571181534797862,
+ -1.5711815347978624,
+ -1.571181534797862,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978615,
+ -1.571181534797862,
+ -1.5711815347978628,
+ -1.571181534797862,
+ -1.5711815347978615,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.571181534797862,
+ -1.571181534797862,
+ -1.5711815347978628,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.571181534797862,
+ -1.571181534797862,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978617,
+ -1.571181534797862,
+ -1.5711815347978628,
+ -1.5711815347978617,
+ -1.571181534797862,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.5711815347978624,
+ -1.571181534797862,
+ -1.5711815347978615,
+ -1.5711815347978624,
+ -1.5711815347978628,
+ -1.5711815347978615,
+ -1.5711815347978615,
+ -1.5711815347978624
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -0.04703339408811402,
+ "y": -6.719228705224012
+ },
+ {
+ "x": -0.04858475810687324,
+ "y": -10.746569596600839
+ },
+ {
+ "x": -0.0031027280375228727,
+ "y": -8.054681782753654
+ },
+ {
+ "x": -0.0023270460281432648,
+ "y": -6.041011337065232
+ },
+ {
+ "x": -0.00308798249595732,
+ "y": -8.016402357810453
+ },
+ {
+ "x": -0.004624600973155424,
+ "y": -12.005463824244096
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.00455318687008
+ },
+ {
+ "x": -0.0038538341442873048,
+ "y": -10.00455318687008
+ },
+ {
+ "x": -0.004239217558721364,
+ "y": -11.005008505557097
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.00455318687008
+ },
+ {
+ "x": -0.003468450729862127,
+ "y": -9.00409786818308
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186870098
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.00455318687008
+ },
+ {
+ "x": -0.0030830673154369492,
+ "y": -8.003642549496064
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.00455318687008
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.00455318687008
+ },
+ {
+ "x": -0.0030830673154280674,
+ "y": -8.003642549496082
+ },
+ {
+ "x": -0.0038538341442873048,
+ "y": -10.00455318687008
+ },
+ {
+ "x": -0.004624600973155424,
+ "y": -12.005463824244096
+ },
+ {
+ "x": -0.004624600973155424,
+ "y": -12.005463824244096
+ },
+ {
+ "x": -0.004239217558721364,
+ "y": -11.005008505557008
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186869991
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186869991
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186869991
+ },
+ {
+ "x": -0.004239217558721364,
+ "y": -11.005008505557008
+ },
+ {
+ "x": -0.004624600973146542,
+ "y": -12.00546382424399
+ },
+ {
+ "x": -0.004624600973155424,
+ "y": -12.00546382424399
+ },
+ {
+ "x": -0.004624600973155424,
+ "y": -12.005463824244025
+ },
+ {
+ "x": -0.004624600973155424,
+ "y": -12.005463824244025
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186869991
+ },
+ {
+ "x": -0.003468450729862127,
+ "y": -9.004097868182974
+ },
+ {
+ "x": -0.0038538341442873048,
+ "y": -10.004553186869991
+ },
+ {
+ "x": -0.003468450729862127,
+ "y": -9.00409786818301
+ },
+ {
+ "x": -0.0034684507298710088,
+ "y": -9.004097868182974
+ },
+ {
+ "x": -0.004239217558730246,
+ "y": -11.005008505557008
+ },
+ {
+ "x": -0.004624600973146542,
+ "y": -12.005463824244167
+ },
+ {
+ "x": -0.004239217558721364,
+ "y": -11.005008505557221
+ },
+ {
+ "x": -0.0034684507298710088,
+ "y": -9.004097868183116
+ },
+ {
+ "x": -0.0030830673154369492,
+ "y": -8.003642549496135
+ },
+ {
+ "x": -0.003468450729862127,
+ "y": -9.004097868183187
+ },
+ {
+ "x": -0.003468450729862127,
+ "y": -9.004097868183116
+ },
+ {
+ "x": -0.0030830673154369492,
+ "y": -8.003642549496135
+ },
+ {
+ "x": -0.003468450729862127,
+ "y": -9.004097868183187
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.003468450729862127,
+ "y": -9.004097868183152
+ },
+ {
+ "x": -0.0030830673154369492,
+ "y": -8.003642549496135
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186870133
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186870204
+ },
+ {
+ "x": -0.0038538341442873048,
+ "y": -10.00455318687024
+ },
+ {
+ "x": -0.004239217558721364,
+ "y": -11.005008505557186
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.003468450729862127,
+ "y": -9.004097868183152
+ },
+ {
+ "x": -0.0030830673154369492,
+ "y": -8.003642549496135
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.0030830673154369492,
+ "y": -8.003642549496135
+ },
+ {
+ "x": -0.0030830673154369492,
+ "y": -8.003642549496135
+ },
+ {
+ "x": -0.0038538341442873048,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.004239217558721364,
+ "y": -11.005008505557186
+ },
+ {
+ "x": -0.0034684507298710088,
+ "y": -9.004097868183152
+ },
+ {
+ "x": -0.003468450729862127,
+ "y": -9.004097868183152
+ },
+ {
+ "x": -0.0038538341442873048,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.004239217558721364,
+ "y": -11.005008505557186
+ },
+ {
+ "x": -0.004239217558721364,
+ "y": -11.005008505557186
+ },
+ {
+ "x": -0.0038538341443006274,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.003468450729866568,
+ "y": -9.004097868183152
+ },
+ {
+ "x": -0.003468450729862127,
+ "y": -9.004097868183152
+ },
+ {
+ "x": -0.003468450729862127,
+ "y": -9.004097868183152
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.004624600973155424,
+ "y": -12.005463824244202
+ },
+ {
+ "x": -0.004624600973146542,
+ "y": -12.005463824244273
+ },
+ {
+ "x": -0.0038538341442917456,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.00308306731544139,
+ "y": -8.003642549496135
+ },
+ {
+ "x": -0.0030830673154325083,
+ "y": -8.003642549496206
+ },
+ {
+ "x": -0.003468450729862127,
+ "y": -9.004097868183152
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.004239217558725805,
+ "y": -11.005008505557115
+ },
+ {
+ "x": -0.004624600973155424,
+ "y": -12.005463824244202
+ },
+ {
+ "x": -0.004239217558721364,
+ "y": -11.005008505557257
+ },
+ {
+ "x": -0.0038538341442873048,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.0038538341442961865,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.0038538341443006274,
+ "y": -10.004553186870098
+ },
+ {
+ "x": -0.0038538341442873048,
+ "y": -10.004553186870169
+ },
+ {
+ "x": -0.004239217558716923,
+ "y": -11.005008505557257
+ },
+ {
+ "x": -0.004624600973155424,
+ "y": -12.005463824244202
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": -2.0466098761061513,
+ "y": -53.07885385757033,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 338.85713578381797,
+ "y": -70.83644799954263,
+ "z": 1.0
+ },
+ {
+ "x": 338.85743867061865,
+ "y": -70.33498894704724,
+ "z": 1.0
+ },
+ {
+ "x": 338.8578021347794,
+ "y": -69.73323808405277,
+ "z": 1.0
+ },
+ {
+ "x": 338.8580444442198,
+ "y": -69.33207084205532,
+ "z": 1.0
+ },
+ {
+ "x": 338.85822617630015,
+ "y": -69.03119541055808,
+ "z": 1.0
+ },
+ {
+ "x": 338.8584689618465,
+ "y": -68.62923992832572,
+ "z": 1.0
+ },
+ {
+ "x": 338.8587117473928,
+ "y": -68.22728444609271,
+ "z": 1.0
+ },
+ {
+ "x": 338.85895453293904,
+ "y": -67.82532896385973,
+ "z": 1.0
+ },
+ {
+ "x": 338.85931871125854,
+ "y": -67.22239574051028,
+ "z": 1.0
+ },
+ {
+ "x": 338.85956149680476,
+ "y": -66.82044025827727,
+ "z": 1.0
+ },
+ {
+ "x": 338.85992567512415,
+ "y": -66.21750703492668,
+ "z": 1.0
+ },
+ {
+ "x": 338.86028985344365,
+ "y": -65.61457381157831,
+ "z": 1.0
+ },
+ {
+ "x": 338.8605933353765,
+ "y": -65.11212945878708,
+ "z": 1.0
+ },
+ {
+ "x": 338.86089681730937,
+ "y": -64.60968510599582,
+ "z": 1.0
+ },
+ {
+ "x": 338.86126099562875,
+ "y": -64.00675188264634,
+ "z": 1.0
+ },
+ {
+ "x": 338.8615037811751,
+ "y": -63.604796400412226,
+ "z": 1.0
+ },
+ {
+ "x": 338.8617465667213,
+ "y": -63.202840918180364,
+ "z": 1.0
+ },
+ {
+ "x": 338.86205004865417,
+ "y": -62.70039656538912,
+ "z": 1.0
+ },
+ {
+ "x": 338.86235353058703,
+ "y": -62.197952212596746,
+ "z": 1.0
+ },
+ {
+ "x": 338.8626570125199,
+ "y": -61.69550785980665,
+ "z": 1.0
+ },
+ {
+ "x": 338.86296049445286,
+ "y": -61.19306350701542,
+ "z": 1.0
+ },
+ {
+ "x": 338.86332467277225,
+ "y": -60.59013028366594,
+ "z": 1.0
+ },
+ {
+ "x": 338.8636281547051,
+ "y": -60.087685930874706,
+ "z": 1.0
+ },
+ {
+ "x": 338.863931636638,
+ "y": -59.585241578083476,
+ "z": 1.0
+ },
+ {
+ "x": 338.86429581495736,
+ "y": -58.982308354733995,
+ "z": 1.0
+ },
+ {
+ "x": 338.8645992968902,
+ "y": -58.479864001942765,
+ "z": 1.0
+ },
+ {
+ "x": 338.86484208243655,
+ "y": -58.07790851970978,
+ "z": 1.0
+ },
+ {
+ "x": 338.8650848679828,
+ "y": -57.67595303747565,
+ "z": 1.0
+ },
+ {
+ "x": 338.86538834991563,
+ "y": -57.17350868468442,
+ "z": 1.0
+ },
+ {
+ "x": 338.86563113546197,
+ "y": -56.77155320245143,
+ "z": 1.0
+ },
+ {
+ "x": 338.86599531378135,
+ "y": -56.16861997910308,
+ "z": 1.0
+ },
+ {
+ "x": 338.8662987957142,
+ "y": -55.66617562631184,
+ "z": 1.0
+ },
+ {
+ "x": 338.86654158126055,
+ "y": -55.26422014407885,
+ "z": 1.0
+ },
+ {
+ "x": 338.86690575957994,
+ "y": -54.66128692072936,
+ "z": 1.0
+ },
+ {
+ "x": 338.86726993789944,
+ "y": -54.05835369737988,
+ "z": 1.0
+ },
+ {
+ "x": 338.86751272344566,
+ "y": -53.65639821514689,
+ "z": 1.0
+ },
+ {
+ "x": 338.867755508992,
+ "y": -53.25444273291391,
+ "z": 1.0
+ },
+ {
+ "x": 338.8681196873114,
+ "y": -52.65150950956443,
+ "z": 1.0
+ },
+ {
+ "x": 338.8683624728577,
+ "y": -52.24955402733144,
+ "z": 1.0
+ },
+ {
+ "x": 338.86860525840405,
+ "y": -51.84759854509846,
+ "z": 1.0
+ },
+ {
+ "x": 338.86896943672343,
+ "y": -51.244665321747846,
+ "z": 1.0
+ },
+ {
+ "x": 338.8692729186563,
+ "y": -50.74222096895887,
+ "z": 1.0
+ },
+ {
+ "x": 338.86957640058915,
+ "y": -50.23977661616764,
+ "z": 1.0
+ },
+ {
+ "x": 338.869879882522,
+ "y": -49.73733226337527,
+ "z": 1.0
+ },
+ {
+ "x": 338.8701833644549,
+ "y": -49.2348879105829,
+ "z": 1.0
+ },
+ {
+ "x": 338.8704261500012,
+ "y": -48.83293242835218,
+ "z": 1.0
+ },
+ {
+ "x": 338.8707903283206,
+ "y": -48.22999920500157,
+ "z": 1.0
+ },
+ {
+ "x": 338.87103311386693,
+ "y": -47.828043722768584,
+ "z": 1.0
+ },
+ {
+ "x": 338.8713365957998,
+ "y": -47.32559936997735,
+ "z": 1.0
+ },
+ {
+ "x": 338.871579381346,
+ "y": -46.92364388774436,
+ "z": 1.0
+ },
+ {
+ "x": 338.87182216689234,
+ "y": -46.52168840551025,
+ "z": 1.0
+ },
+ {
+ "x": 338.87188286327887,
+ "y": -46.42119953495314,
+ "z": 1.0
+ },
+ {
+ "x": 338.8722465969555,
+ "y": -45.81900246170348,
+ "z": 1.0
+ },
+ {
+ "x": 338.87261033063214,
+ "y": -45.21680538845446,
+ "z": 1.0
+ },
+ {
+ "x": 338.8729740643088,
+ "y": -44.61460831520546,
+ "z": 1.0
+ },
+ {
+ "x": 338.8733377979855,
+ "y": -44.01241124195758,
+ "z": 1.0
+ },
+ {
+ "x": 338.87364090938263,
+ "y": -43.51058034758226,
+ "z": 1.0
+ },
+ {
+ "x": 338.87394402077985,
+ "y": -43.0087494532081,
+ "z": 1.0
+ },
+ {
+ "x": 338.87418650989764,
+ "y": -42.607284737709875,
+ "z": 1.0
+ },
+ {
+ "x": 338.8745502435743,
+ "y": -42.00508766445971,
+ "z": 1.0
+ },
+ {
+ "x": 338.8747927326921,
+ "y": -41.603622948960364,
+ "z": 1.0
+ },
+ {
+ "x": 338.87503522180987,
+ "y": -41.202158233461006,
+ "z": 1.0
+ },
+ {
+ "x": 338.8753989554865,
+ "y": -40.599961160211976,
+ "z": 1.0
+ },
+ {
+ "x": 338.8757020668837,
+ "y": -40.09813026583778,
+ "z": 1.0
+ },
+ {
+ "x": 338.87600517828093,
+ "y": -39.59629937146359,
+ "z": 1.0
+ },
+ {
+ "x": 338.8762476673986,
+ "y": -39.19483465596423,
+ "z": 1.0
+ },
+ {
+ "x": 338.87661140107537,
+ "y": -38.592637582716335,
+ "z": 1.0
+ },
+ {
+ "x": 338.87685389019305,
+ "y": -38.191172867215855,
+ "z": 1.0
+ },
+ {
+ "x": 338.87715700159026,
+ "y": -37.68934197284166,
+ "z": 1.0
+ },
+ {
+ "x": 338.8775207352669,
+ "y": -37.08714489959263,
+ "z": 1.0
+ },
+ {
+ "x": 338.87788446894353,
+ "y": -36.4849478263436,
+ "z": 1.0
+ },
+ {
+ "x": 338.8782482026203,
+ "y": -35.8827507530957,
+ "z": 1.0
+ },
+ {
+ "x": 338.87849069173797,
+ "y": -35.48128603759521,
+ "z": 1.0
+ },
+ {
+ "x": 338.8788544254146,
+ "y": -34.87908896434618,
+ "z": 1.0
+ },
+ {
+ "x": 338.87921815909124,
+ "y": -34.27689189109715,
+ "z": 1.0
+ },
+ {
+ "x": 338.87952127048845,
+ "y": -33.77506099672296,
+ "z": 1.0
+ },
+ {
+ "x": 338.8798850041652,
+ "y": -33.172863923475056,
+ "z": 1.0
+ },
+ {
+ "x": 338.8801881155623,
+ "y": -32.67103302909973,
+ "z": 1.0
+ },
+ {
+ "x": 338.88055184923905,
+ "y": -32.06883595585183,
+ "z": 1.0
+ },
+ {
+ "x": 338.8809155829157,
+ "y": -31.466638882602805,
+ "z": 1.0
+ },
+ {
+ "x": 338.8812186943129,
+ "y": -30.96480798822861,
+ "z": 1.0
+ },
+ {
+ "x": 338.8815218057101,
+ "y": -30.46297709385442,
+ "z": 1.0
+ },
+ {
+ "x": 338.88188553938676,
+ "y": -29.860780020605386,
+ "z": 1.0
+ },
+ {
+ "x": 338.882188650784,
+ "y": -29.358949126231195,
+ "z": 1.0
+ },
+ {
+ "x": 338.8825523844606,
+ "y": -28.756752052982165,
+ "z": 1.0
+ },
+ {
+ "x": 338.88291611813725,
+ "y": -28.154554979731998,
+ "z": 1.0
+ },
+ {
+ "x": 338.8832798518139,
+ "y": -27.552357906482968,
+ "z": 1.0
+ },
+ {
+ "x": 338.8836435854905,
+ "y": -26.950160833233937,
+ "z": 1.0
+ },
+ {
+ "x": 338.88394669688773,
+ "y": -26.44832993885975,
+ "z": 1.0
+ },
+ {
+ "x": 338.88431043056437,
+ "y": -25.846132865611864,
+ "z": 1.0
+ },
+ {
+ "x": 338.8846135419616,
+ "y": -25.344301971236543,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 13,
+ "heading": [
+ 1.570192315834742,
+ 1.5701923158345978,
+ 1.5701923158346802,
+ 1.5701923158348252,
+ 1.5701923158348579,
+ 1.5701923158346793,
+ 1.5701923158346276,
+ 1.5701923158347695,
+ 1.5701923158347413,
+ 1.5701923158347413,
+ 1.570192315834855,
+ 1.5701923158347224,
+ 1.5701923158346789,
+ 1.5701923158347413,
+ 1.5701923158347824,
+ 1.570192315834742,
+ 1.5701923158347695,
+ 1.5701923158348159,
+ 1.570192315834742,
+ 1.5701923158347413,
+ 1.5701923158346274,
+ 1.5701923158346796,
+ 1.5701923158347824,
+ 1.5701923158347413,
+ 1.5701923158347824,
+ 1.5701923158347824,
+ 1.5701923158346909,
+ 1.5701923158347704,
+ 1.5701923158348174,
+ 1.5701923158346909,
+ 1.5701923158347406,
+ 1.5701923158347817,
+ 1.5701923158346909,
+ 1.5701923158347413,
+ 1.5701923158347224,
+ 1.5701923158347413,
+ 1.5701923158347695,
+ 1.5701923158347413,
+ 1.5701923158347413,
+ 1.570192315834628,
+ 1.570192315834742,
+ 1.5701923158347817,
+ 1.57019231583474,
+ 1.570192315834742,
+ 1.5701923158347426,
+ 1.5701923158346902,
+ 1.5701923158347406,
+ 1.570192315834742,
+ 1.5701923158346909,
+ 1.5701923158348166,
+ 1.5701923158347704,
+ 1.5701923158347413,
+ 1.5701923158348248,
+ 1.570192315834764,
+ 1.5701923158347635,
+ 1.5701923158346687,
+ 1.5701923158347464,
+ 1.5701923158348399,
+ 1.5701923158347,
+ 1.5701923158347257,
+ 1.5701923158347266,
+ 1.5701923158346691,
+ 1.5701923158347257,
+ 1.5701923158347464,
+ 1.5701923158347257,
+ 1.5701923158348265,
+ 1.570192315834725,
+ 1.5701923158347257,
+ 1.5701923158348272,
+ 1.5701923158347464,
+ 1.5701923158347637,
+ 1.5701923158346687,
+ 1.5701923158347257,
+ 1.5701923158348399,
+ 1.5701923158347637,
+ 1.5701923158347464,
+ 1.570192315834643,
+ 1.5701923158347464,
+ 1.5701923158347464,
+ 1.5701923158346687,
+ 1.5701923158347464,
+ 1.5701923158347257,
+ 1.5701923158347464,
+ 1.5701923158347464,
+ 1.5701923158347464,
+ 1.5701923158347642,
+ 1.5701923158347642,
+ 1.5701923158347637,
+ 1.5701923158347464,
+ 1.5701923158347457,
+ 1.5701923158347464
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": 0.0030288680068224494,
+ "y": 5.014590524953917
+ },
+ {
+ "x": 0.006663509614099894,
+ "y": 11.03209915489856
+ },
+ {
+ "x": 0.006057736011371162,
+ "y": 10.029181049919202
+ },
+ {
+ "x": 0.00424041520773244,
+ "y": 7.020426734946881
+ },
+ {
+ "x": 0.004245176266977069,
+ "y": 7.028309137295992
+ },
+ {
+ "x": 0.004855710926676693,
+ "y": 8.039109644653735
+ },
+ {
+ "x": 0.0048557109255398245,
+ "y": 8.039109644659845
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.04888705582431
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.048887055824594
+ },
+ {
+ "x": 0.006069638656072129,
+ "y": 10.048887055835962
+ },
+ {
+ "x": 0.007283566388878171,
+ "y": 12.058664466989626
+ },
+ {
+ "x": 0.0066766025236120186,
+ "y": 11.053775761396025
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.048887055824878
+ },
+ {
+ "x": 0.00667660252247515,
+ "y": 11.053775761407394
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.048887055835962
+ },
+ {
+ "x": 0.0048557109255398245,
+ "y": 8.039109644659774
+ },
+ {
+ "x": 0.005462674790805977,
+ "y": 9.043998350231064
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.048887055836175
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.048887055824665
+ },
+ {
+ "x": 0.006069638658345866,
+ "y": 10.048887055813296
+ },
+ {
+ "x": 0.0066766025236120186,
+ "y": 11.05377576140711
+ },
+ {
+ "x": 0.00667660252247515,
+ "y": 11.05377576140711
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.048887055824665
+ },
+ {
+ "x": 0.00667660252247515,
+ "y": 11.05377576140711
+ },
+ {
+ "x": 0.00667660252247515,
+ "y": 11.05377576140711
+ },
+ {
+ "x": 0.005462674791942845,
+ "y": 9.043998350242148
+ },
+ {
+ "x": 0.0048557109255398245,
+ "y": 8.039109644671143
+ },
+ {
+ "x": 0.005462674790805977,
+ "y": 9.043998350253588
+ },
+ {
+ "x": 0.005462674791942845,
+ "y": 9.04399835024222
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.048887055813438
+ },
+ {
+ "x": 0.00667660252247515,
+ "y": 11.053775761395883
+ },
+ {
+ "x": 0.005462674791942845,
+ "y": 9.04399835024229
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.048887055824807
+ },
+ {
+ "x": 0.007283566388878171,
+ "y": 12.058664466989697
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.048887055824665
+ },
+ {
+ "x": 0.0048557109255398245,
+ "y": 8.039109644659703
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.048887055824665
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.048887055824665
+ },
+ {
+ "x": 0.004855710926676693,
+ "y": 8.039109644659703
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.048887055835962
+ },
+ {
+ "x": 0.00667660252247515,
+ "y": 11.053775761395883
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.04888705580207
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.048887055835962
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.048887055847402
+ },
+ {
+ "x": 0.005462674791942845,
+ "y": 9.043998350230922
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.048887055813296
+ },
+ {
+ "x": 0.006069638657208998,
+ "y": 10.048887055835962
+ },
+ {
+ "x": 0.005462674791942845,
+ "y": 9.04399835024222
+ },
+ {
+ "x": 0.005462674790805977,
+ "y": 9.04399835024222
+ },
+ {
+ "x": 0.0048557109255398245,
+ "y": 8.039109644671
+ },
+ {
+ "x": 0.003034819328604499,
+ "y": 5.024443527912226
+ },
+ {
+ "x": 0.0042443006316261744,
+ "y": 7.026859438067703
+ },
+ {
+ "x": 0.007274673532720044,
+ "y": 12.043941464986787
+ },
+ {
+ "x": 0.007274673532720044,
+ "y": 12.043941464980179
+ },
+ {
+ "x": 0.007274673533856912,
+ "y": 12.04394146496881
+ },
+ {
+ "x": 0.006668450738516185,
+ "y": 11.040279676231961
+ },
+ {
+ "x": 0.006062227943175458,
+ "y": 10.036617887494828
+ },
+ {
+ "x": 0.005456005150108467,
+ "y": 9.032956098723872
+ },
+ {
+ "x": 0.006062227944312326,
+ "y": 10.036617887483885
+ },
+ {
+ "x": 0.006062227944312326,
+ "y": 10.036617887495112
+ },
+ {
+ "x": 0.004849782355904608,
+ "y": 8.029294309987023
+ },
+ {
+ "x": 0.006062227944312326,
+ "y": 10.036617887483885
+ },
+ {
+ "x": 0.006668450738516185,
+ "y": 11.040279676232245
+ },
+ {
+ "x": 0.006062227944312326,
+ "y": 10.036617887483885
+ },
+ {
+ "x": 0.005456005148971599,
+ "y": 9.032956098735525
+ },
+ {
+ "x": 0.006062227944312326,
+ "y": 10.036617887472516
+ },
+ {
+ "x": 0.006062227944312326,
+ "y": 10.036617887483743
+ },
+ {
+ "x": 0.005456005148971599,
+ "y": 9.032956098746752
+ },
+ {
+ "x": 0.006668450738516185,
+ "y": 11.040279676232245
+ },
+ {
+ "x": 0.007274673532720044,
+ "y": 12.043941464980605
+ },
+ {
+ "x": 0.007274673533856912,
+ "y": 12.043941464969308
+ },
+ {
+ "x": 0.006062227944312326,
+ "y": 10.036617887483885
+ },
+ {
+ "x": 0.006062227943175458,
+ "y": 10.036617887495183
+ },
+ {
+ "x": 0.007274673532720044,
+ "y": 12.043941464980605
+ },
+ {
+ "x": 0.006668450738516185,
+ "y": 11.040279676232245
+ },
+ {
+ "x": 0.0066684507396530535,
+ "y": 11.040279676220948
+ },
+ {
+ "x": 0.006668450738516185,
+ "y": 11.040279676232245
+ },
+ {
+ "x": 0.006668450738516185,
+ "y": 11.040279676232245
+ },
+ {
+ "x": 0.007274673533856912,
+ "y": 12.043941464969272
+ },
+ {
+ "x": 0.006668450738516185,
+ "y": 11.04027967623221
+ },
+ {
+ "x": 0.006062227944312326,
+ "y": 10.03661788748385
+ },
+ {
+ "x": 0.006668450738516185,
+ "y": 11.040279676232245
+ },
+ {
+ "x": 0.006668450738516185,
+ "y": 11.040279676232245
+ },
+ {
+ "x": 0.006668450738516185,
+ "y": 11.04027967623221
+ },
+ {
+ "x": 0.007274673532720044,
+ "y": 12.043941464991974
+ },
+ {
+ "x": 0.007274673532720044,
+ "y": 12.043941464991974
+ },
+ {
+ "x": 0.007274673532720044,
+ "y": 12.043941464980605
+ },
+ {
+ "x": 0.006668450738516185,
+ "y": 11.040279676232174
+ },
+ {
+ "x": 0.006668450738516185,
+ "y": 11.040279676220734
+ },
+ {
+ "x": 0.006668450738516185,
+ "y": 11.040279676232068
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 338.8846135419616,
+ "y": -25.344301971236543,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 393.3504725840923,
+ "y": -327.0485015111582,
+ "z": 1.0
+ },
+ {
+ "x": 393.69005141079685,
+ "y": -326.6858281969275,
+ "z": 1.0
+ },
+ {
+ "x": 394.16622838247656,
+ "y": -326.11265285187653,
+ "z": 1.0
+ },
+ {
+ "x": 394.46051050493213,
+ "y": -325.7123460897148,
+ "z": 1.0
+ },
+ {
+ "x": 394.8011293029479,
+ "y": -325.1930784805868,
+ "z": 1.0
+ },
+ {
+ "x": 395.1103756129993,
+ "y": -324.6545354059099,
+ "z": 1.0
+ },
+ {
+ "x": 395.438600971734,
+ "y": -323.9852775888519,
+ "z": 1.0
+ },
+ {
+ "x": 395.67509170223576,
+ "y": -323.4110529176839,
+ "z": 1.0
+ },
+ {
+ "x": 395.8395177444637,
+ "y": -322.9422111616245,
+ "z": 1.0
+ },
+ {
+ "x": 396.0440198204258,
+ "y": -322.2256531197213,
+ "z": 1.0
+ },
+ {
+ "x": 396.19705673814303,
+ "y": -321.4963701042684,
+ "z": 1.0
+ },
+ {
+ "x": 396.2847072711144,
+ "y": -320.88157522525205,
+ "z": 1.0
+ },
+ {
+ "x": 396.32849329031455,
+ "y": -320.38667352672815,
+ "z": 1.0
+ },
+ {
+ "x": 396.34876069791414,
+ "y": -319.89025260019343,
+ "z": 1.0
+ },
+ {
+ "x": 396.3502793922545,
+ "y": -319.2427121151802,
+ "z": 1.0
+ },
+ {
+ "x": 396.3500450152746,
+ "y": -318.6397023052805,
+ "z": 1.0
+ },
+ {
+ "x": 396.35000595244463,
+ "y": -318.53920067029856,
+ "z": 1.0
+ },
+ {
+ "x": 396.349811556479,
+ "y": -318.03905481818254,
+ "z": 1.0
+ },
+ {
+ "x": 396.3496171605133,
+ "y": -317.5389089660682,
+ "z": 1.0
+ },
+ {
+ "x": 396.34946164374077,
+ "y": -317.13879228437474,
+ "z": 1.0
+ },
+ {
+ "x": 396.3493061269682,
+ "y": -316.73867560268235,
+ "z": 1.0
+ },
+ {
+ "x": 396.3490728518094,
+ "y": -316.13850058014384,
+ "z": 1.0
+ },
+ {
+ "x": 396.3488784558437,
+ "y": -315.6383547280295,
+ "z": 1.0
+ },
+ {
+ "x": 396.34868405987805,
+ "y": -315.13820887591294,
+ "z": 1.0
+ },
+ {
+ "x": 396.34845078471926,
+ "y": -314.53803385337324,
+ "z": 1.0
+ },
+ {
+ "x": 396.3482952679467,
+ "y": -314.13791717168203,
+ "z": 1.0
+ },
+ {
+ "x": 396.3480619927879,
+ "y": -313.53774214914233,
+ "z": 1.0
+ },
+ {
+ "x": 396.34782871762906,
+ "y": -312.9375671266049,
+ "z": 1.0
+ },
+ {
+ "x": 396.3476732008565,
+ "y": -312.5374504449137,
+ "z": 1.0
+ },
+ {
+ "x": 396.34747880489084,
+ "y": -312.0373045927971,
+ "z": 1.0
+ },
+ {
+ "x": 396.34732328811833,
+ "y": -311.6371879111048,
+ "z": 1.0
+ },
+ {
+ "x": 396.3471288921526,
+ "y": -311.1370420589893,
+ "z": 1.0
+ },
+ {
+ "x": 396.34689561699383,
+ "y": -310.53686703645076,
+ "z": 1.0
+ },
+ {
+ "x": 396.3467012210281,
+ "y": -310.03672118433644,
+ "z": 1.0
+ },
+ {
+ "x": 396.3465457042556,
+ "y": -309.63660450264297,
+ "z": 1.0
+ },
+ {
+ "x": 396.3463513082899,
+ "y": -309.13645865052865,
+ "z": 1.0
+ },
+ {
+ "x": 396.3461957915174,
+ "y": -308.7363419688351,
+ "z": 1.0
+ },
+ {
+ "x": 396.3460402747449,
+ "y": -308.33622528714164,
+ "z": 1.0
+ },
+ {
+ "x": 396.34580699958605,
+ "y": -307.7360502646042,
+ "z": 1.0
+ },
+ {
+ "x": 396.34561260362034,
+ "y": -307.2359044124899,
+ "z": 1.0
+ },
+ {
+ "x": 396.34545708684783,
+ "y": -306.8357877307964,
+ "z": 1.0
+ },
+ {
+ "x": 396.34522381168904,
+ "y": -306.23561270825786,
+ "z": 1.0
+ },
+ {
+ "x": 396.3449905365302,
+ "y": -305.6354376857205,
+ "z": 1.0
+ },
+ {
+ "x": 396.3448350197577,
+ "y": -305.23532100402696,
+ "z": 1.0
+ },
+ {
+ "x": 396.3446017445989,
+ "y": -304.63514598148845,
+ "z": 1.0
+ },
+ {
+ "x": 396.3444073486332,
+ "y": -304.135000129373,
+ "z": 1.0
+ },
+ {
+ "x": 396.3441740734744,
+ "y": -303.53482510683443,
+ "z": 1.0
+ },
+ {
+ "x": 396.3440185567019,
+ "y": -303.1347084251421,
+ "z": 1.0
+ },
+ {
+ "x": 396.34378528154303,
+ "y": -302.53453340260353,
+ "z": 1.0
+ },
+ {
+ "x": 396.34362976477047,
+ "y": -302.1344167209112,
+ "z": 1.0
+ },
+ {
+ "x": 396.34347424799796,
+ "y": -301.7343000392188,
+ "z": 1.0
+ },
+ {
+ "x": 396.34324097283917,
+ "y": -301.13412501667915,
+ "z": 1.0
+ },
+ {
+ "x": 396.3430854560666,
+ "y": -300.7340083349879,
+ "z": 1.0
+ },
+ {
+ "x": 396.3429299392941,
+ "y": -300.33389165329555,
+ "z": 1.0
+ },
+ {
+ "x": 396.34277442252153,
+ "y": -299.93377497160316,
+ "z": 1.0
+ },
+ {
+ "x": 396.34261890574896,
+ "y": -299.5336582899108,
+ "z": 1.0
+ },
+ {
+ "x": 396.3424245097833,
+ "y": -299.0335124377953,
+ "z": 1.0
+ },
+ {
+ "x": 396.3422301138176,
+ "y": -298.533366585681,
+ "z": 1.0
+ },
+ {
+ "x": 396.3419968386588,
+ "y": -297.93319156314135,
+ "z": 1.0
+ },
+ {
+ "x": 396.34180244269317,
+ "y": -297.43304571102584,
+ "z": 1.0
+ },
+ {
+ "x": 396.3416469259206,
+ "y": -297.0329290293335,
+ "z": 1.0
+ },
+ {
+ "x": 396.3414136507618,
+ "y": -296.43275400679494,
+ "z": 1.0
+ },
+ {
+ "x": 396.34118037560296,
+ "y": -295.8325789842564,
+ "z": 1.0
+ },
+ {
+ "x": 396.34102485883045,
+ "y": -295.43246230256403,
+ "z": 1.0
+ },
+ {
+ "x": 396.34086934205794,
+ "y": -295.03234562087164,
+ "z": 1.0
+ },
+ {
+ "x": 396.3407138252854,
+ "y": -294.6322289391793,
+ "z": 1.0
+ },
+ {
+ "x": 396.34051942931967,
+ "y": -294.13208308706385,
+ "z": 1.0
+ },
+ {
+ "x": 396.340325033354,
+ "y": -293.6319372349484,
+ "z": 1.0
+ },
+ {
+ "x": 396.34016951658145,
+ "y": -293.23182055325714,
+ "z": 1.0
+ },
+ {
+ "x": 396.33993624142266,
+ "y": -292.63164553071744,
+ "z": 1.0
+ },
+ {
+ "x": 396.33970296626387,
+ "y": -292.0314705081789,
+ "z": 1.0
+ },
+ {
+ "x": 396.33950857029816,
+ "y": -291.5313246560635,
+ "z": 1.0
+ },
+ {
+ "x": 396.3392752951394,
+ "y": -290.9311496335249,
+ "z": 1.0
+ },
+ {
+ "x": 396.3391197783668,
+ "y": -290.5310329518325,
+ "z": 1.0
+ },
+ {
+ "x": 396.3389642615943,
+ "y": -290.1309162701402,
+ "z": 1.0
+ },
+ {
+ "x": 396.3387698656286,
+ "y": -289.6307704180247,
+ "z": 1.0
+ },
+ {
+ "x": 396.3385365904698,
+ "y": -289.03059539548616,
+ "z": 1.0
+ },
+ {
+ "x": 396.338303315311,
+ "y": -288.4304203729476,
+ "z": 1.0
+ },
+ {
+ "x": 396.3381089193453,
+ "y": -287.93027452083214,
+ "z": 1.0
+ },
+ {
+ "x": 396.3378756441865,
+ "y": -287.3300994982936,
+ "z": 1.0
+ },
+ {
+ "x": 396.33768124822086,
+ "y": -286.829953646177,
+ "z": 1.0
+ },
+ {
+ "x": 396.3375257314483,
+ "y": -286.4298369644858,
+ "z": 1.0
+ },
+ {
+ "x": 396.3373702146758,
+ "y": -286.0297202827934,
+ "z": 1.0
+ },
+ {
+ "x": 396.3372146979032,
+ "y": -285.62960360110105,
+ "z": 1.0
+ },
+ {
+ "x": 396.3369814227444,
+ "y": -285.0294285785636,
+ "z": 1.0
+ },
+ {
+ "x": 396.3367481475856,
+ "y": -284.4292535560239,
+ "z": 1.0
+ },
+ {
+ "x": 396.3365926308131,
+ "y": -284.0291368743316,
+ "z": 1.0
+ },
+ {
+ "x": 396.33639823484737,
+ "y": -283.5289910222172,
+ "z": 1.0
+ },
+ {
+ "x": 396.3361649596885,
+ "y": -282.9288159996787,
+ "z": 1.0
+ },
+ {
+ "x": 396.3359316845297,
+ "y": -282.32864097714014,
+ "z": 1.0
+ },
+ {
+ "x": 396.3357372885641,
+ "y": -281.82849512502355,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 14,
+ "heading": [
+ 1.5100439818715332,
+ 0.8182726338896165,
+ 0.8538526685934247,
+ 0.9012926828937182,
+ 0.9665226973987117,
+ 1.019892727772154,
+ 1.085160506298573,
+ 1.1445042776719234,
+ 1.2038418448434116,
+ 1.2690718565066614,
+ 1.3283718560986324,
+ 1.3936018810754445,
+ 1.4529019040221436,
+ 1.5062719155068656,
+ 1.5517541909138082,
+ 1.5697693253906897,
+ 1.5711850053275338,
+ 1.5711850053274206,
+ 1.571185005327503,
+ 1.5711850053274965,
+ 1.571185005327488,
+ 1.5711850053275027,
+ 1.5711850053275083,
+ 1.5711850053275027,
+ 1.5711850053274554,
+ 1.5711850053275027,
+ 1.5711850053275027,
+ 1.5711850053275123,
+ 1.5711850053275604,
+ 1.5711850053274965,
+ 1.5711850053274328,
+ 1.5711850053274965,
+ 1.571185005327508,
+ 1.5711850053275083,
+ 1.5711850053274965,
+ 1.5711850053274965,
+ 1.5711850053274965,
+ 1.5711850053274163,
+ 1.5711850053275027,
+ 1.5711850053275604,
+ 1.5711850053274965,
+ 1.5711850053274454,
+ 1.5711850053275127,
+ 1.5711850053275027,
+ 1.5711850053274454,
+ 1.571185005327508,
+ 1.571185005327508,
+ 1.5711850053274459,
+ 1.5711850053275027,
+ 1.5711850053275596,
+ 1.5711850053274885,
+ 1.5711850053274454,
+ 1.5711850053275027,
+ 1.5711850053274892,
+ 1.5711850053274885,
+ 1.5711850053275596,
+ 1.5711850053274965,
+ 1.5711850053275032,
+ 1.571185005327508,
+ 1.5711850053274559,
+ 1.5711850053274965,
+ 1.5711850053275027,
+ 1.5711850053275123,
+ 1.5711850053275027,
+ 1.5711850053274174,
+ 1.5711850053274885,
+ 1.5711850053275596,
+ 1.5711850053275027,
+ 1.571185005327497,
+ 1.5711850053275027,
+ 1.5711850053274645,
+ 1.571185005327508,
+ 1.571185005327508,
+ 1.5711850053275027,
+ 1.5711850053274885,
+ 1.5711850053274965,
+ 1.571185005327508,
+ 1.571185005327465,
+ 1.571185005327508,
+ 1.571185005327508,
+ 1.5711850053274559,
+ 1.5711850053274965,
+ 1.5711850053274892,
+ 1.5711850053274885,
+ 1.57118500532756,
+ 1.5711850053275123,
+ 1.5711850053274454,
+ 1.571185005327497,
+ 1.57118500532756,
+ 1.5711850053275123,
+ 1.5711850053274559
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": 3.395788267045532,
+ "y": 3.6267331423067617
+ },
+ {
+ "x": 8.157557983842594,
+ "y": 9.358486592816462
+ },
+ {
+ "x": 7.7045909413527625,
+ "y": 9.734821072127033
+ },
+ {
+ "x": 6.349009204713525,
+ "y": 9.19574371289741
+ },
+ {
+ "x": 6.498651080671607,
+ "y": 10.578106838049166
+ },
+ {
+ "x": 6.374716687860769,
+ "y": 12.078008917349052
+ },
+ {
+ "x": 5.647160892364695,
+ "y": 12.434824882259932
+ },
+ {
+ "x": 4.009167727297154,
+ "y": 10.430664272273589
+ },
+ {
+ "x": 3.689281181900128,
+ "y": 11.853997979625888
+ },
+ {
+ "x": 3.5753899367932718,
+ "y": 14.458410573561196
+ },
+ {
+ "x": 2.4068745068865383,
+ "y": 13.44077894469251
+ },
+ {
+ "x": 1.3143655217152173,
+ "y": 11.096965775402623
+ },
+ {
+ "x": 0.6405342679971682,
+ "y": 9.913226250586149
+ },
+ {
+ "x": 0.21786101939937907,
+ "y": 11.439614115479344
+ },
+ {
+ "x": 0.012843173604437652,
+ "y": 12.50550294912955
+ },
+ {
+ "x": -0.0027343980985961025,
+ "y": 7.035114448816557
+ },
+ {
+ "x": -0.0023345879560565663,
+ "y": 6.006474870979446
+ },
+ {
+ "x": -0.0038879193135699097,
+ "y": 10.002917042303352
+ },
+ {
+ "x": -0.0034991273821560753,
+ "y": 9.002625338077905
+ },
+ {
+ "x": -0.003110335450742241,
+ "y": 8.002333633858711
+ },
+ {
+ "x": -0.0038879193135699097,
+ "y": 10.002917042309036
+ },
+ {
+ "x": -0.004276711244983744,
+ "y": 11.00320874652823
+ },
+ {
+ "x": -0.0038879193135699097,
+ "y": 10.002917042309036
+ },
+ {
+ "x": -0.00427671124441531,
+ "y": 11.003208746562905
+ },
+ {
+ "x": -0.0038879193135699097,
+ "y": 10.002917042309036
+ },
+ {
+ "x": -0.0038879193135699097,
+ "y": 10.002917042309036
+ },
+ {
+ "x": -0.0046655031763975785,
+ "y": 12.003500450771298
+ },
+ {
+ "x": -0.003887919314138344,
+ "y": 10.002917042286299
+ },
+ {
+ "x": -0.0034991273821560753,
+ "y": 9.002625338077905
+ },
+ {
+ "x": -0.003499127381587641,
+ "y": 9.002625338089274
+ },
+ {
+ "x": -0.0034991273821560753,
+ "y": 9.002625338077905
+ },
+ {
+ "x": -0.004276711244983744,
+ "y": 11.003208746540167
+ },
+ {
+ "x": -0.004276711244983744,
+ "y": 11.003208746528799
+ },
+ {
+ "x": -0.0034991273821560753,
+ "y": 9.002625338077905
+ },
+ {
+ "x": -0.0034991273821560753,
+ "y": 9.002625338077905
+ },
+ {
+ "x": -0.0034991273821560753,
+ "y": 9.002625338078474
+ },
+ {
+ "x": -0.0031103354501738067,
+ "y": 8.00233363387008
+ },
+ {
+ "x": -0.0038879193135699097,
+ "y": 10.002917042309036
+ },
+ {
+ "x": -0.004276711245552178,
+ "y": 11.00320874651743
+ },
+ {
+ "x": -0.0034991273821560753,
+ "y": 9.002625338077905
+ },
+ {
+ "x": -0.0038879193130014755,
+ "y": 10.002917042320405
+ },
+ {
+ "x": -0.0046655031763975785,
+ "y": 12.003500450759361
+ },
+ {
+ "x": -0.0038879193135699097,
+ "y": 10.002917042309036
+ },
+ {
+ "x": -0.0038879193130014755,
+ "y": 10.002917042320405
+ },
+ {
+ "x": -0.004276711244983744,
+ "y": 11.003208746539599
+ },
+ {
+ "x": -0.004276711244983744,
+ "y": 11.003208746540167
+ },
+ {
+ "x": -0.0038879193130014755,
+ "y": 10.002917042309036
+ },
+ {
+ "x": -0.0038879193135699097,
+ "y": 10.002917042309036
+ },
+ {
+ "x": -0.003887919314138344,
+ "y": 10.002917042309036
+ },
+ {
+ "x": -0.003110335450742241,
+ "y": 8.002333633847343
+ },
+ {
+ "x": -0.0038879193130014755,
+ "y": 10.002917042320405
+ },
+ {
+ "x": -0.0038879193135699097,
+ "y": 10.002917042309036
+ },
+ {
+ "x": -0.003110335450742241,
+ "y": 8.002333633835974
+ },
+ {
+ "x": -0.003110335450742241,
+ "y": 8.002333633847343
+ },
+ {
+ "x": -0.003110335451310675,
+ "y": 8.002333633847343
+ },
+ {
+ "x": -0.0034991273821560753,
+ "y": 9.002625338078474
+ },
+ {
+ "x": -0.0038879193135699097,
+ "y": 10.002917042298236
+ },
+ {
+ "x": -0.004276711244983744,
+ "y": 11.003208746539599
+ },
+ {
+ "x": -0.00427671124441531,
+ "y": 11.003208746551536
+ },
+ {
+ "x": -0.0034991273821560753,
+ "y": 9.002625338078474
+ },
+ {
+ "x": -0.0038879193135699097,
+ "y": 10.002917042309036
+ },
+ {
+ "x": -0.0046655031763975785,
+ "y": 12.003500450771298
+ },
+ {
+ "x": -0.0038879193135699097,
+ "y": 10.002917042309036
+ },
+ {
+ "x": -0.0031103354501738067,
+ "y": 8.002333633847343
+ },
+ {
+ "x": -0.003110335450742241,
+ "y": 8.002333633847343
+ },
+ {
+ "x": -0.0034991273827245095,
+ "y": 9.002625338077905
+ },
+ {
+ "x": -0.0038879193135699097,
+ "y": 10.002917042309036
+ },
+ {
+ "x": -0.0034991273821560753,
+ "y": 9.002625338067105
+ },
+ {
+ "x": -0.0038879193135699097,
+ "y": 10.002917042309605
+ },
+ {
+ "x": -0.004665503175829144,
+ "y": 12.003500450782099
+ },
+ {
+ "x": -0.004276711244983744,
+ "y": 11.003208746539599
+ },
+ {
+ "x": -0.004276711244983744,
+ "y": 11.003208746540167
+ },
+ {
+ "x": -0.0038879193135699097,
+ "y": 10.002917042309605
+ },
+ {
+ "x": -0.003110335450742241,
+ "y": 8.002333633847343
+ },
+ {
+ "x": -0.0034991273821560753,
+ "y": 9.002625338077905
+ },
+ {
+ "x": -0.004276711244983744,
+ "y": 11.003208746540167
+ },
+ {
+ "x": -0.004665503175829144,
+ "y": 12.003500450771298
+ },
+ {
+ "x": -0.004276711244983744,
+ "y": 11.003208746540167
+ },
+ {
+ "x": -0.004276711244983744,
+ "y": 11.003208746540167
+ },
+ {
+ "x": -0.00427671124441531,
+ "y": 11.003208746551536
+ },
+ {
+ "x": -0.0034991273821560753,
+ "y": 9.002625338077905
+ },
+ {
+ "x": -0.003110335450742241,
+ "y": 8.002333633835974
+ },
+ {
+ "x": -0.003110335450742241,
+ "y": 8.002333633847343
+ },
+ {
+ "x": -0.003887919314138344,
+ "y": 10.002917042297668
+ },
+ {
+ "x": -0.0046655031763975785,
+ "y": 12.003500450771298
+ },
+ {
+ "x": -0.0038879193130014755,
+ "y": 10.002917042320405
+ },
+ {
+ "x": -0.0034991273821560753,
+ "y": 9.002625338067105
+ },
+ {
+ "x": -0.004276711245552178,
+ "y": 11.003208746528799
+ },
+ {
+ "x": -0.0046655031763975785,
+ "y": 12.00350045077073
+ },
+ {
+ "x": -0.00427671124441531,
+ "y": 11.003208746551536
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 396.3357372885641,
+ "y": -281.82849512502355,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 83.3983254223986,
+ "y": 2.043585654035443,
+ "z": 1.0
+ },
+ {
+ "x": 82.89595475942362,
+ "y": 2.043421926501252,
+ "z": 1.0
+ },
+ {
+ "x": 82.29310996385367,
+ "y": 2.0432254534602228,
+ "z": 1.0
+ },
+ {
+ "x": 81.8912134334737,
+ "y": 2.0430944714328696,
+ "z": 1.0
+ },
+ {
+ "x": 81.48931690309372,
+ "y": 2.0429634894055173,
+ "z": 1.0
+ },
+ {
+ "x": 80.98694624011875,
+ "y": 2.0427997618713256,
+ "z": 1.0
+ },
+ {
+ "x": 80.48457557714379,
+ "y": 2.042636034337135,
+ "z": 1.0
+ },
+ {
+ "x": 80.0826790467638,
+ "y": 2.0425050523097816,
+ "z": 1.0
+ },
+ {
+ "x": 79.58030838378885,
+ "y": 2.042341324775591,
+ "z": 1.0
+ },
+ {
+ "x": 79.37936011859885,
+ "y": 2.0422758337619147,
+ "z": 1.0
+ },
+ {
+ "x": 78.77892077275439,
+ "y": 2.042080144680581,
+ "z": 1.0
+ },
+ {
+ "x": 78.27855465121736,
+ "y": 2.0419170704461367,
+ "z": 1.0
+ },
+ {
+ "x": 77.87826175398773,
+ "y": 2.0417866110585807,
+ "z": 1.0
+ },
+ {
+ "x": 77.3778956324507,
+ "y": 2.0416235368241367,
+ "z": 1.0
+ },
+ {
+ "x": 76.87752951091366,
+ "y": 2.0414604625896917,
+ "z": 1.0
+ },
+ {
+ "x": 76.27709016506921,
+ "y": 2.0412647735083587,
+ "z": 1.0
+ },
+ {
+ "x": 75.67665081922478,
+ "y": 2.0410690844270247,
+ "z": 1.0
+ },
+ {
+ "x": 75.17628469768773,
+ "y": 2.0409060101925807,
+ "z": 1.0
+ },
+ {
+ "x": 74.77599180045812,
+ "y": 2.0407755508050247,
+ "z": 1.0
+ },
+ {
+ "x": 74.17555245461367,
+ "y": 2.0405798617236917,
+ "z": 1.0
+ },
+ {
+ "x": 73.57511310876923,
+ "y": 2.0403841726423577,
+ "z": 1.0
+ },
+ {
+ "x": 73.07474698723219,
+ "y": 2.0402210984079137,
+ "z": 1.0
+ },
+ {
+ "x": 72.67445409000257,
+ "y": 2.0400906390203577,
+ "z": 1.0
+ },
+ {
+ "x": 72.17408796846553,
+ "y": 2.0399275647859136,
+ "z": 1.0
+ },
+ {
+ "x": 71.7737950712359,
+ "y": 2.039797105398358,
+ "z": 1.0
+ },
+ {
+ "x": 71.17335572539146,
+ "y": 2.0396014163170246,
+ "z": 1.0
+ },
+ {
+ "x": 70.77306282816183,
+ "y": 2.0394709569294687,
+ "z": 1.0
+ },
+ {
+ "x": 70.37276993093221,
+ "y": 2.0393404975419136,
+ "z": 1.0
+ },
+ {
+ "x": 69.77233058508776,
+ "y": 2.0391448084605797,
+ "z": 1.0
+ },
+ {
+ "x": 69.27196446355073,
+ "y": 2.0389817342261356,
+ "z": 1.0
+ },
+ {
+ "x": 68.8716715663211,
+ "y": 2.0388512748385796,
+ "z": 1.0
+ },
+ {
+ "x": 68.27123222047666,
+ "y": 2.0386555857572466,
+ "z": 1.0
+ },
+ {
+ "x": 67.77086609893962,
+ "y": 2.0384925115228016,
+ "z": 1.0
+ },
+ {
+ "x": 67.27049997740258,
+ "y": 2.0383294372883576,
+ "z": 1.0
+ },
+ {
+ "x": 66.87020708017296,
+ "y": 2.0381989779008016,
+ "z": 1.0
+ },
+ {
+ "x": 66.36984095863592,
+ "y": 2.0380359036663576,
+ "z": 1.0
+ },
+ {
+ "x": 65.9695480614063,
+ "y": 2.0379054442788016,
+ "z": 1.0
+ },
+ {
+ "x": 65.36910871556185,
+ "y": 2.0377097551974686,
+ "z": 1.0
+ },
+ {
+ "x": 64.86874259402482,
+ "y": 2.0375466809630236,
+ "z": 1.0
+ },
+ {
+ "x": 64.46844969679519,
+ "y": 2.0374162215754685,
+ "z": 1.0
+ },
+ {
+ "x": 63.96808357525816,
+ "y": 2.0372531473410236,
+ "z": 1.0
+ },
+ {
+ "x": 63.36764422941371,
+ "y": 2.0370574582596905,
+ "z": 1.0
+ },
+ {
+ "x": 62.96735133218408,
+ "y": 2.0369269988721346,
+ "z": 1.0
+ },
+ {
+ "x": 62.36691198633963,
+ "y": 2.0367313097908015,
+ "z": 1.0
+ },
+ {
+ "x": 61.86654586480259,
+ "y": 2.0365682355563566,
+ "z": 1.0
+ },
+ {
+ "x": 61.36617974326553,
+ "y": 2.0364051613219125,
+ "z": 1.0
+ },
+ {
+ "x": 60.765740397421084,
+ "y": 2.0362094722405786,
+ "z": 1.0
+ },
+ {
+ "x": 60.26537427588404,
+ "y": 2.0360463980061345,
+ "z": 1.0
+ },
+ {
+ "x": 59.66493493003959,
+ "y": 2.0358507089248006,
+ "z": 1.0
+ },
+ {
+ "x": 59.26464203280996,
+ "y": 2.0357202495372455,
+ "z": 1.0
+ },
+ {
+ "x": 58.764275911272904,
+ "y": 2.0355571753028006,
+ "z": 1.0
+ },
+ {
+ "x": 58.26390978973586,
+ "y": 2.0353941010683565,
+ "z": 1.0
+ },
+ {
+ "x": 57.86361689250623,
+ "y": 2.0352636416808005,
+ "z": 1.0
+ },
+ {
+ "x": 57.26317754666178,
+ "y": 2.0350679525994675,
+ "z": 1.0
+ },
+ {
+ "x": 56.66273820081733,
+ "y": 2.0348722635181336,
+ "z": 1.0
+ },
+ {
+ "x": 56.162372079280274,
+ "y": 2.0347091892836895,
+ "z": 1.0
+ },
+ {
+ "x": 55.66200595774323,
+ "y": 2.0345461150492445,
+ "z": 1.0
+ },
+ {
+ "x": 55.06156661189878,
+ "y": 2.0343504259679115,
+ "z": 1.0
+ },
+ {
+ "x": 54.46112726605433,
+ "y": 2.0341547368865784,
+ "z": 1.0
+ },
+ {
+ "x": 54.0608343688247,
+ "y": 2.0340242774990225,
+ "z": 1.0
+ },
+ {
+ "x": 53.46039502298024,
+ "y": 2.0338285884176894,
+ "z": 1.0
+ },
+ {
+ "x": 52.960028901443195,
+ "y": 2.0336655141832445,
+ "z": 1.0
+ },
+ {
+ "x": 52.359589555598745,
+ "y": 2.0334698251019114,
+ "z": 1.0
+ },
+ {
+ "x": 51.859223434061704,
+ "y": 2.0333067508674665,
+ "z": 1.0
+ },
+ {
+ "x": 51.45893053683207,
+ "y": 2.0331762914799114,
+ "z": 1.0
+ },
+ {
+ "x": 51.05863763960244,
+ "y": 2.0330458320923555,
+ "z": 1.0
+ },
+ {
+ "x": 50.55827151806538,
+ "y": 2.0328827578579105,
+ "z": 1.0
+ },
+ {
+ "x": 50.15797862083575,
+ "y": 2.0327522984703554,
+ "z": 1.0
+ },
+ {
+ "x": 49.757685723606116,
+ "y": 2.0326218390827995,
+ "z": 1.0
+ },
+ {
+ "x": 49.157246377761666,
+ "y": 2.0324261500014664,
+ "z": 1.0
+ },
+ {
+ "x": 48.656880256224625,
+ "y": 2.0322630757670215,
+ "z": 1.0
+ },
+ {
+ "x": 48.25658735899499,
+ "y": 2.0321326163794664,
+ "z": 1.0
+ },
+ {
+ "x": 47.756221237457936,
+ "y": 2.0319695421450215,
+ "z": 1.0
+ },
+ {
+ "x": 47.3559283402283,
+ "y": 2.0318390827574664,
+ "z": 1.0
+ },
+ {
+ "x": 46.85556221869126,
+ "y": 2.0316760085230214,
+ "z": 1.0
+ },
+ {
+ "x": 46.25512287284681,
+ "y": 2.0314803194416884,
+ "z": 1.0
+ },
+ {
+ "x": 45.65468352700236,
+ "y": 2.0312846303603544,
+ "z": 1.0
+ },
+ {
+ "x": 45.15431740546532,
+ "y": 2.0311215561259104,
+ "z": 1.0
+ },
+ {
+ "x": 44.75402450823567,
+ "y": 2.0309910967383544,
+ "z": 1.0
+ },
+ {
+ "x": 44.25365838669863,
+ "y": 2.0308280225039104,
+ "z": 1.0
+ },
+ {
+ "x": 43.75329226516159,
+ "y": 2.0306649482694654,
+ "z": 1.0
+ },
+ {
+ "x": 43.15285291931714,
+ "y": 2.0304692591881324,
+ "z": 1.0
+ },
+ {
+ "x": 42.75256002208751,
+ "y": 2.0303387998005764,
+ "z": 1.0
+ },
+ {
+ "x": 42.352267124857875,
+ "y": 2.0302083404130213,
+ "z": 1.0
+ },
+ {
+ "x": 41.95197422762823,
+ "y": 2.0300778810254654,
+ "z": 1.0
+ },
+ {
+ "x": 41.551681330398594,
+ "y": 2.0299474216379094,
+ "z": 1.0
+ },
+ {
+ "x": 41.15138843316896,
+ "y": 2.0298169622503544,
+ "z": 1.0
+ },
+ {
+ "x": 40.65102231163192,
+ "y": 2.0296538880159094,
+ "z": 1.0
+ },
+ {
+ "x": 40.05058296578747,
+ "y": 2.0294581989345764,
+ "z": 1.0
+ },
+ {
+ "x": 39.450143619943006,
+ "y": 2.0292625098532433,
+ "z": 1.0
+ },
+ {
+ "x": 38.94977749840598,
+ "y": 2.0290994356187984,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 15,
+ "heading": [
+ -3.1412667437776554,
+ -3.141266743777655,
+ -3.141266743777655,
+ -3.141266743777654,
+ -3.141266743777655,
+ -3.1412667437776545,
+ -3.141266743777654,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776554,
+ -3.141266743777655,
+ -3.1412667437776545,
+ -3.141266743777654,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.141266743777655,
+ -3.1412667437776545,
+ -3.141266743777654,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.141266743777655,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.141266743777655,
+ -3.1412667437776536,
+ -3.1412667437776545,
+ -3.141266743777655,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.141266743777655,
+ -3.141266743777655,
+ -3.1412667437776536,
+ -3.141266743777655,
+ -3.1412667437776545,
+ -3.1412667437776545,
+ -3.141266743777655,
+ -3.1412667437776545
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -5.0237066297498245,
+ "y": -0.001637275341908051
+ },
+ {
+ "x": -11.05215458544933,
+ "y": -0.003602005752201265
+ },
+ {
+ "x": -10.047413259499223,
+ "y": -0.003274550683824984
+ },
+ {
+ "x": -8.037930607599435,
+ "y": -0.002619640547054658
+ },
+ {
+ "x": -9.0426719335494,
+ "y": -0.002947095615439821
+ },
+ {
+ "x": -10.047413259499365,
+ "y": -0.003274550683824984
+ },
+ {
+ "x": -9.042671933549542,
+ "y": -0.002947095615439821
+ },
+ {
+ "x": -9.0426719335494,
+ "y": -0.002947095615439821
+ },
+ {
+ "x": -7.03318928164947,
+ "y": -0.002292185478669495
+ },
+ {
+ "x": -8.013876110344569,
+ "y": -0.002611800950096388
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200046362
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -10.007322430740686,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -12.008786916888852,
+ "y": -0.003913781626669888
+ },
+ {
+ "x": -11.008054673814769,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -10.007322430740686,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -12.008786916888852,
+ "y": -0.003913781626669888
+ },
+ {
+ "x": -11.008054673814769,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -9.006590187666745,
+ "y": -0.0029353362199957544
+ },
+ {
+ "x": -10.007322430740686,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -10.007322430740686,
+ "y": -0.0032614846888945337
+ },
+ {
+ "x": -8.00585794459252,
+ "y": -0.002609187751110298
+ },
+ {
+ "x": -10.007322430740686,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -11.008054673814769,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -10.007322430740686,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -11.008054673814769,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -10.007322430740686,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -11.008054673814769,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -9.006590187666603,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -11.008054673814769,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -10.00732243074097,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -11.008054673815053,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -9.006590187666887,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -10.00732243074097,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -9.006590187666745,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -12.008786916888994,
+ "y": -0.003913781626669888
+ },
+ {
+ "x": -11.008054673815053,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -10.00732243074097,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -12.008786916888994,
+ "y": -0.003913781626661006
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -10.00732243074097,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -11.008054673815053,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -9.006590187666745,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -8.005857944592663,
+ "y": -0.002609187751110298
+ },
+ {
+ "x": -9.006590187666887,
+ "y": -0.002935336220009077
+ },
+ {
+ "x": -9.006590187666887,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -8.005857944592663,
+ "y": -0.002609187751110298
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -9.006590187666745,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -9.006590187666887,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -9.006590187666887,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -9.006590187666745,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -12.008786916888994,
+ "y": -0.003913781626669888
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -9.006590187666887,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -9.006590187666887,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -10.007322430740828,
+ "y": -0.003261484688890093
+ },
+ {
+ "x": -8.005857944592663,
+ "y": -0.002609187751110298
+ },
+ {
+ "x": -8.005857944592805,
+ "y": -0.002609187751110298
+ },
+ {
+ "x": -8.005857944592805,
+ "y": -0.0026091877511191797
+ },
+ {
+ "x": -8.005857944592663,
+ "y": -0.002609187751110298
+ },
+ {
+ "x": -9.006590187666745,
+ "y": -0.0029353362200001953
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ },
+ {
+ "x": -12.008786916889136,
+ "y": -0.003913781626661006
+ },
+ {
+ "x": -11.008054673814911,
+ "y": -0.0035876331577799903
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 38.94977749840598,
+ "y": 2.0290994356187984,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 92.40138135506758,
+ "y": -206.4210177929624,
+ "z": 1.0
+ },
+ {
+ "x": 92.40132027234365,
+ "y": -206.01919131358682,
+ "z": 1.0
+ },
+ {
+ "x": 92.40125918961971,
+ "y": -205.61736483421123,
+ "z": 1.0
+ },
+ {
+ "x": 92.40119810689576,
+ "y": -205.21553835483564,
+ "z": 1.0
+ },
+ {
+ "x": 92.40113702417182,
+ "y": -204.81371187546003,
+ "z": 1.0
+ },
+ {
+ "x": 92.40107594144787,
+ "y": -204.41188539608444,
+ "z": 1.0
+ },
+ {
+ "x": 92.40101485872391,
+ "y": -204.01005891670857,
+ "z": 1.0
+ },
+ {
+ "x": 92.40093850531899,
+ "y": -203.50777581748966,
+ "z": 1.0
+ },
+ {
+ "x": 92.40087742259504,
+ "y": -203.10594933811376,
+ "z": 1.0
+ },
+ {
+ "x": 92.40081633987108,
+ "y": -202.7041228587379,
+ "z": 1.0
+ },
+ {
+ "x": 92.40075525714714,
+ "y": -202.3022963793626,
+ "z": 1.0
+ },
+ {
+ "x": 92.40067890374222,
+ "y": -201.8000132801434,
+ "z": 1.0
+ },
+ {
+ "x": 92.40061782101826,
+ "y": -201.39818680076752,
+ "z": 1.0
+ },
+ {
+ "x": 92.40055673829431,
+ "y": -200.99636032139193,
+ "z": 1.0
+ },
+ {
+ "x": 92.40046511420839,
+ "y": -200.39362060232827,
+ "z": 1.0
+ },
+ {
+ "x": 92.40040403148444,
+ "y": -199.99179412295297,
+ "z": 1.0
+ },
+ {
+ "x": 92.4003429487605,
+ "y": -199.58996764357738,
+ "z": 1.0
+ },
+ {
+ "x": 92.40025132467457,
+ "y": -198.98722792451397,
+ "z": 1.0
+ },
+ {
+ "x": 92.40015970058866,
+ "y": -198.38448820545088,
+ "z": 1.0
+ },
+ {
+ "x": 92.40006807650273,
+ "y": -197.78174848638722,
+ "z": 1.0
+ },
+ {
+ "x": 92.39997645241681,
+ "y": -197.17900876732415,
+ "z": 1.0
+ },
+ {
+ "x": 92.39988482833088,
+ "y": -196.57626904826049,
+ "z": 1.0
+ },
+ {
+ "x": 92.39980847492595,
+ "y": -196.073985949041,
+ "z": 1.0
+ },
+ {
+ "x": 92.39971685084004,
+ "y": -195.4712462299779,
+ "z": 1.0
+ },
+ {
+ "x": 92.39965576811608,
+ "y": -195.06941975060204,
+ "z": 1.0
+ },
+ {
+ "x": 92.39956414403017,
+ "y": -194.46668003153894,
+ "z": 1.0
+ },
+ {
+ "x": 92.39948779062522,
+ "y": -193.96439693231886,
+ "z": 1.0
+ },
+ {
+ "x": 92.3994114372203,
+ "y": -193.46211383309966,
+ "z": 1.0
+ },
+ {
+ "x": 92.39933508381536,
+ "y": -192.95983073388047,
+ "z": 1.0
+ },
+ {
+ "x": 92.39927400109141,
+ "y": -192.55800425450488,
+ "z": 1.0
+ },
+ {
+ "x": 92.39918237700549,
+ "y": -191.9552645354415,
+ "z": 1.0
+ },
+ {
+ "x": 92.39909075291956,
+ "y": -191.3525248163778,
+ "z": 1.0
+ },
+ {
+ "x": 92.39901439951464,
+ "y": -190.8502417171586,
+ "z": 1.0
+ },
+ {
+ "x": 92.39892277542872,
+ "y": -190.24750199809523,
+ "z": 1.0
+ },
+ {
+ "x": 92.39886169270477,
+ "y": -189.84567551871964,
+ "z": 1.0
+ },
+ {
+ "x": 92.39878533929982,
+ "y": -189.34339241949988,
+ "z": 1.0
+ },
+ {
+ "x": 92.39872425657587,
+ "y": -188.9415659401243,
+ "z": 1.0
+ },
+ {
+ "x": 92.39866317385194,
+ "y": -188.53973946074896,
+ "z": 1.0
+ },
+ {
+ "x": 92.39858682044698,
+ "y": -188.03745636152922,
+ "z": 1.0
+ },
+ {
+ "x": 92.39852573772303,
+ "y": -187.6356298821536,
+ "z": 1.0
+ },
+ {
+ "x": 92.39846465499909,
+ "y": -187.23380340277802,
+ "z": 1.0
+ },
+ {
+ "x": 92.39837303091316,
+ "y": -186.63106368371464,
+ "z": 1.0
+ },
+ {
+ "x": 92.39832721887021,
+ "y": -186.32969382418295,
+ "z": 1.0
+ },
+ {
+ "x": 92.39826629054149,
+ "y": -185.92888301800355,
+ "z": 1.0
+ },
+ {
+ "x": 92.39819013013054,
+ "y": -185.42786951027819,
+ "z": 1.0
+ },
+ {
+ "x": 92.39809873763745,
+ "y": -184.82665330100866,
+ "z": 1.0
+ },
+ {
+ "x": 92.39800734514435,
+ "y": -184.22543709173857,
+ "z": 1.0
+ },
+ {
+ "x": 92.39793118473344,
+ "y": -183.72442358401378,
+ "z": 1.0
+ },
+ {
+ "x": 92.39785502432252,
+ "y": -183.22341007628893,
+ "z": 1.0
+ },
+ {
+ "x": 92.39776363182942,
+ "y": -182.62219386701912,
+ "z": 1.0
+ },
+ {
+ "x": 92.39768747141851,
+ "y": -182.12118035929433,
+ "z": 1.0
+ },
+ {
+ "x": 92.39762654308977,
+ "y": -181.72036955311472,
+ "z": 1.0
+ },
+ {
+ "x": 92.39755038267886,
+ "y": -181.21935604538993,
+ "z": 1.0
+ },
+ {
+ "x": 92.39748945435012,
+ "y": -180.81854523920975,
+ "z": 1.0
+ },
+ {
+ "x": 92.3974285260214,
+ "y": -180.4177344330302,
+ "z": 1.0
+ },
+ {
+ "x": 92.3973371335283,
+ "y": -179.8165182237604,
+ "z": 1.0
+ },
+ {
+ "x": 92.39724574103519,
+ "y": -179.2153020144903,
+ "z": 1.0
+ },
+ {
+ "x": 92.39716958062426,
+ "y": -178.7142885067655,
+ "z": 1.0
+ },
+ {
+ "x": 92.39710865229554,
+ "y": -178.3134777005859,
+ "z": 1.0
+ },
+ {
+ "x": 92.3970477239668,
+ "y": -177.9126668944058,
+ "z": 1.0
+ },
+ {
+ "x": 92.39695633147372,
+ "y": -177.31145068513626,
+ "z": 1.0
+ },
+ {
+ "x": 92.39689540314497,
+ "y": -176.9106398789561,
+ "z": 1.0
+ },
+ {
+ "x": 92.39680401065188,
+ "y": -176.30942366968662,
+ "z": 1.0
+ },
+ {
+ "x": 92.39674308232314,
+ "y": -175.90861286350645,
+ "z": 1.0
+ },
+ {
+ "x": 92.39668215399442,
+ "y": -175.5078020573269,
+ "z": 1.0
+ },
+ {
+ "x": 92.39659076150132,
+ "y": -174.9065858480571,
+ "z": 1.0
+ },
+ {
+ "x": 92.39649936900821,
+ "y": -174.305369638787,
+ "z": 1.0
+ },
+ {
+ "x": 92.39643844067947,
+ "y": -173.90455883260745,
+ "z": 1.0
+ },
+ {
+ "x": 92.39636228026856,
+ "y": -173.4035453248826,
+ "z": 1.0
+ },
+ {
+ "x": 92.39628611985765,
+ "y": -172.90253181715775,
+ "z": 1.0
+ },
+ {
+ "x": 92.39622519152891,
+ "y": -172.50172101097786,
+ "z": 1.0
+ },
+ {
+ "x": 92.39616426320018,
+ "y": -172.10091020479797,
+ "z": 1.0
+ },
+ {
+ "x": 92.39607287070707,
+ "y": -171.49969399552788,
+ "z": 1.0
+ },
+ {
+ "x": 92.39598147821397,
+ "y": -170.89847778625807,
+ "z": 1.0
+ },
+ {
+ "x": 92.39592054988525,
+ "y": -170.49766698007852,
+ "z": 1.0
+ },
+ {
+ "x": 92.39584438947433,
+ "y": -169.99665347235367,
+ "z": 1.0
+ },
+ {
+ "x": 92.3957682290634,
+ "y": -169.49563996462882,
+ "z": 1.0
+ },
+ {
+ "x": 92.39567683657032,
+ "y": -168.894423755359,
+ "z": 1.0
+ },
+ {
+ "x": 92.39560067615939,
+ "y": -168.39341024763388,
+ "z": 1.0
+ },
+ {
+ "x": 92.39553974783067,
+ "y": -167.99259944145427,
+ "z": 1.0
+ },
+ {
+ "x": 92.39547881950193,
+ "y": -167.59178863527438,
+ "z": 1.0
+ },
+ {
+ "x": 92.39538742700883,
+ "y": -166.9905724260043,
+ "z": 1.0
+ },
+ {
+ "x": 92.39532649868009,
+ "y": -166.5897616198244,
+ "z": 1.0
+ },
+ {
+ "x": 92.39523510618699,
+ "y": -165.9885454105546,
+ "z": 1.0
+ },
+ {
+ "x": 92.39517417785827,
+ "y": -165.58773460437504,
+ "z": 1.0
+ },
+ {
+ "x": 92.39509801744734,
+ "y": -165.0867210966499,
+ "z": 1.0
+ },
+ {
+ "x": 92.39503708911862,
+ "y": -164.6859102904703,
+ "z": 1.0
+ },
+ {
+ "x": 92.39494569662551,
+ "y": -164.0846940812005,
+ "z": 1.0
+ },
+ {
+ "x": 92.39488476829678,
+ "y": -163.6838832750206,
+ "z": 1.0
+ },
+ {
+ "x": 92.39479337580369,
+ "y": -163.0826670657508,
+ "z": 1.0
+ },
+ {
+ "x": 92.39471721539276,
+ "y": -162.58165355802566,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 16,
+ "heading": [
+ 1.5709483394834876,
+ 1.5709483394834476,
+ 1.5709483394834654,
+ 1.570948339483483,
+ 1.570948339483483,
+ 1.570948339483483,
+ 1.5709483394835007,
+ 1.5709483394834869,
+ 1.5709483394834711,
+ 1.5709483394835004,
+ 1.5709483394835007,
+ 1.5709483394834713,
+ 1.5709483394834869,
+ 1.5709483394835007,
+ 1.57094833948349,
+ 1.57094833948349,
+ 1.5709483394834831,
+ 1.57094833948349,
+ 1.570948339483483,
+ 1.570948339483483,
+ 1.5709483394834947,
+ 1.5709483394834947,
+ 1.5709483394834927,
+ 1.5709483394834798,
+ 1.57094833948349,
+ 1.57094833948349,
+ 1.5709483394834927,
+ 1.57094833948349,
+ 1.570948339483476,
+ 1.5709483394834869,
+ 1.57094833948349,
+ 1.5709483394834947,
+ 1.5709483394834798,
+ 1.5709483394834798,
+ 1.57094833948349,
+ 1.5709483394835027,
+ 1.5709483394835027,
+ 1.5709483394834654,
+ 1.5709483394835027,
+ 1.5709483394835182,
+ 1.570948339483483,
+ 1.57094833948349,
+ 1.5709483394834869,
+ 1.5709483394834647,
+ 1.570948339483503,
+ 1.5709483394835015,
+ 1.5709483394834833,
+ 1.5709483394834887,
+ 1.570948339483481,
+ 1.5709483394834887,
+ 1.5709483394834887,
+ 1.5709483394834873,
+ 1.5709483394834873,
+ 1.5709483394834873,
+ 1.5709483394834773,
+ 1.5709483394834811,
+ 1.570948339483495,
+ 1.5709483394835015,
+ 1.5709483394834873,
+ 1.5709483394834773,
+ 1.570948339483481,
+ 1.570948339483495,
+ 1.570948339483495,
+ 1.570948339483481,
+ 1.5709483394834773,
+ 1.5709483394834811,
+ 1.570948339483495,
+ 1.570948339483495,
+ 1.5709483394834873,
+ 1.570948339483481,
+ 1.5709483394834873,
+ 1.570948339483495,
+ 1.570948339483495,
+ 1.570948339483495,
+ 1.5709483394834811,
+ 1.5709483394834716,
+ 1.570948339483495,
+ 1.5709483394834887,
+ 1.5709483394834887,
+ 1.5709483394834873,
+ 1.5709483394834776,
+ 1.570948339483495,
+ 1.570948339483495,
+ 1.570948339483495,
+ 1.5709483394834811,
+ 1.5709483394834873,
+ 1.5709483394834873,
+ 1.5709483394834811,
+ 1.570948339483495,
+ 1.570948339483481,
+ 1.5709483394834887
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -0.0006108272393134939,
+ "y": 4.018264793755861
+ },
+ {
+ "x": -0.0012216544787690964,
+ "y": 8.036529587511723
+ },
+ {
+ "x": -0.001221654478911205,
+ "y": 8.036529587511723
+ },
+ {
+ "x": -0.001221654478911205,
+ "y": 8.036529587512007
+ },
+ {
+ "x": -0.001221654478911205,
+ "y": 8.036529587512007
+ },
+ {
+ "x": -0.0012216544790533135,
+ "y": 8.036529587514565
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.041095785947846
+ },
+ {
+ "x": -0.0013743612886685241,
+ "y": 9.04109578594813
+ },
+ {
+ "x": -0.0012216544790533135,
+ "y": 8.036529587517691
+ },
+ {
+ "x": -0.0012216544790533135,
+ "y": 8.036529587511723
+ },
+ {
+ "x": -0.0013743612886685241,
+ "y": 9.041095785945004
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.041095785950688
+ },
+ {
+ "x": -0.0012216544790533135,
+ "y": 8.036529587514565
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984392495
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984389653
+ },
+ {
+ "x": -0.001221654478911205,
+ "y": 8.03652958750888
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984389938
+ },
+ {
+ "x": -0.0018324817183668074,
+ "y": 12.054794381265026
+ },
+ {
+ "x": -0.0018324817183668074,
+ "y": 12.054794381267584
+ },
+ {
+ "x": -0.001832481718508916,
+ "y": 12.0547943812673
+ },
+ {
+ "x": -0.001832481718508916,
+ "y": 12.0547943812673
+ },
+ {
+ "x": -0.0016797749086094882,
+ "y": 11.05022818283146
+ },
+ {
+ "x": -0.0016797749084673796,
+ "y": 11.050228182825776
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984389653
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984389653
+ },
+ {
+ "x": -0.0016797749086094882,
+ "y": 11.050228182831745
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.04566198439278
+ },
+ {
+ "x": -0.001527068098567952,
+ "y": 10.045661984383969
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.041095785947846
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984389653
+ },
+ {
+ "x": -0.001832481718508916,
+ "y": 12.05479438127071
+ },
+ {
+ "x": -0.0016797749084673796,
+ "y": 11.050228182828903
+ },
+ {
+ "x": -0.0016797749084673796,
+ "y": 11.050228182825776
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984389653
+ },
+ {
+ "x": -0.0013743612889527412,
+ "y": 9.04109578595353
+ },
+ {
+ "x": -0.0013743612889527412,
+ "y": 9.04109578595353
+ },
+ {
+ "x": -0.0012216544787690964,
+ "y": 8.036529587509165
+ },
+ {
+ "x": -0.0013743612889527412,
+ "y": 9.041095785950688
+ },
+ {
+ "x": -0.0013743612890948498,
+ "y": 9.04109578595353
+ },
+ {
+ "x": -0.001221654478911205,
+ "y": 8.036529587512007
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984389653
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.041095785950688
+ },
+ {
+ "x": -0.0010674037167746064,
+ "y": 7.021806657110972
+ },
+ {
+ "x": -0.0013708873966322699,
+ "y": 9.018243139047684
+ },
+ {
+ "x": -0.00167552904031254,
+ "y": 11.022297169948843
+ },
+ {
+ "x": -0.0018278498619395123,
+ "y": 12.024324185396154
+ },
+ {
+ "x": -0.0016755290401704315,
+ "y": 11.022297169948843
+ },
+ {
+ "x": -0.0015232082182592421,
+ "y": 10.020270154496416
+ },
+ {
+ "x": -0.0016755290401704315,
+ "y": 11.022297169946569
+ },
+ {
+ "x": -0.0016755290401704315,
+ "y": 11.022297169946
+ },
+ {
+ "x": -0.0013708873964901613,
+ "y": 9.018243139043989
+ },
+ {
+ "x": -0.0013708873964901613,
+ "y": 9.018243139043989
+ },
+ {
+ "x": -0.0013708873964901613,
+ "y": 9.018243139049673
+ },
+ {
+ "x": -0.001218566574578972,
+ "y": 8.016216123597246
+ },
+ {
+ "x": -0.0015232082182592421,
+ "y": 10.020270154493574
+ },
+ {
+ "x": -0.0018278498620816208,
+ "y": 12.024324185398996
+ },
+ {
+ "x": -0.00167552904031254,
+ "y": 11.022297169948843
+ },
+ {
+ "x": -0.0013708873964901613,
+ "y": 9.018243139043989
+ },
+ {
+ "x": -0.001218566574578972,
+ "y": 8.016216123597246
+ },
+ {
+ "x": -0.0015232082182592421,
+ "y": 10.020270154496416
+ },
+ {
+ "x": -0.0015232082184013507,
+ "y": 10.020270154496984
+ },
+ {
+ "x": -0.0015232082184013507,
+ "y": 10.020270154496416
+ },
+ {
+ "x": -0.0015232082182592421,
+ "y": 10.020270154496416
+ },
+ {
+ "x": -0.001218566574578972,
+ "y": 8.016216123597246
+ },
+ {
+ "x": -0.0015232082182592421,
+ "y": 10.020270154493574
+ },
+ {
+ "x": -0.0018278498620816208,
+ "y": 12.024324185398996
+ },
+ {
+ "x": -0.0015232082184013507,
+ "y": 10.020270154496416
+ },
+ {
+ "x": -0.0013708873964901613,
+ "y": 9.018243139043989
+ },
+ {
+ "x": -0.0015232082182592421,
+ "y": 10.020270154496984
+ },
+ {
+ "x": -0.0013708873964901613,
+ "y": 9.0182431390474
+ },
+ {
+ "x": -0.0012185665747210805,
+ "y": 8.016216123597815
+ },
+ {
+ "x": -0.0015232082184013507,
+ "y": 10.020270154499826
+ },
+ {
+ "x": -0.0018278498620816208,
+ "y": 12.024324185398996
+ },
+ {
+ "x": -0.0015232082182592421,
+ "y": 10.020270154493574
+ },
+ {
+ "x": -0.0013708873963480528,
+ "y": 9.018243139043989
+ },
+ {
+ "x": -0.0015232082184013507,
+ "y": 10.020270154496984
+ },
+ {
+ "x": -0.0016755290401704315,
+ "y": 11.022297169946569
+ },
+ {
+ "x": -0.0016755290401704315,
+ "y": 11.022297169949411
+ },
+ {
+ "x": -0.0013708873964901613,
+ "y": 9.0182431390474
+ },
+ {
+ "x": -0.001218566574578972,
+ "y": 8.016216123594972
+ },
+ {
+ "x": -0.0015232082184013507,
+ "y": 10.020270154499826
+ },
+ {
+ "x": -0.0015232082184013507,
+ "y": 10.020270154499826
+ },
+ {
+ "x": -0.0015232082184013507,
+ "y": 10.020270154496984
+ },
+ {
+ "x": -0.0015232082182592421,
+ "y": 10.020270154493574
+ },
+ {
+ "x": -0.0013708873964901613,
+ "y": 9.018243139046831
+ },
+ {
+ "x": -0.0013708873964901613,
+ "y": 9.0182431390474
+ },
+ {
+ "x": -0.0015232082182592421,
+ "y": 10.020270154494142
+ },
+ {
+ "x": -0.0015232082184013507,
+ "y": 10.020270154496984
+ },
+ {
+ "x": -0.0015232082182592421,
+ "y": 10.020270154496984
+ },
+ {
+ "x": -0.0016755290401704315,
+ "y": 11.022297169949411
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 92.39471721539276,
+ "y": -162.58165355802566,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 98.51810306057145,
+ "y": -55.50484681194324,
+ "z": 1.0
+ },
+ {
+ "x": 97.90210763219395,
+ "y": -55.54275923928253,
+ "z": 1.0
+ },
+ {
+ "x": 97.1672865624749,
+ "y": -55.63466477552653,
+ "z": 1.0
+ },
+ {
+ "x": 96.68166077772335,
+ "y": -55.72386663030572,
+ "z": 1.0
+ },
+ {
+ "x": 96.20062722226538,
+ "y": -55.835202363034306,
+ "z": 1.0
+ },
+ {
+ "x": 95.72519384633145,
+ "y": -55.96843865514556,
+ "z": 1.0
+ },
+ {
+ "x": 95.25635687268348,
+ "y": -56.123296327664626,
+ "z": 1.0
+ },
+ {
+ "x": 94.56761440630069,
+ "y": -56.395400963932104,
+ "z": 1.0
+ },
+ {
+ "x": 94.00903059441187,
+ "y": -56.65783241733771,
+ "z": 1.0
+ },
+ {
+ "x": 93.35990744115566,
+ "y": -57.01427844825002,
+ "z": 1.0
+ },
+ {
+ "x": 92.73644077798586,
+ "y": -57.414744385709014,
+ "z": 1.0
+ },
+ {
+ "x": 92.33698122798639,
+ "y": -57.70496070084755,
+ "z": 1.0
+ },
+ {
+ "x": 91.85702245212593,
+ "y": -58.09293837455154,
+ "z": 1.0
+ },
+ {
+ "x": 91.39786416293066,
+ "y": -58.51010636110452,
+ "z": 1.0
+ },
+ {
+ "x": 91.04411377147096,
+ "y": -58.869432796682446,
+ "z": 1.0
+ },
+ {
+ "x": 90.70915520760263,
+ "y": -59.246337381510976,
+ "z": 1.0
+ },
+ {
+ "x": 90.24384526998537,
+ "y": -59.84249537269999,
+ "z": 1.0
+ },
+ {
+ "x": 89.89184851897855,
+ "y": -60.3653002596416,
+ "z": 1.0
+ },
+ {
+ "x": 89.63469918666868,
+ "y": -60.799042668986026,
+ "z": 1.0
+ },
+ {
+ "x": 89.2910951948812,
+ "y": -61.47329534779308,
+ "z": 1.0
+ },
+ {
+ "x": 89.00037913616302,
+ "y": -62.171598554025486,
+ "z": 1.0
+ },
+ {
+ "x": 88.83665481370848,
+ "y": -62.64851758812371,
+ "z": 1.0
+ },
+ {
+ "x": 88.69747394854923,
+ "y": -63.13316632318826,
+ "z": 1.0
+ },
+ {
+ "x": 88.53549611385694,
+ "y": -63.871868352028564,
+ "z": 1.0
+ },
+ {
+ "x": 88.44400352070429,
+ "y": -64.49544921231548,
+ "z": 1.0
+ },
+ {
+ "x": 88.39955449165987,
+ "y": -64.99772352931295,
+ "z": 1.0
+ },
+ {
+ "x": 88.37999549573044,
+ "y": -65.73662391198296,
+ "z": 1.0
+ },
+ {
+ "x": 88.38005663906475,
+ "y": -66.13884911037657,
+ "z": 1.0
+ },
+ {
+ "x": 88.3801483540662,
+ "y": -66.74218690796627,
+ "z": 1.0
+ },
+ {
+ "x": 88.38020949740049,
+ "y": -67.1444121063596,
+ "z": 1.0
+ },
+ {
+ "x": 88.38028592656836,
+ "y": -67.64719360435126,
+ "z": 1.0
+ },
+ {
+ "x": 88.38036235573624,
+ "y": -68.1499751023429,
+ "z": 1.0
+ },
+ {
+ "x": 88.38042331674794,
+ "y": -68.55100091016726,
+ "z": 1.0
+ },
+ {
+ "x": 88.38051468344379,
+ "y": -69.15204741485073,
+ "z": 1.0
+ },
+ {
+ "x": 88.380590822357,
+ "y": -69.65291950208695,
+ "z": 1.0
+ },
+ {
+ "x": 88.38065173348757,
+ "y": -70.05361717187591,
+ "z": 1.0
+ },
+ {
+ "x": 88.38072787240077,
+ "y": -70.55448925911213,
+ "z": 1.0
+ },
+ {
+ "x": 88.38081923909662,
+ "y": -71.15553576379558,
+ "z": 1.0
+ },
+ {
+ "x": 88.38091060579247,
+ "y": -71.75658226847905,
+ "z": 1.0
+ },
+ {
+ "x": 88.38098674470567,
+ "y": -72.25745435571554,
+ "z": 1.0
+ },
+ {
+ "x": 88.38107811140152,
+ "y": -72.85850086039872,
+ "z": 1.0
+ },
+ {
+ "x": 88.38115425031474,
+ "y": -73.35937294763522,
+ "z": 1.0
+ },
+ {
+ "x": 88.38121516144531,
+ "y": -73.7600706174239,
+ "z": 1.0
+ },
+ {
+ "x": 88.38130652814115,
+ "y": -74.36111712210736,
+ "z": 1.0
+ },
+ {
+ "x": 88.38139789483701,
+ "y": -74.96216362679083,
+ "z": 1.0
+ },
+ {
+ "x": 88.38148926153285,
+ "y": -75.56321013147428,
+ "z": 1.0
+ },
+ {
+ "x": 88.3815806282287,
+ "y": -76.16425663615775,
+ "z": 1.0
+ },
+ {
+ "x": 88.38164153935926,
+ "y": -76.56495430594671,
+ "z": 1.0
+ },
+ {
+ "x": 88.38171767827248,
+ "y": -77.06582639318293,
+ "z": 1.0
+ },
+ {
+ "x": 88.38177858940304,
+ "y": -77.4665240629719,
+ "z": 1.0
+ },
+ {
+ "x": 88.38185472831624,
+ "y": -77.96739615020812,
+ "z": 1.0
+ },
+ {
+ "x": 88.3819460950121,
+ "y": -78.56844265489157,
+ "z": 1.0
+ },
+ {
+ "x": 88.3820222339253,
+ "y": -79.06931474212779,
+ "z": 1.0
+ },
+ {
+ "x": 88.38208314505587,
+ "y": -79.47001241191676,
+ "z": 1.0
+ },
+ {
+ "x": 88.38214405618643,
+ "y": -79.87071008170574,
+ "z": 1.0
+ },
+ {
+ "x": 88.38222019509963,
+ "y": -80.37158216894196,
+ "z": 1.0
+ },
+ {
+ "x": 88.38231156179549,
+ "y": -80.97262867362541,
+ "z": 1.0
+ },
+ {
+ "x": 88.38237247292605,
+ "y": -81.37332634341438,
+ "z": 1.0
+ },
+ {
+ "x": 88.38243338405663,
+ "y": -81.77402401320336,
+ "z": 1.0
+ },
+ {
+ "x": 88.38252475075247,
+ "y": -82.37507051788681,
+ "z": 1.0
+ },
+ {
+ "x": 88.38260088966568,
+ "y": -82.87594260512303,
+ "z": 1.0
+ },
+ {
+ "x": 88.38269225636154,
+ "y": -83.47698910980648,
+ "z": 1.0
+ },
+ {
+ "x": 88.3827531674921,
+ "y": -83.87768677959545,
+ "z": 1.0
+ },
+ {
+ "x": 88.38282930640531,
+ "y": -84.37855886683167,
+ "z": 1.0
+ },
+ {
+ "x": 88.38292067310115,
+ "y": -84.97960537151513,
+ "z": 1.0
+ },
+ {
+ "x": 88.38301203979701,
+ "y": -85.58065187619859,
+ "z": 1.0
+ },
+ {
+ "x": 88.38310340649285,
+ "y": -86.18169838088205,
+ "z": 1.0
+ },
+ {
+ "x": 88.38316431762343,
+ "y": -86.58239605067102,
+ "z": 1.0
+ },
+ {
+ "x": 88.38324045653663,
+ "y": -87.08326813790724,
+ "z": 1.0
+ },
+ {
+ "x": 88.38331659544984,
+ "y": -87.58414022514346,
+ "z": 1.0
+ },
+ {
+ "x": 88.3833775065804,
+ "y": -87.98483789493243,
+ "z": 1.0
+ },
+ {
+ "x": 88.38346887327624,
+ "y": -88.58588439961588,
+ "z": 1.0
+ },
+ {
+ "x": 88.38354501218946,
+ "y": -89.0867564868521,
+ "z": 1.0
+ },
+ {
+ "x": 88.3836363788853,
+ "y": -89.68780299153555,
+ "z": 1.0
+ },
+ {
+ "x": 88.38372774558115,
+ "y": -90.28884949621902,
+ "z": 1.0
+ },
+ {
+ "x": 88.383819112277,
+ "y": -90.88989600090247,
+ "z": 1.0
+ },
+ {
+ "x": 88.38391047897285,
+ "y": -91.49094250558593,
+ "z": 1.0
+ },
+ {
+ "x": 88.38398661788605,
+ "y": -91.99181459282215,
+ "z": 1.0
+ },
+ {
+ "x": 88.38407798458191,
+ "y": -92.5928610975056,
+ "z": 1.0
+ },
+ {
+ "x": 88.38413889571248,
+ "y": -92.99355876729457,
+ "z": 1.0
+ },
+ {
+ "x": 88.38419980684304,
+ "y": -93.39425643708384,
+ "z": 1.0
+ },
+ {
+ "x": 88.38427594575626,
+ "y": -93.89512852431977,
+ "z": 1.0
+ },
+ {
+ "x": 88.38435208466946,
+ "y": -94.39600061155598,
+ "z": 1.0
+ },
+ {
+ "x": 88.38442822358267,
+ "y": -94.8968726987922,
+ "z": 1.0
+ },
+ {
+ "x": 88.38448913471323,
+ "y": -95.29757036858116,
+ "z": 1.0
+ },
+ {
+ "x": 88.38456527362645,
+ "y": -95.79844245581738,
+ "z": 1.0
+ },
+ {
+ "x": 88.38464141253965,
+ "y": -96.2993145430536,
+ "z": 1.0
+ },
+ {
+ "x": 88.38471755145285,
+ "y": -96.80018663028982,
+ "z": 1.0
+ },
+ {
+ "x": 88.3848089181487,
+ "y": -97.40123313497327,
+ "z": 1.0
+ },
+ {
+ "x": 88.38488505706191,
+ "y": -97.90210522220949,
+ "z": 1.0
+ },
+ {
+ "x": 88.38496119597512,
+ "y": -98.4029773094457,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 17,
+ "heading": [
+ -1.8073716690550956,
+ -3.0801235849284487,
+ -3.045783560178179,
+ -2.9942734138791116,
+ -2.937039928828713,
+ -2.891253154713288,
+ -2.8454663805070655,
+ -2.7882328993815464,
+ -2.736722755012727,
+ -2.6680425608727507,
+ -2.605019650346343,
+ -2.547703940744266,
+ -2.484670601444463,
+ -2.4328508823942907,
+ -2.3791011330762006,
+ -2.322856624015015,
+ -2.259060740481147,
+ -2.2016444200165335,
+ -2.1378485409691073,
+ -2.0676302122575954,
+ -2.0037041380264404,
+ -1.9397715028023987,
+ -1.8759678803709683,
+ -1.81217201350278,
+ -1.7547557105582061,
+ -1.6909598213230572,
+ -1.6223212022660787,
+ -1.587881173364619,
+ -1.5706443141062976,
+ -1.5706443141063116,
+ -1.570644314106307,
+ -1.5706443141062976,
+ -1.5706443141063156,
+ -1.5706443141063124,
+ -1.5706443141063058,
+ -1.570644314106303,
+ -1.570644314106303,
+ -1.5706443141063058,
+ -1.570644314106307,
+ -1.5706443141063187,
+ -1.5706443141063058,
+ -1.570644314106293,
+ -1.5706443141062871,
+ -1.5706443141063045,
+ -1.570644314106307,
+ -1.570644314106307,
+ -1.570644314106307,
+ -1.5706443141063045,
+ -1.570644314106303,
+ -1.570644314106303,
+ -1.5706443141063187,
+ -1.5706443141063058,
+ -1.5706443141063058,
+ -1.570644314106303,
+ -1.570644314106301,
+ -1.5706443141063187,
+ -1.5706443141063058,
+ -1.5706443141063045,
+ -1.570644314106301,
+ -1.5706443141063045,
+ -1.5706443141063058,
+ -1.570644314106293,
+ -1.5706443141063045,
+ -1.570644314106303,
+ -1.5706443141063058,
+ -1.570644314106307,
+ -1.570644314106307,
+ -1.5706443141063045,
+ -1.570644314106303,
+ -1.5706443141063045,
+ -1.570644314106303,
+ -1.5706443141063187,
+ -1.5706443141063058,
+ -1.5706443141063058,
+ -1.570644314106307,
+ -1.570644314106307,
+ -1.570644314106307,
+ -1.5706443141063058,
+ -1.5706443141063058,
+ -1.5706443141062902,
+ -1.570644314106301,
+ -1.570644314106303,
+ -1.5706443141063045,
+ -1.5706443141063045,
+ -1.570644314106303,
+ -1.570644314106303,
+ -1.5706443141063045,
+ -1.5706443141063187,
+ -1.5706443141063058,
+ -1.5706443141063058,
+ -1.5706443141063045
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -6.159954283775022,
+ "y": -0.3791242733929323
+ },
+ {
+ "x": -13.50816498096549,
+ "y": -1.2981796358329234
+ },
+ {
+ "x": -12.204468544705946,
+ "y": -1.8110739102318973
+ },
+ {
+ "x": -9.666593402095174,
+ "y": -2.005375875077746
+ },
+ {
+ "x": -9.564669313919012,
+ "y": -2.445720248398402
+ },
+ {
+ "x": -9.44270349581899,
+ "y": -2.8809396463032044
+ },
+ {
+ "x": -11.575794400307586,
+ "y": -4.269623087865426
+ },
+ {
+ "x": -12.473262782716148,
+ "y": -5.345360896730824
+ },
+ {
+ "x": -12.077069651450358,
+ "y": -6.188774843179132
+ },
+ {
+ "x": -12.725898164260059,
+ "y": -7.569119683713055
+ },
+ {
+ "x": -10.229262131692707,
+ "y": -6.906822525975329
+ },
+ {
+ "x": -8.794183258599304,
+ "y": -6.781939888425228
+ },
+ {
+ "x": -9.391170650557257,
+ "y": -8.051456602569687
+ },
+ {
+ "x": -8.129086806549708,
+ "y": -7.764944221309094
+ },
+ {
+ "x": -6.887089553280248,
+ "y": -7.3623102040645705
+ },
+ {
+ "x": -8.0026850148559,
+ "y": -9.73062576017547
+ },
+ {
+ "x": -8.17306688624086,
+ "y": -11.18962878130624
+ },
+ {
+ "x": -6.091460833166877,
+ "y": -9.565472962860326
+ },
+ {
+ "x": -6.007533240973544,
+ "y": -11.079950881514833
+ },
+ {
+ "x": -6.343200505056643,
+ "y": -13.725558850394606
+ },
+ {
+ "x": -4.544403811727165,
+ "y": -11.752222403306263
+ },
+ {
+ "x": -3.029051876137885,
+ "y": -9.615677691627766
+ },
+ {
+ "x": -3.011586998515412,
+ "y": -12.23350763904854
+ },
+ {
+ "x": -2.5347042784494533,
+ "y": -13.62282889127215
+ },
+ {
+ "x": -1.3594162219706618,
+ "y": -11.258551772843859
+ },
+ {
+ "x": -0.6400802497384461,
+ "y": -12.411746996674822
+ },
+ {
+ "x": -0.19497852595122822,
+ "y": -11.411255810636192
+ },
+ {
+ "x": 0.0015285833575262586,
+ "y": -10.055629959833112
+ },
+ {
+ "x": 0.00152858335738415,
+ "y": -10.05562995983027
+ },
+ {
+ "x": 0.0013757250216883676,
+ "y": -9.050066963849872
+ },
+ {
+ "x": 0.0015285833575262586,
+ "y": -10.055629959833112
+ },
+ {
+ "x": 0.001373901795744814,
+ "y": -9.038073058160023
+ },
+ {
+ "x": 0.0015232770755346792,
+ "y": -10.020723125078206
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196843
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.0018273339169638803,
+ "y": -12.020930093669193
+ },
+ {
+ "x": 0.0016750560904199574,
+ "y": -11.019185919199543
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.0016750560907041745,
+ "y": -11.019185919196843
+ },
+ {
+ "x": 0.0013705004379005459,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744721367
+ },
+ {
+ "x": 0.0018273339169638803,
+ "y": -12.020930093669193
+ },
+ {
+ "x": 0.0018273339169638803,
+ "y": -12.020930093669193
+ },
+ {
+ "x": 0.0018273339169638803,
+ "y": -12.020930093669193
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.0013705004376163288,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.001218222611356623,
+ "y": -8.01395339577951
+ },
+ {
+ "x": 0.0013705004376163288,
+ "y": -9.015697570252001
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.01744174472421
+ },
+ {
+ "x": 0.001218222611356623,
+ "y": -8.01395339577951
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.0016750560907041745,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.01744174472421
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196843
+ },
+ {
+ "x": 0.0018273339169638803,
+ "y": -12.020930093669193
+ },
+ {
+ "x": 0.0018273339169638803,
+ "y": -12.020930093669193
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.001522778264018143,
+ "y": -10.01744174472421
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.0018273339169638803,
+ "y": -12.020930093669193
+ },
+ {
+ "x": 0.0018273339169638803,
+ "y": -12.020930093669193
+ },
+ {
+ "x": 0.0018273339169638803,
+ "y": -12.020930093669193
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196843
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.0015227782643023602,
+ "y": -10.01744174472421
+ },
+ {
+ "x": 0.001218222611356623,
+ "y": -8.013953395782352
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.015697570252001
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744721367
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.01744174472421
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.001522778264018143,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744724351
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 88.38496119597512,
+ "y": -98.4029773094457,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 155.20273178651496,
+ "y": -2.8951887416430546,
+ "z": 1.0
+ },
+ {
+ "x": 154.92579367058397,
+ "y": -3.46365707666486,
+ "z": 1.0
+ },
+ {
+ "x": 154.64273338351381,
+ "y": -4.167631816676954,
+ "z": 1.0
+ },
+ {
+ "x": 154.44890421003072,
+ "y": -4.770275261371781,
+ "z": 1.0
+ },
+ {
+ "x": 154.268611816407,
+ "y": -5.507298142270336,
+ "z": 1.0
+ },
+ {
+ "x": 154.162323368481,
+ "y": -6.130640444882252,
+ "z": 1.0
+ },
+ {
+ "x": 154.09647483718254,
+ "y": -6.759539423961707,
+ "z": 1.0
+ },
+ {
+ "x": 154.07136072828882,
+ "y": -7.38586739845515,
+ "z": 1.0
+ },
+ {
+ "x": 154.07045676264278,
+ "y": -7.796281509985351,
+ "z": 1.0
+ },
+ {
+ "x": 154.06984533725478,
+ "y": -8.299606630835797,
+ "z": 1.0
+ },
+ {
+ "x": 154.0693561969444,
+ "y": -8.702266727515596,
+ "z": 1.0
+ },
+ {
+ "x": 154.06862248647877,
+ "y": -9.306256872536707,
+ "z": 1.0
+ },
+ {
+ "x": 154.06788877601315,
+ "y": -9.910247017557246,
+ "z": 1.0
+ },
+ {
+ "x": 154.06715506554758,
+ "y": -10.514237162577224,
+ "z": 1.0
+ },
+ {
+ "x": 154.0666659252372,
+ "y": -10.916897259258146,
+ "z": 1.0
+ },
+ {
+ "x": 154.06654364015958,
+ "y": -11.01756228342824,
+ "z": 1.0
+ },
+ {
+ "x": 154.06605662413546,
+ "y": -11.418473668533366,
+ "z": 1.0
+ },
+ {
+ "x": 154.06532610009936,
+ "y": -12.019840746190324,
+ "z": 1.0
+ },
+ {
+ "x": 154.06483908407523,
+ "y": -12.42075213129591,
+ "z": 1.0
+ },
+ {
+ "x": 154.06423031404506,
+ "y": -12.92189136267718,
+ "z": 1.0
+ },
+ {
+ "x": 154.06349979000896,
+ "y": -13.52325844033357,
+ "z": 1.0
+ },
+ {
+ "x": 154.06301277398484,
+ "y": -13.924169825439153,
+ "z": 1.0
+ },
+ {
+ "x": 154.06240400395467,
+ "y": -14.425309056820423,
+ "z": 1.0
+ },
+ {
+ "x": 154.0616734799185,
+ "y": -15.026676134477947,
+ "z": 1.0
+ },
+ {
+ "x": 154.0610647098884,
+ "y": -15.527815365859787,
+ "z": 1.0
+ },
+ {
+ "x": 154.06045593985823,
+ "y": -16.02895459724106,
+ "z": 1.0
+ },
+ {
+ "x": 154.05984716982812,
+ "y": -16.530093828622334,
+ "z": 1.0
+ },
+ {
+ "x": 154.059360153804,
+ "y": -16.931005213727346,
+ "z": 1.0
+ },
+ {
+ "x": 154.05875138377388,
+ "y": -17.43214444510862,
+ "z": 1.0
+ },
+ {
+ "x": 154.0581426137437,
+ "y": -17.933283676489893,
+ "z": 1.0
+ },
+ {
+ "x": 154.0575338437136,
+ "y": -18.434422907871166,
+ "z": 1.0
+ },
+ {
+ "x": 154.05680331967744,
+ "y": -19.035789985528126,
+ "z": 1.0
+ },
+ {
+ "x": 154.05631630365332,
+ "y": -19.436701370633706,
+ "z": 1.0
+ },
+ {
+ "x": 154.05558577961716,
+ "y": -20.03806844829067,
+ "z": 1.0
+ },
+ {
+ "x": 154.054855255581,
+ "y": -20.639435525948198,
+ "z": 1.0
+ },
+ {
+ "x": 154.05436823955688,
+ "y": -21.04034691105378,
+ "z": 1.0
+ },
+ {
+ "x": 154.05363771552072,
+ "y": -21.64171398871131,
+ "z": 1.0
+ },
+ {
+ "x": 154.0530289454906,
+ "y": -22.142853220092015,
+ "z": 1.0
+ },
+ {
+ "x": 154.05254192946649,
+ "y": -22.543764605197595,
+ "z": 1.0
+ },
+ {
+ "x": 154.05205491344236,
+ "y": -22.944675990302613,
+ "z": 1.0
+ },
+ {
+ "x": 154.05132438940626,
+ "y": -23.546043067959577,
+ "z": 1.0
+ },
+ {
+ "x": 154.05083737338214,
+ "y": -23.94695445306516,
+ "z": 1.0
+ },
+ {
+ "x": 154.05022860335197,
+ "y": -24.448093684446434,
+ "z": 1.0
+ },
+ {
+ "x": 154.04961983332186,
+ "y": -24.94923291582714,
+ "z": 1.0
+ },
+ {
+ "x": 154.0488893092857,
+ "y": -25.550599993484663,
+ "z": 1.0
+ },
+ {
+ "x": 154.04828053925553,
+ "y": -26.051739224866502,
+ "z": 1.0
+ },
+ {
+ "x": 154.04779352323146,
+ "y": -26.45265060997152,
+ "z": 1.0
+ },
+ {
+ "x": 154.0470629991953,
+ "y": -27.05401768762905,
+ "z": 1.0
+ },
+ {
+ "x": 154.04657598317118,
+ "y": -27.454929072733492,
+ "z": 1.0
+ },
+ {
+ "x": 154.0460889671471,
+ "y": -27.855840457838504,
+ "z": 1.0
+ },
+ {
+ "x": 154.0453584431109,
+ "y": -28.457207535496586,
+ "z": 1.0
+ },
+ {
+ "x": 154.0447496730808,
+ "y": -28.958346766877852,
+ "z": 1.0
+ },
+ {
+ "x": 154.04426265705666,
+ "y": -29.359258151982296,
+ "z": 1.0
+ },
+ {
+ "x": 154.04377564103254,
+ "y": -29.760169537087876,
+ "z": 1.0
+ },
+ {
+ "x": 154.04316687100243,
+ "y": -30.26130876846857,
+ "z": 1.0
+ },
+ {
+ "x": 154.0426798549783,
+ "y": -30.662220153573582,
+ "z": 1.0
+ },
+ {
+ "x": 154.04219283895424,
+ "y": -31.06313153867916,
+ "z": 1.0
+ },
+ {
+ "x": 154.04146231491808,
+ "y": -31.664498616336104,
+ "z": 1.0
+ },
+ {
+ "x": 154.0408535448879,
+ "y": -32.16563784771737,
+ "z": 1.0
+ },
+ {
+ "x": 154.04036652886384,
+ "y": -32.56654923282238,
+ "z": 1.0
+ },
+ {
+ "x": 154.03987951283972,
+ "y": -32.96746061792796,
+ "z": 1.0
+ },
+ {
+ "x": 154.03914898880356,
+ "y": -33.56882769558491,
+ "z": 1.0
+ },
+ {
+ "x": 154.03866197277944,
+ "y": -33.96973908068992,
+ "z": 1.0
+ },
+ {
+ "x": 154.03793144874328,
+ "y": -34.571106158348,
+ "z": 1.0
+ },
+ {
+ "x": 154.0373226787131,
+ "y": -35.07224538972927,
+ "z": 1.0
+ },
+ {
+ "x": 154.036592154677,
+ "y": -35.673612467386214,
+ "z": 1.0
+ },
+ {
+ "x": 154.03610513865289,
+ "y": -36.074523852491794,
+ "z": 1.0
+ },
+ {
+ "x": 154.03549636862272,
+ "y": -36.57566308387306,
+ "z": 1.0
+ },
+ {
+ "x": 154.03476584458656,
+ "y": -37.177030161530006,
+ "z": 1.0
+ },
+ {
+ "x": 154.03415707455645,
+ "y": -37.67816939291127,
+ "z": 1.0
+ },
+ {
+ "x": 154.03354830452628,
+ "y": -38.1793086242931,
+ "z": 1.0
+ },
+ {
+ "x": 154.03281778049012,
+ "y": -38.78067570195062,
+ "z": 1.0
+ },
+ {
+ "x": 154.03220901046,
+ "y": -39.28181493333131,
+ "z": 1.0
+ },
+ {
+ "x": 154.03147848642385,
+ "y": -39.883182010988826,
+ "z": 1.0
+ },
+ {
+ "x": 154.03099147039973,
+ "y": -40.284093396094406,
+ "z": 1.0
+ },
+ {
+ "x": 154.03038270036961,
+ "y": -40.785232627475104,
+ "z": 1.0
+ },
+ {
+ "x": 154.0298956843455,
+ "y": -41.18614401258068,
+ "z": 1.0
+ },
+ {
+ "x": 154.02940866832137,
+ "y": -41.58705539768569,
+ "z": 1.0
+ },
+ {
+ "x": 154.02867814428527,
+ "y": -42.18842247534264,
+ "z": 1.0
+ },
+ {
+ "x": 154.02794762024905,
+ "y": -42.78978955300072,
+ "z": 1.0
+ },
+ {
+ "x": 154.02733885021894,
+ "y": -43.290928784382,
+ "z": 1.0
+ },
+ {
+ "x": 154.02660832618278,
+ "y": -43.89229586203953,
+ "z": 1.0
+ },
+ {
+ "x": 154.02587780214662,
+ "y": -44.493662939697074,
+ "z": 1.0
+ },
+ {
+ "x": 154.0253907861225,
+ "y": -44.8945743248021,
+ "z": 1.0
+ },
+ {
+ "x": 154.0247820160924,
+ "y": -45.395713556183374,
+ "z": 1.0
+ },
+ {
+ "x": 154.02405149205623,
+ "y": -45.99708063384035,
+ "z": 1.0
+ },
+ {
+ "x": 154.02380798404414,
+ "y": -46.197536326393426,
+ "z": 1.0
+ },
+ {
+ "x": 154.02331963718677,
+ "y": -46.59954325286995,
+ "z": 1.0
+ },
+ {
+ "x": 154.02258711690075,
+ "y": -47.20255364258411,
+ "z": 1.0
+ },
+ {
+ "x": 154.02185459661473,
+ "y": -47.80556403229883,
+ "z": 1.0
+ },
+ {
+ "x": 154.02136624975736,
+ "y": -48.20757095877531,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 18,
+ "heading": [
+ -1.5933732308870605,
+ -2.024123654791085,
+ -1.9853844803775595,
+ -1.920753503210538,
+ -1.8431230927316367,
+ -1.7784250031504312,
+ -1.7074032821837042,
+ -1.6431369583595543,
+ -1.5958870555446687,
+ -1.5724547754977745,
+ -1.572011098444287,
+ -1.5720110984443112,
+ -1.5720110984443483,
+ -1.5720110984443023,
+ -1.5720110984442548,
+ -1.5720110984443099,
+ -1.5720110984443811,
+ -1.5720110984442577,
+ -1.5720110984442572,
+ -1.5720110984443574,
+ -1.572011098444279,
+ -1.572011098444258,
+ -1.5720110984443574,
+ -1.5720110984443294,
+ -1.5720110984442772,
+ -1.5720110984443132,
+ -1.5720110984443139,
+ -1.572011098444295,
+ -1.572011098444295,
+ -1.5720110984443139,
+ -1.5720110984443139,
+ -1.5720110984442786,
+ -1.5720110984443139,
+ -1.5720110984443139,
+ -1.5720110984442957,
+ -1.5720110984443132,
+ -1.5720110984443132,
+ -1.5720110984442786,
+ -1.572011098444295,
+ -1.5720110984443414,
+ -1.572011098444258,
+ -1.5720110984442572,
+ -1.5720110984443574,
+ -1.5720110984443145,
+ -1.5720110984442786,
+ -1.5720110984443287,
+ -1.5720110984442943,
+ -1.5720110984442572,
+ -1.5720110984443145,
+ -1.5720110984442723,
+ -1.5720110984443132,
+ -1.5720110984443287,
+ -1.5720110984442959,
+ -1.5720110984443423,
+ -1.572011098444295,
+ -1.5720110984442959,
+ -1.5720110984442706,
+ -1.5720110984442572,
+ -1.57201109844433,
+ -1.572011098444295,
+ -1.5720110984442706,
+ -1.5720110984443139,
+ -1.5720110984443147,
+ -1.5720110984443132,
+ -1.5720110984443287,
+ -1.5720110984442786,
+ -1.5720110984442572,
+ -1.5720110984443574,
+ -1.57201109844433,
+ -1.5720110984442786,
+ -1.5720110984443132,
+ -1.5720110984443287,
+ -1.5720110984442786,
+ -1.5720110984442786,
+ -1.5720110984443132,
+ -1.572011098444295,
+ -1.572011098444295,
+ -1.5720110984443414,
+ -1.572011098444258,
+ -1.572011098444295,
+ -1.5720110984443287,
+ -1.5720110984442779,
+ -1.572011098444295,
+ -1.5720110984443139,
+ -1.572011098444295,
+ -1.5720110984442786,
+ -1.5720110984443423,
+ -1.5720110984443705,
+ -1.5720110984442879,
+ -1.572011098444269,
+ -1.5720110984442872
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -2.769381159309887,
+ "y": -5.684683350218052
+ },
+ {
+ "x": -5.599984030011456,
+ "y": -12.72443075033899
+ },
+ {
+ "x": -4.768894605532523,
+ "y": -13.066181847069211
+ },
+ {
+ "x": -3.741215671068119,
+ "y": -13.396663255933827
+ },
+ {
+ "x": -2.865808415497213,
+ "y": -13.603651835104706
+ },
+ {
+ "x": -1.7213697922446158,
+ "y": -12.522412816913704
+ },
+ {
+ "x": -0.9096264019217415,
+ "y": -12.552269535728984
+ },
+ {
+ "x": -0.2601807453976335,
+ "y": -10.367420860236445
+ },
+ {
+ "x": -0.015153910340472976,
+ "y": -9.137392323806468
+ },
+ {
+ "x": -0.011005656983797962,
+ "y": -9.059852175302447
+ },
+ {
+ "x": -0.012228507760028151,
+ "y": -10.066502417009104
+ },
+ {
+ "x": -0.014674209312488529,
+ "y": -12.079802900416503
+ },
+ {
+ "x": -0.014674209311920094,
+ "y": -12.07980290040517
+ },
+ {
+ "x": -0.012228507759459717,
+ "y": -10.066502417008998
+ },
+ {
+ "x": -0.0061142538800140755,
+ "y": -5.0332512085101655
+ },
+ {
+ "x": -0.006093011017469507,
+ "y": -5.0157640927522
+ },
+ {
+ "x": -0.012175400602245645,
+ "y": -10.022784627620833
+ },
+ {
+ "x": -0.012175400602245645,
+ "y": -10.022784627625434
+ },
+ {
+ "x": -0.010957860542930575,
+ "y": -9.020506164868554
+ },
+ {
+ "x": -0.013392940662697583,
+ "y": -11.025063090376612
+ },
+ {
+ "x": -0.012175400602245645,
+ "y": -10.022784627619732
+ },
+ {
+ "x": -0.010957860542930575,
+ "y": -9.020506164868518
+ },
+ {
+ "x": -0.013392940663266018,
+ "y": -11.025063090387945
+ },
+ {
+ "x": -0.013392940662697583,
+ "y": -11.025063090393648
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.022784627631136
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.02278462762547
+ },
+ {
+ "x": -0.010957860542362141,
+ "y": -9.020506164862852
+ },
+ {
+ "x": -0.010957860542362141,
+ "y": -9.020506164862852
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.02278462762547
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.02278462762547
+ },
+ {
+ "x": -0.013392940662697583,
+ "y": -11.025063090382332
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.022784627625398
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.022784627625434
+ },
+ {
+ "x": -0.014610480723149522,
+ "y": -12.027341553144915
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.022784627631118
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.022784627631118
+ },
+ {
+ "x": -0.013392940662697583,
+ "y": -11.025063090382332
+ },
+ {
+ "x": -0.010957860542362141,
+ "y": -9.020506164862852
+ },
+ {
+ "x": -0.009740320482478637,
+ "y": -8.018227702105989
+ },
+ {
+ "x": -0.012175400602245645,
+ "y": -10.02278462761982
+ },
+ {
+ "x": -0.012175400602245645,
+ "y": -10.02278462762547
+ },
+ {
+ "x": -0.010957860542930575,
+ "y": -9.020506164868571
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.022784627619785
+ },
+ {
+ "x": -0.013392940662697583,
+ "y": -11.025063090382297
+ },
+ {
+ "x": -0.013392940663266018,
+ "y": -11.02506309039363
+ },
+ {
+ "x": -0.010957860542362141,
+ "y": -9.020506164868571
+ },
+ {
+ "x": -0.012175400602245645,
+ "y": -10.02278462762547
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.022784627619714
+ },
+ {
+ "x": -0.009740320481910203,
+ "y": -8.01822770209455
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.02278462763094
+ },
+ {
+ "x": -0.013392940663266018,
+ "y": -11.025063090393488
+ },
+ {
+ "x": -0.010957860542362141,
+ "y": -9.020506164857096
+ },
+ {
+ "x": -0.009740320482478637,
+ "y": -8.018227702100234
+ },
+ {
+ "x": -0.010957860542362141,
+ "y": -9.020506164862745
+ },
+ {
+ "x": -0.010957860542362141,
+ "y": -9.02050616485706
+ },
+ {
+ "x": -0.009740320481910203,
+ "y": -8.018227702105882
+ },
+ {
+ "x": -0.012175400602245645,
+ "y": -10.02278462762522
+ },
+ {
+ "x": -0.013392940663266018,
+ "y": -11.025063090382119
+ },
+ {
+ "x": -0.010957860542362141,
+ "y": -9.02050616486278
+ },
+ {
+ "x": -0.009740320481910203,
+ "y": -8.018227702105918
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.022784627625256
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.022784627619572
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.02278462763094
+ },
+ {
+ "x": -0.013392940663266018,
+ "y": -11.025063090393488
+ },
+ {
+ "x": -0.013392940662697583,
+ "y": -11.025063090382119
+ },
+ {
+ "x": -0.012175400602245645,
+ "y": -10.022784627625256
+ },
+ {
+ "x": -0.010957860542930575,
+ "y": -9.020506164868465
+ },
+ {
+ "x": -0.013392940663266018,
+ "y": -11.025063090382119
+ },
+ {
+ "x": -0.013392940662697583,
+ "y": -11.025063090382119
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.02278462763094
+ },
+ {
+ "x": -0.013392940663266018,
+ "y": -11.025063090393488
+ },
+ {
+ "x": -0.013392940662697583,
+ "y": -11.025063090382119
+ },
+ {
+ "x": -0.013392940662697583,
+ "y": -11.025063090382048
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.02278462763094
+ },
+ {
+ "x": -0.010957860542362141,
+ "y": -9.02050616486278
+ },
+ {
+ "x": -0.010957860542362141,
+ "y": -9.02050616486271
+ },
+ {
+ "x": -0.009740320482478637,
+ "y": -8.018227702105847
+ },
+ {
+ "x": -0.012175400602245645,
+ "y": -10.022784627619643
+ },
+ {
+ "x": -0.014610480723149522,
+ "y": -12.02734155315035
+ },
+ {
+ "x": -0.013392940663266018,
+ "y": -11.025063090393559
+ },
+ {
+ "x": -0.013392940662697583,
+ "y": -11.025063090388088
+ },
+ {
+ "x": -0.014610480723149522,
+ "y": -12.027341553150777
+ },
+ {
+ "x": -0.01217540060281408,
+ "y": -10.022784627625683
+ },
+ {
+ "x": -0.010957860542362141,
+ "y": -9.020506164862994
+ },
+ {
+ "x": -0.013392940662697583,
+ "y": -11.025063090382474
+ },
+ {
+ "x": -0.009740320482478637,
+ "y": -8.018227702100518
+ },
+ {
+ "x": -0.0073185486945703815,
+ "y": -6.0246261902960185
+ },
+ {
+ "x": -0.012208671433882046,
+ "y": -10.050173161906812
+ },
+ {
+ "x": -0.014650405720431081,
+ "y": -12.060207794288829
+ },
+ {
+ "x": -0.012208671433882046,
+ "y": -10.050173161912
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 154.02136624975736,
+ "y": -48.20757095877531,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 327.0808235050242,
+ "y": -195.15922625059818,
+ "z": 1.0
+ },
+ {
+ "x": 326.5771403058819,
+ "y": -195.1591853215736,
+ "z": 1.0
+ },
+ {
+ "x": 326.0734571067396,
+ "y": -195.15914439254902,
+ "z": 1.0
+ },
+ {
+ "x": 325.6705105474251,
+ "y": -195.1591116493294,
+ "z": 1.0
+ },
+ {
+ "x": 325.0697613586538,
+ "y": -195.1590628327749,
+ "z": 1.0
+ },
+ {
+ "x": 324.56942668828424,
+ "y": -195.15902217584997,
+ "z": 1.0
+ },
+ {
+ "x": 324.1691589519886,
+ "y": -195.15898965031002,
+ "z": 1.0
+ },
+ {
+ "x": 323.56875734754516,
+ "y": -195.1589408620001,
+ "z": 1.0
+ },
+ {
+ "x": 323.1684896112495,
+ "y": -195.15890833646017,
+ "z": 1.0
+ },
+ {
+ "x": 322.7682218749539,
+ "y": -195.15887581092022,
+ "z": 1.0
+ },
+ {
+ "x": 322.2678872045844,
+ "y": -195.15883515399528,
+ "z": 1.0
+ },
+ {
+ "x": 321.6674856001403,
+ "y": -195.1587863656854,
+ "z": 1.0
+ },
+ {
+ "x": 321.0670839956975,
+ "y": -195.15873757737546,
+ "z": 1.0
+ },
+ {
+ "x": 320.466682391254,
+ "y": -195.15868878906554,
+ "z": 1.0
+ },
+ {
+ "x": 320.06641465495835,
+ "y": -195.1586562635256,
+ "z": 1.0
+ },
+ {
+ "x": 319.6661469186627,
+ "y": -195.15862373798566,
+ "z": 1.0
+ },
+ {
+ "x": 319.1658122482932,
+ "y": -195.15858308106073,
+ "z": 1.0
+ },
+ {
+ "x": 318.7655445119976,
+ "y": -195.15855055552078,
+ "z": 1.0
+ },
+ {
+ "x": 318.36527677570194,
+ "y": -195.15851802998083,
+ "z": 1.0
+ },
+ {
+ "x": 317.86494210533243,
+ "y": -195.15847737305592,
+ "z": 1.0
+ },
+ {
+ "x": 317.4646743690368,
+ "y": -195.15844484751597,
+ "z": 1.0
+ },
+ {
+ "x": 316.96433969866723,
+ "y": -195.15840419059103,
+ "z": 1.0
+ },
+ {
+ "x": 316.3639380942238,
+ "y": -195.1583554022811,
+ "z": 1.0
+ },
+ {
+ "x": 315.8636034238543,
+ "y": -195.1583147453562,
+ "z": 1.0
+ },
+ {
+ "x": 315.3632687534847,
+ "y": -195.15827408843126,
+ "z": 1.0
+ },
+ {
+ "x": 314.76286714904126,
+ "y": -195.15822530012133,
+ "z": 1.0
+ },
+ {
+ "x": 314.3625994127456,
+ "y": -195.15819277458138,
+ "z": 1.0
+ },
+ {
+ "x": 313.96233167645,
+ "y": -195.15816024904146,
+ "z": 1.0
+ },
+ {
+ "x": 313.36193007200654,
+ "y": -195.15811146073153,
+ "z": 1.0
+ },
+ {
+ "x": 312.861595401637,
+ "y": -195.1580708038066,
+ "z": 1.0
+ },
+ {
+ "x": 312.36126073126746,
+ "y": -195.15803014688169,
+ "z": 1.0
+ },
+ {
+ "x": 311.76085912682396,
+ "y": -195.15798135857176,
+ "z": 1.0
+ },
+ {
+ "x": 311.16045752238057,
+ "y": -195.15793257026183,
+ "z": 1.0
+ },
+ {
+ "x": 310.660122852011,
+ "y": -195.1578919133369,
+ "z": 1.0
+ },
+ {
+ "x": 310.15978818164143,
+ "y": -195.157851256412,
+ "z": 1.0
+ },
+ {
+ "x": 309.55938657719804,
+ "y": -195.15780246810206,
+ "z": 1.0
+ },
+ {
+ "x": 308.95898497275454,
+ "y": -195.15775367979214,
+ "z": 1.0
+ },
+ {
+ "x": 308.458650302385,
+ "y": -195.15771302286723,
+ "z": 1.0
+ },
+ {
+ "x": 307.8582486979416,
+ "y": -195.1576642345573,
+ "z": 1.0
+ },
+ {
+ "x": 307.45798096164594,
+ "y": -195.15763170901735,
+ "z": 1.0
+ },
+ {
+ "x": 307.0577132253503,
+ "y": -195.1575991834774,
+ "z": 1.0
+ },
+ {
+ "x": 306.6574454890547,
+ "y": -195.15756665793748,
+ "z": 1.0
+ },
+ {
+ "x": 306.05704388461123,
+ "y": -195.15751786962755,
+ "z": 1.0
+ },
+ {
+ "x": 305.4566422801678,
+ "y": -195.15746908131763,
+ "z": 1.0
+ },
+ {
+ "x": 305.0563745438716,
+ "y": -195.1574365557777,
+ "z": 1.0
+ },
+ {
+ "x": 304.5560398735026,
+ "y": -195.15739589885277,
+ "z": 1.0
+ },
+ {
+ "x": 304.0557052031331,
+ "y": -195.15735524192783,
+ "z": 1.0
+ },
+ {
+ "x": 303.55537053276356,
+ "y": -195.1573145850029,
+ "z": 1.0
+ },
+ {
+ "x": 302.95496892832006,
+ "y": -195.157265796693,
+ "z": 1.0
+ },
+ {
+ "x": 302.5547011920244,
+ "y": -195.15723327115305,
+ "z": 1.0
+ },
+ {
+ "x": 302.1544334557288,
+ "y": -195.1572007456131,
+ "z": 1.0
+ },
+ {
+ "x": 301.5540318512854,
+ "y": -195.15715195730317,
+ "z": 1.0
+ },
+ {
+ "x": 301.05369718091583,
+ "y": -195.15711130037826,
+ "z": 1.0
+ },
+ {
+ "x": 300.4532955764724,
+ "y": -195.15706251206834,
+ "z": 1.0
+ },
+ {
+ "x": 300.05302784017675,
+ "y": -195.15702998652839,
+ "z": 1.0
+ },
+ {
+ "x": 299.45262623573325,
+ "y": -195.1569811982185,
+ "z": 1.0
+ },
+ {
+ "x": 298.85222463128986,
+ "y": -195.15693240990856,
+ "z": 1.0
+ },
+ {
+ "x": 298.25182302684635,
+ "y": -195.15688362159864,
+ "z": 1.0
+ },
+ {
+ "x": 297.6514214224024,
+ "y": -195.15683483328874,
+ "z": 1.0
+ },
+ {
+ "x": 297.1510867520334,
+ "y": -195.1567941763638,
+ "z": 1.0
+ },
+ {
+ "x": 296.75081901573776,
+ "y": -195.15676165082385,
+ "z": 1.0
+ },
+ {
+ "x": 296.2504843453682,
+ "y": -195.15672099389892,
+ "z": 1.0
+ },
+ {
+ "x": 295.7501496749987,
+ "y": -195.156680336974,
+ "z": 1.0
+ },
+ {
+ "x": 295.24981500462917,
+ "y": -195.15663968004907,
+ "z": 1.0
+ },
+ {
+ "x": 294.64941340018567,
+ "y": -195.15659089173914,
+ "z": 1.0
+ },
+ {
+ "x": 294.24914566389003,
+ "y": -195.1565583661992,
+ "z": 1.0
+ },
+ {
+ "x": 293.7488109935205,
+ "y": -195.15651770927428,
+ "z": 1.0
+ },
+ {
+ "x": 293.248476323151,
+ "y": -195.15647705234935,
+ "z": 1.0
+ },
+ {
+ "x": 292.8482085868554,
+ "y": -195.1564445268094,
+ "z": 1.0
+ },
+ {
+ "x": 292.2478069824119,
+ "y": -195.15639573849947,
+ "z": 1.0
+ },
+ {
+ "x": 291.6474053779685,
+ "y": -195.15634695018957,
+ "z": 1.0
+ },
+ {
+ "x": 291.047003773525,
+ "y": -195.15629816187965,
+ "z": 1.0
+ },
+ {
+ "x": 290.64673603722935,
+ "y": -195.1562656363397,
+ "z": 1.0
+ },
+ {
+ "x": 290.04633443278595,
+ "y": -195.1562168480298,
+ "z": 1.0
+ },
+ {
+ "x": 289.6460666964903,
+ "y": -195.15618432248985,
+ "z": 1.0
+ },
+ {
+ "x": 289.2457989601947,
+ "y": -195.1561517969499,
+ "z": 1.0
+ },
+ {
+ "x": 288.6453973557512,
+ "y": -195.15610300863997,
+ "z": 1.0
+ },
+ {
+ "x": 288.0449957513078,
+ "y": -195.15605422033008,
+ "z": 1.0
+ },
+ {
+ "x": 287.4445941468643,
+ "y": -195.15600543202015,
+ "z": 1.0
+ },
+ {
+ "x": 286.84419254242084,
+ "y": -195.15595664371023,
+ "z": 1.0
+ },
+ {
+ "x": 286.3438578720513,
+ "y": -195.15591598678532,
+ "z": 1.0
+ },
+ {
+ "x": 285.7434562676079,
+ "y": -195.1558671984754,
+ "z": 1.0
+ },
+ {
+ "x": 285.34318853131225,
+ "y": -195.15583467293544,
+ "z": 1.0
+ },
+ {
+ "x": 284.74278692686875,
+ "y": -195.15578588462554,
+ "z": 1.0
+ },
+ {
+ "x": 284.24245225649923,
+ "y": -195.1557452277006,
+ "z": 1.0
+ },
+ {
+ "x": 283.7421175861297,
+ "y": -195.15570457077567,
+ "z": 1.0
+ },
+ {
+ "x": 283.1417159816862,
+ "y": -195.15565578246574,
+ "z": 1.0
+ },
+ {
+ "x": 282.6413813113167,
+ "y": -195.15561512554083,
+ "z": 1.0
+ },
+ {
+ "x": 282.1410466409472,
+ "y": -195.1555744686159,
+ "z": 1.0
+ },
+ {
+ "x": 281.6407119705776,
+ "y": -195.15553381169096,
+ "z": 1.0
+ },
+ {
+ "x": 281.1403773002075,
+ "y": -195.15549315476605,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 19,
+ "heading": [
+ 3.1415113941303776,
+ 3.141511394130359,
+ 3.141511394130359,
+ 3.1415113941303905,
+ 3.141511394130348,
+ 3.1415113941303248,
+ 3.1415113941303634,
+ 3.1415113941303634,
+ 3.141511394130392,
+ 3.141511394130399,
+ 3.1415113941303634,
+ 3.141511394130389,
+ 3.141511394130387,
+ 3.141511394130363,
+ 3.1415113941303634,
+ 3.141511394130399,
+ 3.141511394130395,
+ 3.1415113941303634,
+ 3.1415113941303634,
+ 3.141511394130395,
+ 3.141511394130395,
+ 3.1415113941303634,
+ 3.1415113941303634,
+ 3.141511394130389,
+ 3.141511394130392,
+ 3.1415113941303634,
+ 3.1415113941303634,
+ 3.141511394130399,
+ 3.141511394130392,
+ 3.1415113941303634,
+ 3.141511394130392,
+ 3.141511394130389,
+ 3.1415113941303634,
+ 3.1415113941303634,
+ 3.141511394130392,
+ 3.141511394130389,
+ 3.1415113941303634,
+ 3.141511394130389,
+ 3.141511394130389,
+ 3.1415113941303634,
+ 3.1415113941303634,
+ 3.141511394130399,
+ 3.141511394130392,
+ 3.1415113941303634,
+ 3.141511394130392,
+ 3.141511394130395,
+ 3.141511394130363,
+ 3.1415113941303634,
+ 3.141511394130389,
+ 3.141511394130392,
+ 3.1415113941303634,
+ 3.1415113941303634,
+ 3.141511394130389,
+ 3.141511394130389,
+ 3.1415113941303634,
+ 3.141511394130392,
+ 3.141511394130387,
+ 3.1415113941303634,
+ 3.141511394130387,
+ 3.141511394130389,
+ 3.141511394130363,
+ 3.1415113941303634,
+ 3.141511394130392,
+ 3.141511394130392,
+ 3.1415113941303634,
+ 3.1415113941303634,
+ 3.141511394130395,
+ 3.141511394130392,
+ 3.1415113941303634,
+ 3.1415113941303634,
+ 3.141511394130387,
+ 3.141511394130387,
+ 3.1415113941303634,
+ 3.141511394130392,
+ 3.141511394130392,
+ 3.1415113941303634,
+ 3.1415113941303634,
+ 3.141511394130387,
+ 3.141511394130387,
+ 3.1415113941303634,
+ 3.141511394130389,
+ 3.141511394130389,
+ 3.1415113941303634,
+ 3.141511394130392,
+ 3.141511394130389,
+ 3.1415113941303634,
+ 3.1415113941303634,
+ 3.141511394130389,
+ 3.141511394130392,
+ 3.1415113941303634,
+ 3.141511394130392
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -5.036831991423014,
+ "y": 0.0004092902457841774
+ },
+ {
+ "x": -10.073663982846028,
+ "y": 0.0008185804915683548
+ },
+ {
+ "x": -9.06629758456802,
+ "y": 0.0007367224421273022
+ },
+ {
+ "x": -10.036957480858177,
+ "y": 0.0008155977411661297
+ },
+ {
+ "x": -11.010838591408856,
+ "y": 0.0008947347942012129
+ },
+ {
+ "x": -9.006024066652003,
+ "y": 0.0007318246488807745
+ },
+ {
+ "x": -10.006693407390799,
+ "y": 0.0008131384987564161
+ },
+ {
+ "x": -10.006693407390799,
+ "y": 0.000813138498472199
+ },
+ {
+ "x": -8.005354725912639,
+ "y": 0.0006505107987209158
+ },
+ {
+ "x": -9.006024066651435,
+ "y": 0.0007318246488807745
+ },
+ {
+ "x": -11.007362748135847,
+ "y": 0.0008944523483478406
+ },
+ {
+ "x": -12.008032088868958,
+ "y": 0.0009757661982234822
+ },
+ {
+ "x": -12.008032088863274,
+ "y": 0.0009757661985076993
+ },
+ {
+ "x": -10.006693407391367,
+ "y": 0.0008131384987564161
+ },
+ {
+ "x": -8.005354725912639,
+ "y": 0.0006505107987209158
+ },
+ {
+ "x": -9.006024066651435,
+ "y": 0.0007318246485965574
+ },
+ {
+ "x": -9.006024066651435,
+ "y": 0.0007318246488807745
+ },
+ {
+ "x": -8.005354725912639,
+ "y": 0.0006505107990051329
+ },
+ {
+ "x": -9.006024066651435,
+ "y": 0.0007318246485965574
+ },
+ {
+ "x": -9.006024066651435,
+ "y": 0.0007318246485965574
+ },
+ {
+ "x": -9.006024066652003,
+ "y": 0.0007318246488807745
+ },
+ {
+ "x": -11.007362748130163,
+ "y": 0.0008944523486320577
+ },
+ {
+ "x": -11.007362748129594,
+ "y": 0.0008944523483478406
+ },
+ {
+ "x": -10.006693407390799,
+ "y": 0.000813138498472199
+ },
+ {
+ "x": -11.007362748130163,
+ "y": 0.0008944523486320577
+ },
+ {
+ "x": -10.006693407390799,
+ "y": 0.0008131384987564161
+ },
+ {
+ "x": -8.005354725912639,
+ "y": 0.0006505107987209158
+ },
+ {
+ "x": -10.006693407390799,
+ "y": 0.000813138498472199
+ },
+ {
+ "x": -11.007362748130163,
+ "y": 0.0008944523486320577
+ },
+ {
+ "x": -10.006693407390799,
+ "y": 0.000813138498472199
+ },
+ {
+ "x": -11.007362748130163,
+ "y": 0.0008944523483478406
+ },
+ {
+ "x": -12.008032088868958,
+ "y": 0.0009757661985076993
+ },
+ {
+ "x": -11.007362748129594,
+ "y": 0.0008944523486320577
+ },
+ {
+ "x": -10.006693407391367,
+ "y": 0.000813138498472199
+ },
+ {
+ "x": -11.007362748129594,
+ "y": 0.0008944523483478406
+ },
+ {
+ "x": -12.008032088868958,
+ "y": 0.0009757661985076993
+ },
+ {
+ "x": -11.007362748130163,
+ "y": 0.0008944523483478406
+ },
+ {
+ "x": -11.007362748129594,
+ "y": 0.0008944523483478406
+ },
+ {
+ "x": -10.006693407390799,
+ "y": 0.0008131384987564161
+ },
+ {
+ "x": -8.005354725912639,
+ "y": 0.0006505107990051329
+ },
+ {
+ "x": -8.005354725912639,
+ "y": 0.0006505107987209158
+ },
+ {
+ "x": -10.006693407390799,
+ "y": 0.000813138498472199
+ },
+ {
+ "x": -12.008032088868958,
+ "y": 0.0009757661985076993
+ },
+ {
+ "x": -10.006693407396483,
+ "y": 0.000813138498472199
+ },
+ {
+ "x": -9.006024066652003,
+ "y": 0.0007318246485965574
+ },
+ {
+ "x": -10.006693407385114,
+ "y": 0.0008131384987564161
+ },
+ {
+ "x": -10.00669340739023,
+ "y": 0.0008131384987564161
+ },
+ {
+ "x": -11.007362748130163,
+ "y": 0.0008944523483478406
+ },
+ {
+ "x": -10.006693407391367,
+ "y": 0.000813138498472199
+ },
+ {
+ "x": -8.005354725912639,
+ "y": 0.0006505107990051329
+ },
+ {
+ "x": -10.00669340739023,
+ "y": 0.0008131384987564161
+ },
+ {
+ "x": -11.007362748129594,
+ "y": 0.0008944523483478406
+ },
+ {
+ "x": -11.007362748130163,
+ "y": 0.0008944523483478406
+ },
+ {
+ "x": -10.006693407390799,
+ "y": 0.0008131384987564161
+ },
+ {
+ "x": -10.006693407391367,
+ "y": 0.000813138498472199
+ },
+ {
+ "x": -12.008032088868958,
+ "y": 0.0009757661982234822
+ },
+ {
+ "x": -12.008032088868958,
+ "y": 0.0009757661985076993
+ },
+ {
+ "x": -12.008032088874643,
+ "y": 0.0009757661982234822
+ },
+ {
+ "x": -11.007362748129594,
+ "y": 0.0008944523483478406
+ },
+ {
+ "x": -9.006024066646319,
+ "y": 0.0007318246488807745
+ },
+ {
+ "x": -9.006024066652003,
+ "y": 0.0007318246488807745
+ },
+ {
+ "x": -10.006693407390799,
+ "y": 0.000813138498472199
+ },
+ {
+ "x": -10.00669340739023,
+ "y": 0.000813138498472199
+ },
+ {
+ "x": -11.007362748130163,
+ "y": 0.0008944523486320577
+ },
+ {
+ "x": -10.006693407391367,
+ "y": 0.0008131384987564161
+ },
+ {
+ "x": -9.006024066651435,
+ "y": 0.0007318246485965574
+ },
+ {
+ "x": -10.00669340739023,
+ "y": 0.000813138498472199
+ },
+ {
+ "x": -9.006024066651435,
+ "y": 0.0007318246488807745
+ },
+ {
+ "x": -10.006693407391367,
+ "y": 0.0008131384987564161
+ },
+ {
+ "x": -12.008032088868958,
+ "y": 0.0009757661982234822
+ },
+ {
+ "x": -12.008032088868958,
+ "y": 0.0009757661982234822
+ },
+ {
+ "x": -10.006693407391367,
+ "y": 0.0008131384987564161
+ },
+ {
+ "x": -10.00669340739023,
+ "y": 0.000813138498472199
+ },
+ {
+ "x": -10.00669340739023,
+ "y": 0.000813138498472199
+ },
+ {
+ "x": -8.005354725912639,
+ "y": 0.0006505107990051329
+ },
+ {
+ "x": -10.006693407391367,
+ "y": 0.0008131384987564161
+ },
+ {
+ "x": -12.008032088868958,
+ "y": 0.0009757661982234822
+ },
+ {
+ "x": -12.008032088868958,
+ "y": 0.0009757661982234822
+ },
+ {
+ "x": -12.008032088869527,
+ "y": 0.0009757661985076993
+ },
+ {
+ "x": -11.007362748130163,
+ "y": 0.0008944523483478406
+ },
+ {
+ "x": -11.007362748129594,
+ "y": 0.0008944523483478406
+ },
+ {
+ "x": -10.00669340739023,
+ "y": 0.0008131384987564161
+ },
+ {
+ "x": -10.006693407391367,
+ "y": 0.000813138498472199
+ },
+ {
+ "x": -11.007362748130163,
+ "y": 0.0008944523483478406
+ },
+ {
+ "x": -10.00669340739023,
+ "y": 0.0008131384987564161
+ },
+ {
+ "x": -11.007362748130163,
+ "y": 0.0008944523486320577
+ },
+ {
+ "x": -11.007362748130163,
+ "y": 0.0008944523483478406
+ },
+ {
+ "x": -10.00669340739023,
+ "y": 0.000813138498472199
+ },
+ {
+ "x": -10.006693407390799,
+ "y": 0.0008131384987564161
+ },
+ {
+ "x": -10.006693407397051,
+ "y": 0.000813138498472199
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 281.1403773002075,
+ "y": -195.15549315476605,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 92.39029670785891,
+ "y": -133.50179489117374,
+ "z": 1.0
+ },
+ {
+ "x": 92.39023562513496,
+ "y": -133.09996841179816,
+ "z": 1.0
+ },
+ {
+ "x": 92.39017454241102,
+ "y": -132.69814193242286,
+ "z": 1.0
+ },
+ {
+ "x": 92.39008291832509,
+ "y": -132.0954022133592,
+ "z": 1.0
+ },
+ {
+ "x": 92.39000656492016,
+ "y": -131.5931191141397,
+ "z": 1.0
+ },
+ {
+ "x": 92.38991494083423,
+ "y": -130.99037939507633,
+ "z": 1.0
+ },
+ {
+ "x": 92.38985385811029,
+ "y": -130.58855291570075,
+ "z": 1.0
+ },
+ {
+ "x": 92.38979277538634,
+ "y": -130.18672643632513,
+ "z": 1.0
+ },
+ {
+ "x": 92.38970115130041,
+ "y": -129.58398671726175,
+ "z": 1.0
+ },
+ {
+ "x": 92.38960952721449,
+ "y": -128.98124699819837,
+ "z": 1.0
+ },
+ {
+ "x": 92.38953317380957,
+ "y": -128.47896389897917,
+ "z": 1.0
+ },
+ {
+ "x": 92.38947209108561,
+ "y": -128.0771374196033,
+ "z": 1.0
+ },
+ {
+ "x": 92.38939573768069,
+ "y": -127.5748543203841,
+ "z": 1.0
+ },
+ {
+ "x": 92.38931938427575,
+ "y": -127.0725712211646,
+ "z": 1.0
+ },
+ {
+ "x": 92.38925830155179,
+ "y": -126.67074474178872,
+ "z": 1.0
+ },
+ {
+ "x": 92.38916667746587,
+ "y": -126.06800502272534,
+ "z": 1.0
+ },
+ {
+ "x": 92.38909032406094,
+ "y": -125.56572192350586,
+ "z": 1.0
+ },
+ {
+ "x": 92.389029241337,
+ "y": -125.16389544413025,
+ "z": 1.0
+ },
+ {
+ "x": 92.38895288793206,
+ "y": -124.66161234491105,
+ "z": 1.0
+ },
+ {
+ "x": 92.38887653452713,
+ "y": -124.15932924569157,
+ "z": 1.0
+ },
+ {
+ "x": 92.38881545180318,
+ "y": -123.7575027663157,
+ "z": 1.0
+ },
+ {
+ "x": 92.38875436907924,
+ "y": -123.35567628694037,
+ "z": 1.0
+ },
+ {
+ "x": 92.38866274499331,
+ "y": -122.7529365678767,
+ "z": 1.0
+ },
+ {
+ "x": 92.38857112090739,
+ "y": -122.15019684881332,
+ "z": 1.0
+ },
+ {
+ "x": 92.38847949682147,
+ "y": -121.54745712975023,
+ "z": 1.0
+ },
+ {
+ "x": 92.38841841409752,
+ "y": -121.14563065037433,
+ "z": 1.0
+ },
+ {
+ "x": 92.38832679001159,
+ "y": -120.54289093131095,
+ "z": 1.0
+ },
+ {
+ "x": 92.38825043660665,
+ "y": -120.04060783209147,
+ "z": 1.0
+ },
+ {
+ "x": 92.38821989524469,
+ "y": -119.83969459240367,
+ "z": 1.0
+ },
+ {
+ "x": 92.38815898411413,
+ "y": -119.43899692261479,
+ "z": 1.0
+ },
+ {
+ "x": 92.38806761741827,
+ "y": -118.83795041793134,
+ "z": 1.0
+ },
+ {
+ "x": 92.38799147850507,
+ "y": -118.33707833069512,
+ "z": 1.0
+ },
+ {
+ "x": 92.3879305673745,
+ "y": -117.93638066090614,
+ "z": 1.0
+ },
+ {
+ "x": 92.3878544284613,
+ "y": -117.43550857366992,
+ "z": 1.0
+ },
+ {
+ "x": 92.3877782895481,
+ "y": -116.93463648643372,
+ "z": 1.0
+ },
+ {
+ "x": 92.38768692285224,
+ "y": -116.33358998175025,
+ "z": 1.0
+ },
+ {
+ "x": 92.38762601172168,
+ "y": -115.93289231196128,
+ "z": 1.0
+ },
+ {
+ "x": 92.3875651005911,
+ "y": -115.53219464217231,
+ "z": 1.0
+ },
+ {
+ "x": 92.38747373389526,
+ "y": -114.93114813748885,
+ "z": 1.0
+ },
+ {
+ "x": 92.38739759498205,
+ "y": -114.43027605025264,
+ "z": 1.0
+ },
+ {
+ "x": 92.3873062282862,
+ "y": -113.82922954556918,
+ "z": 1.0
+ },
+ {
+ "x": 92.38724531715565,
+ "y": -113.42853187578021,
+ "z": 1.0
+ },
+ {
+ "x": 92.38718440602507,
+ "y": -113.02783420599124,
+ "z": 1.0
+ },
+ {
+ "x": 92.38710826711186,
+ "y": -112.52696211875502,
+ "z": 1.0
+ },
+ {
+ "x": 92.38704735598128,
+ "y": -112.12626444896576,
+ "z": 1.0
+ },
+ {
+ "x": 92.38698644485072,
+ "y": -111.72556677917707,
+ "z": 1.0
+ },
+ {
+ "x": 92.38689507815488,
+ "y": -111.12452027449362,
+ "z": 1.0
+ },
+ {
+ "x": 92.38681893924166,
+ "y": -110.6236481872574,
+ "z": 1.0
+ },
+ {
+ "x": 92.3867580281111,
+ "y": -110.22295051746842,
+ "z": 1.0
+ },
+ {
+ "x": 92.38668188919789,
+ "y": -109.72207843023222,
+ "z": 1.0
+ },
+ {
+ "x": 92.38660575028469,
+ "y": -109.221206342996,
+ "z": 1.0
+ },
+ {
+ "x": 92.38651438358883,
+ "y": -108.62015983831225,
+ "z": 1.0
+ },
+ {
+ "x": 92.38643824467563,
+ "y": -108.11928775107631,
+ "z": 1.0
+ },
+ {
+ "x": 92.38636210576243,
+ "y": -107.61841566384011,
+ "z": 1.0
+ },
+ {
+ "x": 92.38630119463186,
+ "y": -107.21771799405114,
+ "z": 1.0
+ },
+ {
+ "x": 92.38620982793601,
+ "y": -106.61667148936768,
+ "z": 1.0
+ },
+ {
+ "x": 92.38611846124016,
+ "y": -106.01562498468421,
+ "z": 1.0
+ },
+ {
+ "x": 92.3860575501096,
+ "y": -105.61492731489524,
+ "z": 1.0
+ },
+ {
+ "x": 92.38596618341374,
+ "y": -105.01388081021179,
+ "z": 1.0
+ },
+ {
+ "x": 92.38589004450054,
+ "y": -104.51300872297557,
+ "z": 1.0
+ },
+ {
+ "x": 92.38582913336998,
+ "y": -104.1123110531866,
+ "z": 1.0
+ },
+ {
+ "x": 92.38575299445677,
+ "y": -103.61143896595038,
+ "z": 1.0
+ },
+ {
+ "x": 92.3856920833262,
+ "y": -103.21074129616142,
+ "z": 1.0
+ },
+ {
+ "x": 92.38563117219563,
+ "y": -102.81004362637215,
+ "z": 1.0
+ },
+ {
+ "x": 92.38557026106506,
+ "y": -102.40934595658346,
+ "z": 1.0
+ },
+ {
+ "x": 92.38547889436921,
+ "y": -101.80829945190001,
+ "z": 1.0
+ },
+ {
+ "x": 92.38538752767336,
+ "y": -101.20725294721655,
+ "z": 1.0
+ },
+ {
+ "x": 92.3853266165428,
+ "y": -100.80655527742758,
+ "z": 1.0
+ },
+ {
+ "x": 92.38525047762958,
+ "y": -100.30568319019136,
+ "z": 1.0
+ },
+ {
+ "x": 92.38517433871638,
+ "y": -99.80481110295514,
+ "z": 1.0
+ },
+ {
+ "x": 92.38511342758582,
+ "y": -99.40411343316617,
+ "z": 1.0
+ },
+ {
+ "x": 92.3850372886726,
+ "y": -98.90324134592996,
+ "z": 1.0
+ },
+ {
+ "x": 92.38494592197677,
+ "y": -98.3021948412465,
+ "z": 1.0
+ },
+ {
+ "x": 92.38485455528091,
+ "y": -97.70114833656304,
+ "z": 1.0
+ },
+ {
+ "x": 92.38477841636771,
+ "y": -97.20027624932682,
+ "z": 1.0
+ },
+ {
+ "x": 92.3847022774545,
+ "y": -96.6994041620906,
+ "z": 1.0
+ },
+ {
+ "x": 92.38464136632393,
+ "y": -96.29870649230163,
+ "z": 1.0
+ },
+ {
+ "x": 92.38454999962808,
+ "y": -95.6976599876179,
+ "z": 1.0
+ },
+ {
+ "x": 92.38447386071488,
+ "y": -95.19678790038196,
+ "z": 1.0
+ },
+ {
+ "x": 92.38438249401904,
+ "y": -94.59574139569851,
+ "z": 1.0
+ },
+ {
+ "x": 92.38430635510582,
+ "y": -94.0948693084623,
+ "z": 1.0
+ },
+ {
+ "x": 92.38421498840998,
+ "y": -93.49382280377883,
+ "z": 1.0
+ },
+ {
+ "x": 92.38413884949676,
+ "y": -92.99295071654261,
+ "z": 1.0
+ },
+ {
+ "x": 92.38406271058355,
+ "y": -92.4920786293064,
+ "z": 1.0
+ },
+ {
+ "x": 92.38400179945297,
+ "y": -92.09138095951742,
+ "z": 1.0
+ },
+ {
+ "x": 92.38391043275713,
+ "y": -91.49033445483397,
+ "z": 1.0
+ },
+ {
+ "x": 92.38383429384392,
+ "y": -90.98946236759747,
+ "z": 1.0
+ },
+ {
+ "x": 92.38374292714808,
+ "y": -90.38841586291429,
+ "z": 1.0
+ },
+ {
+ "x": 92.38366678823488,
+ "y": -89.88754377567808,
+ "z": 1.0
+ },
+ {
+ "x": 92.38357542153902,
+ "y": -89.28649727099462,
+ "z": 1.0
+ },
+ {
+ "x": 92.38349928262582,
+ "y": -88.7856251837584,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 20,
+ "heading": [
+ 1.5709483394834882,
+ 1.570948339483483,
+ 1.5709483394834831,
+ 1.57094833948349,
+ 1.5709483394834927,
+ 1.5709483394834927,
+ 1.57094833948349,
+ 1.570948339483483,
+ 1.57094833948349,
+ 1.5709483394834947,
+ 1.5709483394834798,
+ 1.5709483394834869,
+ 1.5709483394834869,
+ 1.570948339483476,
+ 1.5709483394835027,
+ 1.5709483394835042,
+ 1.5709483394834798,
+ 1.5709483394834711,
+ 1.5709483394834869,
+ 1.57094833948349,
+ 1.5709483394834869,
+ 1.570948339483483,
+ 1.57094833948349,
+ 1.5709483394834947,
+ 1.570948339483483,
+ 1.57094833948349,
+ 1.5709483394835042,
+ 1.5709483394834927,
+ 1.570948339483478,
+ 1.5709483394834656,
+ 1.5709483394834889,
+ 1.5709483394834876,
+ 1.5709483394834904,
+ 1.5709483394834904,
+ 1.5709483394834747,
+ 1.5709483394834876,
+ 1.5709483394834889,
+ 1.5709483394834922,
+ 1.5709483394834889,
+ 1.5709483394834876,
+ 1.5709483394834876,
+ 1.5709483394834747,
+ 1.5709483394834922,
+ 1.5709483394835062,
+ 1.570948339483506,
+ 1.5709483394834922,
+ 1.5709483394834747,
+ 1.5709483394834876,
+ 1.5709483394834904,
+ 1.5709483394834904,
+ 1.5709483394834889,
+ 1.5709483394834876,
+ 1.5709483394834876,
+ 1.5709483394834747,
+ 1.5709483394834904,
+ 1.5709483394834889,
+ 1.5709483394834864,
+ 1.5709483394834889,
+ 1.5709483394834889,
+ 1.5709483394834876,
+ 1.5709483394834747,
+ 1.5709483394834904,
+ 1.5709483394834904,
+ 1.5709483394834922,
+ 1.57094833948351,
+ 1.5709483394834889,
+ 1.5709483394834864,
+ 1.5709483394834889,
+ 1.5709483394834904,
+ 1.5709483394834889,
+ 1.5709483394834747,
+ 1.5709483394834904,
+ 1.5709483394834876,
+ 1.5709483394834864,
+ 1.5709483394834876,
+ 1.5709483394834889,
+ 1.5709483394834904,
+ 1.5709483394834887,
+ 1.5709483394834876,
+ 1.5709483394834747,
+ 1.5709483394834876,
+ 1.5709483394834876,
+ 1.5709483394834876,
+ 1.5709483394835029,
+ 1.5709483394835062,
+ 1.5709483394834889,
+ 1.5709483394834876,
+ 1.5709483394834876,
+ 1.5709483394834747,
+ 1.5709483394834876,
+ 1.5709483394834876
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -0.0006108272394556025,
+ "y": 4.018264793755861
+ },
+ {
+ "x": -0.001221654478911205,
+ "y": 8.03652958750888
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984389653
+ },
+ {
+ "x": -0.0016797749086094882,
+ "y": 11.05022818283146
+ },
+ {
+ "x": -0.0016797749086094882,
+ "y": 11.050228182828619
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984389653
+ },
+ {
+ "x": -0.001221654478911205,
+ "y": 8.036529587512007
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984389938
+ },
+ {
+ "x": -0.001832481718508916,
+ "y": 12.054794381267584
+ },
+ {
+ "x": -0.0016797749084673796,
+ "y": 11.050228182825776
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.041095785950688
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.041095785950688
+ },
+ {
+ "x": -0.001527068098567952,
+ "y": 10.045661984387095
+ },
+ {
+ "x": -0.0013743612889527412,
+ "y": 9.041095785953814
+ },
+ {
+ "x": -0.001527068098852169,
+ "y": 10.045661984392495
+ },
+ {
+ "x": -0.0016797749084673796,
+ "y": 11.050228182828619
+ },
+ {
+ "x": -0.0013743612886685241,
+ "y": 9.041095785950972
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.04109578594813
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984386811
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.04109578595353
+ },
+ {
+ "x": -0.001221654478911205,
+ "y": 8.036529587512007
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984389938
+ },
+ {
+ "x": -0.001832481718508916,
+ "y": 12.054794381270426
+ },
+ {
+ "x": -0.0018324817183668074,
+ "y": 12.054794381264742
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984389938
+ },
+ {
+ "x": -0.001527068098852169,
+ "y": 10.04566198439278
+ },
+ {
+ "x": -0.0016797749086094882,
+ "y": 11.050228182828619
+ },
+ {
+ "x": -0.0010689476690117772,
+ "y": 7.031963389072757
+ },
+ {
+ "x": -0.0009145249252640042,
+ "y": 6.016109094766762
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744723357
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.015697570252001
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.015697570252001
+ },
+ {
+ "x": -0.001522778264018143,
+ "y": 10.01744174472421
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.001218222611356623,
+ "y": 8.013953395779367
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.001522778264018143,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.001218222611356623,
+ "y": 8.013953395779367
+ },
+ {
+ "x": -0.0013705004379005459,
+ "y": 9.01569757025186
+ },
+ {
+ "x": -0.0013705004379005459,
+ "y": 9.015697570254844
+ },
+ {
+ "x": -0.001218222611356623,
+ "y": 8.01395339577951
+ },
+ {
+ "x": -0.001522778264018143,
+ "y": 10.017441744721367
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.015697570252001
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.01569757025186
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.01744174472421
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919199685
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196843
+ },
+ {
+ "x": -0.001522778264018143,
+ "y": 10.017441744721367
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.015697570251717
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0018273339169638803,
+ "y": 12.020930093669335
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.01744174472421
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.0013705004376163288,
+ "y": 9.01569757025186
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.01569757025186
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.01569757025186
+ },
+ {
+ "x": -0.001218222611356623,
+ "y": 8.013953395782352
+ },
+ {
+ "x": -0.0012182226114987316,
+ "y": 8.01395339577951
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744721367
+ },
+ {
+ "x": -0.0018273339169638803,
+ "y": 12.020930093669193
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.01569757025186
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0013705004376163288,
+ "y": 9.01569757025186
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.01569757025186
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.0018273339169638803,
+ "y": 12.020930093669193
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196843
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.0013705004377584373,
+ "y": 9.01569757025186
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744727051
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.0016750560904199574,
+ "y": 11.019185919193859
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196843
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196843
+ },
+ {
+ "x": -0.0015227782643023602,
+ "y": 10.01744174472421
+ },
+ {
+ "x": -0.0013705004379005459,
+ "y": 9.01569757025186
+ },
+ {
+ "x": -0.0015227782641602516,
+ "y": 10.017441744724351
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919199543
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196843
+ },
+ {
+ "x": -0.0016750560904199574,
+ "y": 11.019185919193859
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196701
+ },
+ {
+ "x": -0.001675056090562066,
+ "y": 11.019185919196843
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 92.38349928262582,
+ "y": -88.7856251837584,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 88.40609795687595,
+ "y": -237.44900651847365,
+ "z": 1.0
+ },
+ {
+ "x": 88.40617401207619,
+ "y": -237.94932790846892,
+ "z": 1.0
+ },
+ {
+ "x": 88.40625006727643,
+ "y": -238.4496492984642,
+ "z": 1.0
+ },
+ {
+ "x": 88.40631091143662,
+ "y": -238.84990641046042,
+ "z": 1.0
+ },
+ {
+ "x": 88.40638696663686,
+ "y": -239.3502278004557,
+ "z": 1.0
+ },
+ {
+ "x": 88.40647823287715,
+ "y": -239.95061346845003,
+ "z": 1.0
+ },
+ {
+ "x": 88.40656949911744,
+ "y": -240.55099913644437,
+ "z": 1.0
+ },
+ {
+ "x": 88.40663034327763,
+ "y": -240.9512562484406,
+ "z": 1.0
+ },
+ {
+ "x": 88.40669118743781,
+ "y": -241.35151336043683,
+ "z": 1.0
+ },
+ {
+ "x": 88.4067824536781,
+ "y": -241.9518990284309,
+ "z": 1.0
+ },
+ {
+ "x": 88.40685850887834,
+ "y": -242.45222041842644,
+ "z": 1.0
+ },
+ {
+ "x": 88.40691935303853,
+ "y": -242.85247753042268,
+ "z": 1.0
+ },
+ {
+ "x": 88.40698019719873,
+ "y": -243.2527346424186,
+ "z": 1.0
+ },
+ {
+ "x": 88.40705625239896,
+ "y": -243.75305603241418,
+ "z": 1.0
+ },
+ {
+ "x": 88.40714751863925,
+ "y": -244.3534417004085,
+ "z": 1.0
+ },
+ {
+ "x": 88.40723878487954,
+ "y": -244.95382736840284,
+ "z": 1.0
+ },
+ {
+ "x": 88.40729962903973,
+ "y": -245.35408448039905,
+ "z": 1.0
+ },
+ {
+ "x": 88.40737568423997,
+ "y": -245.85440587039434,
+ "z": 1.0
+ },
+ {
+ "x": 88.4074517394402,
+ "y": -246.3547272603896,
+ "z": 1.0
+ },
+ {
+ "x": 88.4075125836004,
+ "y": -246.75498437238585,
+ "z": 1.0
+ },
+ {
+ "x": 88.40758863880063,
+ "y": -247.2553057623811,
+ "z": 1.0
+ },
+ {
+ "x": 88.40766469400087,
+ "y": -247.7556271523764,
+ "z": 1.0
+ },
+ {
+ "x": 88.40775596024116,
+ "y": -248.35601282037072,
+ "z": 1.0
+ },
+ {
+ "x": 88.4078320154414,
+ "y": -248.85633421036601,
+ "z": 1.0
+ },
+ {
+ "x": 88.40789285960159,
+ "y": -249.25659132236223,
+ "z": 1.0
+ },
+ {
+ "x": 88.40795370376178,
+ "y": -249.65684843435847,
+ "z": 1.0
+ },
+ {
+ "x": 88.40804497000208,
+ "y": -250.2572341023525,
+ "z": 1.0
+ },
+ {
+ "x": 88.40813623624236,
+ "y": -250.85761977034713,
+ "z": 1.0
+ },
+ {
+ "x": 88.40822750248265,
+ "y": -251.45800543834147,
+ "z": 1.0
+ },
+ {
+ "x": 88.40831876872294,
+ "y": -252.0583911063358,
+ "z": 1.0
+ },
+ {
+ "x": 88.40837961288312,
+ "y": -252.45864821833175,
+ "z": 1.0
+ },
+ {
+ "x": 88.40845566808336,
+ "y": -252.958969608327,
+ "z": 1.0
+ },
+ {
+ "x": 88.4085317232836,
+ "y": -253.4592909983223,
+ "z": 1.0
+ },
+ {
+ "x": 88.40862298952389,
+ "y": -254.05967666631662,
+ "z": 1.0
+ },
+ {
+ "x": 88.40868383368408,
+ "y": -254.45993377831314,
+ "z": 1.0
+ },
+ {
+ "x": 88.40874467784427,
+ "y": -254.86019089030938,
+ "z": 1.0
+ },
+ {
+ "x": 88.40880552200446,
+ "y": -255.2604480023056,
+ "z": 1.0
+ },
+ {
+ "x": 88.40889678824475,
+ "y": -255.8608336702999,
+ "z": 1.0
+ },
+ {
+ "x": 88.40897284344499,
+ "y": -256.36115506029523,
+ "z": 1.0
+ },
+ {
+ "x": 88.40904889864522,
+ "y": -256.86147645029047,
+ "z": 1.0
+ },
+ {
+ "x": 88.40912495384546,
+ "y": -257.36179784028576,
+ "z": 1.0
+ },
+ {
+ "x": 88.40921622008575,
+ "y": -257.9621835082798,
+ "z": 1.0
+ },
+ {
+ "x": 88.40929227528599,
+ "y": -258.4625048982751,
+ "z": 1.0
+ },
+ {
+ "x": 88.40936833048623,
+ "y": -258.96282628827066,
+ "z": 1.0
+ },
+ {
+ "x": 88.4094595967265,
+ "y": -259.563211956265,
+ "z": 1.0
+ },
+ {
+ "x": 88.40953565192675,
+ "y": -260.0635333462603,
+ "z": 1.0
+ },
+ {
+ "x": 88.40959649608695,
+ "y": -260.4637904582562,
+ "z": 1.0
+ },
+ {
+ "x": 88.40967255128719,
+ "y": -260.9641118482515,
+ "z": 1.0
+ },
+ {
+ "x": 88.40976381752746,
+ "y": -261.5644975162461,
+ "z": 1.0
+ },
+ {
+ "x": 88.40982466168767,
+ "y": -261.9647546282421,
+ "z": 1.0
+ },
+ {
+ "x": 88.40990071688789,
+ "y": -262.4650760182376,
+ "z": 1.0
+ },
+ {
+ "x": 88.4099919831282,
+ "y": -263.0654616862317,
+ "z": 1.0
+ },
+ {
+ "x": 88.41005282728837,
+ "y": -263.4657187982282,
+ "z": 1.0
+ },
+ {
+ "x": 88.41011367144857,
+ "y": -263.8659759102241,
+ "z": 1.0
+ },
+ {
+ "x": 88.41018972664881,
+ "y": -264.3662973002197,
+ "z": 1.0
+ },
+ {
+ "x": 88.410250570809,
+ "y": -264.7665544122159,
+ "z": 1.0
+ },
+ {
+ "x": 88.41031141496919,
+ "y": -265.1668115242121,
+ "z": 1.0
+ },
+ {
+ "x": 88.41037225912937,
+ "y": -265.5670686362084,
+ "z": 1.0
+ },
+ {
+ "x": 88.41044831432961,
+ "y": -266.0673900262036,
+ "z": 1.0
+ },
+ {
+ "x": 88.4105091584898,
+ "y": -266.4676471381999,
+ "z": 1.0
+ },
+ {
+ "x": 88.41060042473009,
+ "y": -267.0680328061942,
+ "z": 1.0
+ },
+ {
+ "x": 88.41067647993033,
+ "y": -267.5683541961895,
+ "z": 1.0
+ },
+ {
+ "x": 88.41075253513057,
+ "y": -268.0686755861847,
+ "z": 1.0
+ },
+ {
+ "x": 88.41081337929077,
+ "y": -268.4689326981807,
+ "z": 1.0
+ },
+ {
+ "x": 88.41090464553105,
+ "y": -269.0693183661753,
+ "z": 1.0
+ },
+ {
+ "x": 88.41096548969124,
+ "y": -269.4695754781715,
+ "z": 1.0
+ },
+ {
+ "x": 88.41102633385142,
+ "y": -269.86983259016773,
+ "z": 1.0
+ },
+ {
+ "x": 88.41111760009171,
+ "y": -270.4702182581621,
+ "z": 1.0
+ },
+ {
+ "x": 88.41119365529195,
+ "y": -270.97053964815734,
+ "z": 1.0
+ },
+ {
+ "x": 88.41126971049219,
+ "y": -271.47086103815263,
+ "z": 1.0
+ },
+ {
+ "x": 88.4113305546524,
+ "y": -271.87111815014856,
+ "z": 1.0
+ },
+ {
+ "x": 88.41140660985262,
+ "y": -272.37143954014414,
+ "z": 1.0
+ },
+ {
+ "x": 88.41148266505286,
+ "y": -272.8717609301394,
+ "z": 1.0
+ },
+ {
+ "x": 88.4115587202531,
+ "y": -273.37208232013495,
+ "z": 1.0
+ },
+ {
+ "x": 88.41163477545334,
+ "y": -273.8724037101299,
+ "z": 1.0
+ },
+ {
+ "x": 88.41171083065358,
+ "y": -274.37272510012514,
+ "z": 1.0
+ },
+ {
+ "x": 88.41178688585381,
+ "y": -274.8730464901204,
+ "z": 1.0
+ },
+ {
+ "x": 88.411847730014,
+ "y": -275.27330360211687,
+ "z": 1.0
+ },
+ {
+ "x": 88.4119085741742,
+ "y": -275.6735607141125,
+ "z": 1.0
+ },
+ {
+ "x": 88.41199984041448,
+ "y": -276.27394638210706,
+ "z": 1.0
+ },
+ {
+ "x": 88.41207589561472,
+ "y": -276.7742677721023,
+ "z": 1.0
+ },
+ {
+ "x": 88.41215195081497,
+ "y": -277.27458916209724,
+ "z": 1.0
+ },
+ {
+ "x": 88.41221279497516,
+ "y": -277.67484627409374,
+ "z": 1.0
+ },
+ {
+ "x": 88.41227363913535,
+ "y": -278.07510338608967,
+ "z": 1.0
+ },
+ {
+ "x": 88.41236490537563,
+ "y": -278.6754890540845,
+ "z": 1.0
+ },
+ {
+ "x": 88.41244096057588,
+ "y": -279.1758104440792,
+ "z": 1.0
+ },
+ {
+ "x": 88.41251701577612,
+ "y": -279.67613183407445,
+ "z": 1.0
+ },
+ {
+ "x": 88.41260828201641,
+ "y": -280.2765175020687,
+ "z": 1.0
+ },
+ {
+ "x": 88.4126691261766,
+ "y": -280.6767746140652,
+ "z": 1.0
+ },
+ {
+ "x": 88.41276039241689,
+ "y": -281.2771602820592,
+ "z": 1.0
+ },
+ {
+ "x": 88.41282123657707,
+ "y": -281.6774173940557,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 21,
+ "heading": [
+ -1.5706443141063056,
+ -1.5706443141063047,
+ -1.5706443141063047,
+ -1.570644314106308,
+ -1.570644314106308,
+ -1.5706443141063022,
+ -1.5706443141063,
+ -1.5706443141063047,
+ -1.5706443141063118,
+ -1.5706443141063047,
+ -1.5706443141063022,
+ -1.570644314106308,
+ -1.570644314106294,
+ -1.570644314106308,
+ -1.570644314106315,
+ -1.5706443141063,
+ -1.5706443141063047,
+ -1.570644314106308,
+ -1.5706443141063047,
+ -1.570644314106308,
+ -1.570644314106308,
+ -1.5706443141063047,
+ -1.5706443141063022,
+ -1.5706443141063022,
+ -1.570644314106308,
+ -1.5706443141063118,
+ -1.5706443141062905,
+ -1.5706443141063,
+ -1.570644314106312,
+ -1.5706443141063,
+ -1.5706443141063047,
+ -1.5706443141063078,
+ -1.5706443141063047,
+ -1.5706443141063022,
+ -1.570644314106305,
+ -1.570644314106312,
+ -1.5706443141063118,
+ -1.5706443141063047,
+ -1.5706443141063022,
+ -1.5706443141063047,
+ -1.5706443141063047,
+ -1.5706443141063022,
+ -1.5706443141063022,
+ -1.570644314106305,
+ -1.570644314106315,
+ -1.570644314106315,
+ -1.570644314106292,
+ -1.570644314106292,
+ -1.570644314106315,
+ -1.570644314106305,
+ -1.570644314106308,
+ -1.5706443141063022,
+ -1.570644314106305,
+ -1.5706443141063118,
+ -1.5706443141062922,
+ -1.570644314106308,
+ -1.5706443141063118,
+ -1.570644314106312,
+ -1.570644314106308,
+ -1.570644314106308,
+ -1.570644314106305,
+ -1.5706443141063022,
+ -1.5706443141063047,
+ -1.570644314106292,
+ -1.570644314106305,
+ -1.570644314106319,
+ -1.5706443141063118,
+ -1.570644314106305,
+ -1.5706443141063022,
+ -1.5706443141063047,
+ -1.570644314106292,
+ -1.570644314106308,
+ -1.570644314106319,
+ -1.570644314106305,
+ -1.5706443141063047,
+ -1.5706443141063047,
+ -1.5706443141063047,
+ -1.570644314106308,
+ -1.570644314106294,
+ -1.5706443141063047,
+ -1.570644314106315,
+ -1.5706443141062905,
+ -1.5706443141062922,
+ -1.5706443141063118,
+ -1.570644314106319,
+ -1.5706443141063022,
+ -1.5706443141062905,
+ -1.5706443141063022,
+ -1.570644314106305,
+ -1.5706443141063047,
+ -1.5706443141063047
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": 0.0007605520023901136,
+ "y": -5.003213899952641
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799905566
+ },
+ {
+ "x": 0.0013689936042737827,
+ "y": -9.005785019915038
+ },
+ {
+ "x": 0.0013689936042737827,
+ "y": -9.005785019915038
+ },
+ {
+ "x": 0.0016732144052866715,
+ "y": -11.007070579896094
+ },
+ {
+ "x": 0.001825324805793116,
+ "y": -12.007713359886623
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799905566
+ },
+ {
+ "x": 0.0012168832037673383,
+ "y": -8.00514223992451
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799903008
+ },
+ {
+ "x": 0.0016732144052866715,
+ "y": -11.007070579896094
+ },
+ {
+ "x": 0.0013689936042737827,
+ "y": -9.00578501991788
+ },
+ {
+ "x": 0.0012168832039094468,
+ "y": -8.005142239921668
+ },
+ {
+ "x": 0.0013689936042737827,
+ "y": -9.005785019915038
+ },
+ {
+ "x": 0.001673214405144563,
+ "y": -11.007070579898937
+ },
+ {
+ "x": 0.001825324805793116,
+ "y": -12.007713359886623
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799905566
+ },
+ {
+ "x": 0.0013689936042737827,
+ "y": -9.005785019915038
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799905566
+ },
+ {
+ "x": 0.0013689936042737827,
+ "y": -9.005785019915038
+ },
+ {
+ "x": 0.0013689936042737827,
+ "y": -9.005785019915038
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799905566
+ },
+ {
+ "x": 0.0016732144052866715,
+ "y": -11.007070579896094
+ },
+ {
+ "x": 0.0016732144052866715,
+ "y": -11.007070579896094
+ },
+ {
+ "x": 0.0013689936042737827,
+ "y": -9.005785019915038
+ },
+ {
+ "x": 0.0012168832037673383,
+ "y": -8.00514223992451
+ },
+ {
+ "x": 0.0015211040049223357,
+ "y": -10.006427799902724
+ },
+ {
+ "x": 0.001825324805793116,
+ "y": -12.007713359886623
+ },
+ {
+ "x": 0.0018253248056510074,
+ "y": -12.007713359889749
+ },
+ {
+ "x": 0.001825324805793116,
+ "y": -12.007713359886623
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799902724
+ },
+ {
+ "x": 0.0013689936042737827,
+ "y": -9.005785019912196
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799905566
+ },
+ {
+ "x": 0.0016732144052866715,
+ "y": -11.007070579896094
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799908408
+ },
+ {
+ "x": 0.0012168832037673383,
+ "y": -8.005142239927636
+ },
+ {
+ "x": 0.0012168832037673383,
+ "y": -8.00514223992451
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799905282
+ },
+ {
+ "x": 0.0016732144052866715,
+ "y": -11.007070579896379
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799905566
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799905282
+ },
+ {
+ "x": 0.0016732144052866715,
+ "y": -11.007070579893252
+ },
+ {
+ "x": 0.0016732144052866715,
+ "y": -11.007070579893252
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799908693
+ },
+ {
+ "x": 0.001673214405144563,
+ "y": -11.007070579898937
+ },
+ {
+ "x": 0.001673214405144563,
+ "y": -11.007070579896094
+ },
+ {
+ "x": 0.0013689936044158912,
+ "y": -9.005785019912196
+ },
+ {
+ "x": 0.0013689936044158912,
+ "y": -9.005785019912196
+ },
+ {
+ "x": 0.001673214405144563,
+ "y": -11.007070579898937
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.00642779990585
+ },
+ {
+ "x": 0.0013689936042737827,
+ "y": -9.005785019915038
+ },
+ {
+ "x": 0.0016732144052866715,
+ "y": -11.007070579896094
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.00642779990585
+ },
+ {
+ "x": 0.0012168832037673383,
+ "y": -8.005142239924226
+ },
+ {
+ "x": 0.0013689936044158912,
+ "y": -9.005785019915038
+ },
+ {
+ "x": 0.0013689936042737827,
+ "y": -9.00578501991788
+ },
+ {
+ "x": 0.0012168832037673383,
+ "y": -8.005142239924226
+ },
+ {
+ "x": 0.0012168832037673383,
+ "y": -8.005142239924794
+ },
+ {
+ "x": 0.0013689936042737827,
+ "y": -9.005785019915038
+ },
+ {
+ "x": 0.0013689936042737827,
+ "y": -9.005785019915038
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.00642779990585
+ },
+ {
+ "x": 0.0016732144052866715,
+ "y": -11.007070579896094
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799905282
+ },
+ {
+ "x": 0.0013689936044158912,
+ "y": -9.005785019912196
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.00642779990585
+ },
+ {
+ "x": 0.0015211040046381186,
+ "y": -10.006427799908124
+ },
+ {
+ "x": 0.0012168832037673383,
+ "y": -8.005142239924226
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.00642779990585
+ },
+ {
+ "x": 0.0016732144052866715,
+ "y": -11.007070579896094
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799905282
+ },
+ {
+ "x": 0.0013689936044158912,
+ "y": -9.005785019912196
+ },
+ {
+ "x": 0.0013689936042737827,
+ "y": -9.005785019915038
+ },
+ {
+ "x": 0.0015211040046381186,
+ "y": -10.006427799908124
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799908124
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799905282
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799901871
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799904714
+ },
+ {
+ "x": 0.0013689936042737827,
+ "y": -9.005785019917312
+ },
+ {
+ "x": 0.0012168832039094468,
+ "y": -8.005142239921383
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799901871
+ },
+ {
+ "x": 0.001673214405144563,
+ "y": -11.0070705798978
+ },
+ {
+ "x": 0.0015211040049223357,
+ "y": -10.006427799901871
+ },
+ {
+ "x": 0.0013689936044158912,
+ "y": -9.00578501991447
+ },
+ {
+ "x": 0.0012168832037673383,
+ "y": -8.005142239924226
+ },
+ {
+ "x": 0.0015211040046381186,
+ "y": -10.006427799907556
+ },
+ {
+ "x": 0.0016732144052866715,
+ "y": -11.007070579895526
+ },
+ {
+ "x": 0.0015211040049223357,
+ "y": -10.006427799899598
+ },
+ {
+ "x": 0.0016732144052866715,
+ "y": -11.007070579894958
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799907556
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799904714
+ },
+ {
+ "x": 0.0015211040047802271,
+ "y": -10.006427799904714
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 88.41282123657707,
+ "y": -281.6774173940557,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 92.38011802850588,
+ "y": -66.54238927212418,
+ "z": 1.0
+ },
+ {
+ "x": 92.38004167510093,
+ "y": -66.0401061729047,
+ "z": 1.0
+ },
+ {
+ "x": 92.37996532169599,
+ "y": -65.53782307368493,
+ "z": 1.0
+ },
+ {
+ "x": 92.37988896829106,
+ "y": -65.03553997446542,
+ "z": 1.0
+ },
+ {
+ "x": 92.37982788556711,
+ "y": -64.63371349509012,
+ "z": 1.0
+ },
+ {
+ "x": 92.37975153216217,
+ "y": -64.13143039587035,
+ "z": 1.0
+ },
+ {
+ "x": 92.37967517875724,
+ "y": -63.629147296650856,
+ "z": 1.0
+ },
+ {
+ "x": 92.3796140960333,
+ "y": -63.22732081727527,
+ "z": 1.0
+ },
+ {
+ "x": 92.37953774262836,
+ "y": -62.72503771805577,
+ "z": 1.0
+ },
+ {
+ "x": 92.37946138922342,
+ "y": -62.22275461883628,
+ "z": 1.0
+ },
+ {
+ "x": 92.3793697651375,
+ "y": -61.62001489977288,
+ "z": 1.0
+ },
+ {
+ "x": 92.37930868241357,
+ "y": -61.21818842039758,
+ "z": 1.0
+ },
+ {
+ "x": 92.37923232900862,
+ "y": -60.7159053211778,
+ "z": 1.0
+ },
+ {
+ "x": 92.37917124628467,
+ "y": -60.314078841802214,
+ "z": 1.0
+ },
+ {
+ "x": 92.37911016356072,
+ "y": -59.912252362426614,
+ "z": 1.0
+ },
+ {
+ "x": 92.3790185394748,
+ "y": -59.30951264336322,
+ "z": 1.0
+ },
+ {
+ "x": 92.37892691538889,
+ "y": -58.70677292430012,
+ "z": 1.0
+ },
+ {
+ "x": 92.37883529130296,
+ "y": -58.10403320523645,
+ "z": 1.0
+ },
+ {
+ "x": 92.37877420857902,
+ "y": -57.70220672586085,
+ "z": 1.0
+ },
+ {
+ "x": 92.37869785517408,
+ "y": -57.19992362664164,
+ "z": 1.0
+ },
+ {
+ "x": 92.37862150176916,
+ "y": -56.697640527421896,
+ "z": 1.0
+ },
+ {
+ "x": 92.37854514836424,
+ "y": -56.19535742820269,
+ "z": 1.0
+ },
+ {
+ "x": 92.3784687949593,
+ "y": -55.69307432898321,
+ "z": 1.0
+ },
+ {
+ "x": 92.37839244155437,
+ "y": -55.19079122976345,
+ "z": 1.0
+ },
+ {
+ "x": 92.37833135883041,
+ "y": -54.78896475038785,
+ "z": 1.0
+ },
+ {
+ "x": 92.37825500542549,
+ "y": -54.28668165116865,
+ "z": 1.0
+ },
+ {
+ "x": 92.37819392270154,
+ "y": -53.884855171793056,
+ "z": 1.0
+ },
+ {
+ "x": 92.37813283997758,
+ "y": -53.48302869241718,
+ "z": 1.0
+ },
+ {
+ "x": 92.37805648657265,
+ "y": -52.980745593197696,
+ "z": 1.0
+ },
+ {
+ "x": 92.37798013316771,
+ "y": -52.4784624939782,
+ "z": 1.0
+ },
+ {
+ "x": 92.37791905044377,
+ "y": -52.07663601460261,
+ "z": 1.0
+ },
+ {
+ "x": 92.37784269703883,
+ "y": -51.57435291538313,
+ "z": 1.0
+ },
+ {
+ "x": 92.37778161431488,
+ "y": -51.17252643600753,
+ "z": 1.0
+ },
+ {
+ "x": 92.37770526090996,
+ "y": -50.670243336788324,
+ "z": 1.0
+ },
+ {
+ "x": 92.37761363682404,
+ "y": -50.06750361772494,
+ "z": 1.0
+ },
+ {
+ "x": 92.37753728341909,
+ "y": -49.56522051850489,
+ "z": 1.0
+ },
+ {
+ "x": 92.37746093001417,
+ "y": -49.06293741928596,
+ "z": 1.0
+ },
+ {
+ "x": 92.37736930592824,
+ "y": -48.46019770022228,
+ "z": 1.0
+ },
+ {
+ "x": 92.37729295252328,
+ "y": -47.95791460100283,
+ "z": 1.0
+ },
+ {
+ "x": 92.37723186979933,
+ "y": -47.55608812162724,
+ "z": 1.0
+ },
+ {
+ "x": 92.3771555163944,
+ "y": -47.053805022407744,
+ "z": 1.0
+ },
+ {
+ "x": 92.37709443367045,
+ "y": -46.651978543032435,
+ "z": 1.0
+ },
+ {
+ "x": 92.37701808026551,
+ "y": -46.14969544381266,
+ "z": 1.0
+ },
+ {
+ "x": 92.37701808026551,
+ "y": -46.14969544381266,
+ "z": 1.0
+ },
+ {
+ "x": 92.37695708299036,
+ "y": -45.74843108063273,
+ "z": 1.0
+ },
+ {
+ "x": 92.37686558707763,
+ "y": -45.146534535862855,
+ "z": 1.0
+ },
+ {
+ "x": 92.37680458980248,
+ "y": -44.745270172682936,
+ "z": 1.0
+ },
+ {
+ "x": 92.37672834320854,
+ "y": -44.243689718708055,
+ "z": 1.0
+ },
+ {
+ "x": 92.3766520966146,
+ "y": -43.74210926473344,
+ "z": 1.0
+ },
+ {
+ "x": 92.37657585002066,
+ "y": -43.24052881075826,
+ "z": 1.0
+ },
+ {
+ "x": 92.37649960342672,
+ "y": -42.738948356783666,
+ "z": 1.0
+ },
+ {
+ "x": 92.376408107514,
+ "y": -42.137051812013794,
+ "z": 1.0
+ },
+ {
+ "x": 92.37631661160125,
+ "y": -41.53515526724364,
+ "z": 1.0
+ },
+ {
+ "x": 92.37624036500732,
+ "y": -41.03357481326876,
+ "z": 1.0
+ },
+ {
+ "x": 92.37616411841337,
+ "y": -40.53199435929386,
+ "z": 1.0
+ },
+ {
+ "x": 92.37607262250064,
+ "y": -39.93009781452399,
+ "z": 1.0
+ },
+ {
+ "x": 92.3760116252255,
+ "y": -39.52883345134437,
+ "z": 1.0
+ },
+ {
+ "x": 92.37592012931276,
+ "y": -38.92693690657421,
+ "z": 1.0
+ },
+ {
+ "x": 92.37584388271883,
+ "y": -38.42535645259932,
+ "z": 1.0
+ },
+ {
+ "x": 92.37576763612489,
+ "y": -37.923775998624706,
+ "z": 1.0
+ },
+ {
+ "x": 92.37569138953094,
+ "y": -37.42219554464954,
+ "z": 1.0
+ },
+ {
+ "x": 92.37561514293701,
+ "y": -36.92061509067493,
+ "z": 1.0
+ },
+ {
+ "x": 92.37552364702428,
+ "y": -36.31871854590506,
+ "z": 1.0
+ },
+ {
+ "x": 92.37543215111154,
+ "y": -35.716822001134915,
+ "z": 1.0
+ },
+ {
+ "x": 92.37534065519881,
+ "y": -35.11492545636504,
+ "z": 1.0
+ },
+ {
+ "x": 92.37526440860488,
+ "y": -34.61334500239043,
+ "z": 1.0
+ },
+ {
+ "x": 92.37517291269215,
+ "y": -34.01144845762056,
+ "z": 1.0
+ },
+ {
+ "x": 92.375111915417,
+ "y": -33.61018409444037,
+ "z": 1.0
+ },
+ {
+ "x": 92.37502041950427,
+ "y": -33.00828754967078,
+ "z": 1.0
+ },
+ {
+ "x": 92.37492892359154,
+ "y": -32.40639100490091,
+ "z": 1.0
+ },
+ {
+ "x": 92.37486792631638,
+ "y": -32.00512664172072,
+ "z": 1.0
+ },
+ {
+ "x": 92.37477643040366,
+ "y": -31.403230096951127,
+ "z": 1.0
+ },
+ {
+ "x": 92.37468493449093,
+ "y": -30.801333552181255,
+ "z": 1.0
+ },
+ {
+ "x": 92.37462393721577,
+ "y": -30.400069189001343,
+ "z": 1.0
+ },
+ {
+ "x": 92.37453244130305,
+ "y": -29.798172644231478,
+ "z": 1.0
+ },
+ {
+ "x": 92.3744561947091,
+ "y": -29.296592190256302,
+ "z": 1.0
+ },
+ {
+ "x": 92.37436469879637,
+ "y": -28.694695645486433,
+ "z": 1.0
+ },
+ {
+ "x": 92.37428845220244,
+ "y": -28.193115191511822,
+ "z": 1.0
+ },
+ {
+ "x": 92.37421220560849,
+ "y": -27.691534737536653,
+ "z": 1.0
+ },
+ {
+ "x": 92.37412070969576,
+ "y": -27.089638192766785,
+ "z": 1.0
+ },
+ {
+ "x": 92.3740597124206,
+ "y": -26.688373829586872,
+ "z": 1.0
+ },
+ {
+ "x": 92.37398346582667,
+ "y": -26.18679337561198,
+ "z": 1.0
+ },
+ {
+ "x": 92.37389196991394,
+ "y": -25.584896830842396,
+ "z": 1.0
+ },
+ {
+ "x": 92.37383097263879,
+ "y": -25.1836324676622,
+ "z": 1.0
+ },
+ {
+ "x": 92.37376997536363,
+ "y": -24.782368104482284,
+ "z": 1.0
+ },
+ {
+ "x": 92.37370897808847,
+ "y": -24.381103741302372,
+ "z": 1.0
+ },
+ {
+ "x": 92.37364798081333,
+ "y": -23.97983937812274,
+ "z": 1.0
+ },
+ {
+ "x": 92.37355648490059,
+ "y": -23.377942833352595,
+ "z": 1.0
+ },
+ {
+ "x": 92.37349548762545,
+ "y": -22.976678470172963,
+ "z": 1.0
+ },
+ {
+ "x": 92.3734192410315,
+ "y": -22.475098016197787,
+ "z": 1.0
+ },
+ {
+ "x": 92.37334299443756,
+ "y": -21.9735175622229,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 22,
+ "heading": [
+ 1.5709483394834889,
+ 1.5709483394835184,
+ 1.5709483394835042,
+ 1.57094833948349,
+ 1.5709483394834869,
+ 1.5709483394834869,
+ 1.57094833948349,
+ 1.5709483394834869,
+ 1.5709483394834869,
+ 1.57094833948349,
+ 1.5709483394834927,
+ 1.570948339483476,
+ 1.5709483394834869,
+ 1.5709483394835027,
+ 1.570948339483483,
+ 1.57094833948349,
+ 1.570948339483483,
+ 1.570948339483483,
+ 1.57094833948349,
+ 1.5709483394834869,
+ 1.5709483394834758,
+ 1.5709483394834618,
+ 1.570948339483476,
+ 1.57094833948349,
+ 1.5709483394835027,
+ 1.5709483394834869,
+ 1.5709483394834711,
+ 1.5709483394835007,
+ 1.5709483394835027,
+ 1.57094833948349,
+ 1.5709483394834869,
+ 1.5709483394834869,
+ 1.5709483394834869,
+ 1.5709483394834711,
+ 1.5709483394834798,
+ 1.5709483394835053,
+ 1.57094833948349,
+ 1.5709483394834798,
+ 1.5709483394835182,
+ 1.5709483394835184,
+ 1.5709483394834869,
+ 1.5709483394834869,
+ 1.5709483394834869,
+ 1.57094833948349,
+ 1.5709483394834967,
+ 1.5709483394834896,
+ 1.5709483394834896,
+ 1.570948339483485,
+ 1.5709483394834753,
+ 1.5709483394834896,
+ 1.5709483394834896,
+ 1.5709483394834804,
+ 1.5709483394834967,
+ 1.5709483394834933,
+ 1.5709483394834896,
+ 1.5709483394834933,
+ 1.5709483394834753,
+ 1.5709483394834896,
+ 1.5709483394834933,
+ 1.5709483394834753,
+ 1.5709483394834896,
+ 1.5709483394834896,
+ 1.5709483394834804,
+ 1.5709483394834967,
+ 1.5709483394834967,
+ 1.5709483394834804,
+ 1.5709483394834804,
+ 1.5709483394834896,
+ 1.5709483394834896,
+ 1.570948339483485,
+ 1.5709483394834896,
+ 1.5709483394834896,
+ 1.570948339483485,
+ 1.5709483394834896,
+ 1.5709483394834896,
+ 1.5709483394834933,
+ 1.5709483394834933,
+ 1.5709483394834804,
+ 1.5709483394834896,
+ 1.5709483394834933,
+ 1.5709483394834896,
+ 1.570948339483485,
+ 1.5709483394834804,
+ 1.5709483394834896,
+ 1.5709483394834967,
+ 1.5709483394834967,
+ 1.570948339483479,
+ 1.5709483394834896,
+ 1.5709483394834896,
+ 1.570948339483485,
+ 1.5709483394834896
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -0.0007635340494971388,
+ "y": 5.022830992194827
+ },
+ {
+ "x": -0.001527068098852169,
+ "y": 10.045661984392495
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.04566198439278
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.04109578594813
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.041095785950688
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984392638
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.04109578595083
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.04109578595083
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984389938
+ },
+ {
+ "x": -0.0016797749086094882,
+ "y": 11.050228182828903
+ },
+ {
+ "x": -0.001527068098567952,
+ "y": 10.045661984386953
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.04109578595083
+ },
+ {
+ "x": -0.0013743612889527412,
+ "y": 9.041095785953672
+ },
+ {
+ "x": -0.001221654478911205,
+ "y": 8.036529587511865
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984389938
+ },
+ {
+ "x": -0.0018324817183668074,
+ "y": 12.054794381264955
+ },
+ {
+ "x": -0.0018324817183668074,
+ "y": 12.054794381267726
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984392709
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.041095785948059
+ },
+ {
+ "x": -0.001527068098567952,
+ "y": 10.045661984389511
+ },
+ {
+ "x": -0.0015270680984258433,
+ "y": 10.045661984389511
+ },
+ {
+ "x": -0.001527068098567952,
+ "y": 10.045661984386882
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984392424
+ },
+ {
+ "x": -0.0013743612889527412,
+ "y": 9.041095785953601
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.041095785947988
+ },
+ {
+ "x": -0.0013743612886685241,
+ "y": 9.041095785947917
+ },
+ {
+ "x": -0.0012216544790533135,
+ "y": 8.036529587514707
+ },
+ {
+ "x": -0.0013743612889527412,
+ "y": 9.041095785953601
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984389795
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.04109578595083
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.041095785950688
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.04109578595083
+ },
+ {
+ "x": -0.0013743612886685241,
+ "y": 9.041095785948059
+ },
+ {
+ "x": -0.0016797749084673796,
+ "y": 11.050228182825919
+ },
+ {
+ "x": -0.0016797749087515967,
+ "y": 11.050228182834374
+ },
+ {
+ "x": -0.0015270680987100604,
+ "y": 10.045661984389795
+ },
+ {
+ "x": -0.0016797749084673796,
+ "y": 11.05022818282606
+ },
+ {
+ "x": -0.0016797749088937053,
+ "y": 11.050228182831319
+ },
+ {
+ "x": -0.0013743612890948498,
+ "y": 9.041095785950404
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.04109578595083
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.041095785948059
+ },
+ {
+ "x": -0.0013743612888106327,
+ "y": 9.04109578595083
+ },
+ {
+ "x": -0.0007635340493550302,
+ "y": 5.02283099219774
+ },
+ {
+ "x": -0.000609972751561827,
+ "y": 4.012643631799335
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079498054
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079497912
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171548007
+ },
+ {
+ "x": -0.0015249318786914046,
+ "y": 10.031609079494928
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079497912
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.0016774250666173884,
+ "y": 11.03476998744469
+ },
+ {
+ "x": -0.0018299182546854809,
+ "y": 12.03793089540028
+ },
+ {
+ "x": -0.001677425066759497,
+ "y": 11.034769987450375
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.001677425066759497,
+ "y": 11.034769987447675
+ },
+ {
+ "x": -0.0015249318786914046,
+ "y": 10.031609079494928
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.001677425066759497,
+ "y": 11.034769987450517
+ },
+ {
+ "x": -0.0015249318786914046,
+ "y": 10.03160907949507
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.0016774250666173884,
+ "y": 11.034769987444832
+ },
+ {
+ "x": -0.0018299182546854809,
+ "y": 12.037930895400137
+ },
+ {
+ "x": -0.0018299182546854809,
+ "y": 12.037930895400137
+ },
+ {
+ "x": -0.0016774250666173884,
+ "y": 11.034769987444832
+ },
+ {
+ "x": -0.0016774250666173884,
+ "y": 11.034769987444832
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079500612
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.0018299182545433723,
+ "y": 12.037930895394595
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079500612
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949784
+ },
+ {
+ "x": -0.0018299182545433723,
+ "y": 12.037930895394666
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949784
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.001677425066759497,
+ "y": 11.03476998745041
+ },
+ {
+ "x": -0.001677425066759497,
+ "y": 11.034769987450446
+ },
+ {
+ "x": -0.0016774250666173884,
+ "y": 11.034769987444797
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079497805
+ },
+ {
+ "x": -0.001677425066759497,
+ "y": 11.034769987450375
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079497805
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171548042
+ },
+ {
+ "x": -0.0016774250666173884,
+ "y": 11.034769987444761
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079497805
+ },
+ {
+ "x": -0.001219945503123654,
+ "y": 8.025287263601122
+ },
+ {
+ "x": -0.001219945503123654,
+ "y": 8.02528726359828
+ },
+ {
+ "x": -0.0012199455029815454,
+ "y": 8.025287263595438
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.03160907949777
+ },
+ {
+ "x": -0.0013724386909075292,
+ "y": 9.028448171548078
+ },
+ {
+ "x": -0.0015249318788335131,
+ "y": 10.031609079500647
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 92.37334299443756,
+ "y": -21.9735175622229,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 88.37158893513006,
+ "y": -10.434921050719414,
+ "z": 1.0
+ },
+ {
+ "x": 88.37165014933649,
+ "y": -10.837612474316,
+ "z": 1.0
+ },
+ {
+ "x": 88.37171136354294,
+ "y": -11.240303897912584,
+ "z": 1.0
+ },
+ {
+ "x": 88.3717723608181,
+ "y": -11.641568261092115,
+ "z": 1.0
+ },
+ {
+ "x": 88.37186385673083,
+ "y": -12.243464805862263,
+ "z": 1.0
+ },
+ {
+ "x": 88.37194010332476,
+ "y": -12.745045259837152,
+ "z": 1.0
+ },
+ {
+ "x": 88.37200110059992,
+ "y": -13.14630962301706,
+ "z": 1.0
+ },
+ {
+ "x": 88.37209259651264,
+ "y": -13.748206167786929,
+ "z": 1.0
+ },
+ {
+ "x": 88.3721535937878,
+ "y": -14.149470530966838,
+ "z": 1.0
+ },
+ {
+ "x": 88.37221459106296,
+ "y": -14.550734894146467,
+ "z": 1.0
+ },
+ {
+ "x": 88.37227558833811,
+ "y": -14.951999257326378,
+ "z": 1.0
+ },
+ {
+ "x": 88.37235183493205,
+ "y": -15.453579711301547,
+ "z": 1.0
+ },
+ {
+ "x": 88.37242808152598,
+ "y": -15.955160165276435,
+ "z": 1.0
+ },
+ {
+ "x": 88.37251957743872,
+ "y": -16.557056710046012,
+ "z": 1.0
+ },
+ {
+ "x": 88.37261107335145,
+ "y": -17.158953254815877,
+ "z": 1.0
+ },
+ {
+ "x": 88.37268731994538,
+ "y": -17.660533708791046,
+ "z": 1.0
+ },
+ {
+ "x": 88.37274831722054,
+ "y": -18.06179807197096,
+ "z": 1.0
+ },
+ {
+ "x": 88.37282456381448,
+ "y": -18.563378525945843,
+ "z": 1.0
+ },
+ {
+ "x": 88.37290081040842,
+ "y": -19.06495897992073,
+ "z": 1.0
+ },
+ {
+ "x": 88.37296180768358,
+ "y": -19.46622334310036,
+ "z": 1.0
+ },
+ {
+ "x": 88.37302280495872,
+ "y": -19.867487706280553,
+ "z": 1.0
+ },
+ {
+ "x": 88.37309905155267,
+ "y": -20.36906816025516,
+ "z": 1.0
+ },
+ {
+ "x": 88.3731752981466,
+ "y": -20.870648614230337,
+ "z": 1.0
+ },
+ {
+ "x": 88.37326679405933,
+ "y": -21.472545159000205,
+ "z": 1.0
+ },
+ {
+ "x": 88.37335828997207,
+ "y": -22.074441703769793,
+ "z": 1.0
+ },
+ {
+ "x": 88.37343453656601,
+ "y": -22.576022157744966,
+ "z": 1.0
+ },
+ {
+ "x": 88.37352603247874,
+ "y": -23.177918702514834,
+ "z": 1.0
+ },
+ {
+ "x": 88.37361752839146,
+ "y": -23.779815247284706,
+ "z": 1.0
+ },
+ {
+ "x": 88.37369377498541,
+ "y": -24.281395701259314,
+ "z": 1.0
+ },
+ {
+ "x": 88.37377002157935,
+ "y": -24.782976155234483,
+ "z": 1.0
+ },
+ {
+ "x": 88.3738462681733,
+ "y": -25.284556609209098,
+ "z": 1.0
+ },
+ {
+ "x": 88.37392251476723,
+ "y": -25.786137063184267,
+ "z": 1.0
+ },
+ {
+ "x": 88.37398351204239,
+ "y": -26.18740142636418,
+ "z": 1.0
+ },
+ {
+ "x": 88.37405975863632,
+ "y": -26.68898188033907,
+ "z": 1.0
+ },
+ {
+ "x": 88.37412075591148,
+ "y": -27.090246243518983,
+ "z": 1.0
+ },
+ {
+ "x": 88.3742122518242,
+ "y": -27.69214278828885,
+ "z": 1.0
+ },
+ {
+ "x": 88.37428849841815,
+ "y": -28.19372324226346,
+ "z": 1.0
+ },
+ {
+ "x": 88.37437999433088,
+ "y": -28.79561978703333,
+ "z": 1.0
+ },
+ {
+ "x": 88.37444099160604,
+ "y": -29.196884150213243,
+ "z": 1.0
+ },
+ {
+ "x": 88.37450198888118,
+ "y": -29.598148513393436,
+ "z": 1.0
+ },
+ {
+ "x": 88.3745934847939,
+ "y": -30.200045058163305,
+ "z": 1.0
+ },
+ {
+ "x": 88.37465448206906,
+ "y": -30.601309421343217,
+ "z": 1.0
+ },
+ {
+ "x": 88.37473072866301,
+ "y": -31.10288987531783,
+ "z": 1.0
+ },
+ {
+ "x": 88.37482222457574,
+ "y": -31.704786420087693,
+ "z": 1.0
+ },
+ {
+ "x": 88.3748832218509,
+ "y": -32.106050783267605,
+ "z": 1.0
+ },
+ {
+ "x": 88.37497471776362,
+ "y": -32.70794732803748,
+ "z": 1.0
+ },
+ {
+ "x": 88.37506621367635,
+ "y": -33.30984387280735,
+ "z": 1.0
+ },
+ {
+ "x": 88.3751272109515,
+ "y": -33.711108235987254,
+ "z": 1.0
+ },
+ {
+ "x": 88.37520345754544,
+ "y": -34.212688689962434,
+ "z": 1.0
+ },
+ {
+ "x": 88.37529495345817,
+ "y": -34.814585234732306,
+ "z": 1.0
+ },
+ {
+ "x": 88.37535595073332,
+ "y": -35.21584959791221,
+ "z": 1.0
+ },
+ {
+ "x": 88.37541694800848,
+ "y": -35.617113961091846,
+ "z": 1.0
+ },
+ {
+ "x": 88.3755084439212,
+ "y": -36.21901050586199,
+ "z": 1.0
+ },
+ {
+ "x": 88.37558469051514,
+ "y": -36.72059095983688,
+ "z": 1.0
+ },
+ {
+ "x": 88.3756456877903,
+ "y": -37.1218553230168,
+ "z": 1.0
+ },
+ {
+ "x": 88.37572193438423,
+ "y": -37.623435776991684,
+ "z": 1.0
+ },
+ {
+ "x": 88.37578293165939,
+ "y": -38.0247001401716,
+ "z": 1.0
+ },
+ {
+ "x": 88.37587442757211,
+ "y": -38.626596684941475,
+ "z": 1.0
+ },
+ {
+ "x": 88.37596592348486,
+ "y": -39.22849322971105,
+ "z": 1.0
+ },
+ {
+ "x": 88.37602692076,
+ "y": -39.62975759289125,
+ "z": 1.0
+ },
+ {
+ "x": 88.37611841667272,
+ "y": -40.231654137661124,
+ "z": 1.0
+ },
+ {
+ "x": 88.37620991258547,
+ "y": -40.83355068243071,
+ "z": 1.0
+ },
+ {
+ "x": 88.37627090986061,
+ "y": -41.2348150456109,
+ "z": 1.0
+ },
+ {
+ "x": 88.37634715645456,
+ "y": -41.73639549958551,
+ "z": 1.0
+ },
+ {
+ "x": 88.37640815372971,
+ "y": -42.13765986276542,
+ "z": 1.0
+ },
+ {
+ "x": 88.37648440032365,
+ "y": -42.6392403167406,
+ "z": 1.0
+ },
+ {
+ "x": 88.37657589623637,
+ "y": -43.24113686151047,
+ "z": 1.0
+ },
+ {
+ "x": 88.37663689351153,
+ "y": -43.642401224690374,
+ "z": 1.0
+ },
+ {
+ "x": 88.37672838942426,
+ "y": -44.244297769460246,
+ "z": 1.0
+ },
+ {
+ "x": 88.37678938669941,
+ "y": -44.64556213263988,
+ "z": 1.0
+ },
+ {
+ "x": 88.37686563329335,
+ "y": -45.14714258661505,
+ "z": 1.0
+ },
+ {
+ "x": 88.3769418798873,
+ "y": -45.64872304058966,
+ "z": 1.0
+ },
+ {
+ "x": 88.37701812648123,
+ "y": -46.15030349456484,
+ "z": 1.0
+ },
+ {
+ "x": 88.37707931482646,
+ "y": -46.55282479273959,
+ "z": 1.0
+ },
+ {
+ "x": 88.377155800258,
+ "y": -47.05597641545811,
+ "z": 1.0
+ },
+ {
+ "x": 88.37721698860321,
+ "y": -47.45849771363293,
+ "z": 1.0
+ },
+ {
+ "x": 88.37727817694844,
+ "y": -47.86101901180774,
+ "z": 1.0
+ },
+ {
+ "x": 88.37736995946628,
+ "y": -48.46480095906996,
+ "z": 1.0
+ },
+ {
+ "x": 88.37746869965171,
+ "y": -48.97708841609315,
+ "z": 1.0
+ },
+ {
+ "x": 88.40185746732712,
+ "y": -49.71365309840904,
+ "z": 1.0
+ },
+ {
+ "x": 88.44585825376632,
+ "y": -50.204616797586624,
+ "z": 1.0
+ },
+ {
+ "x": 88.55335565655965,
+ "y": -50.936077505571575,
+ "z": 1.0
+ },
+ {
+ "x": 88.71019196677977,
+ "y": -51.6585678626945,
+ "z": 1.0
+ },
+ {
+ "x": 88.91564576217036,
+ "y": -52.36876451225841,
+ "z": 1.0
+ },
+ {
+ "x": 89.12332049993944,
+ "y": -52.94884511931964,
+ "z": 1.0
+ },
+ {
+ "x": 89.41529380090776,
+ "y": -53.628069768414065,
+ "z": 1.0
+ },
+ {
+ "x": 89.63524235353502,
+ "y": -54.069212211922306,
+ "z": 1.0
+ },
+ {
+ "x": 89.87491205951238,
+ "y": -54.499960149336395,
+ "z": 1.0
+ },
+ {
+ "x": 90.27056376603892,
+ "y": -55.124948450891765,
+ "z": 1.0
+ },
+ {
+ "x": 90.63189274832027,
+ "y": -55.62401717672893,
+ "z": 1.0
+ },
+ {
+ "x": 90.94090186406459,
+ "y": -56.00807087257196,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 23,
+ "heading": [
+ -1.5260968829987904,
+ -1.5706443141063537,
+ -1.5706443141063184,
+ -1.5706443141062898,
+ -1.5706443141063038,
+ -1.5706443141063127,
+ -1.5706443141063084,
+ -1.5706443141063038,
+ -1.5706443141063038,
+ -1.5706443141062967,
+ -1.5706443141062967,
+ -1.5706443141063084,
+ -1.570644314106318,
+ -1.5706443141062998,
+ -1.5706443141062967,
+ -1.5706443141063127,
+ -1.5706443141063084,
+ -1.5706443141063084,
+ -1.5706443141063038,
+ -1.5706443141062927,
+ -1.5706443141063142,
+ -1.5706443141063084,
+ -1.5706443141063038,
+ -1.5706443141063127,
+ -1.5706443141062967,
+ -1.5706443141062998,
+ -1.5706443141063127,
+ -1.5706443141063084,
+ -1.5706443141062998,
+ -1.5706443141063038,
+ -1.5706443141063038,
+ -1.5706443141063038,
+ -1.5706443141063084,
+ -1.5706443141063084,
+ -1.5706443141063084,
+ -1.5706443141063038,
+ -1.5706443141062998,
+ -1.5706443141062998,
+ -1.5706443141063038,
+ -1.5706443141063144,
+ -1.570644314106318,
+ -1.5706443141063038,
+ -1.5706443141062927,
+ -1.5706443141062998,
+ -1.5706443141063038,
+ -1.5706443141063038,
+ -1.5706443141063084,
+ -1.5706443141063038,
+ -1.5706443141063084,
+ -1.5706443141063127,
+ -1.5706443141063038,
+ -1.5706443141062967,
+ -1.5706443141063038,
+ -1.5706443141063127,
+ -1.5706443141063084,
+ -1.5706443141063084,
+ -1.5706443141063084,
+ -1.5706443141063038,
+ -1.5706443141062967,
+ -1.5706443141063038,
+ -1.570644314106318,
+ -1.5706443141062967,
+ -1.5706443141063038,
+ -1.5706443141063084,
+ -1.5706443141062927,
+ -1.5706443141063084,
+ -1.5706443141063127,
+ -1.5706443141063038,
+ -1.5706443141063038,
+ -1.5706443141063036,
+ -1.5706443141063084,
+ -1.5706443141063038,
+ -1.5706443141063038,
+ -1.5706443141063058,
+ -1.570644314106291,
+ -1.5706443141063064,
+ -1.5706443141063084,
+ -1.570644314106291,
+ -1.5706256181447933,
+ -1.5511908270386274,
+ -1.5151406473842302,
+ -1.4474924853507034,
+ -1.3909568256260652,
+ -1.3231140246525257,
+ -1.2609247954819858,
+ -1.1930819948683404,
+ -1.1421999017184103,
+ -1.0856642517891186,
+ -1.0290687118318207,
+ -0.978121757078758,
+ -0.9215254427402406
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": 0.0006121420642557496,
+ "y": -4.026914235965862
+ },
+ {
+ "x": 0.0012242841287957162,
+ "y": -8.053828471931705
+ },
+ {
+ "x": 0.0012221148161017936,
+ "y": -8.039557867761147
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.031609079496793
+ },
+ {
+ "x": 0.0016774250666173884,
+ "y": -11.034769987450375
+ },
+ {
+ "x": 0.0013724386909075292,
+ "y": -9.028448171547971
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949777
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949777
+ },
+ {
+ "x": 0.001219945503123654,
+ "y": -8.025287263595384
+ },
+ {
+ "x": 0.001219945503123654,
+ "y": -8.025287263595402
+ },
+ {
+ "x": 0.0013724386909075292,
+ "y": -9.028448171550796
+ },
+ {
+ "x": 0.0015249318786914046,
+ "y": -10.031609079500576
+ },
+ {
+ "x": 0.001677425066759497,
+ "y": -11.034769987444655
+ },
+ {
+ "x": 0.0018299182546854809,
+ "y": -12.037930895394418
+ },
+ {
+ "x": 0.0016774250666173884,
+ "y": -11.034769987450339
+ },
+ {
+ "x": 0.0013724386909075292,
+ "y": -9.028448171550814
+ },
+ {
+ "x": 0.0013724386909075292,
+ "y": -9.028448171547971
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.031609079497699
+ },
+ {
+ "x": 0.0013724386910496378,
+ "y": -9.028448171545165
+ },
+ {
+ "x": 0.0012199455029815454,
+ "y": -8.025287263598244
+ },
+ {
+ "x": 0.0013724386909075292,
+ "y": -9.028448171548007
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949784
+ },
+ {
+ "x": 0.0016774250666173884,
+ "y": -11.034769987450446
+ },
+ {
+ "x": 0.0018299182546854809,
+ "y": -12.03793089539456
+ },
+ {
+ "x": 0.001677425066759497,
+ "y": -11.034769987447604
+ },
+ {
+ "x": 0.0016774250666173884,
+ "y": -11.03476998745041
+ },
+ {
+ "x": 0.0018299182545433723,
+ "y": -12.037930895397402
+ },
+ {
+ "x": 0.001677425066759497,
+ "y": -11.034769987444797
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949777
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949784
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949784
+ },
+ {
+ "x": 0.0013724386909075292,
+ "y": -9.028448171550814
+ },
+ {
+ "x": 0.0013724386909075292,
+ "y": -9.028448171548042
+ },
+ {
+ "x": 0.0013724386909075292,
+ "y": -9.028448171548042
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.031609079497805
+ },
+ {
+ "x": 0.001677425066759497,
+ "y": -11.034769987444761
+ },
+ {
+ "x": 0.001677425066759497,
+ "y": -11.034769987444797
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949784
+ },
+ {
+ "x": 0.0012199455029815454,
+ "y": -8.02528726360105
+ },
+ {
+ "x": 0.0015249318786914046,
+ "y": -10.031609079500612
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.031609079497805
+ },
+ {
+ "x": 0.0013724386910496378,
+ "y": -9.028448171545236
+ },
+ {
+ "x": 0.001677425066759497,
+ "y": -11.034769987444761
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949777
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949784
+ },
+ {
+ "x": 0.0018299182545433723,
+ "y": -12.037930895397437
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949777
+ },
+ {
+ "x": 0.0013724386909075292,
+ "y": -9.028448171550849
+ },
+ {
+ "x": 0.0016774250666173884,
+ "y": -11.034769987450517
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949777
+ },
+ {
+ "x": 0.001219945503123654,
+ "y": -8.025287263595402
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949777
+ },
+ {
+ "x": 0.0016774250666173884,
+ "y": -11.034769987450375
+ },
+ {
+ "x": 0.0013724386909075292,
+ "y": -9.028448171548149
+ },
+ {
+ "x": 0.0013724386909075292,
+ "y": -9.028448171548007
+ },
+ {
+ "x": 0.0013724386909075292,
+ "y": -9.028448171548007
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.031609079497912
+ },
+ {
+ "x": 0.0018299182546854809,
+ "y": -12.037930895394453
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949777
+ },
+ {
+ "x": 0.0015249318786914046,
+ "y": -10.031609079500754
+ },
+ {
+ "x": 0.0018299182546854809,
+ "y": -12.037930895394595
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949777
+ },
+ {
+ "x": 0.0013724386909075292,
+ "y": -9.028448171548007
+ },
+ {
+ "x": 0.0013724386910496378,
+ "y": -9.028448171545165
+ },
+ {
+ "x": 0.0013724386909075292,
+ "y": -9.028448171550849
+ },
+ {
+ "x": 0.0016774250666173884,
+ "y": -11.034769987450517
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949777
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949777
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949507
+ },
+ {
+ "x": 0.0013724386909075292,
+ "y": -9.028448171548007
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.03160907949777
+ },
+ {
+ "x": 0.0015249318788335131,
+ "y": -10.031609079497912
+ },
+ {
+ "x": 0.0013743493916251737,
+ "y": -9.041017521499342
+ },
+ {
+ "x": 0.0013767377676288106,
+ "y": -9.056729208932737
+ },
+ {
+ "x": 0.001376737767486702,
+ "y": -9.056729208933376
+ },
+ {
+ "x": 0.0012237669044168342,
+ "y": -8.050425963496295
+ },
+ {
+ "x": 0.0015297086306986785,
+ "y": -10.063032454370315
+ },
+ {
+ "x": 0.0019052270327790666,
+ "y": -11.160694042854118
+ },
+ {
+ "x": 0.24487507860840196,
+ "y": -12.488521393390783
+ },
+ {
+ "x": 0.683895541146029,
+ "y": -12.27528381493471
+ },
+ {
+ "x": 1.5149818923252667,
+ "y": -12.22424407162535
+ },
+ {
+ "x": 2.6433371301345687,
+ "y": -14.539510651078729
+ },
+ {
+ "x": 3.6229010561071107,
+ "y": -14.326870066868338
+ },
+ {
+ "x": 4.131285331596644,
+ "y": -12.902772566251457
+ },
+ {
+ "x": 4.996480387374049,
+ "y": -12.593052561556561
+ },
+ {
+ "x": 5.11921853595581,
+ "y": -11.203670926026632
+ },
+ {
+ "x": 4.596182586046211,
+ "y": -8.718903809223306
+ },
+ {
+ "x": 6.353214125038988,
+ "y": -10.557362389694589
+ },
+ {
+ "x": 7.569806888078858,
+ "y": -11.240570273925314
+ },
+ {
+ "x": 6.703380980256668,
+ "y": -8.831224216801985
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 90.94090186406459,
+ "y": -56.00807087257196,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 334.3018481088766,
+ "y": -5.288249675787207,
+ "z": 1.0
+ },
+ {
+ "x": 334.483777617468,
+ "y": -5.696789019027442,
+ "z": 1.0
+ },
+ {
+ "x": 334.6335298766519,
+ "y": -6.1181936524140035,
+ "z": 1.0
+ },
+ {
+ "x": 334.7327699870293,
+ "y": -6.476662154719557,
+ "z": 1.0
+ },
+ {
+ "x": 334.8211665615416,
+ "y": -6.91505878669135,
+ "z": 1.0
+ },
+ {
+ "x": 334.86871357172106,
+ "y": -7.284721762788378,
+ "z": 1.0
+ },
+ {
+ "x": 334.8941339881858,
+ "y": -7.731212958309326,
+ "z": 1.0
+ },
+ {
+ "x": 334.89504189202273,
+ "y": -8.077929108123932,
+ "z": 1.0
+ },
+ {
+ "x": 334.89473870653876,
+ "y": -8.579882660367307,
+ "z": 1.0
+ },
+ {
+ "x": 334.8944961581516,
+ "y": -8.981445502159971,
+ "z": 1.0
+ },
+ {
+ "x": 334.89413233557093,
+ "y": -9.583789764850664,
+ "z": 1.0
+ },
+ {
+ "x": 334.8938291500871,
+ "y": -10.085743317094039,
+ "z": 1.0
+ },
+ {
+ "x": 334.8935259646031,
+ "y": -10.587696869336284,
+ "z": 1.0
+ },
+ {
+ "x": 334.8934046904095,
+ "y": -10.788478290233183,
+ "z": 1.0
+ },
+ {
+ "x": 334.8931013907418,
+ "y": -11.290620885066517,
+ "z": 1.0
+ },
+ {
+ "x": 334.89279827934456,
+ "y": -11.792451779440704,
+ "z": 1.0
+ },
+ {
+ "x": 334.8924345456679,
+ "y": -12.394648852689727,
+ "z": 1.0
+ },
+ {
+ "x": 334.8920708119913,
+ "y": -12.996845925937615,
+ "z": 1.0
+ },
+ {
+ "x": 334.8918283228735,
+ "y": -13.398310641438098,
+ "z": 1.0
+ },
+ {
+ "x": 334.89146458919686,
+ "y": -14.00050771468712,
+ "z": 1.0
+ },
+ {
+ "x": 334.8911008555202,
+ "y": -14.602704787936144,
+ "z": 1.0
+ },
+ {
+ "x": 334.8907371218436,
+ "y": -15.20490186118403,
+ "z": 1.0
+ },
+ {
+ "x": 334.89037338816695,
+ "y": -15.807098934433052,
+ "z": 1.0
+ },
+ {
+ "x": 334.89007027676973,
+ "y": -16.308929828807237,
+ "z": 1.0
+ },
+ {
+ "x": 334.8897065430931,
+ "y": -16.91112690205739,
+ "z": 1.0
+ },
+ {
+ "x": 334.88934280941646,
+ "y": -17.51332397530641,
+ "z": 1.0
+ },
+ {
+ "x": 334.88903969801925,
+ "y": -18.015154869680593,
+ "z": 1.0
+ },
+ {
+ "x": 334.8886759643426,
+ "y": -18.617351942929613,
+ "z": 1.0
+ },
+ {
+ "x": 334.8884334752248,
+ "y": -19.01881665842783,
+ "z": 1.0
+ },
+ {
+ "x": 334.888190986107,
+ "y": -19.420281373928308,
+ "z": 1.0
+ },
+ {
+ "x": 334.8878878747098,
+ "y": -19.922112268302495,
+ "z": 1.0
+ },
+ {
+ "x": 334.8876453855921,
+ "y": -20.32357698380184,
+ "z": 1.0
+ },
+ {
+ "x": 334.8874028964743,
+ "y": -20.725041699301187,
+ "z": 1.0
+ },
+ {
+ "x": 334.88716040735653,
+ "y": -21.126506414800534,
+ "z": 1.0
+ },
+ {
+ "x": 334.8868572959593,
+ "y": -21.628337309174718,
+ "z": 1.0
+ },
+ {
+ "x": 334.8865541845621,
+ "y": -22.1301682035489,
+ "z": 1.0
+ },
+ {
+ "x": 334.8862510731649,
+ "y": -22.631999097923085,
+ "z": 1.0
+ },
+ {
+ "x": 334.8860085840472,
+ "y": -23.033463813422433,
+ "z": 1.0
+ },
+ {
+ "x": 334.88564485037057,
+ "y": -23.63566088667032,
+ "z": 1.0
+ },
+ {
+ "x": 334.88534173897335,
+ "y": -24.137491781044503,
+ "z": 1.0
+ },
+ {
+ "x": 334.8849780052967,
+ "y": -24.739688854293526,
+ "z": 1.0
+ },
+ {
+ "x": 334.8846748938995,
+ "y": -25.241519748667706,
+ "z": 1.0
+ },
+ {
+ "x": 334.88431116022286,
+ "y": -25.84371682191673,
+ "z": 1.0
+ },
+ {
+ "x": 334.88400804882565,
+ "y": -26.34554771629091,
+ "z": 1.0
+ },
+ {
+ "x": 334.88370493742843,
+ "y": -26.847378610665096,
+ "z": 1.0
+ },
+ {
+ "x": 334.8833412037518,
+ "y": -27.449575683914127,
+ "z": 1.0
+ },
+ {
+ "x": 334.883098714634,
+ "y": -27.851040399414615,
+ "z": 1.0
+ },
+ {
+ "x": 334.8828562255162,
+ "y": -28.252505114912836,
+ "z": 1.0
+ },
+ {
+ "x": 334.88249249183957,
+ "y": -28.854702188163,
+ "z": 1.0
+ },
+ {
+ "x": 334.88212875816293,
+ "y": -29.456899261412033,
+ "z": 1.0
+ },
+ {
+ "x": 334.8817650244863,
+ "y": -30.059096334661064,
+ "z": 1.0
+ },
+ {
+ "x": 334.88140129080966,
+ "y": -30.66129340790896,
+ "z": 1.0
+ },
+ {
+ "x": 334.88109817941245,
+ "y": -31.163124302284288,
+ "z": 1.0
+ },
+ {
+ "x": 334.8807344457358,
+ "y": -31.765321375532185,
+ "z": 1.0
+ },
+ {
+ "x": 334.8804313343386,
+ "y": -32.267152269906376,
+ "z": 1.0
+ },
+ {
+ "x": 334.8801282229414,
+ "y": -32.76898316428171,
+ "z": 1.0
+ },
+ {
+ "x": 334.87982511154416,
+ "y": -33.27081405865589,
+ "z": 1.0
+ },
+ {
+ "x": 334.87952200014695,
+ "y": -33.77264495303008,
+ "z": 1.0
+ },
+ {
+ "x": 334.87921888874973,
+ "y": -34.274475847404275,
+ "z": 1.0
+ },
+ {
+ "x": 334.8789157773525,
+ "y": -34.77630674177734,
+ "z": 1.0
+ },
+ {
+ "x": 334.8786732882347,
+ "y": -35.17777145727783,
+ "z": 1.0
+ },
+ {
+ "x": 334.8783701768375,
+ "y": -35.67960235165202,
+ "z": 1.0
+ },
+ {
+ "x": 334.8780670654403,
+ "y": -36.18143324602622,
+ "z": 1.0
+ },
+ {
+ "x": 334.87770333176366,
+ "y": -36.78363031927525,
+ "z": 1.0
+ },
+ {
+ "x": 334.877460842646,
+ "y": -37.18509503477346,
+ "z": 1.0
+ },
+ {
+ "x": 334.87709710896934,
+ "y": -37.78729210802249,
+ "z": 1.0
+ },
+ {
+ "x": 334.8767939975721,
+ "y": -38.289123002396686,
+ "z": 1.0
+ },
+ {
+ "x": 334.8765515084543,
+ "y": -38.69058771789717,
+ "z": 1.0
+ },
+ {
+ "x": 334.87630901933653,
+ "y": -39.092052433395395,
+ "z": 1.0
+ },
+ {
+ "x": 334.8759452856599,
+ "y": -39.694249506644425,
+ "z": 1.0
+ },
+ {
+ "x": 334.87558155198326,
+ "y": -40.29644657989459,
+ "z": 1.0
+ },
+ {
+ "x": 334.87527844058604,
+ "y": -40.79827747426879,
+ "z": 1.0
+ },
+ {
+ "x": 334.8749147069094,
+ "y": -41.40047454751782,
+ "z": 1.0
+ },
+ {
+ "x": 334.8746722177916,
+ "y": -41.80193926301603,
+ "z": 1.0
+ },
+ {
+ "x": 334.8744297286738,
+ "y": -42.20340397851652,
+ "z": 1.0
+ },
+ {
+ "x": 334.8741266172766,
+ "y": -42.70523487289071,
+ "z": 1.0
+ },
+ {
+ "x": 334.87376288359997,
+ "y": -43.30743194613973,
+ "z": 1.0
+ },
+ {
+ "x": 334.8735203944823,
+ "y": -43.70889666163794,
+ "z": 1.0
+ },
+ {
+ "x": 334.87321728308507,
+ "y": -44.21072755601211,
+ "z": 1.0
+ },
+ {
+ "x": 334.8729747939673,
+ "y": -44.61219227151258,
+ "z": 1.0
+ },
+ {
+ "x": 334.87267168257006,
+ "y": -45.11402316588563,
+ "z": 1.0
+ },
+ {
+ "x": 334.8723079488934,
+ "y": -45.716220239135765,
+ "z": 1.0
+ },
+ {
+ "x": 334.8720048374962,
+ "y": -46.218051133509945,
+ "z": 1.0
+ },
+ {
+ "x": 334.87188359293737,
+ "y": -46.41878349125962,
+ "z": 1.0
+ },
+ {
+ "x": 334.8715801110045,
+ "y": -46.92122784405019,
+ "z": 1.0
+ },
+ {
+ "x": 334.87133732545817,
+ "y": -47.32318332628318,
+ "z": 1.0
+ },
+ {
+ "x": 334.8710338435253,
+ "y": -47.825627679074415,
+ "z": 1.0
+ },
+ {
+ "x": 334.8706696652059,
+ "y": -48.4285609024239,
+ "z": 1.0
+ },
+ {
+ "x": 334.87036618327295,
+ "y": -48.93100525521626,
+ "z": 1.0
+ },
+ {
+ "x": 334.8700627013401,
+ "y": -49.43344960800749,
+ "z": 1.0
+ },
+ {
+ "x": 334.8696985230207,
+ "y": -50.036382831355844,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 24,
+ "heading": [
+ -1.5532445997494864,
+ -1.1518436168635509,
+ -1.1905972608595516,
+ -1.2617530685069873,
+ -1.3395403756927158,
+ -1.4041224818930387,
+ -1.4816294206080958,
+ -1.5376162787349619,
+ -1.5700837783804023,
+ -1.5714003377551682,
+ -1.5714003377550556,
+ -1.5714003377549617,
+ -1.5714003377550543,
+ -1.5714003377551682,
+ -1.5714003377551,
+ -1.57140033775507,
+ -1.5714003377550467,
+ -1.5714003377550303,
+ -1.5714003377550674,
+ -1.5714003377550667,
+ -1.5714003377550296,
+ -1.5714003377550303,
+ -1.5714003377550303,
+ -1.5714003377550467,
+ -1.5714003377550463,
+ -1.5714003377550292,
+ -1.5714003377550467,
+ -1.5714003377550467,
+ -1.571400337755068,
+ -1.571400337755124,
+ -1.5714003377550918,
+ -1.5714003377549668,
+ -1.5714003377549826,
+ -1.571400337755124,
+ -1.5714003377550925,
+ -1.5714003377550674,
+ -1.5714003377550674,
+ -1.5714003377549668,
+ -1.5714003377549548,
+ -1.5714003377550474,
+ -1.5714003377550467,
+ -1.5714003377550467,
+ -1.5714003377550467,
+ -1.5714003377550467,
+ -1.5714003377550674,
+ -1.5714003377550467,
+ -1.5714003377550667,
+ -1.571400337755124,
+ -1.5714003377550674,
+ -1.571400337755029,
+ -1.5714003377550296,
+ -1.5714003377550303,
+ -1.5714003377550467,
+ -1.5714003377550467,
+ -1.5714003377550474,
+ -1.5714003377550667,
+ -1.5714003377550667,
+ -1.5714003377550674,
+ -1.5714003377550674,
+ -1.571400337755068,
+ -1.5714003377550925,
+ -1.5714003377550918,
+ -1.5714003377550674,
+ -1.5714003377550467,
+ -1.5714003377549548,
+ -1.5714003377549548,
+ -1.5714003377550467,
+ -1.5714003377550918,
+ -1.571400337755124,
+ -1.571400337755068,
+ -1.571400337755029,
+ -1.5714003377550463,
+ -1.5714003377550467,
+ -1.571400337755068,
+ -1.571400337755124,
+ -1.5714003377550918,
+ -1.5714003377550467,
+ -1.5714003377549548,
+ -1.5714003377549675,
+ -1.5714003377550918,
+ -1.5714003377550927,
+ -1.5714003377550467,
+ -1.5714003377550463,
+ -1.5714003377550028,
+ -1.5714003377549923,
+ -1.5714003377551027,
+ -1.5714003377551022,
+ -1.571400337755011,
+ -1.5714003377551131,
+ -1.5714003377551644,
+ -1.5714003377550114
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": 1.81929508591395,
+ "y": -4.085393432402347
+ },
+ {
+ "x": 3.316817677753079,
+ "y": -8.299439766267964
+ },
+ {
+ "x": 2.4899236956133564,
+ "y": -7.798731356921156
+ },
+ {
+ "x": 1.8763668488969643,
+ "y": -7.9686513427734695
+ },
+ {
+ "x": 1.3594358469174495,
+ "y": -8.080596080688203
+ },
+ {
+ "x": 0.7296742664419753,
+ "y": -8.161541716179759
+ },
+ {
+ "x": 0.2632832030167265,
+ "y": -7.932073453355546
+ },
+ {
+ "x": 0.006047183529744871,
+ "y": -8.486697020579808
+ },
+ {
+ "x": -0.005457338711494231,
+ "y": -9.035163940360391
+ },
+ {
+ "x": -0.006063709678301166,
+ "y": -10.03907104483357
+ },
+ {
+ "x": -0.006670080645108101,
+ "y": -11.042978149340676
+ },
+ {
+ "x": -0.006063709678301166,
+ "y": -10.0390710448562
+ },
+ {
+ "x": -0.004244596775606624,
+ "y": -7.027349731391439
+ },
+ {
+ "x": -0.004245738613235517,
+ "y": -7.0292401573023255
+ },
+ {
+ "x": -0.006064110649504073,
+ "y": -10.03973489207521
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676232103
+ },
+ {
+ "x": -0.007274673532720044,
+ "y": -12.043941464969112
+ },
+ {
+ "x": -0.006062227944312326,
+ "y": -10.036617887483708
+ },
+ {
+ "x": -0.006062227944312326,
+ "y": -10.036617887495058
+ },
+ {
+ "x": -0.007274673532720044,
+ "y": -12.043941464980463
+ },
+ {
+ "x": -0.007274673532720044,
+ "y": -12.043941464969095
+ },
+ {
+ "x": -0.007274673532720044,
+ "y": -12.043941464969077
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676232068
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676243383
+ },
+ {
+ "x": -0.007274673532720044,
+ "y": -12.043941464991725
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676232032
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676232032
+ },
+ {
+ "x": -0.006062227944312326,
+ "y": -10.036617887472374
+ },
+ {
+ "x": -0.004849782355904608,
+ "y": -8.029294309986952
+ },
+ {
+ "x": -0.005456005150108467,
+ "y": -9.032956098746645
+ },
+ {
+ "x": -0.005456005148971599,
+ "y": -9.032956098735312
+ },
+ {
+ "x": -0.00484978235476774,
+ "y": -8.029294309986916
+ },
+ {
+ "x": -0.004849782355904608,
+ "y": -8.029294309986952
+ },
+ {
+ "x": -0.005456005150108467,
+ "y": -9.032956098735312
+ },
+ {
+ "x": -0.006062227944312326,
+ "y": -10.036617887483672
+ },
+ {
+ "x": -0.006062227944312326,
+ "y": -10.036617887483672
+ },
+ {
+ "x": -0.005456005148971599,
+ "y": -9.032956098735312
+ },
+ {
+ "x": -0.006062227943175458,
+ "y": -10.036617887472339
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676220699
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676232068
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676232032
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676232032
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676232032
+ },
+ {
+ "x": -0.006062227944312326,
+ "y": -10.036617887483672
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676232174
+ },
+ {
+ "x": -0.006062227944312326,
+ "y": -10.036617887495183
+ },
+ {
+ "x": -0.004849782355904608,
+ "y": -8.029294309987094
+ },
+ {
+ "x": -0.006062227944312326,
+ "y": -10.03661788748385
+ },
+ {
+ "x": -0.007274673532720044,
+ "y": -12.043941464991974
+ },
+ {
+ "x": -0.007274673532720044,
+ "y": -12.04394146498064
+ },
+ {
+ "x": -0.007274673532720044,
+ "y": -12.043941464969272
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676232245
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676232245
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676220877
+ },
+ {
+ "x": -0.006062227944312326,
+ "y": -10.036617887495218
+ },
+ {
+ "x": -0.006062227944312326,
+ "y": -10.036617887495112
+ },
+ {
+ "x": -0.006062227944312326,
+ "y": -10.036617887483743
+ },
+ {
+ "x": -0.006062227944312326,
+ "y": -10.036617887483885
+ },
+ {
+ "x": -0.006062227944312326,
+ "y": -10.036617887472588
+ },
+ {
+ "x": -0.005456005150108467,
+ "y": -9.032956098735525
+ },
+ {
+ "x": -0.005456005150108467,
+ "y": -9.032956098746823
+ },
+ {
+ "x": -0.006062227944312326,
+ "y": -10.036617887483885
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676232245
+ },
+ {
+ "x": -0.006062227943175458,
+ "y": -10.036617887472445
+ },
+ {
+ "x": -0.006062227943175458,
+ "y": -10.036617887472445
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676232245
+ },
+ {
+ "x": -0.005456005150108467,
+ "y": -9.032956098746823
+ },
+ {
+ "x": -0.004849782355904608,
+ "y": -8.029294309987094
+ },
+ {
+ "x": -0.006062227944312326,
+ "y": -10.036617887472516
+ },
+ {
+ "x": -0.007274673532720044,
+ "y": -12.043941464991974
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676243614
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676232245
+ },
+ {
+ "x": -0.006062227944312326,
+ "y": -10.036617887472445
+ },
+ {
+ "x": -0.004849782355904608,
+ "y": -8.029294309987023
+ },
+ {
+ "x": -0.005456005150108467,
+ "y": -9.032956098746823
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676232103
+ },
+ {
+ "x": -0.006062227943175458,
+ "y": -10.036617887472232
+ },
+ {
+ "x": -0.005456005148971599,
+ "y": -9.032956098723801
+ },
+ {
+ "x": -0.005456005150108467,
+ "y": -9.032956098746467
+ },
+ {
+ "x": -0.005456005150108467,
+ "y": -9.03295609873517
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676231819
+ },
+ {
+ "x": -0.006668450738516185,
+ "y": -11.040279676243188
+ },
+ {
+ "x": -0.004243559560563881,
+ "y": -7.025632521238521
+ },
+ {
+ "x": -0.004247264917012217,
+ "y": -7.03176710540248
+ },
+ {
+ "x": -0.005462674791942845,
+ "y": -9.043998350235611
+ },
+ {
+ "x": -0.005462674791942845,
+ "y": -9.04399835024222
+ },
+ {
+ "x": -0.00667660252247515,
+ "y": -11.05377576140718
+ },
+ {
+ "x": -0.0066766025236120186,
+ "y": -11.053775761418478
+ },
+ {
+ "x": -0.006069638658345866,
+ "y": -10.048887055835962
+ },
+ {
+ "x": -0.00667660252247515,
+ "y": -11.053775761395812
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 334.8696985230207,
+ "y": -50.036382831355844,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 335.72938655142246,
+ "y": -58.63575611077631,
+ "z": 1.0
+ },
+ {
+ "x": 335.26862518724147,
+ "y": -58.22155991552123,
+ "z": 1.0
+ },
+ {
+ "x": 334.698387263307,
+ "y": -57.76731713412676,
+ "z": 1.0
+ },
+ {
+ "x": 334.3028154287997,
+ "y": -57.48483981665477,
+ "z": 1.0
+ },
+ {
+ "x": 333.8957244634312,
+ "y": -57.219229528144716,
+ "z": 1.0
+ },
+ {
+ "x": 333.4774670769269,
+ "y": -56.970813165394034,
+ "z": 1.0
+ },
+ {
+ "x": 333.0494715041758,
+ "y": -56.740398386255336,
+ "z": 1.0
+ },
+ {
+ "x": 332.61217496998677,
+ "y": -56.52816815784608,
+ "z": 1.0
+ },
+ {
+ "x": 331.94048368733047,
+ "y": -56.244729219671626,
+ "z": 1.0
+ },
+ {
+ "x": 331.3680067648105,
+ "y": -56.04123961894434,
+ "z": 1.0
+ },
+ {
+ "x": 330.6681152139086,
+ "y": -55.83714288248695,
+ "z": 1.0
+ },
+ {
+ "x": 329.95675694016956,
+ "y": -55.67754008286519,
+ "z": 1.0
+ },
+ {
+ "x": 329.2367567288088,
+ "y": -55.56306505257391,
+ "z": 1.0
+ },
+ {
+ "x": 328.63221699389953,
+ "y": -55.502475293783945,
+ "z": 1.0
+ },
+ {
+ "x": 327.9038158309816,
+ "y": -55.471785085123855,
+ "z": 1.0
+ },
+ {
+ "x": 327.47163572658246,
+ "y": -55.47111336395268,
+ "z": 1.0
+ },
+ {
+ "x": 326.96905200000987,
+ "y": -55.471174605179854,
+ "z": 1.0
+ },
+ {
+ "x": 326.3659515281231,
+ "y": -55.471248094652466,
+ "z": 1.0
+ },
+ {
+ "x": 325.8633678015507,
+ "y": -55.47130933587964,
+ "z": 1.0
+ },
+ {
+ "x": 325.46130082029276,
+ "y": -55.471358328861356,
+ "z": 1.0
+ },
+ {
+ "x": 325.15975058434924,
+ "y": -55.47139507359766,
+ "z": 1.0
+ },
+ {
+ "x": 324.6594655975632,
+ "y": -55.47145603471698,
+ "z": 1.0
+ },
+ {
+ "x": 324.1591806107769,
+ "y": -55.47151699583631,
+ "z": 1.0
+ },
+ {
+ "x": 323.65889562399076,
+ "y": -55.47157795695564,
+ "z": 1.0
+ },
+ {
+ "x": 323.1586106372048,
+ "y": -55.47163891807496,
+ "z": 1.0
+ },
+ {
+ "x": 322.65832565041853,
+ "y": -55.47169987919429,
+ "z": 1.0
+ },
+ {
+ "x": 322.0579836662754,
+ "y": -55.471773032537484,
+ "z": 1.0
+ },
+ {
+ "x": 321.45764168213185,
+ "y": -55.47184618588068,
+ "z": 1.0
+ },
+ {
+ "x": 320.85729969798865,
+ "y": -55.47191933922386,
+ "z": 1.0
+ },
+ {
+ "x": 320.3570147112025,
+ "y": -55.47198030034319,
+ "z": 1.0
+ },
+ {
+ "x": 319.756672727059,
+ "y": -55.472053453686385,
+ "z": 1.0
+ },
+ {
+ "x": 319.35644473763034,
+ "y": -55.47210222258184,
+ "z": 1.0
+ },
+ {
+ "x": 318.9562167482014,
+ "y": -55.47215099147729,
+ "z": 1.0
+ },
+ {
+ "x": 318.35587476405806,
+ "y": -55.47222414482049,
+ "z": 1.0
+ },
+ {
+ "x": 317.7555327799147,
+ "y": -55.47229729816368,
+ "z": 1.0
+ },
+ {
+ "x": 317.3553047904859,
+ "y": -55.47234606705915,
+ "z": 1.0
+ },
+ {
+ "x": 316.7549628063425,
+ "y": -55.47241922040233,
+ "z": 1.0
+ },
+ {
+ "x": 316.2546778195562,
+ "y": -55.47248018152166,
+ "z": 1.0
+ },
+ {
+ "x": 315.7543928327701,
+ "y": -55.47254114264099,
+ "z": 1.0
+ },
+ {
+ "x": 315.3541648433412,
+ "y": -55.472589911536446,
+ "z": 1.0
+ },
+ {
+ "x": 314.9539368539124,
+ "y": -55.4726386804319,
+ "z": 1.0
+ },
+ {
+ "x": 314.35359486976915,
+ "y": -55.472711833775094,
+ "z": 1.0
+ },
+ {
+ "x": 313.95336688034024,
+ "y": -55.47276060267056,
+ "z": 1.0
+ },
+ {
+ "x": 313.55313889091116,
+ "y": -55.472809371566015,
+ "z": 1.0
+ },
+ {
+ "x": 313.1529109014824,
+ "y": -55.47285814046148,
+ "z": 1.0
+ },
+ {
+ "x": 312.55256891733916,
+ "y": -55.47293129380468,
+ "z": 1.0
+ },
+ {
+ "x": 312.15234092791025,
+ "y": -55.47298006270013,
+ "z": 1.0
+ },
+ {
+ "x": 311.75211293848133,
+ "y": -55.4730288315956,
+ "z": 1.0
+ },
+ {
+ "x": 311.15177095433796,
+ "y": -55.47310198493878,
+ "z": 1.0
+ },
+ {
+ "x": 310.75154296490905,
+ "y": -55.47315075383425,
+ "z": 1.0
+ },
+ {
+ "x": 310.2512579781229,
+ "y": -55.473211714953564,
+ "z": 1.0
+ },
+ {
+ "x": 309.6509159939795,
+ "y": -55.47328486829676,
+ "z": 1.0
+ },
+ {
+ "x": 309.15063100719334,
+ "y": -55.47334582941609,
+ "z": 1.0
+ },
+ {
+ "x": 308.65034602040726,
+ "y": -55.47340679053542,
+ "z": 1.0
+ },
+ {
+ "x": 308.25011803097834,
+ "y": -55.473455559430874,
+ "z": 1.0
+ },
+ {
+ "x": 307.6497760468351,
+ "y": -55.47352871277407,
+ "z": 1.0
+ },
+ {
+ "x": 307.2495480574063,
+ "y": -55.47357748166952,
+ "z": 1.0
+ },
+ {
+ "x": 306.6492060732629,
+ "y": -55.47365063501272,
+ "z": 1.0
+ },
+ {
+ "x": 306.248978083834,
+ "y": -55.47369940390817,
+ "z": 1.0
+ },
+ {
+ "x": 305.6486360996905,
+ "y": -55.473772557251365,
+ "z": 1.0
+ },
+ {
+ "x": 305.2484081102616,
+ "y": -55.47382132614683,
+ "z": 1.0
+ },
+ {
+ "x": 304.84818012083275,
+ "y": -55.47387009504229,
+ "z": 1.0
+ },
+ {
+ "x": 304.24783813668955,
+ "y": -55.47394324838548,
+ "z": 1.0
+ },
+ {
+ "x": 303.7475531499034,
+ "y": -55.47400420950481,
+ "z": 1.0
+ },
+ {
+ "x": 303.3473251604744,
+ "y": -55.474052978400266,
+ "z": 1.0
+ },
+ {
+ "x": 302.9470971710456,
+ "y": -55.474101747295734,
+ "z": 1.0
+ },
+ {
+ "x": 302.3467551869023,
+ "y": -55.474174900638914,
+ "z": 1.0
+ },
+ {
+ "x": 301.9465271974734,
+ "y": -55.47422366953438,
+ "z": 1.0
+ },
+ {
+ "x": 301.5462992080445,
+ "y": -55.474272438429836,
+ "z": 1.0
+ },
+ {
+ "x": 301.1460712186156,
+ "y": -55.4743212073253,
+ "z": 1.0
+ },
+ {
+ "x": 300.5457292344722,
+ "y": -55.474394360668484,
+ "z": 1.0
+ },
+ {
+ "x": 300.1455012450434,
+ "y": -55.47444312956395,
+ "z": 1.0
+ },
+ {
+ "x": 299.6452162582573,
+ "y": -55.47450409068327,
+ "z": 1.0
+ },
+ {
+ "x": 299.24498826882837,
+ "y": -55.474552859578736,
+ "z": 1.0
+ },
+ {
+ "x": 298.7447032820422,
+ "y": -55.47461382069807,
+ "z": 1.0
+ },
+ {
+ "x": 298.3444752926133,
+ "y": -55.47466258959352,
+ "z": 1.0
+ },
+ {
+ "x": 297.7441333084698,
+ "y": -55.474735742936716,
+ "z": 1.0
+ },
+ {
+ "x": 297.2438483216839,
+ "y": -55.47479670405605,
+ "z": 1.0
+ },
+ {
+ "x": 296.843620332255,
+ "y": -55.4748454729515,
+ "z": 1.0
+ },
+ {
+ "x": 296.24327834811163,
+ "y": -55.474918626294695,
+ "z": 1.0
+ },
+ {
+ "x": 295.8430503586827,
+ "y": -55.47496739519015,
+ "z": 1.0
+ },
+ {
+ "x": 295.24270837453935,
+ "y": -55.47504054853334,
+ "z": 1.0
+ },
+ {
+ "x": 294.7424233877531,
+ "y": -55.475101509652674,
+ "z": 1.0
+ },
+ {
+ "x": 294.3421953983243,
+ "y": -55.47515027854813,
+ "z": 1.0
+ },
+ {
+ "x": 293.7418534141807,
+ "y": -55.47522343189132,
+ "z": 1.0
+ },
+ {
+ "x": 293.14151143003744,
+ "y": -55.47529658523452,
+ "z": 1.0
+ },
+ {
+ "x": 292.6412264432512,
+ "y": -55.475357546353834,
+ "z": 1.0
+ },
+ {
+ "x": 292.2409984538223,
+ "y": -55.4754063152493,
+ "z": 1.0
+ },
+ {
+ "x": 291.74071346703613,
+ "y": -55.47546727636862,
+ "z": 1.0
+ },
+ {
+ "x": 291.3404854776071,
+ "y": -55.47551604526409,
+ "z": 1.0
+ },
+ {
+ "x": 290.84020049082096,
+ "y": -55.4755770063834,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 25,
+ "heading": [
+ -2.0911486832018613,
+ 2.409364246695374,
+ 2.4415698129842616,
+ 2.4899494772842057,
+ 2.5424788063606654,
+ 2.584577189082867,
+ 2.6266809113227545,
+ 2.668743372007666,
+ 2.7212726952459185,
+ 2.76854909399482,
+ 2.8315843006733368,
+ 2.8893665716104087,
+ 2.952401781124309,
+ 3.010184052581499,
+ 3.0732192687883306,
+ 3.1145766226218736,
+ 3.14093956899561,
+ -3.141470800804608,
+ -3.141470800804608,
+ -3.141470800804635,
+ -3.1414708008046373,
+ -3.14147080080462,
+ -3.141470800804616,
+ -3.1414708008046017,
+ -3.141470800804616,
+ -3.141470800804616,
+ -3.141470800804604,
+ -3.141470800804606,
+ -3.141470800804618,
+ -3.1414708008046173,
+ -3.1414708008046044,
+ -3.141470800804616,
+ -3.14147080080463,
+ -3.141470800804616,
+ -3.141470800804606,
+ -3.1414708008046017,
+ -3.141470800804616,
+ -3.1414708008046173,
+ -3.1414708008046017,
+ -3.141470800804614,
+ -3.14147080080463,
+ -3.141470800804616,
+ -3.1414708008046017,
+ -3.1414708008046124,
+ -3.1414708008046124,
+ -3.1414708008046017,
+ -3.141470800804616,
+ -3.1414708008046124,
+ -3.141470800804616,
+ -3.141470800804616,
+ -3.141470800804614,
+ -3.1414708008046173,
+ -3.1414708008046044,
+ -3.1414708008046017,
+ -3.141470800804614,
+ -3.141470800804616,
+ -3.141470800804616,
+ -3.141470800804616,
+ -3.141470800804616,
+ -3.141470800804616,
+ -3.1414708008046017,
+ -3.1414708008046124,
+ -3.141470800804616,
+ -3.141470800804604,
+ -3.141470800804614,
+ -3.1414708008046124,
+ -3.141470800804616,
+ -3.141470800804616,
+ -3.1414708008046124,
+ -3.1414708008046124,
+ -3.141470800804616,
+ -3.141470800804616,
+ -3.141470800804614,
+ -3.141470800804614,
+ -3.1414708008045986,
+ -3.141470800804614,
+ -3.141470800804616,
+ -3.141470800804604,
+ -3.141470800804614,
+ -3.141470800804616,
+ -3.141470800804616,
+ -3.141470800804616,
+ -3.1414708008046044,
+ -3.141470800804614,
+ -3.141470800804616,
+ -3.141470800804606,
+ -3.1414708008046173,
+ -3.141470800804614,
+ -3.141470800804614,
+ -3.141470800804614,
+ -3.141470800804614
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -4.607613641809962,
+ "y": 4.141961952550801
+ },
+ {
+ "x": -10.309992881154812,
+ "y": 8.6843897664955
+ },
+ {
+ "x": -9.658097584417646,
+ "y": 7.367200988664635
+ },
+ {
+ "x": -8.026627998758045,
+ "y": 5.480876059820474
+ },
+ {
+ "x": -8.253483518727762,
+ "y": 5.140266512607354
+ },
+ {
+ "x": -8.462529592553665,
+ "y": 4.788311418893798
+ },
+ {
+ "x": -8.6529210694016,
+ "y": 4.426450075479522
+ },
+ {
+ "x": -11.089878168453424,
+ "y": 4.9566916658370985
+ },
+ {
+ "x": -12.441682051762655,
+ "y": 4.869285389017435
+ },
+ {
+ "x": -12.723684734218637,
+ "y": 4.075863371846751
+ },
+ {
+ "x": -14.112498246409473,
+ "y": 3.6369953607914596
+ },
+ {
+ "x": -14.313584850997927,
+ "y": 2.7407782991303975
+ },
+ {
+ "x": -13.24539946270022,
+ "y": 1.7506478908124734
+ },
+ {
+ "x": -13.329408978272,
+ "y": 0.9127996745005618
+ },
+ {
+ "x": -11.605812673170703,
+ "y": 0.3136192983126307
+ },
+ {
+ "x": -9.347638309717468,
+ "y": 0.006104799440009856
+ },
+ {
+ "x": -11.056841984593575,
+ "y": -0.001347306997843134
+ },
+ {
+ "x": -11.05684198459187,
+ "y": -0.001347306997843134
+ },
+ {
+ "x": -9.04650707830342,
+ "y": -0.0011023420888989222
+ },
+ {
+ "x": -7.036172172014403,
+ "y": -0.0008573771802389274
+ },
+ {
+ "x": -8.018352227295509,
+ "y": -0.0009770585562307588
+ },
+ {
+ "x": -10.005699735723397,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -10.005699735724534,
+ "y": -0.0012192223866236418
+ },
+ {
+ "x": -10.005699735721123,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -10.00569973572226,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -11.006269709293974,
+ "y": -0.0013411446252575843
+ },
+ {
+ "x": -12.006839682866826,
+ "y": -0.0014630668638915267
+ },
+ {
+ "x": -12.006839682867394,
+ "y": -0.0014630668637494182
+ },
+ {
+ "x": -11.006269709293406,
+ "y": -0.0013411446251154757
+ },
+ {
+ "x": -11.006269709296248,
+ "y": -0.0013411446252575843
+ },
+ {
+ "x": -10.005699735721691,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -8.004559788575989,
+ "y": -0.0009753779090715398
+ },
+ {
+ "x": -10.005699735722828,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -12.006839682867394,
+ "y": -0.0014630668638915267
+ },
+ {
+ "x": -10.005699735721691,
+ "y": -0.0012192223866236418
+ },
+ {
+ "x": -10.005699735721691,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -11.006269709296816,
+ "y": -0.0013411446251154757
+ },
+ {
+ "x": -10.005699735723965,
+ "y": -0.0012192223866236418
+ },
+ {
+ "x": -9.005129762149977,
+ "y": -0.0010973001478475908
+ },
+ {
+ "x": -8.004559788577126,
+ "y": -0.0009753779090715398
+ },
+ {
+ "x": -10.005699735720555,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -10.005699735721691,
+ "y": -0.0012192223866236418
+ },
+ {
+ "x": -8.004559788579968,
+ "y": -0.0009753779092136483
+ },
+ {
+ "x": -8.004559788578263,
+ "y": -0.0009753779092136483
+ },
+ {
+ "x": -10.005699735719986,
+ "y": -0.0012192223866236418
+ },
+ {
+ "x": -10.005699735721691,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -8.004559788578263,
+ "y": -0.0009753779092136483
+ },
+ {
+ "x": -10.005699735722828,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -10.005699735722828,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -9.005129762150546,
+ "y": -0.0010973001478475908
+ },
+ {
+ "x": -11.00626970929568,
+ "y": -0.0013411446251154757
+ },
+ {
+ "x": -11.00626970929568,
+ "y": -0.0013411446252575843
+ },
+ {
+ "x": -10.00569973572226,
+ "y": -0.0012192223866236418
+ },
+ {
+ "x": -9.005129762149977,
+ "y": -0.0010973001478475908
+ },
+ {
+ "x": -10.005699735721691,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -10.005699735720555,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -10.005699735721691,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -10.005699735722828,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -10.005699735723965,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -10.005699735723965,
+ "y": -0.0012192223866236418
+ },
+ {
+ "x": -8.004559788577694,
+ "y": -0.0009753779092136483
+ },
+ {
+ "x": -10.005699735720555,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -11.006269709293406,
+ "y": -0.0013411446252575843
+ },
+ {
+ "x": -9.005129762151682,
+ "y": -0.0010973001478475908
+ },
+ {
+ "x": -8.004559788578263,
+ "y": -0.0009753779092136483
+ },
+ {
+ "x": -10.005699735720555,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -10.005699735721691,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -8.004559788578263,
+ "y": -0.0009753779092136483
+ },
+ {
+ "x": -8.004559788578263,
+ "y": -0.0009753779092136483
+ },
+ {
+ "x": -10.005699735722828,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -10.005699735721691,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -9.005129762149409,
+ "y": -0.0010973001478475908
+ },
+ {
+ "x": -9.005129762150546,
+ "y": -0.0010973001478475908
+ },
+ {
+ "x": -9.005129762150546,
+ "y": -0.0010973001479896993
+ },
+ {
+ "x": -9.005129762150546,
+ "y": -0.0010973001478475908
+ },
+ {
+ "x": -10.005699735723965,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -11.006269709293974,
+ "y": -0.0013411446252575843
+ },
+ {
+ "x": -9.005129762148272,
+ "y": -0.0010973001478475908
+ },
+ {
+ "x": -10.005699735722828,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -10.005699735722828,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -10.005699735722828,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -11.006269709296248,
+ "y": -0.0013411446252575843
+ },
+ {
+ "x": -9.005129762150546,
+ "y": -0.0010973001478475908
+ },
+ {
+ "x": -10.005699735723965,
+ "y": -0.0012192223864815332
+ },
+ {
+ "x": -12.00683968286853,
+ "y": -0.0014630668638915267
+ },
+ {
+ "x": -11.006269709295111,
+ "y": -0.0013411446251154757
+ },
+ {
+ "x": -9.005129762151682,
+ "y": -0.0010973001478475908
+ },
+ {
+ "x": -9.005129762150546,
+ "y": -0.0010973001478475908
+ },
+ {
+ "x": -9.005129762151682,
+ "y": -0.0010973001478475908
+ },
+ {
+ "x": -9.005129762151682,
+ "y": -0.0010973001478475908
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 290.84020049082096,
+ "y": -55.4755770063834,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 334.7845708455262,
+ "y": -190.97367165224483,
+ "z": 1.0
+ },
+ {
+ "x": 334.7842674203806,
+ "y": -191.47602198796034,
+ "z": 1.0
+ },
+ {
+ "x": 334.7839639952351,
+ "y": -191.97837232367357,
+ "z": 1.0
+ },
+ {
+ "x": 334.78359988506054,
+ "y": -192.5811927265308,
+ "z": 1.0
+ },
+ {
+ "x": 334.78335714494415,
+ "y": -192.98307299510117,
+ "z": 1.0
+ },
+ {
+ "x": 334.78299303476956,
+ "y": -193.58589339795952,
+ "z": 1.0
+ },
+ {
+ "x": 334.782628924595,
+ "y": -194.1887138008168,
+ "z": 1.0
+ },
+ {
+ "x": 334.7823861844786,
+ "y": -194.59059406938712,
+ "z": 1.0
+ },
+ {
+ "x": 334.7821434443622,
+ "y": -194.99247433795864,
+ "z": 1.0
+ },
+ {
+ "x": 334.7819007042457,
+ "y": -195.3943546065313,
+ "z": 1.0
+ },
+ {
+ "x": 334.7816579641293,
+ "y": -195.79623487510275,
+ "z": 1.0
+ },
+ {
+ "x": 334.7812938539547,
+ "y": -196.39905527795884,
+ "z": 1.0
+ },
+ {
+ "x": 334.7810511138383,
+ "y": -196.8009355465315,
+ "z": 1.0
+ },
+ {
+ "x": 334.78068700366373,
+ "y": -197.4037559493887,
+ "z": 1.0
+ },
+ {
+ "x": 334.78032289348914,
+ "y": -198.00657635224485,
+ "z": 1.0
+ },
+ {
+ "x": 334.78001946834354,
+ "y": -198.50892668796035,
+ "z": 1.0
+ },
+ {
+ "x": 334.77965535816895,
+ "y": -199.11174709081644,
+ "z": 1.0
+ },
+ {
+ "x": 334.77941261805256,
+ "y": -199.51362735938795,
+ "z": 1.0
+ },
+ {
+ "x": 334.7791091929071,
+ "y": -200.01597769510346,
+ "z": 1.0
+ },
+ {
+ "x": 334.7788057677616,
+ "y": -200.51832803081783,
+ "z": 1.0
+ },
+ {
+ "x": 334.7784416575869,
+ "y": -201.12114843367505,
+ "z": 1.0
+ },
+ {
+ "x": 334.7781382324414,
+ "y": -201.6234987693894,
+ "z": 1.0
+ },
+ {
+ "x": 334.7777741222668,
+ "y": -202.2263191722467,
+ "z": 1.0
+ },
+ {
+ "x": 334.7774100120922,
+ "y": -202.8291395751039,
+ "z": 1.0
+ },
+ {
+ "x": 334.77704590191763,
+ "y": -203.43195997796113,
+ "z": 1.0
+ },
+ {
+ "x": 334.77674247677214,
+ "y": -203.93431031367436,
+ "z": 1.0
+ },
+ {
+ "x": 334.77637836659744,
+ "y": -204.53713071653277,
+ "z": 1.0
+ },
+ {
+ "x": 334.77601425642285,
+ "y": -205.13995111939,
+ "z": 1.0
+ },
+ {
+ "x": 334.77571083127737,
+ "y": -205.64230145510322,
+ "z": 1.0
+ },
+ {
+ "x": 334.7754074061319,
+ "y": -206.14465179081873,
+ "z": 1.0
+ },
+ {
+ "x": 334.7751039809864,
+ "y": -206.6470021265331,
+ "z": 1.0
+ },
+ {
+ "x": 334.7747398708117,
+ "y": -207.24982252939145,
+ "z": 1.0
+ },
+ {
+ "x": 334.7744364456662,
+ "y": -207.75217286510355,
+ "z": 1.0
+ },
+ {
+ "x": 334.7740723354916,
+ "y": -208.35499326796304,
+ "z": 1.0
+ },
+ {
+ "x": 334.7737689103461,
+ "y": -208.85734360367633,
+ "z": 1.0
+ },
+ {
+ "x": 334.7735868552588,
+ "y": -209.15875380510494,
+ "z": 1.0
+ },
+ {
+ "x": 334.77322414725745,
+ "y": -209.7592527713511,
+ "z": 1.0
+ },
+ {
+ "x": 334.77298234192335,
+ "y": -210.1595854155138,
+ "z": 1.0
+ },
+ {
+ "x": 334.77274053658914,
+ "y": -210.55991805967767,
+ "z": 1.0
+ },
+ {
+ "x": 334.7724987312549,
+ "y": -210.96025070384263,
+ "z": 1.0
+ },
+ {
+ "x": 334.7722569259207,
+ "y": -211.36058334800651,
+ "z": 1.0
+ },
+ {
+ "x": 334.77189421791945,
+ "y": -211.96108231425114,
+ "z": 1.0
+ },
+ {
+ "x": 334.7715315099182,
+ "y": -212.56158128049805,
+ "z": 1.0
+ },
+ {
+ "x": 334.771289704584,
+ "y": -212.96191392466193,
+ "z": 1.0
+ },
+ {
+ "x": 334.77098744791624,
+ "y": -213.46232972986672,
+ "z": 1.0
+ },
+ {
+ "x": 334.770745642582,
+ "y": -213.8626623740306,
+ "z": 1.0
+ },
+ {
+ "x": 334.7704433859144,
+ "y": -214.3630781792354,
+ "z": 1.0
+ },
+ {
+ "x": 334.77014112924667,
+ "y": -214.86349398443912,
+ "z": 1.0
+ },
+ {
+ "x": 334.76983887257893,
+ "y": -215.3639097896439,
+ "z": 1.0
+ },
+ {
+ "x": 334.7695366159111,
+ "y": -215.8643255948499,
+ "z": 1.0
+ },
+ {
+ "x": 334.76917390790993,
+ "y": -216.46482456109453,
+ "z": 1.0
+ },
+ {
+ "x": 334.7689321025757,
+ "y": -216.86515720525836,
+ "z": 1.0
+ },
+ {
+ "x": 334.768629845908,
+ "y": -217.3655730104632,
+ "z": 1.0
+ },
+ {
+ "x": 334.76832758924013,
+ "y": -217.86598881566914,
+ "z": 1.0
+ },
+ {
+ "x": 334.76808578390603,
+ "y": -218.2663214598319,
+ "z": 1.0
+ },
+ {
+ "x": 334.76772307590477,
+ "y": -218.8668204260788,
+ "z": 1.0
+ },
+ {
+ "x": 334.76742081923703,
+ "y": -219.3672362312825,
+ "z": 1.0
+ },
+ {
+ "x": 334.7671790139028,
+ "y": -219.76756887544747,
+ "z": 1.0
+ },
+ {
+ "x": 334.7669372085686,
+ "y": -220.16790151961135,
+ "z": 1.0
+ },
+ {
+ "x": 334.76657450056734,
+ "y": -220.76840048585598,
+ "z": 1.0
+ },
+ {
+ "x": 334.76633269523313,
+ "y": -221.1687331300198,
+ "z": 1.0
+ },
+ {
+ "x": 334.7660908898989,
+ "y": -221.56906577418482,
+ "z": 1.0
+ },
+ {
+ "x": 334.7657886332312,
+ "y": -222.06948157938962,
+ "z": 1.0
+ },
+ {
+ "x": 334.7654259252299,
+ "y": -222.66998054563544,
+ "z": 1.0
+ },
+ {
+ "x": 334.76506321722866,
+ "y": -223.27047951188007,
+ "z": 1.0
+ },
+ {
+ "x": 334.7647609605609,
+ "y": -223.770895317086,
+ "z": 1.0
+ },
+ {
+ "x": 334.7645191552267,
+ "y": -224.17122796124988,
+ "z": 1.0
+ },
+ {
+ "x": 334.76415644722545,
+ "y": -224.7717269274945,
+ "z": 1.0
+ },
+ {
+ "x": 334.76391464189123,
+ "y": -225.17205957165953,
+ "z": 1.0
+ },
+ {
+ "x": 334.76355193388997,
+ "y": -225.77255853790416,
+ "z": 1.0
+ },
+ {
+ "x": 334.7633101285559,
+ "y": -226.17289118206799,
+ "z": 1.0
+ },
+ {
+ "x": 334.76306832322166,
+ "y": -226.573223826233,
+ "z": 1.0
+ },
+ {
+ "x": 334.7627660665539,
+ "y": -227.07363963143666,
+ "z": 1.0
+ },
+ {
+ "x": 334.7624638098862,
+ "y": -227.57405543664146,
+ "z": 1.0
+ },
+ {
+ "x": 334.7621011018849,
+ "y": -228.17455440288722,
+ "z": 1.0
+ },
+ {
+ "x": 334.76173839388355,
+ "y": -228.77505336913418,
+ "z": 1.0
+ },
+ {
+ "x": 334.7613756858823,
+ "y": -229.3755523353788,
+ "z": 1.0
+ },
+ {
+ "x": 334.7611338805481,
+ "y": -229.77588497954264,
+ "z": 1.0
+ },
+ {
+ "x": 334.760892075214,
+ "y": -230.17621762370766,
+ "z": 1.0
+ },
+ {
+ "x": 334.76065026987976,
+ "y": -230.57655026787148,
+ "z": 1.0
+ },
+ {
+ "x": 334.760348013212,
+ "y": -231.07696607307628,
+ "z": 1.0
+ },
+ {
+ "x": 334.7601062078778,
+ "y": -231.47729871724016,
+ "z": 1.0
+ },
+ {
+ "x": 334.7598644025436,
+ "y": -231.87763136140285,
+ "z": 1.0
+ },
+ {
+ "x": 334.7596225972095,
+ "y": -232.27796400556667,
+ "z": 1.0
+ },
+ {
+ "x": 334.7593807918753,
+ "y": -232.6782966497317,
+ "z": 1.0
+ },
+ {
+ "x": 334.7590180838739,
+ "y": -233.27879561597746,
+ "z": 1.0
+ },
+ {
+ "x": 334.7587762785398,
+ "y": -233.67912826014015,
+ "z": 1.0
+ },
+ {
+ "x": 334.7584740218721,
+ "y": -234.17954406534614,
+ "z": 1.0
+ },
+ {
+ "x": 334.7581113138708,
+ "y": -234.78004303159076,
+ "z": 1.0
+ },
+ {
+ "x": 334.75780905720296,
+ "y": -235.2804588367967,
+ "z": 1.0
+ },
+ {
+ "x": 334.75756725186886,
+ "y": -235.68079148095939,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 26,
+ "heading": [
+ -1.5714003377550525,
+ -1.5714003377552381,
+ -1.5714003377551264,
+ -1.5714003377550139,
+ -1.5714003377550139,
+ -1.5714003377550132,
+ -1.5714003377550128,
+ -1.5714003377550139,
+ -1.571400337755014,
+ -1.5714003377551538,
+ -1.5714003377551538,
+ -1.5714003377550139,
+ -1.5714003377550132,
+ -1.5714003377550125,
+ -1.5714003377550139,
+ -1.571400337755116,
+ -1.5714003377551162,
+ -1.5714003377550139,
+ -1.5714003377550125,
+ -1.5714003377550125,
+ -1.5714003377551162,
+ -1.5714003377551162,
+ -1.5714003377550132,
+ -1.5714003377550132,
+ -1.5714003377550132,
+ -1.5714003377550139,
+ -1.571400337755116,
+ -1.571400337755107,
+ -1.5714003377550139,
+ -1.5714003377550132,
+ -1.5714003377550125,
+ -1.5714003377551156,
+ -1.5714003377551167,
+ -1.5714003377550132,
+ -1.5714003377550125,
+ -1.571400337755014,
+ -1.5714003377551413,
+ -1.571400337755055,
+ -1.5714003377549701,
+ -1.5714003377551105,
+ -1.5714003377551105,
+ -1.5714003377550552,
+ -1.5714003377550168,
+ -1.5714003377550538,
+ -1.5714003377550798,
+ -1.5714003377550798,
+ -1.5714003377549535,
+ -1.5714003377549417,
+ -1.5714003377550552,
+ -1.5714003377551675,
+ -1.5714003377550338,
+ -1.5714003377549417,
+ -1.5714003377550798,
+ -1.5714003377551675,
+ -1.5714003377550798,
+ -1.571400337754941,
+ -1.5714003377550338,
+ -1.5714003377550798,
+ -1.5714003377551105,
+ -1.5714003377550552,
+ -1.5714003377550552,
+ -1.5714003377551105,
+ -1.571400337755079,
+ -1.5714003377550338,
+ -1.5714003377550172,
+ -1.5714003377550338,
+ -1.571400337755079,
+ -1.5714003377550552,
+ -1.5714003377550545,
+ -1.5714003377550545,
+ -1.5714003377549417,
+ -1.5714003377549686,
+ -1.5714003377550798,
+ -1.5714003377550552,
+ -1.5714003377550338,
+ -1.5714003377551107,
+ -1.5714003377551113,
+ -1.5714003377550552,
+ -1.5714003377549686,
+ -1.5714003377549686,
+ -1.5714003377550798,
+ -1.5714003377550798,
+ -1.5714003377551122,
+ -1.5714003377549701,
+ -1.5714003377549686,
+ -1.5714003377551675,
+ -1.5714003377550552,
+ -1.5714003377549535,
+ -1.5714003377550338,
+ -1.571400337755137,
+ -1.5714003377550798
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -0.003034251456028869,
+ "y": -5.02350335715505
+ },
+ {
+ "x": -0.00606850291092087,
+ "y": -10.047006714287363
+ },
+ {
+ "x": -0.006675353200762402,
+ "y": -11.051707385704503
+ },
+ {
+ "x": -0.0060685029097840015,
+ "y": -10.047006714275994
+ },
+ {
+ "x": -0.0060685029097840015,
+ "y": -10.047006714287363
+ },
+ {
+ "x": -0.007282203491740802,
+ "y": -12.056408057156318
+ },
+ {
+ "x": -0.0060685029097840015,
+ "y": -10.047006714275994
+ },
+ {
+ "x": -0.004854802327827201,
+ "y": -8.037605371418408
+ },
+ {
+ "x": -0.00485480232896407,
+ "y": -8.037605371441714
+ },
+ {
+ "x": -0.00485480232896407,
+ "y": -8.037605371441146
+ },
+ {
+ "x": -0.0060685029097840015,
+ "y": -10.047006714275426
+ },
+ {
+ "x": -0.0060685029097840015,
+ "y": -10.047006714287363
+ },
+ {
+ "x": -0.0060685029097840015,
+ "y": -10.047006714298732
+ },
+ {
+ "x": -0.007282203491740802,
+ "y": -12.05640805713358
+ },
+ {
+ "x": -0.00667535320189927,
+ "y": -11.05170738571644
+ },
+ {
+ "x": -0.00667535320189927,
+ "y": -11.051707385715872
+ },
+ {
+ "x": -0.0060685029097840015,
+ "y": -10.047006714275994
+ },
+ {
+ "x": -0.005461652618805601,
+ "y": -9.042306042870223
+ },
+ {
+ "x": -0.0060685029097840015,
+ "y": -10.047006714298732
+ },
+ {
+ "x": -0.00667535320189927,
+ "y": -11.051707385715872
+ },
+ {
+ "x": -0.00667535320189927,
+ "y": -11.051707385715872
+ },
+ {
+ "x": -0.006675353200762402,
+ "y": -11.05170738571644
+ },
+ {
+ "x": -0.007282203491740802,
+ "y": -12.05640805714495
+ },
+ {
+ "x": -0.007282203491740802,
+ "y": -12.056408057144381
+ },
+ {
+ "x": -0.006675353200762402,
+ "y": -11.051707385704503
+ },
+ {
+ "x": -0.00667535320189927,
+ "y": -11.05170738571644
+ },
+ {
+ "x": -0.00728220349287767,
+ "y": -12.056408057156318
+ },
+ {
+ "x": -0.006675353200762402,
+ "y": -11.051707385704503
+ },
+ {
+ "x": -0.0060685029097840015,
+ "y": -10.047006714287363
+ },
+ {
+ "x": -0.0060685029097840015,
+ "y": -10.047006714298732
+ },
+ {
+ "x": -0.00667535320189927,
+ "y": -11.05170738572724
+ },
+ {
+ "x": -0.00667535320189927,
+ "y": -11.051707385704503
+ },
+ {
+ "x": -0.006675353200762402,
+ "y": -11.051707385715872
+ },
+ {
+ "x": -0.006675353200762402,
+ "y": -11.05170738572781
+ },
+ {
+ "x": -0.004854802327827201,
+ "y": -8.037605371418977
+ },
+ {
+ "x": -0.005447630886692423,
+ "y": -9.019091676747735
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104088522
+ },
+ {
+ "x": -0.004836106683114849,
+ "y": -8.006652883265701
+ },
+ {
+ "x": -0.0048361066842517175,
+ "y": -8.006652883288439
+ },
+ {
+ "x": -0.0048361066842517175,
+ "y": -8.006652883288439
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104085111
+ },
+ {
+ "x": -0.007254160025240708,
+ "y": -12.00997932491532
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104107848
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686775
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686775
+ },
+ {
+ "x": -0.005440620018362097,
+ "y": -9.007484493686775
+ },
+ {
+ "x": -0.006045133353609344,
+ "y": -10.008316104085111
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104085111
+ },
+ {
+ "x": -0.006045133355883081,
+ "y": -10.008316104107848
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714506184
+ },
+ {
+ "x": -0.006045133353609344,
+ "y": -10.008316104084543
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686775
+ },
+ {
+ "x": -0.006045133355883081,
+ "y": -10.008316104107848
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686775
+ },
+ {
+ "x": -0.006045133353609344,
+ "y": -10.00831610409648
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714506184
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686775
+ },
+ {
+ "x": -0.0048361066842517175,
+ "y": -8.006652883288439
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104085111
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104084543
+ },
+ {
+ "x": -0.0048361066842517175,
+ "y": -8.006652883288439
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493698144
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714506184
+ },
+ {
+ "x": -0.007254160025240708,
+ "y": -12.00997932490452
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714505616
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493698144
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104085111
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.00831610409648
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.00831610409648
+ },
+ {
+ "x": -0.006045133353609344,
+ "y": -10.008316104084543
+ },
+ {
+ "x": -0.004836106683114849,
+ "y": -8.006652883288439
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686775
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104084543
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714505616
+ },
+ {
+ "x": -0.007254160026377576,
+ "y": -12.009979324927258
+ },
+ {
+ "x": -0.007254160026377576,
+ "y": -12.00997932491589
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104084543
+ },
+ {
+ "x": -0.004836106683114849,
+ "y": -8.006652883288439
+ },
+ {
+ "x": -0.004836106683114849,
+ "y": -8.006652883288439
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686206
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686775
+ },
+ {
+ "x": -0.0048361066842517175,
+ "y": -8.006652883265701
+ },
+ {
+ "x": -0.004836106683114849,
+ "y": -8.006652883265133
+ },
+ {
+ "x": -0.004836106683114849,
+ "y": -8.006652883288439
+ },
+ {
+ "x": -0.006045133355883081,
+ "y": -10.008316104107848
+ },
+ {
+ "x": -0.006045133354746213,
+ "y": -10.008316104084543
+ },
+ {
+ "x": -0.005440620018362097,
+ "y": -9.007484493686775
+ },
+ {
+ "x": -0.00664964668999346,
+ "y": -11.009147714506184
+ },
+ {
+ "x": -0.006649646691130329,
+ "y": -11.009147714505616
+ },
+ {
+ "x": -0.005440620019498965,
+ "y": -9.007484493686206
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 334.75756725186886,
+ "y": -235.68079148095939,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 329.263169991849,
+ "y": 1.9436457072073068,
+ "z": 1.0
+ },
+ {
+ "x": 328.7804214359283,
+ "y": 1.9852061222393989,
+ "z": 1.0
+ },
+ {
+ "x": 328.29636526433956,
+ "y": 2.0067022980379825,
+ "z": 1.0
+ },
+ {
+ "x": 327.63924552920065,
+ "y": 2.010254613561665,
+ "z": 1.0
+ },
+ {
+ "x": 327.2376770785852,
+ "y": 2.0104679414741553,
+ "z": 1.0
+ },
+ {
+ "x": 326.635324402662,
+ "y": 2.010787933342891,
+ "z": 1.0
+ },
+ {
+ "x": 326.03297172673877,
+ "y": 2.011107925211627,
+ "z": 1.0
+ },
+ {
+ "x": 325.6314032761233,
+ "y": 2.0113212531241174,
+ "z": 1.0
+ },
+ {
+ "x": 325.6314032761233,
+ "y": 2.0113212531241174,
+ "z": 1.0
+ },
+ {
+ "x": 325.2306859929232,
+ "y": 2.0115341288652,
+ "z": 1.0
+ },
+ {
+ "x": 324.63011428605995,
+ "y": 2.0118531746177477,
+ "z": 1.0
+ },
+ {
+ "x": 324.2297331481511,
+ "y": 2.012065871786113,
+ "z": 1.0
+ },
+ {
+ "x": 323.7292567257651,
+ "y": 2.0123317432465693,
+ "z": 1.0
+ },
+ {
+ "x": 323.22878030337904,
+ "y": 2.0125976147070257,
+ "z": 1.0
+ },
+ {
+ "x": 322.8283991654702,
+ "y": 2.0128103118753917,
+ "z": 1.0
+ },
+ {
+ "x": 322.227827458607,
+ "y": 2.0131293576279394,
+ "z": 1.0
+ },
+ {
+ "x": 321.8274463206982,
+ "y": 2.0133420547963046,
+ "z": 1.0
+ },
+ {
+ "x": 321.42706518278936,
+ "y": 2.0135547519646697,
+ "z": 1.0
+ },
+ {
+ "x": 320.9265887604033,
+ "y": 2.013820623425126,
+ "z": 1.0
+ },
+ {
+ "x": 320.32601705354006,
+ "y": 2.014139669177674,
+ "z": 1.0
+ },
+ {
+ "x": 319.825540631154,
+ "y": 2.0144055406381303,
+ "z": 1.0
+ },
+ {
+ "x": 319.4251594932452,
+ "y": 2.0146182378064954,
+ "z": 1.0
+ },
+ {
+ "x": 319.02477835533637,
+ "y": 2.0148309349748605,
+ "z": 1.0
+ },
+ {
+ "x": 318.5243019329503,
+ "y": 2.015096806435317,
+ "z": 1.0
+ },
+ {
+ "x": 318.1239207950415,
+ "y": 2.015309503603683,
+ "z": 1.0
+ },
+ {
+ "x": 317.62344437265546,
+ "y": 2.0155753750641394,
+ "z": 1.0
+ },
+ {
+ "x": 317.1229679502694,
+ "y": 2.015841246524596,
+ "z": 1.0
+ },
+ {
+ "x": 316.62249152788337,
+ "y": 2.0161071179850523,
+ "z": 1.0
+ },
+ {
+ "x": 316.1220151054973,
+ "y": 2.0163729894455087,
+ "z": 1.0
+ },
+ {
+ "x": 315.62153868311134,
+ "y": 2.016638860905965,
+ "z": 1.0
+ },
+ {
+ "x": 315.1210622607253,
+ "y": 2.0169047323664215,
+ "z": 1.0
+ },
+ {
+ "x": 314.62058583833925,
+ "y": 2.017170603826878,
+ "z": 1.0
+ },
+ {
+ "x": 314.020014131476,
+ "y": 2.0174896495794266,
+ "z": 1.0
+ },
+ {
+ "x": 313.51953770908995,
+ "y": 2.017755521039883,
+ "z": 1.0
+ },
+ {
+ "x": 313.01906128670396,
+ "y": 2.0180213925003394,
+ "z": 1.0
+ },
+ {
+ "x": 312.5185848643179,
+ "y": 2.018287263960796,
+ "z": 1.0
+ },
+ {
+ "x": 312.1182037264091,
+ "y": 2.018499961129161,
+ "z": 1.0
+ },
+ {
+ "x": 311.51763201954583,
+ "y": 2.0188190068817087,
+ "z": 1.0
+ },
+ {
+ "x": 311.117250881637,
+ "y": 2.019031704050074,
+ "z": 1.0
+ },
+ {
+ "x": 310.61677445925096,
+ "y": 2.0192975755105302,
+ "z": 1.0
+ },
+ {
+ "x": 310.1162980368649,
+ "y": 2.0195634469709867,
+ "z": 1.0
+ },
+ {
+ "x": 309.51572633000166,
+ "y": 2.0198824927235353,
+ "z": 1.0
+ },
+ {
+ "x": 309.11534519209283,
+ "y": 2.0200951898919004,
+ "z": 1.0
+ },
+ {
+ "x": 308.5147734852296,
+ "y": 2.020414235644448,
+ "z": 1.0
+ },
+ {
+ "x": 308.1143923473208,
+ "y": 2.0206269328128132,
+ "z": 1.0
+ },
+ {
+ "x": 307.7140112094119,
+ "y": 2.0208396299811784,
+ "z": 1.0
+ },
+ {
+ "x": 307.3136300715031,
+ "y": 2.0210523271495435,
+ "z": 1.0
+ },
+ {
+ "x": 306.7130583646399,
+ "y": 2.0213713729020912,
+ "z": 1.0
+ },
+ {
+ "x": 306.1124866577766,
+ "y": 2.021690418654639,
+ "z": 1.0
+ },
+ {
+ "x": 305.6120102353906,
+ "y": 2.0219562901150954,
+ "z": 1.0
+ },
+ {
+ "x": 305.11153381300454,
+ "y": 2.0222221615755527,
+ "z": 1.0
+ },
+ {
+ "x": 304.7111526750957,
+ "y": 2.022434858743918,
+ "z": 1.0
+ },
+ {
+ "x": 304.2106762527097,
+ "y": 2.0227007302043742,
+ "z": 1.0
+ },
+ {
+ "x": 303.7101998303237,
+ "y": 2.0229666016648307,
+ "z": 1.0
+ },
+ {
+ "x": 303.20972340793764,
+ "y": 2.023232473125287,
+ "z": 1.0
+ },
+ {
+ "x": 302.6091517010744,
+ "y": 2.023551518877835,
+ "z": 1.0
+ },
+ {
+ "x": 302.20877056316556,
+ "y": 2.0237642160462,
+ "z": 1.0
+ },
+ {
+ "x": 301.6081988563023,
+ "y": 2.0240832617987476,
+ "z": 1.0
+ },
+ {
+ "x": 301.10772243391625,
+ "y": 2.024349133259204,
+ "z": 1.0
+ },
+ {
+ "x": 300.7073412960074,
+ "y": 2.02456183042757,
+ "z": 1.0
+ },
+ {
+ "x": 300.1067695891442,
+ "y": 2.024880876180118,
+ "z": 1.0
+ },
+ {
+ "x": 299.6062931667582,
+ "y": 2.0251467476405742,
+ "z": 1.0
+ },
+ {
+ "x": 299.20591202884935,
+ "y": 2.0253594448089394,
+ "z": 1.0
+ },
+ {
+ "x": 298.7054356064633,
+ "y": 2.025625316269396,
+ "z": 1.0
+ },
+ {
+ "x": 298.10486389960005,
+ "y": 2.0259443620219435,
+ "z": 1.0
+ },
+ {
+ "x": 297.7044827616912,
+ "y": 2.0261570591903086,
+ "z": 1.0
+ },
+ {
+ "x": 297.2040063393052,
+ "y": 2.026422930650765,
+ "z": 1.0
+ },
+ {
+ "x": 296.80362520139636,
+ "y": 2.02663562781913,
+ "z": 1.0
+ },
+ {
+ "x": 296.3031487790103,
+ "y": 2.0269014992795875,
+ "z": 1.0
+ },
+ {
+ "x": 295.7025770721471,
+ "y": 2.0272205450321352,
+ "z": 1.0
+ },
+ {
+ "x": 295.10200536528384,
+ "y": 2.027539590784683,
+ "z": 1.0
+ },
+ {
+ "x": 294.5014336584206,
+ "y": 2.0278586365372306,
+ "z": 1.0
+ },
+ {
+ "x": 293.9008619515574,
+ "y": 2.0281776822897783,
+ "z": 1.0
+ },
+ {
+ "x": 293.50048081364855,
+ "y": 2.0283903794581435,
+ "z": 1.0
+ },
+ {
+ "x": 293.1000996757397,
+ "y": 2.0286030766265086,
+ "z": 1.0
+ },
+ {
+ "x": 292.6997185378309,
+ "y": 2.0288157737948738,
+ "z": 1.0
+ },
+ {
+ "x": 292.19924211544486,
+ "y": 2.02908164525533,
+ "z": 1.0
+ },
+ {
+ "x": 291.7988609775361,
+ "y": 2.0292943424236953,
+ "z": 1.0
+ },
+ {
+ "x": 291.19828927067283,
+ "y": 2.029613388176244,
+ "z": 1.0
+ },
+ {
+ "x": 290.797908132764,
+ "y": 2.029826085344609,
+ "z": 1.0
+ },
+ {
+ "x": 290.2965826672941,
+ "y": 2.030018519555301,
+ "z": 1.0
+ },
+ {
+ "x": 289.6960108791071,
+ "y": 2.0300826181407468,
+ "z": 1.0
+ },
+ {
+ "x": 289.2956296869824,
+ "y": 2.030125350531044,
+ "z": 1.0
+ },
+ {
+ "x": 288.69505789879537,
+ "y": 2.03018944911649,
+ "z": 1.0
+ },
+ {
+ "x": 288.09448611060833,
+ "y": 2.0302535477019354,
+ "z": 1.0
+ },
+ {
+ "x": 287.6941049184836,
+ "y": 2.030296280092233,
+ "z": 1.0
+ },
+ {
+ "x": 287.29372372635896,
+ "y": 2.0303390124825302,
+ "z": 1.0
+ },
+ {
+ "x": 286.6931519381719,
+ "y": 2.030403111067976,
+ "z": 1.0
+ },
+ {
+ "x": 286.0925801499849,
+ "y": 2.0304672096534215,
+ "z": 1.0
+ },
+ {
+ "x": 285.592103659829,
+ "y": 2.0305206251412926,
+ "z": 1.0
+ },
+ {
+ "x": 285.09162716967313,
+ "y": 2.0305740406291646,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 27,
+ "heading": [
+ 3.1391704606677107,
+ 3.0557131807973996,
+ 3.0764632585844023,
+ 3.1196464578883,
+ 3.138035772908013,
+ 3.141061416905,
+ 3.141061416905,
+ 3.141061416905,
+ 3.141061416905,
+ 3.141061416905023,
+ 3.1410614169050093,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049986,
+ 3.1410614169049986,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049986,
+ 3.1410614169049986,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.141061416904999,
+ 3.141061416904999,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.141061416904999,
+ 3.1410614169049986,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.141061416905,
+ 3.141061416905,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049986,
+ 3.1410614169049986,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049986,
+ 3.1410614169049986,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049986,
+ 3.141061416904999,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049995,
+ 3.1410614169049986,
+ 3.1410614169049986,
+ 3.141143359606275,
+ 3.1413598435064105,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.1414859243253432,
+ 3.1414859243253437,
+ 3.1414859243253437,
+ 3.141485924325344,
+ 3.1414859243253437
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -4.827485559206934,
+ "y": 0.4156041503209207
+ },
+ {
+ "x": -9.668047275094409,
+ "y": 0.6305659083067572
+ },
+ {
+ "x": -11.411759067276535,
+ "y": 0.2504849132226594
+ },
+ {
+ "x": -10.58688185754363,
+ "y": 0.03765643436172805
+ },
+ {
+ "x": -10.039211265386712,
+ "y": 0.005333197812262824
+ },
+ {
+ "x": -12.047053518464281,
+ "y": 0.006399837374715389
+ },
+ {
+ "x": -10.039211265386712,
+ "y": 0.005333197812262824
+ },
+ {
+ "x": -4.015684506154571,
+ "y": 0.0021332791249051297
+ },
+ {
+ "x": -4.007172832000947,
+ "y": 0.0021287574108264096
+ },
+ {
+ "x": -10.012889900633581,
+ "y": 0.005319214936303496
+ },
+ {
+ "x": -10.009528447720868,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288215629
+ },
+ {
+ "x": -10.009528447720868,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288224511
+ },
+ {
+ "x": -10.0095284477203,
+ "y": 0.005317429209137359
+ },
+ {
+ "x": -10.0095284477203,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -8.007622758176467,
+ "y": 0.0042539433673027816
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288215629
+ },
+ {
+ "x": -11.010481292493068,
+ "y": 0.005849172130041325
+ },
+ {
+ "x": -11.010481292493068,
+ "y": 0.005849172130041325
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288215629
+ },
+ {
+ "x": -8.007622758176467,
+ "y": 0.0042539433673027816
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288215629
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288224511
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288224511
+ },
+ {
+ "x": -10.009528447720868,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -10.009528447720868,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -10.009528447720868,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -10.0095284477203,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -10.0095284477203,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -10.009528447720868,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -11.010481292493068,
+ "y": 0.005849172130050206
+ },
+ {
+ "x": -11.010481292493068,
+ "y": 0.005849172130050206
+ },
+ {
+ "x": -10.0095284477203,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -10.0095284477203,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288215629
+ },
+ {
+ "x": -10.009528447720868,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -10.009528447720868,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288215629
+ },
+ {
+ "x": -10.009528447720868,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -11.010481292493068,
+ "y": 0.005849172130050206
+ },
+ {
+ "x": -10.009528447720868,
+ "y": 0.005317429209137359
+ },
+ {
+ "x": -10.0095284477203,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -10.0095284477203,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -8.007622758177035,
+ "y": 0.0042539433673027816
+ },
+ {
+ "x": -8.007622758177035,
+ "y": 0.0042539433673027816
+ },
+ {
+ "x": -10.0095284477203,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -12.0114341372647,
+ "y": 0.006380915050954172
+ },
+ {
+ "x": -11.010481292493068,
+ "y": 0.005849172130041325
+ },
+ {
+ "x": -10.009528447720868,
+ "y": 0.005317429209137359
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288224511
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288215629
+ },
+ {
+ "x": -10.0095284477203,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -10.0095284477203,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -11.010481292493068,
+ "y": 0.005849172130041325
+ },
+ {
+ "x": -10.009528447720868,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -10.009528447720868,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -11.010481292493068,
+ "y": 0.005849172130041325
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288224511
+ },
+ {
+ "x": -10.0095284477203,
+ "y": 0.005317429209137359
+ },
+ {
+ "x": -11.0104812924925,
+ "y": 0.005849172130041325
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288215629
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288215629
+ },
+ {
+ "x": -11.010481292493068,
+ "y": 0.005849172130041325
+ },
+ {
+ "x": -10.009528447720868,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288215629
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288215629
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288224511
+ },
+ {
+ "x": -11.0104812924925,
+ "y": 0.005849172130050206
+ },
+ {
+ "x": -12.0114341372647,
+ "y": 0.006380915050954172
+ },
+ {
+ "x": -12.011434137265269,
+ "y": 0.006380915050954172
+ },
+ {
+ "x": -12.0114341372647,
+ "y": 0.006380915050954172
+ },
+ {
+ "x": -10.0095284477203,
+ "y": 0.005317429209128477
+ },
+ {
+ "x": -8.007622758176467,
+ "y": 0.0042539433673027816
+ },
+ {
+ "x": -8.007622758176467,
+ "y": 0.0042539433673027816
+ },
+ {
+ "x": -9.008575602948667,
+ "y": 0.004785686288215629
+ },
+ {
+ "x": -9.008575602948099,
+ "y": 0.004785686288215629
+ },
+ {
+ "x": -10.0095284477203,
+ "y": 0.005317429209137359
+ },
+ {
+ "x": -10.009528447720868,
+ "y": 0.005317429209137359
+ },
+ {
+ "x": -9.017066033787273,
+ "y": 0.0040513137905717755
+ },
+ {
+ "x": -11.018972536568867,
+ "y": 0.002565327961376873
+ },
+ {
+ "x": -10.009529803116948,
+ "y": 0.0010683097574304412
+ },
+ {
+ "x": -10.009529803117516,
+ "y": 0.0010683097574304412
+ },
+ {
+ "x": -12.011435763740792,
+ "y": 0.0012819717089129767
+ },
+ {
+ "x": -10.009529803117516,
+ "y": 0.0010683097574304412
+ },
+ {
+ "x": -8.007623842493672,
+ "y": 0.0008546478059479057
+ },
+ {
+ "x": -10.009529803116948,
+ "y": 0.0010683097574304412
+ },
+ {
+ "x": -12.011435763740792,
+ "y": 0.0012819717089129767
+ },
+ {
+ "x": -11.010482783429438,
+ "y": 0.001175140733167268
+ },
+ {
+ "x": -10.009529803117516,
+ "y": 0.0010683097574304412
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 285.09162716967313,
+ "y": 2.0305740406291646,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 104.12054777946341,
+ "y": -133.416111777875,
+ "z": 1.0
+ },
+ {
+ "x": 104.62081546714708,
+ "y": -133.4163352943318,
+ "z": 1.0
+ },
+ {
+ "x": 105.22113669236818,
+ "y": -133.41660351407995,
+ "z": 1.0
+ },
+ {
+ "x": 105.62135084251558,
+ "y": -133.41678232724541,
+ "z": 1.0
+ },
+ {
+ "x": 106.22167206773668,
+ "y": -133.41705054699358,
+ "z": 1.0
+ },
+ {
+ "x": 106.82199329295777,
+ "y": -133.41731876674174,
+ "z": 1.0
+ },
+ {
+ "x": 107.22220744310516,
+ "y": -133.4174975799072,
+ "z": 1.0
+ },
+ {
+ "x": 107.62242159325257,
+ "y": -133.41767639307264,
+ "z": 1.0
+ },
+ {
+ "x": 108.02263574339996,
+ "y": -133.4178552062381,
+ "z": 1.0
+ },
+ {
+ "x": 108.52290343108422,
+ "y": -133.4180787226949,
+ "z": 1.0
+ },
+ {
+ "x": 109.12322465630531,
+ "y": -133.41834694244307,
+ "z": 1.0
+ },
+ {
+ "x": 109.5234388064527,
+ "y": -133.41852575560853,
+ "z": 1.0
+ },
+ {
+ "x": 110.02370649413696,
+ "y": -133.41874927206533,
+ "z": 1.0
+ },
+ {
+ "x": 110.52397418182177,
+ "y": -133.41897278852215,
+ "z": 1.0
+ },
+ {
+ "x": 111.02424186950545,
+ "y": -133.41919630497895,
+ "z": 1.0
+ },
+ {
+ "x": 111.42445601965285,
+ "y": -133.4193751181444,
+ "z": 1.0
+ },
+ {
+ "x": 111.9247237073371,
+ "y": -133.41959863460121,
+ "z": 1.0
+ },
+ {
+ "x": 112.52504493255819,
+ "y": -133.41986685434938,
+ "z": 1.0
+ },
+ {
+ "x": 113.1253661577793,
+ "y": -133.42013507409754,
+ "z": 1.0
+ },
+ {
+ "x": 113.52558030792669,
+ "y": -133.420313887263,
+ "z": 1.0
+ },
+ {
+ "x": 114.02584799561093,
+ "y": -133.4205374037198,
+ "z": 1.0
+ },
+ {
+ "x": 114.52611568329576,
+ "y": -133.42076092017663,
+ "z": 1.0
+ },
+ {
+ "x": 115.02638337097943,
+ "y": -133.42098443663343,
+ "z": 1.0
+ },
+ {
+ "x": 115.52665105866369,
+ "y": -133.42120795309023,
+ "z": 1.0
+ },
+ {
+ "x": 115.92686520881108,
+ "y": -133.4213867662557,
+ "z": 1.0
+ },
+ {
+ "x": 116.52718643403217,
+ "y": -133.42165498600386,
+ "z": 1.0
+ },
+ {
+ "x": 116.92740058418013,
+ "y": -133.42183379916932,
+ "z": 1.0
+ },
+ {
+ "x": 117.32761473432697,
+ "y": -133.42201261233475,
+ "z": 1.0
+ },
+ {
+ "x": 117.92793595954807,
+ "y": -133.42228083208292,
+ "z": 1.0
+ },
+ {
+ "x": 118.52825718476973,
+ "y": -133.4225490518311,
+ "z": 1.0
+ },
+ {
+ "x": 119.0285248724534,
+ "y": -133.4227725682879,
+ "z": 1.0
+ },
+ {
+ "x": 119.62884609767448,
+ "y": -133.42304078803608,
+ "z": 1.0
+ },
+ {
+ "x": 120.22916732289558,
+ "y": -133.42330900778424,
+ "z": 1.0
+ },
+ {
+ "x": 120.72943501057982,
+ "y": -133.42353252424107,
+ "z": 1.0
+ },
+ {
+ "x": 121.32975623580091,
+ "y": -133.42380074398923,
+ "z": 1.0
+ },
+ {
+ "x": 121.83002392348516,
+ "y": -133.42402426044603,
+ "z": 1.0
+ },
+ {
+ "x": 122.3302916111694,
+ "y": -133.42424777690286,
+ "z": 1.0
+ },
+ {
+ "x": 122.83055929885364,
+ "y": -133.42447129335966,
+ "z": 1.0
+ },
+ {
+ "x": 123.43088052407474,
+ "y": -133.42473951310782,
+ "z": 1.0
+ },
+ {
+ "x": 123.93114821175898,
+ "y": -133.42496302956465,
+ "z": 1.0
+ },
+ {
+ "x": 124.43141589944322,
+ "y": -133.42518654602145,
+ "z": 1.0
+ },
+ {
+ "x": 124.83163004959118,
+ "y": -133.4253653591869,
+ "z": 1.0
+ },
+ {
+ "x": 125.33189773727486,
+ "y": -133.4255888756437,
+ "z": 1.0
+ },
+ {
+ "x": 125.73211188742226,
+ "y": -133.42576768880915,
+ "z": 1.0
+ },
+ {
+ "x": 126.2323795751065,
+ "y": -133.42599120526597,
+ "z": 1.0
+ },
+ {
+ "x": 126.73264726279075,
+ "y": -133.42621472172277,
+ "z": 1.0
+ },
+ {
+ "x": 127.33296848801184,
+ "y": -133.42648294147094,
+ "z": 1.0
+ },
+ {
+ "x": 127.93328971323294,
+ "y": -133.42675116121913,
+ "z": 1.0
+ },
+ {
+ "x": 128.33350386338032,
+ "y": -133.42692997438456,
+ "z": 1.0
+ },
+ {
+ "x": 128.83377155106513,
+ "y": -133.4271534908414,
+ "z": 1.0
+ },
+ {
+ "x": 129.43409277628567,
+ "y": -133.42742171058956,
+ "z": 1.0
+ },
+ {
+ "x": 130.03441400150675,
+ "y": -133.42768993033772,
+ "z": 1.0
+ },
+ {
+ "x": 130.534681689191,
+ "y": -133.42791344679452,
+ "z": 1.0
+ },
+ {
+ "x": 131.1350029144121,
+ "y": -133.4281816665427,
+ "z": 1.0
+ },
+ {
+ "x": 131.53521706455948,
+ "y": -133.42836047970815,
+ "z": 1.0
+ },
+ {
+ "x": 132.13553828978058,
+ "y": -133.4286286994563,
+ "z": 1.0
+ },
+ {
+ "x": 132.73585951500166,
+ "y": -133.4288969192045,
+ "z": 1.0
+ },
+ {
+ "x": 133.2361272026859,
+ "y": -133.4291204356613,
+ "z": 1.0
+ },
+ {
+ "x": 133.83644842790702,
+ "y": -133.42938865540947,
+ "z": 1.0
+ },
+ {
+ "x": 134.23666257805442,
+ "y": -133.42956746857493,
+ "z": 1.0
+ },
+ {
+ "x": 134.7369302657387,
+ "y": -133.42979098503173,
+ "z": 1.0
+ },
+ {
+ "x": 135.3372514909598,
+ "y": -133.4300592047799,
+ "z": 1.0
+ },
+ {
+ "x": 135.7374656411072,
+ "y": -133.43023801794536,
+ "z": 1.0
+ },
+ {
+ "x": 136.33778686632832,
+ "y": -133.43050623769352,
+ "z": 1.0
+ },
+ {
+ "x": 136.8380545540126,
+ "y": -133.43072975415032,
+ "z": 1.0
+ },
+ {
+ "x": 137.33832224169683,
+ "y": -133.43095327060715,
+ "z": 1.0
+ },
+ {
+ "x": 137.8385899293811,
+ "y": -133.43117678706395,
+ "z": 1.0
+ },
+ {
+ "x": 138.2388040795285,
+ "y": -133.4313556002294,
+ "z": 1.0
+ },
+ {
+ "x": 138.73907176721278,
+ "y": -133.4315791166862,
+ "z": 1.0
+ },
+ {
+ "x": 139.13928591736075,
+ "y": -133.43175792985167,
+ "z": 1.0
+ },
+ {
+ "x": 139.63955360504445,
+ "y": -133.43198144630847,
+ "z": 1.0
+ },
+ {
+ "x": 140.03976775519186,
+ "y": -133.4321602594739,
+ "z": 1.0
+ },
+ {
+ "x": 140.43998190533927,
+ "y": -133.43233907263937,
+ "z": 1.0
+ },
+ {
+ "x": 140.94024959302354,
+ "y": -133.43256258909616,
+ "z": 1.0
+ },
+ {
+ "x": 141.34046374317094,
+ "y": -133.43274140226163,
+ "z": 1.0
+ },
+ {
+ "x": 141.74067789331835,
+ "y": -133.43292021542706,
+ "z": 1.0
+ },
+ {
+ "x": 142.2409455810026,
+ "y": -133.4331437318839,
+ "z": 1.0
+ },
+ {
+ "x": 142.64115973115,
+ "y": -133.43332254504932,
+ "z": 1.0
+ },
+ {
+ "x": 143.14142741883484,
+ "y": -133.43354606150615,
+ "z": 1.0
+ },
+ {
+ "x": 143.64169510651854,
+ "y": -133.43376957796295,
+ "z": 1.0
+ },
+ {
+ "x": 144.24201633173965,
+ "y": -133.4340377977111,
+ "z": 1.0
+ },
+ {
+ "x": 144.7422840194245,
+ "y": -133.43426131416794,
+ "z": 1.0
+ },
+ {
+ "x": 145.14249816957133,
+ "y": -133.43444012733337,
+ "z": 1.0
+ },
+ {
+ "x": 145.74281939479243,
+ "y": -133.43470834708154,
+ "z": 1.0
+ },
+ {
+ "x": 146.2430870824767,
+ "y": -133.43493186353837,
+ "z": 1.0
+ },
+ {
+ "x": 146.74335477016095,
+ "y": -133.43515537999517,
+ "z": 1.0
+ },
+ {
+ "x": 147.14356892030892,
+ "y": -133.43533419316063,
+ "z": 1.0
+ },
+ {
+ "x": 147.54378307045576,
+ "y": -133.43551300632606,
+ "z": 1.0
+ },
+ {
+ "x": 148.04405075814003,
+ "y": -133.43573652278286,
+ "z": 1.0
+ },
+ {
+ "x": 148.44426490828744,
+ "y": -133.43591533594832,
+ "z": 1.0
+ },
+ {
+ "x": 148.9445325959717,
+ "y": -133.43613885240512,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 28,
+ "heading": [
+ -0.0004467936815410096,
+ -0.00044679368152074914,
+ -0.0004467936815256359,
+ -0.0004467936815486416,
+ -0.0004467936815486416,
+ -0.0004467936815297082,
+ -0.00044679368154864794,
+ -0.0004467936815415416,
+ -0.0004467936815415416,
+ -0.000446793681545486,
+ -0.00044679368152539934,
+ -0.00044679368154864794,
+ -0.000446793681545486,
+ -0.0004467936815483878,
+ -0.00044679368154864794,
+ -0.00044679368151420533,
+ -0.000446793681545486,
+ -0.0004467936815512292,
+ -0.0004467936815297029,
+ -0.0004467936815486416,
+ -0.00044679368154549307,
+ -0.0004467936815483878,
+ -0.0004467936815486416,
+ -0.00044679368152048893,
+ -0.000446793681545486,
+ -0.00044679368154864794,
+ -0.0004467936815483941,
+ -0.0004467936815415416,
+ -0.00044679368152048893,
+ -0.00044679368155316874,
+ -0.0004467936815512292,
+ -0.00044679368152564166,
+ -0.0004467936815297135,
+ -0.0004467936815512292,
+ -0.0004467936815512292,
+ -0.00044679368152540514,
+ -0.00044679368154864794,
+ -0.00044679368154864794,
+ -0.00044679368152540514,
+ -0.0004467936815512292,
+ -0.00044679368154864794,
+ -0.00044679368154521107,
+ -0.00044679368154549307,
+ -0.00044679368151420533,
+ -0.000446793681545486,
+ -0.00044679368154864794,
+ -0.00044679368152540514,
+ -0.00044679368155338026,
+ -0.0004467936815486543,
+ -0.0004467936815452181,
+ -0.00044679368155122346,
+ -0.0004467936815299197,
+ -0.0004467936815254109,
+ -0.00044679368155122346,
+ -0.00044679368154864794,
+ -0.00044679368152024146,
+ -0.00044679368155338026,
+ -0.000446793681551235,
+ -0.00044679368152539934,
+ -0.00044679368154863525,
+ -0.00044679368154547193,
+ -0.00044679368152538784,
+ -0.00044679368154863525,
+ -0.00044679368154863525,
+ -0.00044679368152538784,
+ -0.00044679368154863525,
+ -0.00044679368154863525,
+ -0.00044679368154547193,
+ -0.00044679368154547193,
+ -0.0004467936815451899,
+ -0.00044679368154547193,
+ -0.0004467936815141912,
+ -0.0004467936815415336,
+ -0.00044679368154547193,
+ -0.00044679368154547193,
+ -0.0004467936815415336,
+ -0.000446793681545486,
+ -0.000446793681545486,
+ -0.0004467936815451899,
+ -0.00044679368154862257,
+ -0.00044679368152561856,
+ -0.00044679368155098114,
+ -0.00044679368154547193,
+ -0.0004467936815204826,
+ -0.0004467936815512119,
+ -0.00044679368154863525,
+ -0.000446793681545204,
+ -0.0004467936815415336,
+ -0.0004467936815141912,
+ -0.00044679368154547193,
+ -0.00044679368154547193
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": 5.002676876836745,
+ "y": -0.0022351645679918875
+ },
+ {
+ "x": 11.005889129047688,
+ "y": -0.004917362049638996
+ },
+ {
+ "x": 10.005353753685,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 10.005353753685,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 12.006424504421886,
+ "y": -0.005364394963294217
+ },
+ {
+ "x": 10.005353753684858,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 8.004283002947972,
+ "y": -0.00357626330895755
+ },
+ {
+ "x": 8.004283002947972,
+ "y": -0.00357626330895755
+ },
+ {
+ "x": 9.004818378316486,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 11.005889129053514,
+ "y": -0.004917362049638996
+ },
+ {
+ "x": 10.005353753684858,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 9.004818378316486,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 10.005353753690684,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 10.005353753684858,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 9.004818378310802,
+ "y": -0.004023296222328554
+ },
+ {
+ "x": 9.004818378316486,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 11.005889129053372,
+ "y": -0.004917362049923213
+ },
+ {
+ "x": 12.006424504422029,
+ "y": -0.005364394963294217
+ },
+ {
+ "x": 10.005353753685,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 9.004818378316344,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 10.005353753690684,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 10.005353753685,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 10.005353753679316,
+ "y": -0.004470329135983775
+ },
+ {
+ "x": 9.004818378316486,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 10.005353753684858,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 10.005353753690542,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 8.004283002947972,
+ "y": -0.00357626330895755
+ },
+ {
+ "x": 10.005353753679316,
+ "y": -0.004470329135983775
+ },
+ {
+ "x": 12.00642450442757,
+ "y": -0.005364394963578434
+ },
+ {
+ "x": 11.005889129053372,
+ "y": -0.004917362049923213
+ },
+ {
+ "x": 11.005889129047546,
+ "y": -0.004917362049638996
+ },
+ {
+ "x": 12.006424504421744,
+ "y": -0.005364394963294217
+ },
+ {
+ "x": 11.005889129053372,
+ "y": -0.004917362049923213
+ },
+ {
+ "x": 11.005889129053372,
+ "y": -0.004917362049923213
+ },
+ {
+ "x": 11.005889129053372,
+ "y": -0.004917362049638996
+ },
+ {
+ "x": 10.005353753684858,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 10.005353753684858,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 11.005889129053372,
+ "y": -0.004917362049638996
+ },
+ {
+ "x": 11.005889129053372,
+ "y": -0.004917362049923213
+ },
+ {
+ "x": 10.005353753684858,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 9.004818378322028,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 9.004818378316344,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 9.004818378310802,
+ "y": -0.004023296222328554
+ },
+ {
+ "x": 9.004818378316486,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 10.005353753684858,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 11.005889129053372,
+ "y": -0.004917362049638996
+ },
+ {
+ "x": 12.006424504421886,
+ "y": -0.005364394963578434
+ },
+ {
+ "x": 10.005353753684716,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 9.004818378321886,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 11.005889129053514,
+ "y": -0.004917362049923213
+ },
+ {
+ "x": 12.006424504416202,
+ "y": -0.005364394963294217
+ },
+ {
+ "x": 11.00588912905323,
+ "y": -0.004917362049638996
+ },
+ {
+ "x": 11.005889129053514,
+ "y": -0.004917362049923213
+ },
+ {
+ "x": 10.005353753684858,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 10.005353753684858,
+ "y": -0.004470329135983775
+ },
+ {
+ "x": 12.006424504421886,
+ "y": -0.005364394963578434
+ },
+ {
+ "x": 11.00588912905323,
+ "y": -0.004917362049923213
+ },
+ {
+ "x": 11.005889129053514,
+ "y": -0.004917362049638996
+ },
+ {
+ "x": 10.005353753685142,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 9.00481837831677,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 11.005889129053799,
+ "y": -0.004917362049638996
+ },
+ {
+ "x": 10.005353753685142,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 10.005353753685142,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 11.005889129053799,
+ "y": -0.004917362049638996
+ },
+ {
+ "x": 10.005353753685142,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 10.005353753685142,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 9.00481837831677,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 9.00481837831677,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 9.004818378322454,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 9.00481837831677,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 9.004818378311086,
+ "y": -0.004023296222328554
+ },
+ {
+ "x": 8.004283002948114,
+ "y": -0.00357626330895755
+ },
+ {
+ "x": 9.00481837831677,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 9.00481837831677,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 8.004283002948114,
+ "y": -0.00357626330895755
+ },
+ {
+ "x": 9.004818378316486,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 9.004818378316486,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 9.004818378322454,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 10.005353753685426,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 11.005889129048114,
+ "y": -0.004917362049638996
+ },
+ {
+ "x": 11.005889129059483,
+ "y": -0.004917362049923213
+ },
+ {
+ "x": 9.00481837831677,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 10.005353753679458,
+ "y": -0.004470329135983775
+ },
+ {
+ "x": 11.005889129053799,
+ "y": -0.004917362049923213
+ },
+ {
+ "x": 10.005353753685142,
+ "y": -0.004470329136267992
+ },
+ {
+ "x": 9.00481837832217,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 8.004283002948114,
+ "y": -0.00357626330895755
+ },
+ {
+ "x": 9.004818378311086,
+ "y": -0.004023296222328554
+ },
+ {
+ "x": 9.00481837831677,
+ "y": -0.004023296222612771
+ },
+ {
+ "x": 9.00481837831677,
+ "y": -0.004023296222612771
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 148.9445325959717,
+ "y": -133.43613885240512,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 88.3788047961567,
+ "y": -57.90372801630079,
+ "z": 1.0
+ },
+ {
+ "x": 88.37888114956165,
+ "y": -58.40601111552,
+ "z": 1.0
+ },
+ {
+ "x": 88.37894223228558,
+ "y": -58.80783759489587,
+ "z": 1.0
+ },
+ {
+ "x": 88.3790338563715,
+ "y": -59.410577313959266,
+ "z": 1.0
+ },
+ {
+ "x": 88.37909493909547,
+ "y": -59.81240379333458,
+ "z": 1.0
+ },
+ {
+ "x": 88.37917129250039,
+ "y": -60.31468689255435,
+ "z": 1.0
+ },
+ {
+ "x": 88.37924764590532,
+ "y": -60.816969991773846,
+ "z": 1.0
+ },
+ {
+ "x": 88.37932399931026,
+ "y": -61.31925309099334,
+ "z": 1.0
+ },
+ {
+ "x": 88.37941562339618,
+ "y": -61.92199281005672,
+ "z": 1.0
+ },
+ {
+ "x": 88.3794919768011,
+ "y": -62.42427590927622,
+ "z": 1.0
+ },
+ {
+ "x": 88.37955305952507,
+ "y": -62.82610238865182,
+ "z": 1.0
+ },
+ {
+ "x": 88.37964468361099,
+ "y": -63.4288421077152,
+ "z": 1.0
+ },
+ {
+ "x": 88.37972103701591,
+ "y": -63.931125206934695,
+ "z": 1.0
+ },
+ {
+ "x": 88.37979739042085,
+ "y": -64.4334083061542,
+ "z": 1.0
+ },
+ {
+ "x": 88.37988901450677,
+ "y": -65.03614802521759,
+ "z": 1.0
+ },
+ {
+ "x": 88.3799806385927,
+ "y": -65.63888774428096,
+ "z": 1.0
+ },
+ {
+ "x": 88.38004172131664,
+ "y": -66.0407142236563,
+ "z": 1.0
+ },
+ {
+ "x": 88.38013334540257,
+ "y": -66.64345394271993,
+ "z": 1.0
+ },
+ {
+ "x": 88.3802249694885,
+ "y": -67.24619366178331,
+ "z": 1.0
+ },
+ {
+ "x": 88.3803165935744,
+ "y": -67.84893338084669,
+ "z": 1.0
+ },
+ {
+ "x": 88.38036240561738,
+ "y": -68.15030324037838,
+ "z": 1.0
+ },
+ {
+ "x": 88.38043854453058,
+ "y": -68.6511753276148,
+ "z": 1.0
+ },
+ {
+ "x": 88.38052991122643,
+ "y": -69.25222183229796,
+ "z": 1.0
+ },
+ {
+ "x": 88.38062127792227,
+ "y": -69.85326833698171,
+ "z": 1.0
+ },
+ {
+ "x": 88.38068218905285,
+ "y": -70.2539660067704,
+ "z": 1.0
+ },
+ {
+ "x": 88.38077355574869,
+ "y": -70.85501251145385,
+ "z": 1.0
+ },
+ {
+ "x": 88.38083446687926,
+ "y": -71.25571018124283,
+ "z": 1.0
+ },
+ {
+ "x": 88.38091060579247,
+ "y": -71.75658226847905,
+ "z": 1.0
+ },
+ {
+ "x": 88.38097151692303,
+ "y": -72.15727993826802,
+ "z": 1.0
+ },
+ {
+ "x": 88.3810324280536,
+ "y": -72.55797760805699,
+ "z": 1.0
+ },
+ {
+ "x": 88.38112379474946,
+ "y": -73.15902411274045,
+ "z": 1.0
+ },
+ {
+ "x": 88.38118470588003,
+ "y": -73.55972178252942,
+ "z": 1.0
+ },
+ {
+ "x": 88.38126084479323,
+ "y": -74.06059386976564,
+ "z": 1.0
+ },
+ {
+ "x": 88.38133698370643,
+ "y": -74.56146595700213,
+ "z": 1.0
+ },
+ {
+ "x": 88.38139789483701,
+ "y": -74.96216362679083,
+ "z": 1.0
+ },
+ {
+ "x": 88.38145880596757,
+ "y": -75.3628612965798,
+ "z": 1.0
+ },
+ {
+ "x": 88.38155017266342,
+ "y": -75.96390780126325,
+ "z": 1.0
+ },
+ {
+ "x": 88.38161108379398,
+ "y": -76.36460547105223,
+ "z": 1.0
+ },
+ {
+ "x": 88.38170245048984,
+ "y": -76.96565197573568,
+ "z": 1.0
+ },
+ {
+ "x": 88.38179381718568,
+ "y": -77.56669848041915,
+ "z": 1.0
+ },
+ {
+ "x": 88.38185472831624,
+ "y": -77.96739615020812,
+ "z": 1.0
+ },
+ {
+ "x": 88.38193086722946,
+ "y": -78.46826823744433,
+ "z": 1.0
+ },
+ {
+ "x": 88.38200700614266,
+ "y": -78.96914032468055,
+ "z": 1.0
+ },
+ {
+ "x": 88.38209837283851,
+ "y": -79.570186829364,
+ "z": 1.0
+ },
+ {
+ "x": 88.38217451175171,
+ "y": -80.07105891660022,
+ "z": 1.0
+ },
+ {
+ "x": 88.38226587844757,
+ "y": -80.67210542128367,
+ "z": 1.0
+ },
+ {
+ "x": 88.38234201736077,
+ "y": -81.17297750851989,
+ "z": 1.0
+ },
+ {
+ "x": 88.38240292849133,
+ "y": -81.57367517830914,
+ "z": 1.0
+ },
+ {
+ "x": 88.3824638396219,
+ "y": -81.97437284809784,
+ "z": 1.0
+ },
+ {
+ "x": 88.38255520631775,
+ "y": -82.5754193527813,
+ "z": 1.0
+ },
+ {
+ "x": 88.38261611744832,
+ "y": -82.97611702257026,
+ "z": 1.0
+ },
+ {
+ "x": 88.38269225636154,
+ "y": -83.47698910980648,
+ "z": 1.0
+ },
+ {
+ "x": 88.38278362305739,
+ "y": -84.07803561448995,
+ "z": 1.0
+ },
+ {
+ "x": 88.38287498975323,
+ "y": -84.6790821191734,
+ "z": 1.0
+ },
+ {
+ "x": 88.3829359008838,
+ "y": -85.07977978896237,
+ "z": 1.0
+ },
+ {
+ "x": 88.38302726757965,
+ "y": -85.68082629364584,
+ "z": 1.0
+ },
+ {
+ "x": 88.38310340649285,
+ "y": -86.18169838088205,
+ "z": 1.0
+ },
+ {
+ "x": 88.3831947731887,
+ "y": -86.7827448855655,
+ "z": 1.0
+ },
+ {
+ "x": 88.38325568431927,
+ "y": -87.18344255535447,
+ "z": 1.0
+ },
+ {
+ "x": 88.38333182323248,
+ "y": -87.68431464259069,
+ "z": 1.0
+ },
+ {
+ "x": 88.38340796214568,
+ "y": -88.18518672982691,
+ "z": 1.0
+ },
+ {
+ "x": 88.38348410105888,
+ "y": -88.68605881706341,
+ "z": 1.0
+ },
+ {
+ "x": 88.38354501218946,
+ "y": -89.0867564868521,
+ "z": 1.0
+ },
+ {
+ "x": 88.3836363788853,
+ "y": -89.68780299153555,
+ "z": 1.0
+ },
+ {
+ "x": 88.38372774558115,
+ "y": -90.28884949621902,
+ "z": 1.0
+ },
+ {
+ "x": 88.383819112277,
+ "y": -90.88989600090247,
+ "z": 1.0
+ },
+ {
+ "x": 88.38388002340757,
+ "y": -91.29059367069145,
+ "z": 1.0
+ },
+ {
+ "x": 88.38395616232077,
+ "y": -91.79146575792767,
+ "z": 1.0
+ },
+ {
+ "x": 88.38401707345133,
+ "y": -92.19216342771692,
+ "z": 1.0
+ },
+ {
+ "x": 88.38409321236455,
+ "y": -92.69303551495285,
+ "z": 1.0
+ },
+ {
+ "x": 88.38416935127776,
+ "y": -93.19390760218907,
+ "z": 1.0
+ },
+ {
+ "x": 88.38426071797362,
+ "y": -93.79495410687252,
+ "z": 1.0
+ },
+ {
+ "x": 88.38433685688682,
+ "y": -94.29582619410874,
+ "z": 1.0
+ },
+ {
+ "x": 88.38442822358267,
+ "y": -94.8968726987922,
+ "z": 1.0
+ },
+ {
+ "x": 88.38450436249587,
+ "y": -95.39774478602841,
+ "z": 1.0
+ },
+ {
+ "x": 88.38456527362645,
+ "y": -95.79844245581738,
+ "z": 1.0
+ },
+ {
+ "x": 88.38464141253965,
+ "y": -96.2993145430536,
+ "z": 1.0
+ },
+ {
+ "x": 88.38473277923549,
+ "y": -96.90036104773735,
+ "z": 1.0
+ },
+ {
+ "x": 88.3848089181487,
+ "y": -97.40123313497327,
+ "z": 1.0
+ },
+ {
+ "x": 88.38490028484455,
+ "y": -98.00227963965673,
+ "z": 1.0
+ },
+ {
+ "x": 88.38496119597512,
+ "y": -98.4029773094457,
+ "z": 1.0
+ },
+ {
+ "x": 88.38505256267096,
+ "y": -99.00402381412917,
+ "z": 1.0
+ },
+ {
+ "x": 88.38514392936682,
+ "y": -99.60507031881262,
+ "z": 1.0
+ },
+ {
+ "x": 88.38520484049738,
+ "y": -100.00576798860159,
+ "z": 1.0
+ },
+ {
+ "x": 88.3852809794106,
+ "y": -100.50664007583781,
+ "z": 1.0
+ },
+ {
+ "x": 88.38537234610644,
+ "y": -101.10768658052127,
+ "z": 1.0
+ },
+ {
+ "x": 88.385433257237,
+ "y": -101.50838425031024,
+ "z": 1.0
+ },
+ {
+ "x": 88.38552462393285,
+ "y": -102.1094307549937,
+ "z": 1.0
+ },
+ {
+ "x": 88.3856159906287,
+ "y": -102.71047725967743,
+ "z": 1.0
+ },
+ {
+ "x": 88.38570735732456,
+ "y": -103.31152376436062,
+ "z": 1.0
+ },
+ {
+ "x": 88.38578349623776,
+ "y": -103.81239585159683,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 29,
+ "heading": [
+ -1.5706443141063042,
+ -1.570644314106275,
+ -1.5706443141063064,
+ -1.5706443141063173,
+ -1.5706443141062891,
+ -1.5706443141063064,
+ -1.5706443141063173,
+ -1.5706443141063031,
+ -1.5706443141063007,
+ -1.5706443141063136,
+ -1.5706443141063064,
+ -1.5706443141062891,
+ -1.5706443141063136,
+ -1.5706443141063173,
+ -1.5706443141063007,
+ -1.5706443141062985,
+ -1.5706443141063031,
+ -1.5706443141063031,
+ -1.5706443141062985,
+ -1.5706443141063102,
+ -1.5706443141063064,
+ -1.5706443141063022,
+ -1.5706443141063058,
+ -1.570644314106307,
+ -1.5706443141063045,
+ -1.5706443141063045,
+ -1.5706443141063045,
+ -1.570644314106303,
+ -1.5706443141063187,
+ -1.570644314106301,
+ -1.5706443141062902,
+ -1.5706443141062902,
+ -1.570644314106303,
+ -1.5706443141063187,
+ -1.570644314106303,
+ -1.570644314106301,
+ -1.5706443141063045,
+ -1.5706443141063045,
+ -1.5706443141063045,
+ -1.570644314106307,
+ -1.5706443141063187,
+ -1.570644314106303,
+ -1.5706443141063045,
+ -1.5706443141063058,
+ -1.5706443141063058,
+ -1.5706443141063058,
+ -1.5706443141063058,
+ -1.5706443141063187,
+ -1.570644314106301,
+ -1.5706443141063045,
+ -1.5706443141063045,
+ -1.5706443141062871,
+ -1.570644314106293,
+ -1.570644314106307,
+ -1.5706443141063187,
+ -1.5706443141063045,
+ -1.5706443141063058,
+ -1.5706443141063058,
+ -1.5706443141063045,
+ -1.570644314106303,
+ -1.5706443141063045,
+ -1.5706443141063187,
+ -1.570644314106303,
+ -1.5706443141063045,
+ -1.570644314106307,
+ -1.570644314106307,
+ -1.5706443141063045,
+ -1.570644314106303,
+ -1.5706443141063187,
+ -1.570644314106303,
+ -1.5706443141062902,
+ -1.570644314106293,
+ -1.5706443141063058,
+ -1.5706443141063058,
+ -1.5706443141063058,
+ -1.570644314106303,
+ -1.570644314106303,
+ -1.5706443141063187,
+ -1.5706443141063058,
+ -1.5706443141063058,
+ -1.5706443141063045,
+ -1.5706443141063045,
+ -1.570644314106307,
+ -1.5706443141063045,
+ -1.570644314106303,
+ -1.5706443141063058,
+ -1.5706443141063187,
+ -1.5706443141063045,
+ -1.570644314106307,
+ -1.570644314106295,
+ -1.570644314106293
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": 0.0007635340494971388,
+ "y": -5.022830992192127
+ },
+ {
+ "x": 0.0013743612888106327,
+ "y": -9.04109578595083
+ },
+ {
+ "x": 0.001527068098567952,
+ "y": -10.045661984392638
+ },
+ {
+ "x": 0.001527068098852169,
+ "y": -10.045661984387095
+ },
+ {
+ "x": 0.0013743612888106327,
+ "y": -9.04109578595083
+ },
+ {
+ "x": 0.001527068098567952,
+ "y": -10.045661984392638
+ },
+ {
+ "x": 0.0015270680987100604,
+ "y": -10.045661984389938
+ },
+ {
+ "x": 0.0016797749086094882,
+ "y": -11.05022818282876
+ },
+ {
+ "x": 0.0016797749084673796,
+ "y": -11.05022818282876
+ },
+ {
+ "x": 0.0013743612888106327,
+ "y": -9.041095785950972
+ },
+ {
+ "x": 0.001527068098852169,
+ "y": -10.045661984389795
+ },
+ {
+ "x": 0.0016797749084673796,
+ "y": -11.05022818282876
+ },
+ {
+ "x": 0.001527068098567952,
+ "y": -10.04566198439008
+ },
+ {
+ "x": 0.0016797749086094882,
+ "y": -11.050228182828903
+ },
+ {
+ "x": 0.001832481718508916,
+ "y": -12.054794381267584
+ },
+ {
+ "x": 0.0015270680987100604,
+ "y": -10.045661984387095
+ },
+ {
+ "x": 0.0015270680987100604,
+ "y": -10.045661984389653
+ },
+ {
+ "x": 0.001832481718508916,
+ "y": -12.054794381270142
+ },
+ {
+ "x": 0.0018324817183668074,
+ "y": -12.054794381267584
+ },
+ {
+ "x": 0.0013743612888106327,
+ "y": -9.041095785950688
+ },
+ {
+ "x": 0.0012195095617073548,
+ "y": -8.022419467681061
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919195849
+ },
+ {
+ "x": 0.0018273339169638803,
+ "y": -12.020930093669193
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744721367
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.015697570252001
+ },
+ {
+ "x": 0.0013705004376163288,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.001218222611356623,
+ "y": -8.013953395779367
+ },
+ {
+ "x": 0.0015227782643023602,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.0015227782643023602,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.001522778264018143,
+ "y": -10.017441744727051
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.001218222611356623,
+ "y": -8.013953395776667
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.01744174472421
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.0018273339169638803,
+ "y": -12.020930093669193
+ },
+ {
+ "x": 0.001522778264018143,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.0013705004376163288,
+ "y": -9.015697570254702
+ },
+ {
+ "x": 0.001218222611356623,
+ "y": -8.01395339577951
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.01744174472151
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.01744174472421
+ },
+ {
+ "x": 0.0013705004379005459,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.0016750560907041745,
+ "y": -11.019185919196843
+ },
+ {
+ "x": 0.0018273339169638803,
+ "y": -12.020930093669193
+ },
+ {
+ "x": 0.001522778264018143,
+ "y": -10.01744174472421
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196843
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.01744174472421
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.001522778264018143,
+ "y": -10.017441744727194
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744721367
+ },
+ {
+ "x": 0.0018273339169638803,
+ "y": -12.020930093669193
+ },
+ {
+ "x": 0.0018273339169638803,
+ "y": -12.020930093669193
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.015697570252001
+ },
+ {
+ "x": 0.0013705004376163288,
+ "y": -9.015697570254702
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.0015227782643023602,
+ "y": -10.01744174472151
+ },
+ {
+ "x": 0.0016750560907041745,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.0016750560904199574,
+ "y": -11.019185919199685
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196701
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919193859
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.0018273339169638803,
+ "y": -12.020930093669193
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.01744174472421
+ },
+ {
+ "x": 0.0013705004377584373,
+ "y": -9.01569757025186
+ },
+ {
+ "x": 0.001675056090562066,
+ "y": -11.019185919196843
+ },
+ {
+ "x": 0.001522778264018143,
+ "y": -10.017441744724351
+ },
+ {
+ "x": 0.0015227782641602516,
+ "y": -10.01744174472421
+ },
+ {
+ "x": 0.0018273339169638803,
+ "y": -12.020930093671893
+ },
+ {
+ "x": 0.0018273339171059888,
+ "y": -12.020930093669193
+ },
+ {
+ "x": 0.0016750560907041745,
+ "y": -11.019185919194001
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 88.38578349623776,
+ "y": -103.81239585159683,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 158.03439763122856,
+ "y": -37.48257278576148,
+ "z": 1.0
+ },
+ {
+ "x": 158.03488464725268,
+ "y": -37.08166140065703,
+ "z": 1.0
+ },
+ {
+ "x": 158.0354934172828,
+ "y": -36.580522169275206,
+ "z": 1.0
+ },
+ {
+ "x": 158.0361021873129,
+ "y": -36.07938293789394,
+ "z": 1.0
+ },
+ {
+ "x": 158.03658920333703,
+ "y": -35.678471552789496,
+ "z": 1.0
+ },
+ {
+ "x": 158.03719797336714,
+ "y": -35.17733232140766,
+ "z": 1.0
+ },
+ {
+ "x": 158.03768498939127,
+ "y": -34.77642093630322,
+ "z": 1.0
+ },
+ {
+ "x": 158.0381720054154,
+ "y": -34.37550955119821,
+ "z": 1.0
+ },
+ {
+ "x": 158.0386590214395,
+ "y": -33.9745981660932,
+ "z": 1.0
+ },
+ {
+ "x": 158.03914603746358,
+ "y": -33.57368678098819,
+ "z": 1.0
+ },
+ {
+ "x": 158.03987656149974,
+ "y": -32.97231970333011,
+ "z": 1.0
+ },
+ {
+ "x": 158.0406070855359,
+ "y": -32.370952625672594,
+ "z": 1.0
+ },
+ {
+ "x": 158.04121585556607,
+ "y": -31.869813394291327,
+ "z": 1.0
+ },
+ {
+ "x": 158.0417028715902,
+ "y": -31.468902009186884,
+ "z": 1.0
+ },
+ {
+ "x": 158.0424333956263,
+ "y": -30.8675349315288,
+ "z": 1.0
+ },
+ {
+ "x": 158.0431639196625,
+ "y": -30.266167853871853,
+ "z": 1.0
+ },
+ {
+ "x": 158.04377268969262,
+ "y": -29.76502862249002,
+ "z": 1.0
+ },
+ {
+ "x": 158.04438145972279,
+ "y": -29.263889391109323,
+ "z": 1.0
+ },
+ {
+ "x": 158.0449902297529,
+ "y": -28.762750159727496,
+ "z": 1.0
+ },
+ {
+ "x": 158.04547724577696,
+ "y": -28.361838774622484,
+ "z": 1.0
+ },
+ {
+ "x": 158.0459642618011,
+ "y": -27.96092738951804,
+ "z": 1.0
+ },
+ {
+ "x": 158.04669478583725,
+ "y": -27.35956031185996,
+ "z": 1.0
+ },
+ {
+ "x": 158.0474253098734,
+ "y": -26.758193234202437,
+ "z": 1.0
+ },
+ {
+ "x": 158.04803407990357,
+ "y": -26.257054002821164,
+ "z": 1.0
+ },
+ {
+ "x": 158.04864284993369,
+ "y": -25.75591477143989,
+ "z": 1.0
+ },
+ {
+ "x": 158.0492516199638,
+ "y": -25.254775540058617,
+ "z": 1.0
+ },
+ {
+ "x": 158.049982144,
+ "y": -24.653408462401657,
+ "z": 1.0
+ },
+ {
+ "x": 158.05059091403012,
+ "y": -24.152269231020387,
+ "z": 1.0
+ },
+ {
+ "x": 158.05132143806628,
+ "y": -23.55090215336286,
+ "z": 1.0
+ },
+ {
+ "x": 158.0518084540904,
+ "y": -23.149990768257275,
+ "z": 1.0
+ },
+ {
+ "x": 158.05253897812656,
+ "y": -22.548623690599747,
+ "z": 1.0
+ },
+ {
+ "x": 158.05326950216272,
+ "y": -21.94725661294222,
+ "z": 1.0
+ },
+ {
+ "x": 158.0537565181868,
+ "y": -21.5463452278372,
+ "z": 1.0
+ },
+ {
+ "x": 158.0542435342109,
+ "y": -21.14543384273219,
+ "z": 1.0
+ },
+ {
+ "x": 158.05497405824707,
+ "y": -20.54406676507466,
+ "z": 1.0
+ },
+ {
+ "x": 158.0554610742712,
+ "y": -20.14315537996964,
+ "z": 1.0
+ },
+ {
+ "x": 158.0560698443013,
+ "y": -19.642016148588368,
+ "z": 1.0
+ },
+ {
+ "x": 158.05680036833752,
+ "y": -19.04064907093141,
+ "z": 1.0
+ },
+ {
+ "x": 158.05753089237368,
+ "y": -18.439281993273312,
+ "z": 1.0
+ },
+ {
+ "x": 158.05801790839774,
+ "y": -18.0383706081683,
+ "z": 1.0
+ },
+ {
+ "x": 158.0586266784279,
+ "y": -17.537231376787027,
+ "z": 1.0
+ },
+ {
+ "x": 158.05923544845803,
+ "y": -17.036092145406318,
+ "z": 1.0
+ },
+ {
+ "x": 158.05972246448215,
+ "y": -16.635180760300734,
+ "z": 1.0
+ },
+ {
+ "x": 158.0604529885183,
+ "y": -16.033813682643206,
+ "z": 1.0
+ },
+ {
+ "x": 158.06094000454243,
+ "y": -15.632902297538756,
+ "z": 1.0
+ },
+ {
+ "x": 158.0614270205665,
+ "y": -15.231990912433172,
+ "z": 1.0
+ },
+ {
+ "x": 158.06203579059667,
+ "y": -14.730851681051899,
+ "z": 1.0
+ },
+ {
+ "x": 158.06276631463282,
+ "y": -14.129484603394374,
+ "z": 1.0
+ },
+ {
+ "x": 158.06337508466294,
+ "y": -13.628345372013104,
+ "z": 1.0
+ },
+ {
+ "x": 158.06386210068706,
+ "y": -13.227433986908089,
+ "z": 1.0
+ },
+ {
+ "x": 158.06459262472322,
+ "y": -12.626066909251133,
+ "z": 1.0
+ },
+ {
+ "x": 158.06532314875938,
+ "y": -12.024699831593606,
+ "z": 1.0
+ },
+ {
+ "x": 158.0658101647835,
+ "y": -11.62378844648859,
+ "z": 1.0
+ },
+ {
+ "x": 158.06629718080762,
+ "y": -11.222877061383572,
+ "z": 1.0
+ },
+ {
+ "x": 158.06654068881966,
+ "y": -11.022421368830496,
+ "z": 1.0
+ },
+ {
+ "x": 158.06702812465142,
+ "y": -10.621164398262831,
+ "z": 1.0
+ },
+ {
+ "x": 158.06775927839897,
+ "y": -10.01927894240989,
+ "z": 1.0
+ },
+ {
+ "x": 158.06824671423072,
+ "y": -9.618021971841639,
+ "z": 1.0
+ },
+ {
+ "x": 158.0688560090204,
+ "y": -9.11645075863133,
+ "z": 1.0
+ },
+ {
+ "x": 158.0693434448521,
+ "y": -8.715193788063083,
+ "z": 1.0
+ },
+ {
+ "x": 158.07007459859972,
+ "y": -8.113308332210707,
+ "z": 1.0
+ },
+ {
+ "x": 158.07056203443148,
+ "y": -7.712051361642459,
+ "z": 1.0
+ },
+ {
+ "x": 158.06648688551132,
+ "y": -7.1584986324351565,
+ "z": 1.0
+ },
+ {
+ "x": 158.02461504747117,
+ "y": -6.51829522095581,
+ "z": 1.0
+ },
+ {
+ "x": 157.91537219000054,
+ "y": -5.756265280126636,
+ "z": 1.0
+ },
+ {
+ "x": 157.80713622040798,
+ "y": -5.254505269284559,
+ "z": 1.0
+ },
+ {
+ "x": 157.59217082782527,
+ "y": -4.514683268550397,
+ "z": 1.0
+ },
+ {
+ "x": 157.3662201428967,
+ "y": -3.9142137585897396,
+ "z": 1.0
+ },
+ {
+ "x": 157.15553063700315,
+ "y": -3.4461523429930967,
+ "z": 1.0
+ },
+ {
+ "x": 156.79117762382486,
+ "y": -2.7680225145010073,
+ "z": 1.0
+ },
+ {
+ "x": 156.3711601304941,
+ "y": -2.1228895130661045,
+ "z": 1.0
+ },
+ {
+ "x": 156.0616732746556,
+ "y": -1.7133932466808826,
+ "z": 1.0
+ },
+ {
+ "x": 155.72972937947105,
+ "y": -1.3218789148370773,
+ "z": 1.0
+ },
+ {
+ "x": 155.3763707435337,
+ "y": -0.9495760774742261,
+ "z": 1.0
+ },
+ {
+ "x": 154.9083553058013,
+ "y": -0.5146331051925972,
+ "z": 1.0
+ },
+ {
+ "x": 154.42830485703843,
+ "y": -0.12187522067055712,
+ "z": 1.0
+ },
+ {
+ "x": 153.82225338896444,
+ "y": 0.31096146168839445,
+ "z": 1.0
+ },
+ {
+ "x": 153.18733284384513,
+ "y": 0.699261120180888,
+ "z": 1.0
+ },
+ {
+ "x": 152.74938521124585,
+ "y": 0.9325766110953226,
+ "z": 1.0
+ },
+ {
+ "x": 152.0729321872387,
+ "y": 1.242908208394323,
+ "z": 1.0
+ },
+ {
+ "x": 151.37610097632384,
+ "y": 1.5042882774523922,
+ "z": 1.0
+ },
+ {
+ "x": 150.9019679824224,
+ "y": 1.6506809930010826,
+ "z": 1.0
+ },
+ {
+ "x": 150.30040348196218,
+ "y": 1.8017426140988086,
+ "z": 1.0
+ },
+ {
+ "x": 149.5682777598086,
+ "y": 1.9355006328820132,
+ "z": 1.0
+ },
+ {
+ "x": 148.95215542328614,
+ "y": 2.0069078165924625,
+ "z": 1.0
+ },
+ {
+ "x": 148.20833740082458,
+ "y": 2.044065519194717,
+ "z": 1.0
+ },
+ {
+ "x": 147.66901799637068,
+ "y": 2.045241054680691,
+ "z": 1.0
+ },
+ {
+ "x": 147.26776073202618,
+ "y": 2.045283880573532,
+ "z": 1.0
+ },
+ {
+ "x": 146.6658748355094,
+ "y": 2.0453481194127936,
+ "z": 1.0
+ },
+ {
+ "x": 146.2646175711649,
+ "y": 2.045390945305635,
+ "z": 1.0
+ },
+ {
+ "x": 145.76304599073424,
+ "y": 2.0454444776716865,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 30,
+ "heading": [
+ 1.85681491850764,
+ 1.5695815551454493,
+ 1.5695815551454981,
+ 1.5695815551455368,
+ 1.5695815551454975,
+ 1.5695815551454981,
+ 1.5695815551454981,
+ 1.5695815551454502,
+ 1.5695815551454508,
+ 1.569581555145522,
+ 1.5695815551455368,
+ 1.5695815551454988,
+ 1.5695815551454637,
+ 1.5695815551454344,
+ 1.569581555145536,
+ 1.5695815551454981,
+ 1.5695815551454637,
+ 1.5695815551454793,
+ 1.5695815551454793,
+ 1.5695815551455619,
+ 1.569581555145521,
+ 1.5695815551454793,
+ 1.5695815551454988,
+ 1.569581555145464,
+ 1.5695815551454793,
+ 1.569581555145536,
+ 1.5695815551454633,
+ 1.5695815551454633,
+ 1.5695815551455155,
+ 1.56958155514548,
+ 1.56958155514548,
+ 1.5695815551454981,
+ 1.569581555145536,
+ 1.569581555145522,
+ 1.5695815551454793,
+ 1.5695815551454793,
+ 1.5695815551454981,
+ 1.5695815551454633,
+ 1.569581555145451,
+ 1.5695815551455368,
+ 1.5695815551454981,
+ 1.5695815551454786,
+ 1.5695815551454981,
+ 1.56958155514548,
+ 1.5695815551454786,
+ 1.569581555145522,
+ 1.569581555145499,
+ 1.569581555145464,
+ 1.5695815551455155,
+ 1.5695815551454981,
+ 1.5695815551454786,
+ 1.5695815551454977,
+ 1.5695815551454793,
+ 1.569581555145451,
+ 1.5695815551454995,
+ 1.569581555145491,
+ 1.5695815551455252,
+ 1.5695815551455259,
+ 1.569581555145456,
+ 1.569581555145519,
+ 1.5695815551455252,
+ 1.5695815551454686,
+ 1.5745538254927947,
+ 1.6092667617277412,
+ 1.6781491685846572,
+ 1.7412118605974554,
+ 1.8254586180935752,
+ 1.8886150095974155,
+ 1.9587252808138194,
+ 2.0358018759865435,
+ 2.105871504850858,
+ 2.1759411589315487,
+ 2.246010784166259,
+ 2.3020664946610165,
+ 2.364869264322417,
+ 2.423872974200282,
+ 2.491630517482241,
+ 2.557044715117108,
+ 2.6164612050779623,
+ 2.687721824022901,
+ 2.74710565983511,
+ 2.8064895092109574,
+ 2.871811731469634,
+ 2.9311956033917057,
+ 2.990579471172711,
+ 3.0619309698677264,
+ 3.1117269203157245,
+ 3.14029731984635,
+ 3.1414859243253437,
+ 3.1414859243253432,
+ 3.1414859243253432
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": 0.0048701602412393186,
+ "y": 4.009113851044432
+ },
+ {
+ "x": 0.010957860542362141,
+ "y": 9.02050616486271
+ },
+ {
+ "x": 0.012175400602245645,
+ "y": 10.02278462763094
+ },
+ {
+ "x": 0.010957860542362141,
+ "y": 9.020506164857096
+ },
+ {
+ "x": 0.010957860542362141,
+ "y": 9.02050616486278
+ },
+ {
+ "x": 0.010957860542362141,
+ "y": 9.02050616486278
+ },
+ {
+ "x": 0.009740320482478637,
+ "y": 8.018227702094478
+ },
+ {
+ "x": 0.009740320482478637,
+ "y": 8.018227702100162
+ },
+ {
+ "x": 0.009740320481910203,
+ "y": 8.018227702100234
+ },
+ {
+ "x": 0.012175400602245645,
+ "y": 10.02278462763094
+ },
+ {
+ "x": 0.014610480723149522,
+ "y": 12.027341553155964
+ },
+ {
+ "x": 0.013392940663266018,
+ "y": 11.025063090387803
+ },
+ {
+ "x": 0.010957860542930575,
+ "y": 9.020506164857096
+ },
+ {
+ "x": 0.012175400602245645,
+ "y": 10.022784627625256
+ },
+ {
+ "x": 0.014610480723149522,
+ "y": 12.027341553150315
+ },
+ {
+ "x": 0.013392940663266018,
+ "y": 11.025063090387803
+ },
+ {
+ "x": 0.01217540060281408,
+ "y": 10.022784627625292
+ },
+ {
+ "x": 0.01217540060281408,
+ "y": 10.022784627625256
+ },
+ {
+ "x": 0.010957860541793707,
+ "y": 9.020506164868394
+ },
+ {
+ "x": 0.009740320481910203,
+ "y": 8.01822770209455
+ },
+ {
+ "x": 0.01217540060281408,
+ "y": 10.022784627625256
+ },
+ {
+ "x": 0.014610480723149522,
+ "y": 12.027341553156035
+ },
+ {
+ "x": 0.013392940663266018,
+ "y": 11.025063090387945
+ },
+ {
+ "x": 0.01217540060281408,
+ "y": 10.02278462762547
+ },
+ {
+ "x": 0.012175400602245645,
+ "y": 10.02278462762547
+ },
+ {
+ "x": 0.013392940663266018,
+ "y": 11.025063090382332
+ },
+ {
+ "x": 0.013392940663266018,
+ "y": 11.025063090382297
+ },
+ {
+ "x": 0.013392940662697583,
+ "y": 11.025063090387981
+ },
+ {
+ "x": 0.01217540060281408,
+ "y": 10.022784627631118
+ },
+ {
+ "x": 0.01217540060281408,
+ "y": 10.022784627631118
+ },
+ {
+ "x": 0.014610480723149522,
+ "y": 12.027341553150563
+ },
+ {
+ "x": 0.012175400602245645,
+ "y": 10.02278462762547
+ },
+ {
+ "x": 0.009740320481910203,
+ "y": 8.018227702100305
+ },
+ {
+ "x": 0.01217540060281408,
+ "y": 10.022784627625398
+ },
+ {
+ "x": 0.01217540060281408,
+ "y": 10.02278462762547
+ },
+ {
+ "x": 0.010957860542362141,
+ "y": 9.020506164862923
+ },
+ {
+ "x": 0.013392940663266018,
+ "y": 11.025063090382332
+ },
+ {
+ "x": 0.014610480723717956,
+ "y": 12.027341553150563
+ },
+ {
+ "x": 0.012175400602245645,
+ "y": 10.022784627631083
+ },
+ {
+ "x": 0.010957860542362141,
+ "y": 9.020506164862852
+ },
+ {
+ "x": 0.01217540060281408,
+ "y": 10.02278462761982
+ },
+ {
+ "x": 0.010957860542362141,
+ "y": 9.020506164862923
+ },
+ {
+ "x": 0.01217540060281408,
+ "y": 10.022784627631118
+ },
+ {
+ "x": 0.01217540060281408,
+ "y": 10.022784627619785
+ },
+ {
+ "x": 0.009740320481910203,
+ "y": 8.01822770210034
+ },
+ {
+ "x": 0.010957860542362141,
+ "y": 9.020506164868571
+ },
+ {
+ "x": 0.013392940663266018,
+ "y": 11.025063090387981
+ },
+ {
+ "x": 0.013392940662697583,
+ "y": 11.025063090387945
+ },
+ {
+ "x": 0.010957860542362141,
+ "y": 9.020506164862852
+ },
+ {
+ "x": 0.01217540060281408,
+ "y": 10.022784627619714
+ },
+ {
+ "x": 0.014610480723149522,
+ "y": 12.027341553144826
+ },
+ {
+ "x": 0.01217540060281408,
+ "y": 10.022784627625434
+ },
+ {
+ "x": 0.009740320482478637,
+ "y": 8.01822770210034
+ },
+ {
+ "x": 0.007305240361574761,
+ "y": 6.0136707765809305
+ },
+ {
+ "x": 0.00730943843791465,
+ "y": 6.0171266312074145
+ },
+ {
+ "x": 0.01218589579309537,
+ "y": 10.03142426420606
+ },
+ {
+ "x": 0.01218589579309537,
+ "y": 10.031424264211921
+ },
+ {
+ "x": 0.01096730621441111,
+ "y": 9.028281837785599
+ },
+ {
+ "x": 0.010967306213842676,
+ "y": 9.028281837785563
+ },
+ {
+ "x": 0.01218589579309537,
+ "y": 10.031424264206237
+ },
+ {
+ "x": 0.012185895793663803,
+ "y": 10.031424264206237
+ },
+ {
+ "x": -0.035877130883932296,
+ "y": 9.548096997755504
+ },
+ {
+ "x": -0.4594698696030264,
+ "y": 11.937561406866486
+ },
+ {
+ "x": -1.5111469551078471,
+ "y": 14.022333523085209
+ },
+ {
+ "x": -2.1747882706318933,
+ "y": 12.637899516712512
+ },
+ {
+ "x": -3.232013621752685,
+ "y": 12.415820115762388
+ },
+ {
+ "x": -4.409160775112753,
+ "y": 13.402915106948194
+ },
+ {
+ "x": -4.366401908221178,
+ "y": 10.685309255573001
+ },
+ {
+ "x": -5.750425190718431,
+ "y": 11.461912440887323
+ },
+ {
+ "x": -7.843705065090489,
+ "y": 13.232628299269921
+ },
+ {
+ "x": -7.295043491692752,
+ "y": 10.546292678201247
+ },
+ {
+ "x": -6.414307510230515,
+ "y": 8.010105982290272
+ },
+ {
+ "x": -6.853025311218914,
+ "y": 7.638171692066564
+ },
+ {
+ "x": -8.213740736697446,
+ "y": 8.0724580964448
+ },
+ {
+ "x": -9.480658864952716,
+ "y": 8.27700856803669
+ },
+ {
+ "x": -10.86101916836867,
+ "y": 8.255945668809916
+ },
+ {
+ "x": -12.409720131933,
+ "y": 8.211363408514451
+ },
+ {
+ "x": -10.728681777185898,
+ "y": 6.2161514940692815
+ },
+ {
+ "x": -11.144006566064206,
+ "y": 5.4364708821343495
+ },
+ {
+ "x": -13.732842349220107,
+ "y": 5.717116663570696
+ },
+ {
+ "x": -11.709642048163005,
+ "y": 4.077727846067596
+ },
+ {
+ "x": -10.756974943616626,
+ "y": 2.974543366464164
+ },
+ {
+ "x": -13.336902226137965,
+ "y": 2.848196398809306
+ },
+ {
+ "x": -13.482480586760346,
+ "y": 2.051652024936539
+ },
+ {
+ "x": -13.599403589840335,
+ "y": 1.0856488631270356
+ },
+ {
+ "x": -12.831374269154594,
+ "y": 0.38333238088228416
+ },
+ {
+ "x": -9.405766687983999,
+ "y": 0.01218361378815036
+ },
+ {
+ "x": -10.031431608612706,
+ "y": 0.0010706473210264633
+ },
+ {
+ "x": -10.031431608612706,
+ "y": 0.0010706473210309042
+ },
+ {
+ "x": -9.02828844775172,
+ "y": 0.000963582588928702
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 145.76304599073424,
+ "y": 2.0454444776716865,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 334.8085442829706,
+ "y": -151.28327510229786,
+ "z": 1.0
+ },
+ {
+ "x": 334.80818118447087,
+ "y": -151.88442057736455,
+ "z": 1.0
+ },
+ {
+ "x": 334.80793911880437,
+ "y": -152.28518422740973,
+ "z": 1.0
+ },
+ {
+ "x": 334.80763653672125,
+ "y": -152.78613878996623,
+ "z": 1.0
+ },
+ {
+ "x": 334.8073339546381,
+ "y": -153.28709335252273,
+ "z": 1.0
+ },
+ {
+ "x": 334.807031372555,
+ "y": -153.78804791507923,
+ "z": 1.0
+ },
+ {
+ "x": 334.80666827405526,
+ "y": -154.389193390147,
+ "z": 1.0
+ },
+ {
+ "x": 334.80636569197213,
+ "y": -154.8901479527035,
+ "z": 1.0
+ },
+ {
+ "x": 334.80612362630563,
+ "y": -155.29091160274868,
+ "z": 1.0
+ },
+ {
+ "x": 334.80588156063914,
+ "y": -155.6916752527939,
+ "z": 1.0
+ },
+ {
+ "x": 334.805578978556,
+ "y": -156.19262981535041,
+ "z": 1.0
+ },
+ {
+ "x": 334.80521588005627,
+ "y": -156.79377529041818,
+ "z": 1.0
+ },
+ {
+ "x": 334.80491329797314,
+ "y": -157.29472985297468,
+ "z": 1.0
+ },
+ {
+ "x": 334.8045501994734,
+ "y": -157.89587532804245,
+ "z": 1.0
+ },
+ {
+ "x": 334.80418710097365,
+ "y": -158.49702080311027,
+ "z": 1.0
+ },
+ {
+ "x": 334.8038240024739,
+ "y": -159.09816627817918,
+ "z": 1.0
+ },
+ {
+ "x": 334.80346090397427,
+ "y": -159.69931175324473,
+ "z": 1.0
+ },
+ {
+ "x": 334.80315832189103,
+ "y": -160.2002663158035,
+ "z": 1.0
+ },
+ {
+ "x": 334.8028557398079,
+ "y": -160.70122087836,
+ "z": 1.0
+ },
+ {
+ "x": 334.8024926413083,
+ "y": -161.3023663534267,
+ "z": 1.0
+ },
+ {
+ "x": 334.80219005922504,
+ "y": -161.80332091598433,
+ "z": 1.0
+ },
+ {
+ "x": 334.80188747714203,
+ "y": -162.3042754785397,
+ "z": 1.0
+ },
+ {
+ "x": 334.80164541147553,
+ "y": -162.70503912858487,
+ "z": 1.0
+ },
+ {
+ "x": 334.8013428293924,
+ "y": -163.20599369114137,
+ "z": 1.0
+ },
+ {
+ "x": 334.8010402473093,
+ "y": -163.70694825369787,
+ "z": 1.0
+ },
+ {
+ "x": 334.8007981816428,
+ "y": -164.1077119037431,
+ "z": 1.0
+ },
+ {
+ "x": 334.80049559955967,
+ "y": -164.6086664662996,
+ "z": 1.0
+ },
+ {
+ "x": 334.80025353389317,
+ "y": -165.0094301163448,
+ "z": 1.0
+ },
+ {
+ "x": 334.80001146822667,
+ "y": -165.41019376639002,
+ "z": 1.0
+ },
+ {
+ "x": 334.79970888614355,
+ "y": -165.91114832894652,
+ "z": 1.0
+ },
+ {
+ "x": 334.7993457876438,
+ "y": -166.5122938040143,
+ "z": 1.0
+ },
+ {
+ "x": 334.79898268914405,
+ "y": -167.11343927908212,
+ "z": 1.0
+ },
+ {
+ "x": 334.79868010706093,
+ "y": -167.61439384163862,
+ "z": 1.0
+ },
+ {
+ "x": 334.7983170085612,
+ "y": -168.21553931670644,
+ "z": 1.0
+ },
+ {
+ "x": 334.7980749428947,
+ "y": -168.61630296675162,
+ "z": 1.0
+ },
+ {
+ "x": 334.79777236081156,
+ "y": -169.11725752930812,
+ "z": 1.0
+ },
+ {
+ "x": 334.7974092623118,
+ "y": -169.71840300437594,
+ "z": 1.0
+ },
+ {
+ "x": 334.79704616381207,
+ "y": -170.31954847944263,
+ "z": 1.0
+ },
+ {
+ "x": 334.79674358172895,
+ "y": -170.82050304199913,
+ "z": 1.0
+ },
+ {
+ "x": 334.79650151606245,
+ "y": -171.22126669204658,
+ "z": 1.0
+ },
+ {
+ "x": 334.7961384175627,
+ "y": -171.82241216711327,
+ "z": 1.0
+ },
+ {
+ "x": 334.7958358354796,
+ "y": -172.3233667296709,
+ "z": 1.0
+ },
+ {
+ "x": 334.79547273697983,
+ "y": -172.9245122047376,
+ "z": 1.0
+ },
+ {
+ "x": 334.7951701548967,
+ "y": -173.4254667672941,
+ "z": 1.0
+ },
+ {
+ "x": 334.7949280892302,
+ "y": -173.82623041733814,
+ "z": 1.0
+ },
+ {
+ "x": 334.79456499073046,
+ "y": -174.4273758924071,
+ "z": 1.0
+ },
+ {
+ "x": 334.79432292506397,
+ "y": -174.82813954245228,
+ "z": 1.0
+ },
+ {
+ "x": 334.7939598265642,
+ "y": -175.4292850175201,
+ "z": 1.0
+ },
+ {
+ "x": 334.7936572444811,
+ "y": -175.9302395800766,
+ "z": 1.0
+ },
+ {
+ "x": 334.793354662398,
+ "y": -176.4311941426331,
+ "z": 1.0
+ },
+ {
+ "x": 334.7931125967315,
+ "y": -176.83195779267828,
+ "z": 1.0
+ },
+ {
+ "x": 334.792870531065,
+ "y": -177.23272144272346,
+ "z": 1.0
+ },
+ {
+ "x": 334.79256794898185,
+ "y": -177.73367600527996,
+ "z": 1.0
+ },
+ {
+ "x": 334.79226536689873,
+ "y": -178.23463056783646,
+ "z": 1.0
+ },
+ {
+ "x": 334.7919627848156,
+ "y": -178.73558513039404,
+ "z": 1.0
+ },
+ {
+ "x": 334.7916602027325,
+ "y": -179.2365396929494,
+ "z": 1.0
+ },
+ {
+ "x": 334.7914181370661,
+ "y": -179.63730334299345,
+ "z": 1.0
+ },
+ {
+ "x": 334.7911760713995,
+ "y": -180.03806699303976,
+ "z": 1.0
+ },
+ {
+ "x": 334.7909340057331,
+ "y": -180.43883064308386,
+ "z": 1.0
+ },
+ {
+ "x": 334.79063142364987,
+ "y": -180.93978520564258,
+ "z": 1.0
+ },
+ {
+ "x": 334.7903893579834,
+ "y": -181.34054885568668,
+ "z": 1.0
+ },
+ {
+ "x": 334.7901472923169,
+ "y": -181.741312505733,
+ "z": 1.0
+ },
+ {
+ "x": 334.78978419381724,
+ "y": -182.34245798079849,
+ "z": 1.0
+ },
+ {
+ "x": 334.7894210953175,
+ "y": -182.94360345586625,
+ "z": 1.0
+ },
+ {
+ "x": 334.7891790296509,
+ "y": -183.34436710591376,
+ "z": 1.0
+ },
+ {
+ "x": 334.7889369639845,
+ "y": -183.74513075595667,
+ "z": 1.0
+ },
+ {
+ "x": 334.7886343819014,
+ "y": -184.2460853185143,
+ "z": 1.0
+ },
+ {
+ "x": 334.78839231623476,
+ "y": -184.64684896856062,
+ "z": 1.0
+ },
+ {
+ "x": 334.78808973415175,
+ "y": -185.14780353111593,
+ "z": 1.0
+ },
+ {
+ "x": 334.78778715206863,
+ "y": -185.64875809367243,
+ "z": 1.0
+ },
+ {
+ "x": 334.7875444119521,
+ "y": -186.050638362244,
+ "z": 1.0
+ },
+ {
+ "x": 334.78718030177754,
+ "y": -186.65345876510128,
+ "z": 1.0
+ },
+ {
+ "x": 334.78693756166115,
+ "y": -187.0553390336716,
+ "z": 1.0
+ },
+ {
+ "x": 334.78669482154476,
+ "y": -187.4572193022454,
+ "z": 1.0
+ },
+ {
+ "x": 334.78645208142837,
+ "y": -187.85909957081577,
+ "z": 1.0
+ },
+ {
+ "x": 334.7860879712538,
+ "y": -188.461919973673,
+ "z": 1.0
+ },
+ {
+ "x": 334.7858452311374,
+ "y": -188.86380024224337,
+ "z": 1.0
+ },
+ {
+ "x": 334.7856024910209,
+ "y": -189.2656805108171,
+ "z": 1.0
+ },
+ {
+ "x": 334.7852990658754,
+ "y": -189.7680308465292,
+ "z": 1.0
+ },
+ {
+ "x": 334.7849349557008,
+ "y": -190.37085124938875,
+ "z": 1.0
+ },
+ {
+ "x": 334.7845708455262,
+ "y": -190.97367165224483,
+ "z": 1.0
+ },
+ {
+ "x": 334.78420673535163,
+ "y": -191.57649205510205,
+ "z": 1.0
+ },
+ {
+ "x": 334.7839639952351,
+ "y": -191.97837232367357,
+ "z": 1.0
+ },
+ {
+ "x": 334.78372125511873,
+ "y": -192.38025259224509,
+ "z": 1.0
+ },
+ {
+ "x": 334.78335714494415,
+ "y": -192.98307299510117,
+ "z": 1.0
+ },
+ {
+ "x": 334.78311440482776,
+ "y": -193.38495326367382,
+ "z": 1.0
+ },
+ {
+ "x": 334.78275029465317,
+ "y": -193.98777366653104,
+ "z": 1.0
+ },
+ {
+ "x": 334.7824468695077,
+ "y": -194.4901240022454,
+ "z": 1.0
+ },
+ {
+ "x": 334.7822041293913,
+ "y": -194.89200427081693,
+ "z": 1.0
+ },
+ {
+ "x": 334.7819007042457,
+ "y": -195.3943546065313,
+ "z": 1.0
+ },
+ {
+ "x": 334.7816579641293,
+ "y": -195.79623487510275,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 31,
+ "heading": [
+ -1.571400337755052,
+ -1.5714003377550565,
+ -1.571400337755056,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.571400337755055,
+ -1.5714003377549615,
+ -1.5714003377550554,
+ -1.5714003377551675,
+ -1.5714003377549528,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377549302,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.571400337755056,
+ -1.571400337755056,
+ -1.5714003377550538,
+ -1.5714003377550547,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.571400337755056,
+ -1.5714003377550563,
+ -1.5714003377550554,
+ -1.5714003377550547,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550547,
+ -1.5714003377550554,
+ -1.5714003377549308,
+ -1.5714003377550554,
+ -1.5714003377550554,
+ -1.5714003377550547,
+ -1.5714003377551808,
+ -1.5714003377550554,
+ -1.5714003377549426,
+ -1.5714003377549621,
+ -1.5714003377551675,
+ -1.5714003377550554,
+ -1.5714003377549302,
+ -1.57140033775518,
+ -1.5714003377550554,
+ -1.5714003377549426,
+ -1.5714003377551624,
+ -1.5714003377551262,
+ -1.5714003377550139,
+ -1.5714003377550123,
+ -1.5714003377550123,
+ -1.5714003377550139,
+ -1.5714003377550139,
+ -1.5714003377551538,
+ -1.571400337755139,
+ -1.5714003377550132,
+ -1.5714003377550128,
+ -1.5714003377550139,
+ -1.5714003377551264,
+ -1.5714003377551546,
+ -1.5714003377550139,
+ -1.5714003377550132,
+ -1.5714003377550125,
+ -1.5714003377550132,
+ -1.5714003377550132,
+ -1.5714003377551389,
+ -1.571400337755139
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -0.003630984997471387,
+ "y": -6.011454750666871
+ },
+ {
+ "x": -0.006051641662452312,
+ "y": -10.019091251118653
+ },
+ {
+ "x": -0.0054464774962070805,
+ "y": -9.017182126016792
+ },
+ {
+ "x": -0.006051641662452312,
+ "y": -10.019091251130021
+ },
+ {
+ "x": -0.006051641662452312,
+ "y": -10.019091251130021
+ },
+ {
+ "x": -0.006656805828697543,
+ "y": -11.021000376242682
+ },
+ {
+ "x": -0.006656805828697543,
+ "y": -11.021000376242682
+ },
+ {
+ "x": -0.0054464774962070805,
+ "y": -9.017182126016792
+ },
+ {
+ "x": -0.004841313329961849,
+ "y": -8.01527300090413
+ },
+ {
+ "x": -0.0054464774962070805,
+ "y": -9.01718212601736
+ },
+ {
+ "x": -0.006656805828697543,
+ "y": -11.021000376242682
+ },
+ {
+ "x": -0.006656805828697543,
+ "y": -11.021000376242682
+ },
+ {
+ "x": -0.006656805828697543,
+ "y": -11.021000376242682
+ },
+ {
+ "x": -0.007261969994942774,
+ "y": -12.022909501355912
+ },
+ {
+ "x": -0.007261969994942774,
+ "y": -12.02290950136728
+ },
+ {
+ "x": -0.007261969993805906,
+ "y": -12.022909501344543
+ },
+ {
+ "x": -0.006656805828697543,
+ "y": -11.02100037624325
+ },
+ {
+ "x": -0.00605164166358918,
+ "y": -10.019091251152759
+ },
+ {
+ "x": -0.0066568058275606745,
+ "y": -11.021000376231882
+ },
+ {
+ "x": -0.006656805828697543,
+ "y": -11.02100037624325
+ },
+ {
+ "x": -0.006051641662452312,
+ "y": -10.019091251130021
+ },
+ {
+ "x": -0.005446477495070212,
+ "y": -9.017182126005423
+ },
+ {
+ "x": -0.0054464774962070805,
+ "y": -9.017182126016792
+ },
+ {
+ "x": -0.006051641662452312,
+ "y": -10.019091251130021
+ },
+ {
+ "x": -0.0054464774962070805,
+ "y": -9.01718212601736
+ },
+ {
+ "x": -0.0054464774962070805,
+ "y": -9.01718212601736
+ },
+ {
+ "x": -0.0054464774962070805,
+ "y": -9.017182126016792
+ },
+ {
+ "x": -0.004841313329961849,
+ "y": -8.01527300090413
+ },
+ {
+ "x": -0.0054464774962070805,
+ "y": -9.01718212601736
+ },
+ {
+ "x": -0.006656805828697543,
+ "y": -11.021000376242682
+ },
+ {
+ "x": -0.007261969994942774,
+ "y": -12.022909501355912
+ },
+ {
+ "x": -0.006656805828697543,
+ "y": -11.02100037624325
+ },
+ {
+ "x": -0.006656805828697543,
+ "y": -11.02100037624325
+ },
+ {
+ "x": -0.006051641662452312,
+ "y": -10.019091251130021
+ },
+ {
+ "x": -0.0054464774962070805,
+ "y": -9.017182126016792
+ },
+ {
+ "x": -0.006656805828697543,
+ "y": -11.02100037624325
+ },
+ {
+ "x": -0.007261969994942774,
+ "y": -12.022909501345111
+ },
+ {
+ "x": -0.006656805828697543,
+ "y": -11.021000376231882
+ },
+ {
+ "x": -0.0054464774962070805,
+ "y": -9.017182126039529
+ },
+ {
+ "x": -0.006051641662452312,
+ "y": -10.01909125114139
+ },
+ {
+ "x": -0.006656805828697543,
+ "y": -11.02100037624325
+ },
+ {
+ "x": -0.006656805828697543,
+ "y": -11.02100037624325
+ },
+ {
+ "x": -0.006656805828697543,
+ "y": -11.021000376231882
+ },
+ {
+ "x": -0.0054464774962070805,
+ "y": -9.017182126005423
+ },
+ {
+ "x": -0.006051641662452312,
+ "y": -10.019091251130021
+ },
+ {
+ "x": -0.006051641662452312,
+ "y": -10.01909125114139
+ },
+ {
+ "x": -0.006051641662452312,
+ "y": -10.019091251130021
+ },
+ {
+ "x": -0.006656805828697543,
+ "y": -11.02100037624325
+ },
+ {
+ "x": -0.006051641662452312,
+ "y": -10.019091251130021
+ },
+ {
+ "x": -0.0054464774962070805,
+ "y": -9.017182126016792
+ },
+ {
+ "x": -0.004841313329961849,
+ "y": -8.015273000903562
+ },
+ {
+ "x": -0.0054464774962070805,
+ "y": -9.017182126016792
+ },
+ {
+ "x": -0.006051641662452312,
+ "y": -10.019091251130021
+ },
+ {
+ "x": -0.006051641662452312,
+ "y": -10.019091251140821
+ },
+ {
+ "x": -0.006051641662452312,
+ "y": -10.019091251129453
+ },
+ {
+ "x": -0.005446477495070212,
+ "y": -9.017182125994054
+ },
+ {
+ "x": -0.004841313329961849,
+ "y": -8.015273000903562
+ },
+ {
+ "x": -0.004841313329961849,
+ "y": -8.01527300090413
+ },
+ {
+ "x": -0.0054464774962070805,
+ "y": -9.01718212602816
+ },
+ {
+ "x": -0.005446477497343949,
+ "y": -9.01718212602816
+ },
+ {
+ "x": -0.004841313329961849,
+ "y": -8.01527300090413
+ },
+ {
+ "x": -0.006051641661315443,
+ "y": -10.019091251118084
+ },
+ {
+ "x": -0.007261969993805906,
+ "y": -12.022909501332606
+ },
+ {
+ "x": -0.00605164166358918,
+ "y": -10.019091251152759
+ },
+ {
+ "x": -0.004841313329961849,
+ "y": -8.01527300090413
+ },
+ {
+ "x": -0.005446477495070212,
+ "y": -9.017182126005423
+ },
+ {
+ "x": -0.005446477497343949,
+ "y": -9.017182126039529
+ },
+ {
+ "x": -0.0054464774962070805,
+ "y": -9.017182126016223
+ },
+ {
+ "x": -0.006051641661315443,
+ "y": -10.019091251118084
+ },
+ {
+ "x": -0.005453221996276625,
+ "y": -9.028348311280752
+ },
+ {
+ "x": -0.00606850291092087,
+ "y": -10.0470067142885
+ },
+ {
+ "x": -0.0060685029097840015,
+ "y": -10.047006714275994
+ },
+ {
+ "x": -0.004854802327827201,
+ "y": -8.037605371441146
+ },
+ {
+ "x": -0.004854802327827201,
+ "y": -8.037605371441714
+ },
+ {
+ "x": -0.0060685029097840015,
+ "y": -10.047006714275994
+ },
+ {
+ "x": -0.0060685029097840015,
+ "y": -10.047006714275994
+ },
+ {
+ "x": -0.00485480232896407,
+ "y": -8.037605371441146
+ },
+ {
+ "x": -0.00546165261994247,
+ "y": -9.042306042858286
+ },
+ {
+ "x": -0.006675353200762402,
+ "y": -11.05170738571644
+ },
+ {
+ "x": -0.007282203491740802,
+ "y": -12.056408057156318
+ },
+ {
+ "x": -0.007282203491740802,
+ "y": -12.056408057133012
+ },
+ {
+ "x": -0.00606850291092087,
+ "y": -10.047006714287363
+ },
+ {
+ "x": -0.00485480232896407,
+ "y": -8.037605371430345
+ },
+ {
+ "x": -0.0060685029097840015,
+ "y": -10.047006714275994
+ },
+ {
+ "x": -0.0060685029097840015,
+ "y": -10.047006714287363
+ },
+ {
+ "x": -0.0060685029097840015,
+ "y": -10.047006714298732
+ },
+ {
+ "x": -0.006675353200762402,
+ "y": -11.051707385715872
+ },
+ {
+ "x": -0.005461652618805601,
+ "y": -9.042306042858854
+ },
+ {
+ "x": -0.00546165261994247,
+ "y": -9.042306042858854
+ },
+ {
+ "x": -0.00546165261994247,
+ "y": -9.042306042858286
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 334.7816579641293,
+ "y": -195.79623487510275,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ },
+ {
+ "position": [
+ {
+ "x": 333.4145457505004,
+ "y": -126.94869021368251,
+ "z": 1.0
+ },
+ {
+ "x": 333.11065915516724,
+ "y": -127.28159127629539,
+ "z": 1.0
+ },
+ {
+ "x": 332.8388202990402,
+ "y": -127.5408461529031,
+ "z": 1.0
+ },
+ {
+ "x": 332.4740998353168,
+ "y": -127.84544927046008,
+ "z": 1.0
+ },
+ {
+ "x": 332.21851234968426,
+ "y": -128.0375613087877,
+ "z": 1.0
+ },
+ {
+ "x": 331.8883716074788,
+ "y": -128.26280080705058,
+ "z": 1.0
+ },
+ {
+ "x": 331.5471902743561,
+ "y": -128.47094126593532,
+ "z": 1.0
+ },
+ {
+ "x": 331.2668891448755,
+ "y": -128.62477820697123,
+ "z": 1.0
+ },
+ {
+ "x": 330.90852362645415,
+ "y": -128.8004960130125,
+ "z": 1.0
+ },
+ {
+ "x": 330.5411803754363,
+ "y": -128.95793338659394,
+ "z": 1.0
+ },
+ {
+ "x": 330.2418326926179,
+ "y": -129.07028837051308,
+ "z": 1.0
+ },
+ {
+ "x": 329.86162131658267,
+ "y": -129.19343286851142,
+ "z": 1.0
+ },
+ {
+ "x": 329.39783113296505,
+ "y": -129.31541954743648,
+ "z": 1.0
+ },
+ {
+ "x": 329.0062340233228,
+ "y": -129.39527707047642,
+ "z": 1.0
+ },
+ {
+ "x": 328.69034455550616,
+ "y": -129.44474248388758,
+ "z": 1.0
+ },
+ {
+ "x": 328.2930775110379,
+ "y": -129.4884137314665,
+ "z": 1.0
+ },
+ {
+ "x": 327.89463092744916,
+ "y": -129.51171443296764,
+ "z": 1.0
+ },
+ {
+ "x": 327.4468638830473,
+ "y": -129.51589217222232,
+ "z": 1.0
+ },
+ {
+ "x": 326.8449815717829,
+ "y": -129.51562325499071,
+ "z": 1.0
+ },
+ {
+ "x": 326.4437266976067,
+ "y": -129.5154439768363,
+ "z": 1.0
+ },
+ {
+ "x": 325.84184438634173,
+ "y": -129.5151750596047,
+ "z": 1.0
+ },
+ {
+ "x": 325.6412169492547,
+ "y": -129.5150854205275,
+ "z": 1.0
+ },
+ {
+ "x": 325.24065291057445,
+ "y": -129.51490645103408,
+ "z": 1.0
+ },
+ {
+ "x": 324.64033168535275,
+ "y": -129.51463823128591,
+ "z": 1.0
+ },
+ {
+ "x": 324.0400104601322,
+ "y": -129.51437001153772,
+ "z": 1.0
+ },
+ {
+ "x": 323.5397427724479,
+ "y": -129.51414649508092,
+ "z": 1.0
+ },
+ {
+ "x": 322.93942154722663,
+ "y": -129.51387827533276,
+ "z": 1.0
+ },
+ {
+ "x": 322.3391003220055,
+ "y": -129.51361005558456,
+ "z": 1.0
+ },
+ {
+ "x": 321.93888617185803,
+ "y": -129.51343124241913,
+ "z": 1.0
+ },
+ {
+ "x": 321.5386720217107,
+ "y": -129.51325242925367,
+ "z": 1.0
+ },
+ {
+ "x": 321.1384578715632,
+ "y": -129.51307361608823,
+ "z": 1.0
+ },
+ {
+ "x": 320.5381366463421,
+ "y": -129.51280539634007,
+ "z": 1.0
+ },
+ {
+ "x": 319.93781542112094,
+ "y": -129.51253717659188,
+ "z": 1.0
+ },
+ {
+ "x": 319.43754773343665,
+ "y": -129.51231366013508,
+ "z": 1.0
+ },
+ {
+ "x": 318.93728004575235,
+ "y": -129.51209014367828,
+ "z": 1.0
+ },
+ {
+ "x": 318.43701235806805,
+ "y": -129.51186662722145,
+ "z": 1.0
+ },
+ {
+ "x": 318.0367982079206,
+ "y": -129.51168781405602,
+ "z": 1.0
+ },
+ {
+ "x": 317.6365840577731,
+ "y": -129.51150900089056,
+ "z": 1.0
+ },
+ {
+ "x": 317.23636990762566,
+ "y": -129.51133018772512,
+ "z": 1.0
+ },
+ {
+ "x": 316.73610221994136,
+ "y": -129.5111066712683,
+ "z": 1.0
+ },
+ {
+ "x": 316.1357809947202,
+ "y": -129.51083845152013,
+ "z": 1.0
+ },
+ {
+ "x": 315.5354597694991,
+ "y": -129.51057023177196,
+ "z": 1.0
+ },
+ {
+ "x": 315.1352456193516,
+ "y": -129.5103914186065,
+ "z": 1.0
+ },
+ {
+ "x": 314.5349243941305,
+ "y": -129.51012319885834,
+ "z": 1.0
+ },
+ {
+ "x": 313.93460316890935,
+ "y": -129.50985497911017,
+ "z": 1.0
+ },
+ {
+ "x": 313.5343890187619,
+ "y": -129.5096761659447,
+ "z": 1.0
+ },
+ {
+ "x": 313.0341213310776,
+ "y": -129.5094526494879,
+ "z": 1.0
+ },
+ {
+ "x": 312.5338536433933,
+ "y": -129.5092291330311,
+ "z": 1.0
+ },
+ {
+ "x": 312.033585955709,
+ "y": -129.50900561657429,
+ "z": 1.0
+ },
+ {
+ "x": 311.6333718055615,
+ "y": -129.50882680340885,
+ "z": 1.0
+ },
+ {
+ "x": 311.0330505803404,
+ "y": -129.5085585836607,
+ "z": 1.0
+ },
+ {
+ "x": 310.43272935511925,
+ "y": -129.5082903639125,
+ "z": 1.0
+ },
+ {
+ "x": 309.8324081298981,
+ "y": -129.50802214416433,
+ "z": 1.0
+ },
+ {
+ "x": 309.43219397975065,
+ "y": -129.5078433309989,
+ "z": 1.0
+ },
+ {
+ "x": 308.93192629206635,
+ "y": -129.50761981454207,
+ "z": 1.0
+ },
+ {
+ "x": 308.5317121419189,
+ "y": -129.50744100137663,
+ "z": 1.0
+ },
+ {
+ "x": 308.13149799177154,
+ "y": -129.50726218821117,
+ "z": 1.0
+ },
+ {
+ "x": 307.7312838416241,
+ "y": -129.50708337504574,
+ "z": 1.0
+ },
+ {
+ "x": 307.13096261640237,
+ "y": -129.50681515529757,
+ "z": 1.0
+ },
+ {
+ "x": 306.5306413911818,
+ "y": -129.50654693554938,
+ "z": 1.0
+ },
+ {
+ "x": 305.93032016596055,
+ "y": -129.50627871580122,
+ "z": 1.0
+ },
+ {
+ "x": 305.43005247827625,
+ "y": -129.50605519934442,
+ "z": 1.0
+ },
+ {
+ "x": 304.8297312530551,
+ "y": -129.50578697959622,
+ "z": 1.0
+ },
+ {
+ "x": 304.229410027834,
+ "y": -129.50551875984806,
+ "z": 1.0
+ },
+ {
+ "x": 303.7291423401497,
+ "y": -129.50529524339126,
+ "z": 1.0
+ },
+ {
+ "x": 303.3289281900022,
+ "y": -129.5051164302258,
+ "z": 1.0
+ },
+ {
+ "x": 302.8286605023179,
+ "y": -129.504892913769,
+ "z": 1.0
+ },
+ {
+ "x": 302.2283392770968,
+ "y": -129.50462469402083,
+ "z": 1.0
+ },
+ {
+ "x": 301.7280715894125,
+ "y": -129.504401177564,
+ "z": 1.0
+ },
+ {
+ "x": 301.327857439265,
+ "y": -129.50422236439857,
+ "z": 1.0
+ },
+ {
+ "x": 300.7275362140433,
+ "y": -129.5039541446504,
+ "z": 1.0
+ },
+ {
+ "x": 300.3273220638964,
+ "y": -129.50377533148495,
+ "z": 1.0
+ },
+ {
+ "x": 299.8270543762121,
+ "y": -129.50355181502815,
+ "z": 1.0
+ },
+ {
+ "x": 299.3267866885278,
+ "y": -129.50332829857132,
+ "z": 1.0
+ },
+ {
+ "x": 298.92657253838047,
+ "y": -129.50314948540588,
+ "z": 1.0
+ },
+ {
+ "x": 298.32625131315876,
+ "y": -129.50288126565772,
+ "z": 1.0
+ },
+ {
+ "x": 297.82598362547503,
+ "y": -129.5026577492009,
+ "z": 1.0
+ },
+ {
+ "x": 297.2256624002538,
+ "y": -129.50238952945273,
+ "z": 1.0
+ },
+ {
+ "x": 296.7253947125689,
+ "y": -129.50216601299593,
+ "z": 1.0
+ },
+ {
+ "x": 296.12507348734835,
+ "y": -129.50189779324774,
+ "z": 1.0
+ },
+ {
+ "x": 295.7248593372009,
+ "y": -129.5017189800823,
+ "z": 1.0
+ },
+ {
+ "x": 295.1245381119792,
+ "y": -129.50145076033414,
+ "z": 1.0
+ },
+ {
+ "x": 294.7243239618324,
+ "y": -129.50127194716868,
+ "z": 1.0
+ },
+ {
+ "x": 294.32410981168437,
+ "y": -129.50109313400324,
+ "z": 1.0
+ },
+ {
+ "x": 293.82384212400063,
+ "y": -129.5008696175464,
+ "z": 1.0
+ },
+ {
+ "x": 293.4236279738532,
+ "y": -129.50069080438098,
+ "z": 1.0
+ },
+ {
+ "x": 292.9233602861689,
+ "y": -129.50046728792415,
+ "z": 1.0
+ },
+ {
+ "x": 292.32303906094774,
+ "y": -129.500199068176,
+ "z": 1.0
+ },
+ {
+ "x": 291.9228249108003,
+ "y": -129.50002025501055,
+ "z": 1.0
+ },
+ {
+ "x": 291.32250368557914,
+ "y": -129.49975203526236,
+ "z": 1.0
+ },
+ {
+ "x": 290.9222895354317,
+ "y": -129.49957322209693,
+ "z": 1.0
+ }
+ ],
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": 32,
+ "heading": [
+ 1.9659351147996624,
+ -2.3106621792270796,
+ -2.342126791184687,
+ -2.4166839819179406,
+ -2.4663910593611247,
+ -2.5225037539646777,
+ -2.5683436896219303,
+ -2.614183605833329,
+ -2.6652237205605016,
+ -2.7112171490512793,
+ -2.757063638376234,
+ -2.8079968773903605,
+ -2.858930107778461,
+ -2.9098633595080114,
+ -2.960796591246271,
+ -3.011729844024768,
+ -3.057624659728072,
+ -3.1091318330827113,
+ -3.1378687395670917,
+ 3.141145859908236,
+ 3.141145859908236,
+ 3.1411458599082356,
+ 3.1411458599082875,
+ 3.141145859908284,
+ 3.14114585990824,
+ 3.141145859908242,
+ 3.141145859908268,
+ 3.14114585990824,
+ 3.1411458599082445,
+ 3.1411458599082516,
+ 3.1411458599082516,
+ 3.141145859908273,
+ 3.14114585990824,
+ 3.1411458599082422,
+ 3.141145859908273,
+ 3.1411458599082445,
+ 3.141145859908248,
+ 3.1411458599082516,
+ 3.1411458599082516,
+ 3.141145859908248,
+ 3.1411458599082422,
+ 3.1411458599082636,
+ 3.1411458599082445,
+ 3.1411458599082445,
+ 3.1411458599082636,
+ 3.1411458599082445,
+ 3.141145859908248,
+ 3.141145859908273,
+ 3.1411458599082445,
+ 3.141145859908248,
+ 3.141145859908273,
+ 3.14114585990824,
+ 3.14114585990824,
+ 3.141145859908273,
+ 3.141145859908248,
+ 3.141145859908248,
+ 3.1411458599082516,
+ 3.1411458599082516,
+ 3.1411458599082733,
+ 3.14114585990824,
+ 3.1411458599082396,
+ 3.141145859908268,
+ 3.1411458599082422,
+ 3.14114585990824,
+ 3.141145859908268,
+ 3.141145859908248,
+ 3.141145859908248,
+ 3.141145859908268,
+ 3.1411458599082422,
+ 3.141145859908248,
+ 3.1411458599082733,
+ 3.1411458599082445,
+ 3.1411458599082476,
+ 3.1411458599082445,
+ 3.1411458599082476,
+ 3.1411458599082733,
+ 3.1411458599082422,
+ 3.141145859908242,
+ 3.141145859908268,
+ 3.1411458599082422,
+ 3.1411458599082445,
+ 3.1411458599082733,
+ 3.1411458599082445,
+ 3.1411458599082516,
+ 3.141145859908248,
+ 3.1411458599082476,
+ 3.141145859908248,
+ 3.1411458599082422,
+ 3.141145859908273,
+ 3.1411458599082445,
+ 3.1411458599082445
+ ],
+ "velocity": [
+ {
+ "x": 0.0,
+ "y": 0.0
+ },
+ {
+ "x": -3.0388659533315376,
+ "y": -3.3290106261287633
+ },
+ {
+ "x": -5.757254514601868,
+ "y": -5.921559392205893
+ },
+ {
+ "x": -6.3655931985044845,
+ "y": -5.638579941646924
+ },
+ {
+ "x": -6.203079493559471,
+ "y": -4.9671515588460124
+ },
+ {
+ "x": -5.857282278379898,
+ "y": -4.173515365905018
+ },
+ {
+ "x": -6.713220753281348,
+ "y": -4.33379957147622
+ },
+ {
+ "x": -6.214824626032964,
+ "y": -3.6197739992064726
+ },
+ {
+ "x": -6.386666479019709,
+ "y": -3.2955474707716803
+ },
+ {
+ "x": -7.257087694392226,
+ "y": -3.3315517962270746
+ },
+ {
+ "x": -6.666909338362643,
+ "y": -2.697923575005916
+ },
+ {
+ "x": -6.795590588536129,
+ "y": -2.3549948191748626
+ },
+ {
+ "x": -8.440015596528383,
+ "y": -2.4513117692339392
+ },
+ {
+ "x": -8.553872932598665,
+ "y": -2.018442019650024
+ },
+ {
+ "x": -7.074865774588943,
+ "y": -1.2932293645110349
+ },
+ {
+ "x": -7.131565122849111,
+ "y": -0.9313666099006923
+ },
+ {
+ "x": -7.957136280570012,
+ "y": -0.6697194908005599
+ },
+ {
+ "x": -8.462136279906076,
+ "y": -0.27478440755828615
+ },
+ {
+ "x": -10.496493556662472,
+ "y": -0.039088220230780735
+ },
+ {
+ "x": -10.031371854406075,
+ "y": 0.004481953860135945
+ },
+ {
+ "x": -10.03137185441176,
+ "y": 0.004481953860135945
+ },
+ {
+ "x": -8.025097483519517,
+ "y": 0.0035855630881087563
+ },
+ {
+ "x": -6.011914757672798,
+ "y": 0.0026860857062160903
+ },
+ {
+ "x": -10.008852639019779,
+ "y": 0.00447189241583601
+ },
+ {
+ "x": -12.00642450442274,
+ "y": 0.005364394963578434
+ },
+ {
+ "x": -11.005889129048683,
+ "y": 0.004917362049923213
+ },
+ {
+ "x": -11.005889129055504,
+ "y": 0.004917362049638996
+ },
+ {
+ "x": -12.006424504423876,
+ "y": 0.005364394963578434
+ },
+ {
+ "x": -10.005353753685995,
+ "y": 0.004470329136267992
+ },
+ {
+ "x": -8.004283002948114,
+ "y": 0.00357626330895755
+ },
+ {
+ "x": -8.004283002948114,
+ "y": 0.00357626330895755
+ },
+ {
+ "x": -10.005353753685995,
+ "y": 0.004470329135983775
+ },
+ {
+ "x": -12.00642450442274,
+ "y": 0.005364394963578434
+ },
+ {
+ "x": -11.005889129054367,
+ "y": 0.004917362049923213
+ },
+ {
+ "x": -10.005353753685995,
+ "y": 0.004470329135983775
+ },
+ {
+ "x": -10.005353753685995,
+ "y": 0.004470329136267992
+ },
+ {
+ "x": -9.004818378317623,
+ "y": 0.004023296222612771
+ },
+ {
+ "x": -8.00428300294925,
+ "y": 0.00357626330895755
+ },
+ {
+ "x": -8.00428300294925,
+ "y": 0.00357626330895755
+ },
+ {
+ "x": -9.004818378317623,
+ "y": 0.004023296222612771
+ },
+ {
+ "x": -11.005889129054367,
+ "y": 0.004917362049923213
+ },
+ {
+ "x": -12.00642450442274,
+ "y": 0.005364394963294217
+ },
+ {
+ "x": -10.005353753685995,
+ "y": 0.004470329136267992
+ },
+ {
+ "x": -10.005353753685995,
+ "y": 0.004470329136267992
+ },
+ {
+ "x": -12.00642450442274,
+ "y": 0.005364394963294217
+ },
+ {
+ "x": -10.005353753685995,
+ "y": 0.004470329136267992
+ },
+ {
+ "x": -9.004818378317623,
+ "y": 0.004023296222612771
+ },
+ {
+ "x": -10.005353753685995,
+ "y": 0.004470329135983775
+ },
+ {
+ "x": -10.005353753685995,
+ "y": 0.004470329136267992
+ },
+ {
+ "x": -9.004818378317623,
+ "y": 0.004023296222612771
+ },
+ {
+ "x": -10.005353753685995,
+ "y": 0.004470329135983775
+ },
+ {
+ "x": -12.00642450442274,
+ "y": 0.005364394963578434
+ },
+ {
+ "x": -12.00642450442274,
+ "y": 0.005364394963578434
+ },
+ {
+ "x": -10.005353753685995,
+ "y": 0.004470329135983775
+ },
+ {
+ "x": -9.004818378317623,
+ "y": 0.004023296222612771
+ },
+ {
+ "x": -9.004818378317623,
+ "y": 0.004023296222612771
+ },
+ {
+ "x": -8.004283002948114,
+ "y": 0.00357626330895755
+ },
+ {
+ "x": -8.004283002948114,
+ "y": 0.00357626330895755
+ },
+ {
+ "x": -10.00535375369168,
+ "y": 0.004470329135983775
+ },
+ {
+ "x": -12.00642450442274,
+ "y": 0.005364394963578434
+ },
+ {
+ "x": -12.006424504418192,
+ "y": 0.005364394963578434
+ },
+ {
+ "x": -11.005889129055504,
+ "y": 0.004917362049638996
+ },
+ {
+ "x": -11.005889129054367,
+ "y": 0.004917362049923213
+ },
+ {
+ "x": -12.00642450442274,
+ "y": 0.005364394963578434
+ },
+ {
+ "x": -11.005889129054367,
+ "y": 0.004917362049638996
+ },
+ {
+ "x": -9.004818378317623,
+ "y": 0.004023296222612771
+ },
+ {
+ "x": -9.004818378317623,
+ "y": 0.004023296222612771
+ },
+ {
+ "x": -11.005889129054367,
+ "y": 0.004917362049638996
+ },
+ {
+ "x": -11.005889129054367,
+ "y": 0.004917362049923213
+ },
+ {
+ "x": -9.004818378317623,
+ "y": 0.004023296222612771
+ },
+ {
+ "x": -10.00535375369168,
+ "y": 0.004470329135983775
+ },
+ {
+ "x": -10.005353753685995,
+ "y": 0.004470329136267992
+ },
+ {
+ "x": -9.004818378311938,
+ "y": 0.004023296222612771
+ },
+ {
+ "x": -10.005353753685995,
+ "y": 0.004470329136267992
+ },
+ {
+ "x": -9.004818378316486,
+ "y": 0.004023296222612771
+ },
+ {
+ "x": -10.005353753690542,
+ "y": 0.004470329135983775
+ },
+ {
+ "x": -11.005889129054367,
+ "y": 0.004917362049923213
+ },
+ {
+ "x": -11.00588912904982,
+ "y": 0.004917362049923213
+ },
+ {
+ "x": -11.005889129061188,
+ "y": 0.004917362049638996
+ },
+ {
+ "x": -11.005889129054367,
+ "y": 0.004917362049923213
+ },
+ {
+ "x": -10.00535375368031,
+ "y": 0.004470329136267992
+ },
+ {
+ "x": -10.00535375369168,
+ "y": 0.004470329135983775
+ },
+ {
+ "x": -10.005353753684858,
+ "y": 0.004470329136267992
+ },
+ {
+ "x": -8.004283002948114,
+ "y": 0.00357626330895755
+ },
+ {
+ "x": -9.004818378317623,
+ "y": 0.004023296222612771
+ },
+ {
+ "x": -9.004818378311938,
+ "y": 0.004023296222612771
+ },
+ {
+ "x": -9.004818378317623,
+ "y": 0.004023296222612771
+ },
+ {
+ "x": -11.005889129054367,
+ "y": 0.004917362049923213
+ },
+ {
+ "x": -10.005353753685995,
+ "y": 0.004470329135983775
+ },
+ {
+ "x": -10.005353753685995,
+ "y": 0.004470329136267992
+ },
+ {
+ "x": -10.005353753685995,
+ "y": 0.004470329136267992
+ }
+ ],
+ "valid": [
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true
+ ],
+ "goalPosition": {
+ "x": 290.9222895354317,
+ "y": -129.49957322209693,
+ "z": 1.0
+ },
+ "type": "vehicle",
+ "mark_as_expert": false
+ }
+ ],
+ "roads": [
+ {
+ "id": 0,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 348.227876521873,
+ "y": -4.0006836701775725,
+ "z": 0.0
+ },
+ {
+ "x": 349.26673351814094,
+ "y": -4.001235549176161,
+ "z": 0.0
+ },
+ {
+ "x": 350.3055905144089,
+ "y": -4.001787428174748,
+ "z": 0.0
+ },
+ {
+ "x": 351.34444751067684,
+ "y": -4.002339307173337,
+ "z": 0.0
+ },
+ {
+ "x": 352.3833045069448,
+ "y": -4.002891186171924,
+ "z": 0.0
+ },
+ {
+ "x": 353.42216150321275,
+ "y": -4.0034430651705115,
+ "z": 0.0
+ },
+ {
+ "x": 354.4610184994807,
+ "y": -4.0039949441691,
+ "z": 0.0
+ },
+ {
+ "x": 355.49987549574865,
+ "y": -4.004546823167687,
+ "z": 0.0
+ },
+ {
+ "x": 356.5387324920166,
+ "y": -4.005098702166276,
+ "z": 0.0
+ },
+ {
+ "x": 357.57758948828456,
+ "y": -4.005650581164863,
+ "z": 0.0
+ },
+ {
+ "x": 358.6164464845525,
+ "y": -4.006202460163451,
+ "z": 0.0
+ },
+ {
+ "x": 359.65530348082046,
+ "y": -4.006754339162039,
+ "z": 0.0
+ },
+ {
+ "x": 360.6941604770884,
+ "y": -4.007306218160627,
+ "z": 0.0
+ },
+ {
+ "x": 361.7330174733564,
+ "y": -4.007858097159215,
+ "z": 0.0
+ },
+ {
+ "x": 362.7718744696244,
+ "y": -4.008409976157803,
+ "z": 0.0
+ },
+ {
+ "x": 363.81073146589233,
+ "y": -4.00896185515639,
+ "z": 0.0
+ },
+ {
+ "x": 364.8495884621603,
+ "y": -4.009513734154979,
+ "z": 0.0
+ },
+ {
+ "x": 365.88844545842824,
+ "y": -4.010065613153566,
+ "z": 0.0
+ },
+ {
+ "x": 366.9273024546962,
+ "y": -4.0106174921521545,
+ "z": 0.0
+ },
+ {
+ "x": 367.96615945096414,
+ "y": -4.011169371150742,
+ "z": 0.0
+ },
+ {
+ "x": 369.0050164472321,
+ "y": -4.011721250149329,
+ "z": 0.0
+ },
+ {
+ "x": 370.04387344350005,
+ "y": -4.012273129147918,
+ "z": 0.0
+ },
+ {
+ "x": 371.082730439768,
+ "y": -4.012825008146505,
+ "z": 0.0
+ },
+ {
+ "x": 372.12158743603595,
+ "y": -4.013376887145093,
+ "z": 0.0
+ },
+ {
+ "x": 373.1604444323039,
+ "y": -4.013928766143681,
+ "z": 0.0
+ },
+ {
+ "x": 374.19930142857186,
+ "y": -4.014480645142269,
+ "z": 0.0
+ },
+ {
+ "x": 375.2381584248398,
+ "y": -4.015032524140857,
+ "z": 0.0
+ },
+ {
+ "x": 376.27701542110776,
+ "y": -4.015584403139445,
+ "z": 0.0
+ },
+ {
+ "x": 377.3158724173757,
+ "y": -4.016136282138032,
+ "z": 0.0
+ },
+ {
+ "x": 378.35472941364367,
+ "y": -4.016688161136621,
+ "z": 0.0
+ },
+ {
+ "x": 379.3935864099116,
+ "y": -4.017240040135208,
+ "z": 0.0
+ },
+ {
+ "x": 380.4324434061796,
+ "y": -4.0177919191337965,
+ "z": 0.0
+ },
+ {
+ "x": 381.4713004024475,
+ "y": -4.018343798132384,
+ "z": 0.0
+ },
+ {
+ "x": 382.5101573987155,
+ "y": -4.018895677130972,
+ "z": 0.0
+ },
+ {
+ "x": 383.54901439498343,
+ "y": -4.01944755612956,
+ "z": 0.0
+ },
+ {
+ "x": 384.5878713912514,
+ "y": -4.019999435128147,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 1,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 384.59212128452987,
+ "y": 3.9799994360222173,
+ "z": 0.0
+ },
+ {
+ "x": 383.5532642882619,
+ "y": 3.980551315020805,
+ "z": 0.0
+ },
+ {
+ "x": 382.51440729199396,
+ "y": 3.981103194019393,
+ "z": 0.0
+ },
+ {
+ "x": 381.475550295726,
+ "y": 3.981655073017981,
+ "z": 0.0
+ },
+ {
+ "x": 380.43669329945806,
+ "y": 3.982206952016569,
+ "z": 0.0
+ },
+ {
+ "x": 379.3978363031901,
+ "y": 3.9827588310151567,
+ "z": 0.0
+ },
+ {
+ "x": 378.35897930692215,
+ "y": 3.9833107100137446,
+ "z": 0.0
+ },
+ {
+ "x": 377.3201223106542,
+ "y": 3.9838625890123325,
+ "z": 0.0
+ },
+ {
+ "x": 376.28126531438625,
+ "y": 3.9844144680109204,
+ "z": 0.0
+ },
+ {
+ "x": 375.2424083181183,
+ "y": 3.984966347009508,
+ "z": 0.0
+ },
+ {
+ "x": 374.20355132185034,
+ "y": 3.9855182260080957,
+ "z": 0.0
+ },
+ {
+ "x": 373.1646943255824,
+ "y": 3.9860701050066836,
+ "z": 0.0
+ },
+ {
+ "x": 372.12583732931444,
+ "y": 3.9866219840052715,
+ "z": 0.0
+ },
+ {
+ "x": 371.0869803330465,
+ "y": 3.9871738630038593,
+ "z": 0.0
+ },
+ {
+ "x": 370.04812333677853,
+ "y": 3.9877257420024472,
+ "z": 0.0
+ },
+ {
+ "x": 369.0092663405106,
+ "y": 3.988277621001035,
+ "z": 0.0
+ },
+ {
+ "x": 367.9704093442426,
+ "y": 3.988829499999623,
+ "z": 0.0
+ },
+ {
+ "x": 366.9315523479747,
+ "y": 3.989381378998211,
+ "z": 0.0
+ },
+ {
+ "x": 365.8926953517067,
+ "y": 3.9899332579967988,
+ "z": 0.0
+ },
+ {
+ "x": 364.85383835543877,
+ "y": 3.9904851369953867,
+ "z": 0.0
+ },
+ {
+ "x": 363.8149813591708,
+ "y": 3.9910370159939745,
+ "z": 0.0
+ },
+ {
+ "x": 362.77612436290286,
+ "y": 3.9915888949925624,
+ "z": 0.0
+ },
+ {
+ "x": 361.7372673666349,
+ "y": 3.9921407739911503,
+ "z": 0.0
+ },
+ {
+ "x": 360.6984103703669,
+ "y": 3.992692652989738,
+ "z": 0.0
+ },
+ {
+ "x": 359.65955337409895,
+ "y": 3.9932445319883256,
+ "z": 0.0
+ },
+ {
+ "x": 358.620696377831,
+ "y": 3.9937964109869135,
+ "z": 0.0
+ },
+ {
+ "x": 357.58183938156304,
+ "y": 3.9943482899855014,
+ "z": 0.0
+ },
+ {
+ "x": 356.5429823852951,
+ "y": 3.9949001689840893,
+ "z": 0.0
+ },
+ {
+ "x": 355.50412538902714,
+ "y": 3.995452047982677,
+ "z": 0.0
+ },
+ {
+ "x": 354.4652683927592,
+ "y": 3.996003926981265,
+ "z": 0.0
+ },
+ {
+ "x": 353.42641139649123,
+ "y": 3.996555805979853,
+ "z": 0.0
+ },
+ {
+ "x": 352.3875544002233,
+ "y": 3.997107684978441,
+ "z": 0.0
+ },
+ {
+ "x": 351.3486974039553,
+ "y": 3.9976595639770287,
+ "z": 0.0
+ },
+ {
+ "x": 350.3098404076874,
+ "y": 3.9982114429756166,
+ "z": 0.0
+ },
+ {
+ "x": 349.2709834114194,
+ "y": 3.9987633219742045,
+ "z": 0.0
+ },
+ {
+ "x": 348.23212641515147,
+ "y": 3.9993152009727924,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 2,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 384.5899963378906,
+ "y": -0.019999999552965164,
+ "z": 0.0
+ },
+ {
+ "x": 383.5511393416227,
+ "y": -0.019448120554377307,
+ "z": 0.0
+ },
+ {
+ "x": 382.5122823453547,
+ "y": -0.01889624155578945,
+ "z": 0.0
+ },
+ {
+ "x": 381.47342534908677,
+ "y": -0.018344362557201593,
+ "z": 0.0
+ },
+ {
+ "x": 380.4345683528188,
+ "y": -0.017792483558613733,
+ "z": 0.0
+ },
+ {
+ "x": 379.39571135655086,
+ "y": -0.017240604560025876,
+ "z": 0.0
+ },
+ {
+ "x": 378.3568543602829,
+ "y": -0.01668872556143802,
+ "z": 0.0
+ },
+ {
+ "x": 377.31799736401496,
+ "y": -0.016136846562850162,
+ "z": 0.0
+ },
+ {
+ "x": 376.279140367747,
+ "y": -0.015584967564262307,
+ "z": 0.0
+ },
+ {
+ "x": 375.24028337147905,
+ "y": -0.01503308856567445,
+ "z": 0.0
+ },
+ {
+ "x": 374.2014263752111,
+ "y": -0.014481209567086591,
+ "z": 0.0
+ },
+ {
+ "x": 373.16256937894315,
+ "y": -0.013929330568498734,
+ "z": 0.0
+ },
+ {
+ "x": 372.1237123826752,
+ "y": -0.013377451569910877,
+ "z": 0.0
+ },
+ {
+ "x": 371.08485538640724,
+ "y": -0.01282557257132305,
+ "z": 0.0
+ },
+ {
+ "x": 370.0459983901393,
+ "y": -0.012273693572735195,
+ "z": 0.0
+ },
+ {
+ "x": 369.00714139387134,
+ "y": -0.011721814574147336,
+ "z": 0.0
+ },
+ {
+ "x": 367.9682843976034,
+ "y": -0.01116993557555948,
+ "z": 0.0
+ },
+ {
+ "x": 366.92942740133543,
+ "y": -0.01061805657697162,
+ "z": 0.0
+ },
+ {
+ "x": 365.8905704050675,
+ "y": -0.010066177578383764,
+ "z": 0.0
+ },
+ {
+ "x": 364.8517134087995,
+ "y": -0.009514298579795905,
+ "z": 0.0
+ },
+ {
+ "x": 363.8128564125316,
+ "y": -0.008962419581208046,
+ "z": 0.0
+ },
+ {
+ "x": 362.7739994162636,
+ "y": -0.00841054058262019,
+ "z": 0.0
+ },
+ {
+ "x": 361.73514241999567,
+ "y": -0.00785866158403233,
+ "z": 0.0
+ },
+ {
+ "x": 360.69628542372766,
+ "y": -0.007306782585444471,
+ "z": 0.0
+ },
+ {
+ "x": 359.6574284274597,
+ "y": -0.006754903586856614,
+ "z": 0.0
+ },
+ {
+ "x": 358.61857143119175,
+ "y": -0.0062030245882687554,
+ "z": 0.0
+ },
+ {
+ "x": 357.5797144349238,
+ "y": -0.005651145589680897,
+ "z": 0.0
+ },
+ {
+ "x": 356.54085743865585,
+ "y": -0.00509926659109304,
+ "z": 0.0
+ },
+ {
+ "x": 355.5020004423879,
+ "y": -0.004547387592505183,
+ "z": 0.0
+ },
+ {
+ "x": 354.46314344611994,
+ "y": -0.003995508593917322,
+ "z": 0.0
+ },
+ {
+ "x": 353.424286449852,
+ "y": -0.0034436295953294634,
+ "z": 0.0
+ },
+ {
+ "x": 352.38542945358404,
+ "y": -0.0028917505967416064,
+ "z": 0.0
+ },
+ {
+ "x": 351.3465724573161,
+ "y": -0.002339871598153753,
+ "z": 0.0
+ },
+ {
+ "x": 350.30771546104813,
+ "y": -0.001787992599565896,
+ "z": 0.0
+ },
+ {
+ "x": 349.2688584647802,
+ "y": -0.0012361136009780352,
+ "z": 0.0
+ },
+ {
+ "x": 348.2300014685122,
+ "y": -0.0006842346023901782,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 3,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 348.2289389951926,
+ "y": -2.0006839523899815,
+ "z": 0.0
+ },
+ {
+ "x": 349.26779599146056,
+ "y": -2.0012358313885694,
+ "z": 0.0
+ },
+ {
+ "x": 350.3066529877285,
+ "y": -2.0017877103871573,
+ "z": 0.0
+ },
+ {
+ "x": 351.34550998399646,
+ "y": -2.002339589385745,
+ "z": 0.0
+ },
+ {
+ "x": 352.3843669802644,
+ "y": -2.0028914683843326,
+ "z": 0.0
+ },
+ {
+ "x": 353.42322397653237,
+ "y": -2.0034433473829205,
+ "z": 0.0
+ },
+ {
+ "x": 354.4620809728003,
+ "y": -2.0039952263815084,
+ "z": 0.0
+ },
+ {
+ "x": 355.5009379690683,
+ "y": -2.0045471053800963,
+ "z": 0.0
+ },
+ {
+ "x": 356.5397949653362,
+ "y": -2.005098984378684,
+ "z": 0.0
+ },
+ {
+ "x": 357.5786519616042,
+ "y": -2.005650863377272,
+ "z": 0.0
+ },
+ {
+ "x": 358.61750895787213,
+ "y": -2.00620274237586,
+ "z": 0.0
+ },
+ {
+ "x": 359.6563659541401,
+ "y": -2.006754621374448,
+ "z": 0.0
+ },
+ {
+ "x": 360.69522295040804,
+ "y": -2.0073065003730357,
+ "z": 0.0
+ },
+ {
+ "x": 361.73407994667605,
+ "y": -2.0078583793716236,
+ "z": 0.0
+ },
+ {
+ "x": 362.772936942944,
+ "y": -2.0084102583702115,
+ "z": 0.0
+ },
+ {
+ "x": 363.81179393921195,
+ "y": -2.0089621373687994,
+ "z": 0.0
+ },
+ {
+ "x": 364.8506509354799,
+ "y": -2.0095140163673872,
+ "z": 0.0
+ },
+ {
+ "x": 365.88950793174786,
+ "y": -2.010065895365975,
+ "z": 0.0
+ },
+ {
+ "x": 366.9283649280158,
+ "y": -2.010617774364563,
+ "z": 0.0
+ },
+ {
+ "x": 367.96722192428376,
+ "y": -2.011169653363151,
+ "z": 0.0
+ },
+ {
+ "x": 369.0060789205517,
+ "y": -2.0117215323617383,
+ "z": 0.0
+ },
+ {
+ "x": 370.04493591681967,
+ "y": -2.0122734113603262,
+ "z": 0.0
+ },
+ {
+ "x": 371.0837929130876,
+ "y": -2.012825290358914,
+ "z": 0.0
+ },
+ {
+ "x": 372.1226499093556,
+ "y": -2.013377169357502,
+ "z": 0.0
+ },
+ {
+ "x": 373.1615069056235,
+ "y": -2.01392904835609,
+ "z": 0.0
+ },
+ {
+ "x": 374.2003639018915,
+ "y": -2.0144809273546778,
+ "z": 0.0
+ },
+ {
+ "x": 375.23922089815943,
+ "y": -2.0150328063532656,
+ "z": 0.0
+ },
+ {
+ "x": 376.2780778944274,
+ "y": -2.0155846853518535,
+ "z": 0.0
+ },
+ {
+ "x": 377.31693489069534,
+ "y": -2.0161365643504414,
+ "z": 0.0
+ },
+ {
+ "x": 378.3557918869633,
+ "y": -2.0166884433490293,
+ "z": 0.0
+ },
+ {
+ "x": 379.39464888323124,
+ "y": -2.017240322347617,
+ "z": 0.0
+ },
+ {
+ "x": 380.4335058794992,
+ "y": -2.017792201346205,
+ "z": 0.0
+ },
+ {
+ "x": 381.47236287576715,
+ "y": -2.018344080344793,
+ "z": 0.0
+ },
+ {
+ "x": 382.5112198720351,
+ "y": -2.018895959343381,
+ "z": 0.0
+ },
+ {
+ "x": 383.55007686830305,
+ "y": -2.0194478383419687,
+ "z": 0.0
+ },
+ {
+ "x": 384.588933864571,
+ "y": -2.019999717340556,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 4,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 384.59105881121025,
+ "y": 1.979999718234626,
+ "z": 0.0
+ },
+ {
+ "x": 383.5522018149423,
+ "y": 1.980551597233214,
+ "z": 0.0
+ },
+ {
+ "x": 382.51334481867434,
+ "y": 1.9811034762318018,
+ "z": 0.0
+ },
+ {
+ "x": 381.4744878224064,
+ "y": 1.9816553552303897,
+ "z": 0.0
+ },
+ {
+ "x": 380.43563082613844,
+ "y": 1.9822072342289776,
+ "z": 0.0
+ },
+ {
+ "x": 379.3967738298705,
+ "y": 1.9827591132275655,
+ "z": 0.0
+ },
+ {
+ "x": 378.35791683360253,
+ "y": 1.9833109922261534,
+ "z": 0.0
+ },
+ {
+ "x": 377.3190598373346,
+ "y": 1.9838628712247413,
+ "z": 0.0
+ },
+ {
+ "x": 376.2802028410666,
+ "y": 1.9844147502233291,
+ "z": 0.0
+ },
+ {
+ "x": 375.2413458447987,
+ "y": 1.9849666292219166,
+ "z": 0.0
+ },
+ {
+ "x": 374.2024888485307,
+ "y": 1.9855185082205045,
+ "z": 0.0
+ },
+ {
+ "x": 373.16363185226277,
+ "y": 1.9860703872190923,
+ "z": 0.0
+ },
+ {
+ "x": 372.1247748559948,
+ "y": 1.9866222662176802,
+ "z": 0.0
+ },
+ {
+ "x": 371.08591785972686,
+ "y": 1.9871741452162681,
+ "z": 0.0
+ },
+ {
+ "x": 370.0470608634589,
+ "y": 1.987726024214856,
+ "z": 0.0
+ },
+ {
+ "x": 369.00820386719096,
+ "y": 1.9882779032134439,
+ "z": 0.0
+ },
+ {
+ "x": 367.969346870923,
+ "y": 1.9888297822120318,
+ "z": 0.0
+ },
+ {
+ "x": 366.93048987465505,
+ "y": 1.9893816612106197,
+ "z": 0.0
+ },
+ {
+ "x": 365.8916328783871,
+ "y": 1.9899335402092075,
+ "z": 0.0
+ },
+ {
+ "x": 364.85277588211915,
+ "y": 1.9904854192077954,
+ "z": 0.0
+ },
+ {
+ "x": 363.8139188858512,
+ "y": 1.9910372982063833,
+ "z": 0.0
+ },
+ {
+ "x": 362.77506188958324,
+ "y": 1.9915891772049712,
+ "z": 0.0
+ },
+ {
+ "x": 361.7362048933153,
+ "y": 1.992141056203559,
+ "z": 0.0
+ },
+ {
+ "x": 360.6973478970473,
+ "y": 1.992692935202147,
+ "z": 0.0
+ },
+ {
+ "x": 359.6584909007793,
+ "y": 1.9932448142007344,
+ "z": 0.0
+ },
+ {
+ "x": 358.6196339045114,
+ "y": 1.9937966931993223,
+ "z": 0.0
+ },
+ {
+ "x": 357.5807769082434,
+ "y": 1.9943485721979102,
+ "z": 0.0
+ },
+ {
+ "x": 356.54191991197547,
+ "y": 1.994900451196498,
+ "z": 0.0
+ },
+ {
+ "x": 355.5030629157075,
+ "y": 1.995452330195086,
+ "z": 0.0
+ },
+ {
+ "x": 354.46420591943956,
+ "y": 1.9960042091936738,
+ "z": 0.0
+ },
+ {
+ "x": 353.4253489231716,
+ "y": 1.9965560881922617,
+ "z": 0.0
+ },
+ {
+ "x": 352.38649192690366,
+ "y": 1.9971079671908496,
+ "z": 0.0
+ },
+ {
+ "x": 351.3476349306357,
+ "y": 1.9976598461894375,
+ "z": 0.0
+ },
+ {
+ "x": 350.30877793436775,
+ "y": 1.9982117251880254,
+ "z": 0.0
+ },
+ {
+ "x": 349.2699209380998,
+ "y": 1.9987636041866133,
+ "z": 0.0
+ },
+ {
+ "x": 348.23106394183185,
+ "y": 1.9993154831852011,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 5,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 168.07958339564385,
+ "y": -3.956937384133082,
+ "z": 0.0
+ },
+ {
+ "x": 169.08308657463155,
+ "y": -3.957044487289655,
+ "z": 0.0
+ },
+ {
+ "x": 170.08658975361928,
+ "y": -3.957151590446228,
+ "z": 0.0
+ },
+ {
+ "x": 171.090092932607,
+ "y": -3.957258693602801,
+ "z": 0.0
+ },
+ {
+ "x": 172.0935961115947,
+ "y": -3.9573657967593734,
+ "z": 0.0
+ },
+ {
+ "x": 173.0970992905824,
+ "y": -3.9574728999159463,
+ "z": 0.0
+ },
+ {
+ "x": 174.10060246957013,
+ "y": -3.9575800030725192,
+ "z": 0.0
+ },
+ {
+ "x": 175.10410564855783,
+ "y": -3.957687106229092,
+ "z": 0.0
+ },
+ {
+ "x": 176.10760882754556,
+ "y": -3.957794209385665,
+ "z": 0.0
+ },
+ {
+ "x": 177.11111200653326,
+ "y": -3.9579013125422375,
+ "z": 0.0
+ },
+ {
+ "x": 178.114615185521,
+ "y": -3.9580084156988105,
+ "z": 0.0
+ },
+ {
+ "x": 179.1181183645087,
+ "y": -3.9581155188553834,
+ "z": 0.0
+ },
+ {
+ "x": 180.1216215434964,
+ "y": -3.9582226220119563,
+ "z": 0.0
+ },
+ {
+ "x": 181.12512472248412,
+ "y": -3.958329725168529,
+ "z": 0.0
+ },
+ {
+ "x": 182.12862790147184,
+ "y": -3.9584368283251017,
+ "z": 0.0
+ },
+ {
+ "x": 183.13213108045954,
+ "y": -3.9585439314816746,
+ "z": 0.0
+ },
+ {
+ "x": 184.13563425944724,
+ "y": -3.9586510346382475,
+ "z": 0.0
+ },
+ {
+ "x": 185.13913743843494,
+ "y": -3.9587581377948204,
+ "z": 0.0
+ },
+ {
+ "x": 186.1426406174227,
+ "y": -3.9588652409513934,
+ "z": 0.0
+ },
+ {
+ "x": 187.1461437964104,
+ "y": -3.958972344107966,
+ "z": 0.0
+ },
+ {
+ "x": 188.1496469753981,
+ "y": -3.9590794472645388,
+ "z": 0.0
+ },
+ {
+ "x": 189.1531501543858,
+ "y": -3.9591865504211117,
+ "z": 0.0
+ },
+ {
+ "x": 190.15665333337355,
+ "y": -3.9592936535776846,
+ "z": 0.0
+ },
+ {
+ "x": 191.16015651236125,
+ "y": -3.9594007567342575,
+ "z": 0.0
+ },
+ {
+ "x": 192.16365969134895,
+ "y": -3.95950785989083,
+ "z": 0.0
+ },
+ {
+ "x": 193.16716287033665,
+ "y": -3.959614963047403,
+ "z": 0.0
+ },
+ {
+ "x": 194.17066604932438,
+ "y": -3.959722066203976,
+ "z": 0.0
+ },
+ {
+ "x": 195.1741692283121,
+ "y": -3.9598291693605487,
+ "z": 0.0
+ },
+ {
+ "x": 196.1776724072998,
+ "y": -3.9599362725171217,
+ "z": 0.0
+ },
+ {
+ "x": 197.18117558628754,
+ "y": -3.960043375673694,
+ "z": 0.0
+ },
+ {
+ "x": 198.1846787652752,
+ "y": -3.960150478830267,
+ "z": 0.0
+ },
+ {
+ "x": 199.18818194426294,
+ "y": -3.96025758198684,
+ "z": 0.0
+ },
+ {
+ "x": 200.1916851232506,
+ "y": -3.960364685143413,
+ "z": 0.0
+ },
+ {
+ "x": 201.19518830223834,
+ "y": -3.9604717882999854,
+ "z": 0.0
+ },
+ {
+ "x": 202.198691481226,
+ "y": -3.9605788914565583,
+ "z": 0.0
+ },
+ {
+ "x": 203.20219466021373,
+ "y": -3.960685994613131,
+ "z": 0.0
+ },
+ {
+ "x": 204.2056978392014,
+ "y": -3.960793097769704,
+ "z": 0.0
+ },
+ {
+ "x": 205.2092010181891,
+ "y": -3.960900200926277,
+ "z": 0.0
+ },
+ {
+ "x": 206.2127041971768,
+ "y": -3.9610073040828495,
+ "z": 0.0
+ },
+ {
+ "x": 207.2162073761645,
+ "y": -3.9611144072394224,
+ "z": 0.0
+ },
+ {
+ "x": 208.2197105551522,
+ "y": -3.9612215103959953,
+ "z": 0.0
+ },
+ {
+ "x": 209.2232137341399,
+ "y": -3.9613286135525683,
+ "z": 0.0
+ },
+ {
+ "x": 210.2267169131276,
+ "y": -3.961435716709141,
+ "z": 0.0
+ },
+ {
+ "x": 211.2302200921153,
+ "y": -3.9615428198657137,
+ "z": 0.0
+ },
+ {
+ "x": 212.233723271103,
+ "y": -3.9616499230222866,
+ "z": 0.0
+ },
+ {
+ "x": 213.2372264500907,
+ "y": -3.9617570261788595,
+ "z": 0.0
+ },
+ {
+ "x": 214.2407296290784,
+ "y": -3.9618641293354324,
+ "z": 0.0
+ },
+ {
+ "x": 215.2442328080661,
+ "y": -3.9619712324920053,
+ "z": 0.0
+ },
+ {
+ "x": 216.2477359870538,
+ "y": -3.962078335648578,
+ "z": 0.0
+ },
+ {
+ "x": 217.2512391660415,
+ "y": -3.9621854388051507,
+ "z": 0.0
+ },
+ {
+ "x": 218.2547423450292,
+ "y": -3.9622925419617236,
+ "z": 0.0
+ },
+ {
+ "x": 219.2582455240169,
+ "y": -3.9623996451182966,
+ "z": 0.0
+ },
+ {
+ "x": 220.2617487030046,
+ "y": -3.962506748274869,
+ "z": 0.0
+ },
+ {
+ "x": 221.2652518819923,
+ "y": -3.962613851431442,
+ "z": 0.0
+ },
+ {
+ "x": 222.26875506098,
+ "y": -3.962720954588015,
+ "z": 0.0
+ },
+ {
+ "x": 223.2722582399677,
+ "y": -3.962828057744588,
+ "z": 0.0
+ },
+ {
+ "x": 224.2757614189554,
+ "y": -3.9629351609011607,
+ "z": 0.0
+ },
+ {
+ "x": 225.2792645979431,
+ "y": -3.963042264057733,
+ "z": 0.0
+ },
+ {
+ "x": 226.2827677769308,
+ "y": -3.963149367214306,
+ "z": 0.0
+ },
+ {
+ "x": 227.2862709559185,
+ "y": -3.963256470370879,
+ "z": 0.0
+ },
+ {
+ "x": 228.2897741349062,
+ "y": -3.963363573527452,
+ "z": 0.0
+ },
+ {
+ "x": 229.2932773138939,
+ "y": -3.963470676684025,
+ "z": 0.0
+ },
+ {
+ "x": 230.2967804928816,
+ "y": -3.9635777798405973,
+ "z": 0.0
+ },
+ {
+ "x": 231.3002836718693,
+ "y": -3.9636848829971703,
+ "z": 0.0
+ },
+ {
+ "x": 232.303786850857,
+ "y": -3.963791986153743,
+ "z": 0.0
+ },
+ {
+ "x": 233.3072900298447,
+ "y": -3.963899089310316,
+ "z": 0.0
+ },
+ {
+ "x": 234.3107932088324,
+ "y": -3.9640061924668886,
+ "z": 0.0
+ },
+ {
+ "x": 235.3142963878201,
+ "y": -3.9641132956234615,
+ "z": 0.0
+ },
+ {
+ "x": 236.31779956680776,
+ "y": -3.9642203987800344,
+ "z": 0.0
+ },
+ {
+ "x": 237.3213027457955,
+ "y": -3.9643275019366073,
+ "z": 0.0
+ },
+ {
+ "x": 238.32480592478316,
+ "y": -3.9644346050931802,
+ "z": 0.0
+ },
+ {
+ "x": 239.3283091037709,
+ "y": -3.9645417082497527,
+ "z": 0.0
+ },
+ {
+ "x": 240.33181228275856,
+ "y": -3.9646488114063256,
+ "z": 0.0
+ },
+ {
+ "x": 241.3353154617463,
+ "y": -3.9647559145628986,
+ "z": 0.0
+ },
+ {
+ "x": 242.33881864073396,
+ "y": -3.9648630177194715,
+ "z": 0.0
+ },
+ {
+ "x": 243.34232181972166,
+ "y": -3.9649701208760444,
+ "z": 0.0
+ },
+ {
+ "x": 244.34582499870936,
+ "y": -3.965077224032617,
+ "z": 0.0
+ },
+ {
+ "x": 245.34932817769706,
+ "y": -3.96518432718919,
+ "z": 0.0
+ },
+ {
+ "x": 246.35283135668476,
+ "y": -3.9652914303457627,
+ "z": 0.0
+ },
+ {
+ "x": 247.35633453567246,
+ "y": -3.9653985335023356,
+ "z": 0.0
+ },
+ {
+ "x": 248.35983771466016,
+ "y": -3.9655056366589085,
+ "z": 0.0
+ },
+ {
+ "x": 249.36334089364786,
+ "y": -3.965612739815481,
+ "z": 0.0
+ },
+ {
+ "x": 250.36684407263556,
+ "y": -3.965719842972054,
+ "z": 0.0
+ },
+ {
+ "x": 251.37034725162326,
+ "y": -3.965826946128627,
+ "z": 0.0
+ },
+ {
+ "x": 252.37385043061096,
+ "y": -3.9659340492851998,
+ "z": 0.0
+ },
+ {
+ "x": 253.37735360959866,
+ "y": -3.9660411524417722,
+ "z": 0.0
+ },
+ {
+ "x": 254.38085678858636,
+ "y": -3.966148255598345,
+ "z": 0.0
+ },
+ {
+ "x": 255.38435996757406,
+ "y": -3.966255358754918,
+ "z": 0.0
+ },
+ {
+ "x": 256.38786314656176,
+ "y": -3.966362461911491,
+ "z": 0.0
+ },
+ {
+ "x": 257.3913663255494,
+ "y": -3.966469565068064,
+ "z": 0.0
+ },
+ {
+ "x": 258.39486950453716,
+ "y": -3.9665766682246364,
+ "z": 0.0
+ },
+ {
+ "x": 259.3983726835248,
+ "y": -3.9666837713812093,
+ "z": 0.0
+ },
+ {
+ "x": 260.40187586251255,
+ "y": -3.9667908745377822,
+ "z": 0.0
+ },
+ {
+ "x": 261.4053790415002,
+ "y": -3.966897977694355,
+ "z": 0.0
+ },
+ {
+ "x": 262.40888222048795,
+ "y": -3.967005080850928,
+ "z": 0.0
+ },
+ {
+ "x": 263.4123853994757,
+ "y": -3.9671121840075005,
+ "z": 0.0
+ },
+ {
+ "x": 264.41588857846335,
+ "y": -3.9672192871640735,
+ "z": 0.0
+ },
+ {
+ "x": 265.4193917574511,
+ "y": -3.9673263903206464,
+ "z": 0.0
+ },
+ {
+ "x": 266.42289493643875,
+ "y": -3.9674334934772193,
+ "z": 0.0
+ },
+ {
+ "x": 267.4263981154265,
+ "y": -3.9675405966337918,
+ "z": 0.0
+ },
+ {
+ "x": 268.4299012944142,
+ "y": -3.9676476997903647,
+ "z": 0.0
+ },
+ {
+ "x": 269.4334044734019,
+ "y": -3.9677548029469376,
+ "z": 0.0
+ },
+ {
+ "x": 270.4369076523896,
+ "y": -3.9678619061035105,
+ "z": 0.0
+ },
+ {
+ "x": 271.4404108313773,
+ "y": -3.9679690092600834,
+ "z": 0.0
+ },
+ {
+ "x": 272.443914010365,
+ "y": -3.968076112416656,
+ "z": 0.0
+ },
+ {
+ "x": 273.44741718935273,
+ "y": -3.968183215573229,
+ "z": 0.0
+ },
+ {
+ "x": 274.4509203683404,
+ "y": -3.9682903187298018,
+ "z": 0.0
+ },
+ {
+ "x": 275.45442354732813,
+ "y": -3.9683974218863747,
+ "z": 0.0
+ },
+ {
+ "x": 276.45792672631586,
+ "y": -3.9685045250429476,
+ "z": 0.0
+ },
+ {
+ "x": 277.46142990530353,
+ "y": -3.96861162819952,
+ "z": 0.0
+ },
+ {
+ "x": 278.46493308429126,
+ "y": -3.968718731356093,
+ "z": 0.0
+ },
+ {
+ "x": 279.46843626327893,
+ "y": -3.968825834512666,
+ "z": 0.0
+ },
+ {
+ "x": 280.47193944226666,
+ "y": -3.968932937669239,
+ "z": 0.0
+ },
+ {
+ "x": 281.4754426212544,
+ "y": -3.9690400408258117,
+ "z": 0.0
+ },
+ {
+ "x": 282.47894580024206,
+ "y": -3.969147143982384,
+ "z": 0.0
+ },
+ {
+ "x": 283.4824489792298,
+ "y": -3.969254247138957,
+ "z": 0.0
+ },
+ {
+ "x": 284.48595215821746,
+ "y": -3.96936135029553,
+ "z": 0.0
+ },
+ {
+ "x": 285.4894553372052,
+ "y": -3.969468453452103,
+ "z": 0.0
+ },
+ {
+ "x": 286.4929585161929,
+ "y": -3.969575556608676,
+ "z": 0.0
+ },
+ {
+ "x": 287.4964616951806,
+ "y": -3.9696826597652484,
+ "z": 0.0
+ },
+ {
+ "x": 288.4999648741683,
+ "y": -3.9697897629218213,
+ "z": 0.0
+ },
+ {
+ "x": 289.50346805315604,
+ "y": -3.969896866078394,
+ "z": 0.0
+ },
+ {
+ "x": 290.50684979722337,
+ "y": -3.9700344178870632,
+ "z": 0.0
+ },
+ {
+ "x": 291.5088343943909,
+ "y": -3.970552431015961,
+ "z": 0.0
+ },
+ {
+ "x": 292.512279288484,
+ "y": -3.971085498227681,
+ "z": 0.0
+ },
+ {
+ "x": 293.51578233158676,
+ "y": -3.971618595907629,
+ "z": 0.0
+ },
+ {
+ "x": 294.51928537468945,
+ "y": -3.972151693587575,
+ "z": 0.0
+ },
+ {
+ "x": 295.5227884177921,
+ "y": -3.9726847912675227,
+ "z": 0.0
+ },
+ {
+ "x": 296.52629146089487,
+ "y": -3.9732178889474707,
+ "z": 0.0
+ },
+ {
+ "x": 297.52979450399755,
+ "y": -3.973750986627417,
+ "z": 0.0
+ },
+ {
+ "x": 298.53329754710023,
+ "y": -3.974284084307364,
+ "z": 0.0
+ },
+ {
+ "x": 299.536800590203,
+ "y": -3.974817181987312,
+ "z": 0.0
+ },
+ {
+ "x": 300.54030363330565,
+ "y": -3.9753502796672584,
+ "z": 0.0
+ },
+ {
+ "x": 301.54380667640834,
+ "y": -3.975883377347206,
+ "z": 0.0
+ },
+ {
+ "x": 302.5473097195111,
+ "y": -3.976416475027154,
+ "z": 0.0
+ },
+ {
+ "x": 303.55081276261376,
+ "y": -3.9769495727071003,
+ "z": 0.0
+ },
+ {
+ "x": 304.55431580571644,
+ "y": -3.9774826703870474,
+ "z": 0.0
+ },
+ {
+ "x": 305.5578188488192,
+ "y": -3.9780157680669954,
+ "z": 0.0
+ },
+ {
+ "x": 306.56132189192186,
+ "y": -3.978548865746942,
+ "z": 0.0
+ },
+ {
+ "x": 307.56482493502455,
+ "y": -3.9790819634268892,
+ "z": 0.0
+ },
+ {
+ "x": 308.5683279781273,
+ "y": -3.9796150611068373,
+ "z": 0.0
+ },
+ {
+ "x": 309.57183102122997,
+ "y": -3.9801481587867835,
+ "z": 0.0
+ },
+ {
+ "x": 310.57533406433265,
+ "y": -3.9806812564667307,
+ "z": 0.0
+ },
+ {
+ "x": 311.5788371074354,
+ "y": -3.981214354146679,
+ "z": 0.0
+ },
+ {
+ "x": 312.5823401505381,
+ "y": -3.9817474518266254,
+ "z": 0.0
+ },
+ {
+ "x": 313.58584319364076,
+ "y": -3.9822805495065725,
+ "z": 0.0
+ },
+ {
+ "x": 314.58934623674344,
+ "y": -3.9828136471865196,
+ "z": 0.0
+ },
+ {
+ "x": 315.5928492798462,
+ "y": -3.9833467448664677,
+ "z": 0.0
+ },
+ {
+ "x": 316.59635232294886,
+ "y": -3.9838798425464144,
+ "z": 0.0
+ },
+ {
+ "x": 317.59985536605154,
+ "y": -3.9844129402263615,
+ "z": 0.0
+ },
+ {
+ "x": 318.6033584091543,
+ "y": -3.9849460379063095,
+ "z": 0.0
+ },
+ {
+ "x": 319.60686145225696,
+ "y": -3.9854791355862558,
+ "z": 0.0
+ },
+ {
+ "x": 320.61036449535965,
+ "y": -3.986012233266203,
+ "z": 0.0
+ },
+ {
+ "x": 321.6138675384624,
+ "y": -3.986545330946151,
+ "z": 0.0
+ },
+ {
+ "x": 322.61737058156507,
+ "y": -3.9870784286260976,
+ "z": 0.0
+ },
+ {
+ "x": 323.62087362466775,
+ "y": -3.9876115263060448,
+ "z": 0.0
+ },
+ {
+ "x": 324.6243766677705,
+ "y": -3.988144623985993,
+ "z": 0.0
+ },
+ {
+ "x": 325.6278797108732,
+ "y": -3.988677721665939,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 6,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 325.63212960415166,
+ "y": 4.011321149484425,
+ "z": 0.0
+ },
+ {
+ "x": 324.628626561049,
+ "y": 4.011854247164374,
+ "z": 0.0
+ },
+ {
+ "x": 323.62512351794624,
+ "y": 4.012387344844321,
+ "z": 0.0
+ },
+ {
+ "x": 322.62162047484355,
+ "y": 4.012920442524267,
+ "z": 0.0
+ },
+ {
+ "x": 321.61811743174087,
+ "y": 4.013453540204216,
+ "z": 0.0
+ },
+ {
+ "x": 320.61461438863813,
+ "y": 4.0139866378841615,
+ "z": 0.0
+ },
+ {
+ "x": 319.61111134553545,
+ "y": 4.014519735564109,
+ "z": 0.0
+ },
+ {
+ "x": 318.60760830243277,
+ "y": 4.015052833244058,
+ "z": 0.0
+ },
+ {
+ "x": 317.60410525933,
+ "y": 4.015585930924003,
+ "z": 0.0
+ },
+ {
+ "x": 316.60060221622734,
+ "y": 4.016119028603951,
+ "z": 0.0
+ },
+ {
+ "x": 315.59709917312466,
+ "y": 4.016652126283899,
+ "z": 0.0
+ },
+ {
+ "x": 314.5935961300219,
+ "y": 4.017185223963845,
+ "z": 0.0
+ },
+ {
+ "x": 313.59009308691924,
+ "y": 4.017718321643793,
+ "z": 0.0
+ },
+ {
+ "x": 312.58659004381656,
+ "y": 4.0182514193237395,
+ "z": 0.0
+ },
+ {
+ "x": 311.5830870007139,
+ "y": 4.018784517003688,
+ "z": 0.0
+ },
+ {
+ "x": 310.57958395761113,
+ "y": 4.019317614683634,
+ "z": 0.0
+ },
+ {
+ "x": 309.57608091450845,
+ "y": 4.019850712363581,
+ "z": 0.0
+ },
+ {
+ "x": 308.57257787140577,
+ "y": 4.02038381004353,
+ "z": 0.0
+ },
+ {
+ "x": 307.56907482830303,
+ "y": 4.020916907723476,
+ "z": 0.0
+ },
+ {
+ "x": 306.56557178520035,
+ "y": 4.021450005403423,
+ "z": 0.0
+ },
+ {
+ "x": 305.56206874209767,
+ "y": 4.021983103083371,
+ "z": 0.0
+ },
+ {
+ "x": 304.5585656989949,
+ "y": 4.0225162007633175,
+ "z": 0.0
+ },
+ {
+ "x": 303.55506265589224,
+ "y": 4.023049298443264,
+ "z": 0.0
+ },
+ {
+ "x": 302.55155961278956,
+ "y": 4.023582396123213,
+ "z": 0.0
+ },
+ {
+ "x": 301.5480565696868,
+ "y": 4.024115493803159,
+ "z": 0.0
+ },
+ {
+ "x": 300.54455352658414,
+ "y": 4.024648591483106,
+ "z": 0.0
+ },
+ {
+ "x": 299.54105048348146,
+ "y": 4.0251816891630545,
+ "z": 0.0
+ },
+ {
+ "x": 298.5375474403787,
+ "y": 4.025714786843,
+ "z": 0.0
+ },
+ {
+ "x": 297.53404439727603,
+ "y": 4.026247884522948,
+ "z": 0.0
+ },
+ {
+ "x": 296.53054135417335,
+ "y": 4.026780982202896,
+ "z": 0.0
+ },
+ {
+ "x": 295.5270383110706,
+ "y": 4.027314079882842,
+ "z": 0.0
+ },
+ {
+ "x": 294.52353526796793,
+ "y": 4.02784717756279,
+ "z": 0.0
+ },
+ {
+ "x": 293.52003222486525,
+ "y": 4.028380275242737,
+ "z": 0.0
+ },
+ {
+ "x": 292.5165291817625,
+ "y": 4.028913372922684,
+ "z": 0.0
+ },
+ {
+ "x": 291.5129679896503,
+ "y": 4.029446501070859,
+ "z": 0.0
+ },
+ {
+ "x": 290.5079464882093,
+ "y": 4.029965506942243,
+ "z": 0.0
+ },
+ {
+ "x": 289.50432188727,
+ "y": 4.0301030883570625,
+ "z": 0.0
+ },
+ {
+ "x": 288.5008187082823,
+ "y": 4.0302101915136355,
+ "z": 0.0
+ },
+ {
+ "x": 287.49731552929455,
+ "y": 4.030317294670208,
+ "z": 0.0
+ },
+ {
+ "x": 286.4938123503069,
+ "y": 4.030424397826781,
+ "z": 0.0
+ },
+ {
+ "x": 285.49030917131915,
+ "y": 4.030531500983354,
+ "z": 0.0
+ },
+ {
+ "x": 284.4868059923314,
+ "y": 4.030638604139927,
+ "z": 0.0
+ },
+ {
+ "x": 283.48330281334376,
+ "y": 4.030745707296499,
+ "z": 0.0
+ },
+ {
+ "x": 282.479799634356,
+ "y": 4.030852810453072,
+ "z": 0.0
+ },
+ {
+ "x": 281.47629645536836,
+ "y": 4.030959913609645,
+ "z": 0.0
+ },
+ {
+ "x": 280.4727932763806,
+ "y": 4.031067016766218,
+ "z": 0.0
+ },
+ {
+ "x": 279.4692900973929,
+ "y": 4.031174119922791,
+ "z": 0.0
+ },
+ {
+ "x": 278.46578691840523,
+ "y": 4.031281223079364,
+ "z": 0.0
+ },
+ {
+ "x": 277.4622837394175,
+ "y": 4.031388326235937,
+ "z": 0.0
+ },
+ {
+ "x": 276.45878056042983,
+ "y": 4.03149542939251,
+ "z": 0.0
+ },
+ {
+ "x": 275.4552773814421,
+ "y": 4.0316025325490825,
+ "z": 0.0
+ },
+ {
+ "x": 274.4517742024544,
+ "y": 4.0317096357056545,
+ "z": 0.0
+ },
+ {
+ "x": 273.4482710234667,
+ "y": 4.0318167388622275,
+ "z": 0.0
+ },
+ {
+ "x": 272.444767844479,
+ "y": 4.0319238420188,
+ "z": 0.0
+ },
+ {
+ "x": 271.44126466549125,
+ "y": 4.032030945175373,
+ "z": 0.0
+ },
+ {
+ "x": 270.4377614865036,
+ "y": 4.032138048331946,
+ "z": 0.0
+ },
+ {
+ "x": 269.43425830751585,
+ "y": 4.032245151488519,
+ "z": 0.0
+ },
+ {
+ "x": 268.4307551285282,
+ "y": 4.032352254645092,
+ "z": 0.0
+ },
+ {
+ "x": 267.42725194954045,
+ "y": 4.032459357801665,
+ "z": 0.0
+ },
+ {
+ "x": 266.4237487705527,
+ "y": 4.032566460958238,
+ "z": 0.0
+ },
+ {
+ "x": 265.42024559156505,
+ "y": 4.032673564114811,
+ "z": 0.0
+ },
+ {
+ "x": 264.4167424125773,
+ "y": 4.032780667271383,
+ "z": 0.0
+ },
+ {
+ "x": 263.41323923358965,
+ "y": 4.032887770427956,
+ "z": 0.0
+ },
+ {
+ "x": 262.4097360546019,
+ "y": 4.032994873584529,
+ "z": 0.0
+ },
+ {
+ "x": 261.4062328756142,
+ "y": 4.033101976741102,
+ "z": 0.0
+ },
+ {
+ "x": 260.4027296966265,
+ "y": 4.0332090798976745,
+ "z": 0.0
+ },
+ {
+ "x": 259.3992265176388,
+ "y": 4.033316183054247,
+ "z": 0.0
+ },
+ {
+ "x": 258.3957233386511,
+ "y": 4.03342328621082,
+ "z": 0.0
+ },
+ {
+ "x": 257.3922201596634,
+ "y": 4.033530389367393,
+ "z": 0.0
+ },
+ {
+ "x": 256.3887169806757,
+ "y": 4.033637492523966,
+ "z": 0.0
+ },
+ {
+ "x": 255.38521380168802,
+ "y": 4.033744595680538,
+ "z": 0.0
+ },
+ {
+ "x": 254.38171062270033,
+ "y": 4.033851698837111,
+ "z": 0.0
+ },
+ {
+ "x": 253.37820744371263,
+ "y": 4.033958801993684,
+ "z": 0.0
+ },
+ {
+ "x": 252.37470426472493,
+ "y": 4.034065905150257,
+ "z": 0.0
+ },
+ {
+ "x": 251.37120108573723,
+ "y": 4.03417300830683,
+ "z": 0.0
+ },
+ {
+ "x": 250.36769790674953,
+ "y": 4.034280111463403,
+ "z": 0.0
+ },
+ {
+ "x": 249.36419472776183,
+ "y": 4.034387214619976,
+ "z": 0.0
+ },
+ {
+ "x": 248.36069154877413,
+ "y": 4.034494317776549,
+ "z": 0.0
+ },
+ {
+ "x": 247.35718836978643,
+ "y": 4.034601420933122,
+ "z": 0.0
+ },
+ {
+ "x": 246.35368519079873,
+ "y": 4.0347085240896945,
+ "z": 0.0
+ },
+ {
+ "x": 245.35018201181103,
+ "y": 4.0348156272462665,
+ "z": 0.0
+ },
+ {
+ "x": 244.34667883282333,
+ "y": 4.034922730402839,
+ "z": 0.0
+ },
+ {
+ "x": 243.34317565383563,
+ "y": 4.035029833559412,
+ "z": 0.0
+ },
+ {
+ "x": 242.33967247484793,
+ "y": 4.035136936715985,
+ "z": 0.0
+ },
+ {
+ "x": 241.33616929586026,
+ "y": 4.035244039872558,
+ "z": 0.0
+ },
+ {
+ "x": 240.33266611687253,
+ "y": 4.035351143029131,
+ "z": 0.0
+ },
+ {
+ "x": 239.32916293788486,
+ "y": 4.035458246185704,
+ "z": 0.0
+ },
+ {
+ "x": 238.32565975889713,
+ "y": 4.035565349342277,
+ "z": 0.0
+ },
+ {
+ "x": 237.32215657990946,
+ "y": 4.03567245249885,
+ "z": 0.0
+ },
+ {
+ "x": 236.31865340092173,
+ "y": 4.035779555655422,
+ "z": 0.0
+ },
+ {
+ "x": 235.31515022193406,
+ "y": 4.035886658811995,
+ "z": 0.0
+ },
+ {
+ "x": 234.31164704294636,
+ "y": 4.035993761968568,
+ "z": 0.0
+ },
+ {
+ "x": 233.30814386395866,
+ "y": 4.036100865125141,
+ "z": 0.0
+ },
+ {
+ "x": 232.30464068497096,
+ "y": 4.036207968281714,
+ "z": 0.0
+ },
+ {
+ "x": 231.30113750598326,
+ "y": 4.0363150714382865,
+ "z": 0.0
+ },
+ {
+ "x": 230.29763432699556,
+ "y": 4.036422174594859,
+ "z": 0.0
+ },
+ {
+ "x": 229.29413114800786,
+ "y": 4.036529277751432,
+ "z": 0.0
+ },
+ {
+ "x": 228.29062796902016,
+ "y": 4.036636380908005,
+ "z": 0.0
+ },
+ {
+ "x": 227.28712479003246,
+ "y": 4.036743484064578,
+ "z": 0.0
+ },
+ {
+ "x": 226.28362161104477,
+ "y": 4.03685058722115,
+ "z": 0.0
+ },
+ {
+ "x": 225.28011843205707,
+ "y": 4.036957690377723,
+ "z": 0.0
+ },
+ {
+ "x": 224.27661525306937,
+ "y": 4.037064793534296,
+ "z": 0.0
+ },
+ {
+ "x": 223.27311207408167,
+ "y": 4.037171896690869,
+ "z": 0.0
+ },
+ {
+ "x": 222.26960889509397,
+ "y": 4.037278999847442,
+ "z": 0.0
+ },
+ {
+ "x": 221.26610571610627,
+ "y": 4.037386103004015,
+ "z": 0.0
+ },
+ {
+ "x": 220.26260253711857,
+ "y": 4.037493206160588,
+ "z": 0.0
+ },
+ {
+ "x": 219.25909935813087,
+ "y": 4.037600309317161,
+ "z": 0.0
+ },
+ {
+ "x": 218.25559617914317,
+ "y": 4.0377074124737335,
+ "z": 0.0
+ },
+ {
+ "x": 217.25209300015547,
+ "y": 4.037814515630306,
+ "z": 0.0
+ },
+ {
+ "x": 216.24858982116777,
+ "y": 4.0379216187868785,
+ "z": 0.0
+ },
+ {
+ "x": 215.24508664218007,
+ "y": 4.038028721943451,
+ "z": 0.0
+ },
+ {
+ "x": 214.24158346319237,
+ "y": 4.038135825100024,
+ "z": 0.0
+ },
+ {
+ "x": 213.23808028420467,
+ "y": 4.038242928256597,
+ "z": 0.0
+ },
+ {
+ "x": 212.23457710521697,
+ "y": 4.03835003141317,
+ "z": 0.0
+ },
+ {
+ "x": 211.23107392622927,
+ "y": 4.038457134569743,
+ "z": 0.0
+ },
+ {
+ "x": 210.22757074724157,
+ "y": 4.038564237726316,
+ "z": 0.0
+ },
+ {
+ "x": 209.22406756825387,
+ "y": 4.038671340882889,
+ "z": 0.0
+ },
+ {
+ "x": 208.22056438926617,
+ "y": 4.038778444039462,
+ "z": 0.0
+ },
+ {
+ "x": 207.21706121027847,
+ "y": 4.038885547196034,
+ "z": 0.0
+ },
+ {
+ "x": 206.21355803129077,
+ "y": 4.038992650352607,
+ "z": 0.0
+ },
+ {
+ "x": 205.21005485230307,
+ "y": 4.03909975350918,
+ "z": 0.0
+ },
+ {
+ "x": 204.20655167331537,
+ "y": 4.039206856665753,
+ "z": 0.0
+ },
+ {
+ "x": 203.2030484943277,
+ "y": 4.0393139598223256,
+ "z": 0.0
+ },
+ {
+ "x": 202.19954531533998,
+ "y": 4.0394210629788985,
+ "z": 0.0
+ },
+ {
+ "x": 201.1960421363523,
+ "y": 4.039528166135471,
+ "z": 0.0
+ },
+ {
+ "x": 200.19253895736458,
+ "y": 4.039635269292044,
+ "z": 0.0
+ },
+ {
+ "x": 199.1890357783769,
+ "y": 4.039742372448617,
+ "z": 0.0
+ },
+ {
+ "x": 198.18553259938918,
+ "y": 4.039849475605189,
+ "z": 0.0
+ },
+ {
+ "x": 197.1820294204015,
+ "y": 4.039956578761762,
+ "z": 0.0
+ },
+ {
+ "x": 196.17852624141378,
+ "y": 4.040063681918335,
+ "z": 0.0
+ },
+ {
+ "x": 195.17502306242608,
+ "y": 4.040170785074908,
+ "z": 0.0
+ },
+ {
+ "x": 194.17151988343835,
+ "y": 4.040277888231481,
+ "z": 0.0
+ },
+ {
+ "x": 193.16801670445062,
+ "y": 4.040384991388054,
+ "z": 0.0
+ },
+ {
+ "x": 192.16451352546292,
+ "y": 4.040492094544627,
+ "z": 0.0
+ },
+ {
+ "x": 191.16101034647522,
+ "y": 4.0405991977012,
+ "z": 0.0
+ },
+ {
+ "x": 190.15750716748752,
+ "y": 4.040706300857773,
+ "z": 0.0
+ },
+ {
+ "x": 189.15400398849977,
+ "y": 4.0408134040143455,
+ "z": 0.0
+ },
+ {
+ "x": 188.15050080951207,
+ "y": 4.0409205071709176,
+ "z": 0.0
+ },
+ {
+ "x": 187.14699763052437,
+ "y": 4.0410276103274905,
+ "z": 0.0
+ },
+ {
+ "x": 186.14349445153667,
+ "y": 4.041134713484063,
+ "z": 0.0
+ },
+ {
+ "x": 185.1399912725489,
+ "y": 4.041241816640636,
+ "z": 0.0
+ },
+ {
+ "x": 184.1364880935612,
+ "y": 4.041348919797209,
+ "z": 0.0
+ },
+ {
+ "x": 183.1329849145735,
+ "y": 4.041456022953782,
+ "z": 0.0
+ },
+ {
+ "x": 182.1294817355858,
+ "y": 4.041563126110355,
+ "z": 0.0
+ },
+ {
+ "x": 181.12597855659808,
+ "y": 4.041670229266928,
+ "z": 0.0
+ },
+ {
+ "x": 180.12247537761036,
+ "y": 4.041777332423501,
+ "z": 0.0
+ },
+ {
+ "x": 179.11897219862266,
+ "y": 4.041884435580073,
+ "z": 0.0
+ },
+ {
+ "x": 178.11546901963496,
+ "y": 4.041991538736646,
+ "z": 0.0
+ },
+ {
+ "x": 177.11196584064723,
+ "y": 4.042098641893219,
+ "z": 0.0
+ },
+ {
+ "x": 176.10846266165953,
+ "y": 4.042205745049792,
+ "z": 0.0
+ },
+ {
+ "x": 175.1049594826718,
+ "y": 4.042312848206365,
+ "z": 0.0
+ },
+ {
+ "x": 174.1014563036841,
+ "y": 4.0424199513629375,
+ "z": 0.0
+ },
+ {
+ "x": 173.09795312469637,
+ "y": 4.04252705451951,
+ "z": 0.0
+ },
+ {
+ "x": 172.09444994570867,
+ "y": 4.042634157676083,
+ "z": 0.0
+ },
+ {
+ "x": 171.09094676672098,
+ "y": 4.042741260832656,
+ "z": 0.0
+ },
+ {
+ "x": 170.08744358773325,
+ "y": 4.042848363989229,
+ "z": 0.0
+ },
+ {
+ "x": 169.08394040874552,
+ "y": 4.042955467145801,
+ "z": 0.0
+ },
+ {
+ "x": 168.08043722975782,
+ "y": 4.043062570302374,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 7,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 325.6300046575124,
+ "y": 0.01132171390924333,
+ "z": 0.0
+ },
+ {
+ "x": 324.62650161440973,
+ "y": 0.01185481158919055,
+ "z": 0.0
+ },
+ {
+ "x": 323.622998571307,
+ "y": 0.012387909269137768,
+ "z": 0.0
+ },
+ {
+ "x": 322.6194955282043,
+ "y": 0.012921006949084988,
+ "z": 0.0
+ },
+ {
+ "x": 321.61599248510163,
+ "y": 0.013454104629032206,
+ "z": 0.0
+ },
+ {
+ "x": 320.6124894419989,
+ "y": 0.013987202308979426,
+ "z": 0.0
+ },
+ {
+ "x": 319.6089863988962,
+ "y": 0.014520299988926646,
+ "z": 0.0
+ },
+ {
+ "x": 318.6054833557935,
+ "y": 0.015053397668873866,
+ "z": 0.0
+ },
+ {
+ "x": 317.6019803126908,
+ "y": 0.015586495348821084,
+ "z": 0.0
+ },
+ {
+ "x": 316.5984772695881,
+ "y": 0.016119593028768302,
+ "z": 0.0
+ },
+ {
+ "x": 315.5949742264854,
+ "y": 0.016652690708715546,
+ "z": 0.0
+ },
+ {
+ "x": 314.5914711833827,
+ "y": 0.017185788388662773,
+ "z": 0.0
+ },
+ {
+ "x": 313.58796814028,
+ "y": 0.017718886068609992,
+ "z": 0.0
+ },
+ {
+ "x": 312.5844650971773,
+ "y": 0.018251983748557212,
+ "z": 0.0
+ },
+ {
+ "x": 311.58096205407463,
+ "y": 0.01878508142850443,
+ "z": 0.0
+ },
+ {
+ "x": 310.5774590109719,
+ "y": 0.019318179108451648,
+ "z": 0.0
+ },
+ {
+ "x": 309.5739559678692,
+ "y": 0.019851276788398868,
+ "z": 0.0
+ },
+ {
+ "x": 308.5704529247665,
+ "y": 0.020384374468346088,
+ "z": 0.0
+ },
+ {
+ "x": 307.5669498816638,
+ "y": 0.020917472148293304,
+ "z": 0.0
+ },
+ {
+ "x": 306.5634468385611,
+ "y": 0.021450569828240527,
+ "z": 0.0
+ },
+ {
+ "x": 305.5599437954584,
+ "y": 0.021983667508187747,
+ "z": 0.0
+ },
+ {
+ "x": 304.5564407523557,
+ "y": 0.022516765188134964,
+ "z": 0.0
+ },
+ {
+ "x": 303.552937709253,
+ "y": 0.023049862868082183,
+ "z": 0.0
+ },
+ {
+ "x": 302.5494346661503,
+ "y": 0.023582960548029403,
+ "z": 0.0
+ },
+ {
+ "x": 301.5459316230476,
+ "y": 0.024116058227976623,
+ "z": 0.0
+ },
+ {
+ "x": 300.5424285799449,
+ "y": 0.024649155907923843,
+ "z": 0.0
+ },
+ {
+ "x": 299.5389255368422,
+ "y": 0.025182253587871063,
+ "z": 0.0
+ },
+ {
+ "x": 298.5354224937395,
+ "y": 0.025715351267818282,
+ "z": 0.0
+ },
+ {
+ "x": 297.5319194506368,
+ "y": 0.0262484489477655,
+ "z": 0.0
+ },
+ {
+ "x": 296.5284164075341,
+ "y": 0.02678154662771272,
+ "z": 0.0
+ },
+ {
+ "x": 295.52491336443137,
+ "y": 0.027314644307659938,
+ "z": 0.0
+ },
+ {
+ "x": 294.5214103213287,
+ "y": 0.02784774198760716,
+ "z": 0.0
+ },
+ {
+ "x": 293.517907278226,
+ "y": 0.028380839667554406,
+ "z": 0.0
+ },
+ {
+ "x": 292.51440423512327,
+ "y": 0.02891393734750163,
+ "z": 0.0
+ },
+ {
+ "x": 291.5109011920206,
+ "y": 0.02944703502744885,
+ "z": 0.0
+ },
+ {
+ "x": 290.50739814271634,
+ "y": 0.029965544527589767,
+ "z": 0.0
+ },
+ {
+ "x": 289.503894970213,
+ "y": 0.03010311113933422,
+ "z": 0.0
+ },
+ {
+ "x": 288.5003917912253,
+ "y": 0.030210214295907045,
+ "z": 0.0
+ },
+ {
+ "x": 287.49688861223757,
+ "y": 0.03031731745247987,
+ "z": 0.0
+ },
+ {
+ "x": 286.4933854332499,
+ "y": 0.030424420609052698,
+ "z": 0.0
+ },
+ {
+ "x": 285.48988225426217,
+ "y": 0.030531523765625523,
+ "z": 0.0
+ },
+ {
+ "x": 284.48637907527444,
+ "y": 0.030638626922198348,
+ "z": 0.0
+ },
+ {
+ "x": 283.48287589628677,
+ "y": 0.030745730078771173,
+ "z": 0.0
+ },
+ {
+ "x": 282.47937271729904,
+ "y": 0.030852833235343997,
+ "z": 0.0
+ },
+ {
+ "x": 281.4758695383114,
+ "y": 0.030959936391916822,
+ "z": 0.0
+ },
+ {
+ "x": 280.47236635932364,
+ "y": 0.031067039548489647,
+ "z": 0.0
+ },
+ {
+ "x": 279.4688631803359,
+ "y": 0.031174142705062476,
+ "z": 0.0
+ },
+ {
+ "x": 278.46536000134824,
+ "y": 0.031281245861635304,
+ "z": 0.0
+ },
+ {
+ "x": 277.4618568223605,
+ "y": 0.031388349018208125,
+ "z": 0.0
+ },
+ {
+ "x": 276.45835364337285,
+ "y": 0.031495452174780954,
+ "z": 0.0
+ },
+ {
+ "x": 275.4548504643851,
+ "y": 0.031602555331353775,
+ "z": 0.0
+ },
+ {
+ "x": 274.4513472853974,
+ "y": 0.0317096584879266,
+ "z": 0.0
+ },
+ {
+ "x": 273.4478441064097,
+ "y": 0.03181676164449943,
+ "z": 0.0
+ },
+ {
+ "x": 272.444340927422,
+ "y": 0.03192386480107225,
+ "z": 0.0
+ },
+ {
+ "x": 271.44083774843426,
+ "y": 0.03203096795764508,
+ "z": 0.0
+ },
+ {
+ "x": 270.4373345694466,
+ "y": 0.0321380711142179,
+ "z": 0.0
+ },
+ {
+ "x": 269.43383139045886,
+ "y": 0.03224517427079073,
+ "z": 0.0
+ },
+ {
+ "x": 268.4303282114712,
+ "y": 0.03235227742736355,
+ "z": 0.0
+ },
+ {
+ "x": 267.42682503248346,
+ "y": 0.03245938058393638,
+ "z": 0.0
+ },
+ {
+ "x": 266.42332185349574,
+ "y": 0.0325664837405092,
+ "z": 0.0
+ },
+ {
+ "x": 265.41981867450806,
+ "y": 0.03267358689708203,
+ "z": 0.0
+ },
+ {
+ "x": 264.41631549552034,
+ "y": 0.03278069005365486,
+ "z": 0.0
+ },
+ {
+ "x": 263.41281231653267,
+ "y": 0.03288779321022768,
+ "z": 0.0
+ },
+ {
+ "x": 262.40930913754494,
+ "y": 0.03299489636680051,
+ "z": 0.0
+ },
+ {
+ "x": 261.4058059585572,
+ "y": 0.03310199952337333,
+ "z": 0.0
+ },
+ {
+ "x": 260.40230277956954,
+ "y": 0.03320910267994615,
+ "z": 0.0
+ },
+ {
+ "x": 259.3987996005818,
+ "y": 0.03331620583651898,
+ "z": 0.0
+ },
+ {
+ "x": 258.39529642159414,
+ "y": 0.03342330899309181,
+ "z": 0.0
+ },
+ {
+ "x": 257.3917932426064,
+ "y": 0.03353041214966463,
+ "z": 0.0
+ },
+ {
+ "x": 256.38829006361874,
+ "y": 0.03363751530623746,
+ "z": 0.0
+ },
+ {
+ "x": 255.38478688463104,
+ "y": 0.03374461846281028,
+ "z": 0.0
+ },
+ {
+ "x": 254.38128370564334,
+ "y": 0.0338517216193831,
+ "z": 0.0
+ },
+ {
+ "x": 253.37778052665564,
+ "y": 0.03395882477595593,
+ "z": 0.0
+ },
+ {
+ "x": 252.37427734766794,
+ "y": 0.03406592793252876,
+ "z": 0.0
+ },
+ {
+ "x": 251.37077416868024,
+ "y": 0.03417303108910158,
+ "z": 0.0
+ },
+ {
+ "x": 250.36727098969254,
+ "y": 0.03428013424567441,
+ "z": 0.0
+ },
+ {
+ "x": 249.36376781070484,
+ "y": 0.03438723740224723,
+ "z": 0.0
+ },
+ {
+ "x": 248.36026463171714,
+ "y": 0.03449434055882005,
+ "z": 0.0
+ },
+ {
+ "x": 247.35676145272944,
+ "y": 0.03460144371539288,
+ "z": 0.0
+ },
+ {
+ "x": 246.35325827374174,
+ "y": 0.0347085468719657,
+ "z": 0.0
+ },
+ {
+ "x": 245.34975509475404,
+ "y": 0.03481565002853853,
+ "z": 0.0
+ },
+ {
+ "x": 244.34625191576635,
+ "y": 0.03492275318511135,
+ "z": 0.0
+ },
+ {
+ "x": 243.34274873677865,
+ "y": 0.03502985634168418,
+ "z": 0.0
+ },
+ {
+ "x": 242.33924555779095,
+ "y": 0.035136959498257,
+ "z": 0.0
+ },
+ {
+ "x": 241.33574237880327,
+ "y": 0.03524406265482983,
+ "z": 0.0
+ },
+ {
+ "x": 240.33223919981555,
+ "y": 0.03535116581140265,
+ "z": 0.0
+ },
+ {
+ "x": 239.32873602082788,
+ "y": 0.03545826896797548,
+ "z": 0.0
+ },
+ {
+ "x": 238.32523284184015,
+ "y": 0.0355653721245483,
+ "z": 0.0
+ },
+ {
+ "x": 237.32172966285248,
+ "y": 0.03567247528112112,
+ "z": 0.0
+ },
+ {
+ "x": 236.31822648386475,
+ "y": 0.03577957843769394,
+ "z": 0.0
+ },
+ {
+ "x": 235.31472330487708,
+ "y": 0.03588668159426677,
+ "z": 0.0
+ },
+ {
+ "x": 234.31122012588938,
+ "y": 0.03599378475083959,
+ "z": 0.0
+ },
+ {
+ "x": 233.30771694690168,
+ "y": 0.03610088790741242,
+ "z": 0.0
+ },
+ {
+ "x": 232.30421376791398,
+ "y": 0.03620799106398524,
+ "z": 0.0
+ },
+ {
+ "x": 231.30071058892628,
+ "y": 0.03631509422055807,
+ "z": 0.0
+ },
+ {
+ "x": 230.29720740993858,
+ "y": 0.03642219737713089,
+ "z": 0.0
+ },
+ {
+ "x": 229.29370423095088,
+ "y": 0.03652930053370372,
+ "z": 0.0
+ },
+ {
+ "x": 228.29020105196318,
+ "y": 0.03663640369027654,
+ "z": 0.0
+ },
+ {
+ "x": 227.28669787297548,
+ "y": 0.036743506846849364,
+ "z": 0.0
+ },
+ {
+ "x": 226.28319469398778,
+ "y": 0.03685061000342219,
+ "z": 0.0
+ },
+ {
+ "x": 225.27969151500008,
+ "y": 0.03695771315999501,
+ "z": 0.0
+ },
+ {
+ "x": 224.27618833601238,
+ "y": 0.03706481631656784,
+ "z": 0.0
+ },
+ {
+ "x": 223.27268515702468,
+ "y": 0.03717191947314067,
+ "z": 0.0
+ },
+ {
+ "x": 222.26918197803698,
+ "y": 0.03727902262971349,
+ "z": 0.0
+ },
+ {
+ "x": 221.26567879904928,
+ "y": 0.03738612578628631,
+ "z": 0.0
+ },
+ {
+ "x": 220.26217562006158,
+ "y": 0.03749322894285914,
+ "z": 0.0
+ },
+ {
+ "x": 219.25867244107388,
+ "y": 0.03760033209943196,
+ "z": 0.0
+ },
+ {
+ "x": 218.25516926208618,
+ "y": 0.037707435256004784,
+ "z": 0.0
+ },
+ {
+ "x": 217.25166608309848,
+ "y": 0.03781453841257761,
+ "z": 0.0
+ },
+ {
+ "x": 216.24816290411079,
+ "y": 0.03792164156915044,
+ "z": 0.0
+ },
+ {
+ "x": 215.24465972512309,
+ "y": 0.03802874472572326,
+ "z": 0.0
+ },
+ {
+ "x": 214.2411565461354,
+ "y": 0.03813584788229609,
+ "z": 0.0
+ },
+ {
+ "x": 213.2376533671477,
+ "y": 0.03824295103886891,
+ "z": 0.0
+ },
+ {
+ "x": 212.23415018816,
+ "y": 0.038350054195441734,
+ "z": 0.0
+ },
+ {
+ "x": 211.2306470091723,
+ "y": 0.03845715735201456,
+ "z": 0.0
+ },
+ {
+ "x": 210.2271438301846,
+ "y": 0.03856426050858739,
+ "z": 0.0
+ },
+ {
+ "x": 209.2236406511969,
+ "y": 0.03867136366516021,
+ "z": 0.0
+ },
+ {
+ "x": 208.2201374722092,
+ "y": 0.03877846682173303,
+ "z": 0.0
+ },
+ {
+ "x": 207.2166342932215,
+ "y": 0.03888556997830586,
+ "z": 0.0
+ },
+ {
+ "x": 206.2131311142338,
+ "y": 0.03899267313487868,
+ "z": 0.0
+ },
+ {
+ "x": 205.2096279352461,
+ "y": 0.03909977629145151,
+ "z": 0.0
+ },
+ {
+ "x": 204.2061247562584,
+ "y": 0.03920687944802433,
+ "z": 0.0
+ },
+ {
+ "x": 203.20262157727072,
+ "y": 0.03931398260459716,
+ "z": 0.0
+ },
+ {
+ "x": 202.199118398283,
+ "y": 0.03942108576116999,
+ "z": 0.0
+ },
+ {
+ "x": 201.19561521929532,
+ "y": 0.03952818891774281,
+ "z": 0.0
+ },
+ {
+ "x": 200.1921120403076,
+ "y": 0.03963529207431563,
+ "z": 0.0
+ },
+ {
+ "x": 199.18860886131992,
+ "y": 0.03974239523088846,
+ "z": 0.0
+ },
+ {
+ "x": 198.1851056823322,
+ "y": 0.03984949838746128,
+ "z": 0.0
+ },
+ {
+ "x": 197.18160250334452,
+ "y": 0.03995660154403411,
+ "z": 0.0
+ },
+ {
+ "x": 196.1780993243568,
+ "y": 0.04006370470060694,
+ "z": 0.0
+ },
+ {
+ "x": 195.1745961453691,
+ "y": 0.04017080785717976,
+ "z": 0.0
+ },
+ {
+ "x": 194.17109296638137,
+ "y": 0.04027791101375259,
+ "z": 0.0
+ },
+ {
+ "x": 193.16758978739364,
+ "y": 0.04038501417032541,
+ "z": 0.0
+ },
+ {
+ "x": 192.16408660840594,
+ "y": 0.04049211732689824,
+ "z": 0.0
+ },
+ {
+ "x": 191.16058342941824,
+ "y": 0.04059922048347107,
+ "z": 0.0
+ },
+ {
+ "x": 190.15708025043054,
+ "y": 0.04070632364004389,
+ "z": 0.0
+ },
+ {
+ "x": 189.15357707144278,
+ "y": 0.04081342679661672,
+ "z": 0.0
+ },
+ {
+ "x": 188.15007389245508,
+ "y": 0.040920529953189545,
+ "z": 0.0
+ },
+ {
+ "x": 187.14657071346738,
+ "y": 0.041027633109762374,
+ "z": 0.0
+ },
+ {
+ "x": 186.14306753447968,
+ "y": 0.041134736266335195,
+ "z": 0.0
+ },
+ {
+ "x": 185.13956435549193,
+ "y": 0.04124183942290802,
+ "z": 0.0
+ },
+ {
+ "x": 184.13606117650423,
+ "y": 0.04134894257948085,
+ "z": 0.0
+ },
+ {
+ "x": 183.13255799751653,
+ "y": 0.04145604573605368,
+ "z": 0.0
+ },
+ {
+ "x": 182.12905481852883,
+ "y": 0.0415631488926265,
+ "z": 0.0
+ },
+ {
+ "x": 181.1255516395411,
+ "y": 0.04167025204919933,
+ "z": 0.0
+ },
+ {
+ "x": 180.12204846055337,
+ "y": 0.04177735520577216,
+ "z": 0.0
+ },
+ {
+ "x": 179.11854528156567,
+ "y": 0.04188445836234498,
+ "z": 0.0
+ },
+ {
+ "x": 178.11504210257797,
+ "y": 0.04199156151891781,
+ "z": 0.0
+ },
+ {
+ "x": 177.11153892359025,
+ "y": 0.04209866467549064,
+ "z": 0.0
+ },
+ {
+ "x": 176.10803574460255,
+ "y": 0.04220576783206346,
+ "z": 0.0
+ },
+ {
+ "x": 175.10453256561482,
+ "y": 0.042312870988636286,
+ "z": 0.0
+ },
+ {
+ "x": 174.10102938662712,
+ "y": 0.042419974145209115,
+ "z": 0.0
+ },
+ {
+ "x": 173.0975262076394,
+ "y": 0.042527077301781936,
+ "z": 0.0
+ },
+ {
+ "x": 172.0940230286517,
+ "y": 0.042634180458354765,
+ "z": 0.0
+ },
+ {
+ "x": 171.090519849664,
+ "y": 0.042741283614927586,
+ "z": 0.0
+ },
+ {
+ "x": 170.08701667067626,
+ "y": 0.042848386771500414,
+ "z": 0.0
+ },
+ {
+ "x": 169.08351349168854,
+ "y": 0.04295548992807324,
+ "z": 0.0
+ },
+ {
+ "x": 168.08001031270084,
+ "y": 0.043062593084646064,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 8,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 168.07979685417234,
+ "y": -1.956937395524218,
+ "z": 0.0
+ },
+ {
+ "x": 169.08330003316004,
+ "y": -1.957044498680791,
+ "z": 0.0
+ },
+ {
+ "x": 170.08680321214777,
+ "y": -1.9571516018373638,
+ "z": 0.0
+ },
+ {
+ "x": 171.0903063911355,
+ "y": -1.9572587049939367,
+ "z": 0.0
+ },
+ {
+ "x": 172.0938095701232,
+ "y": -1.9573658081505094,
+ "z": 0.0
+ },
+ {
+ "x": 173.0973127491109,
+ "y": -1.9574729113070821,
+ "z": 0.0
+ },
+ {
+ "x": 174.10081592809863,
+ "y": -1.957580014463655,
+ "z": 0.0
+ },
+ {
+ "x": 175.10431910708633,
+ "y": -1.957687117620228,
+ "z": 0.0
+ },
+ {
+ "x": 176.10782228607405,
+ "y": -1.9577942207768009,
+ "z": 0.0
+ },
+ {
+ "x": 177.11132546506175,
+ "y": -1.9579013239333733,
+ "z": 0.0
+ },
+ {
+ "x": 178.11482864404948,
+ "y": -1.9580084270899463,
+ "z": 0.0
+ },
+ {
+ "x": 179.11833182303718,
+ "y": -1.9581155302465192,
+ "z": 0.0
+ },
+ {
+ "x": 180.12183500202488,
+ "y": -1.958222633403092,
+ "z": 0.0
+ },
+ {
+ "x": 181.1253381810126,
+ "y": -1.958329736559665,
+ "z": 0.0
+ },
+ {
+ "x": 182.12884136000034,
+ "y": -1.9584368397162375,
+ "z": 0.0
+ },
+ {
+ "x": 183.13234453898804,
+ "y": -1.9585439428728104,
+ "z": 0.0
+ },
+ {
+ "x": 184.13584771797574,
+ "y": -1.9586510460293833,
+ "z": 0.0
+ },
+ {
+ "x": 185.13935089696344,
+ "y": -1.9587581491859563,
+ "z": 0.0
+ },
+ {
+ "x": 186.1428540759512,
+ "y": -1.9588652523425292,
+ "z": 0.0
+ },
+ {
+ "x": 187.1463572549389,
+ "y": -1.9589723554991016,
+ "z": 0.0
+ },
+ {
+ "x": 188.1498604339266,
+ "y": -1.9590794586556746,
+ "z": 0.0
+ },
+ {
+ "x": 189.1533636129143,
+ "y": -1.9591865618122475,
+ "z": 0.0
+ },
+ {
+ "x": 190.15686679190205,
+ "y": -1.9592936649688204,
+ "z": 0.0
+ },
+ {
+ "x": 191.16036997088975,
+ "y": -1.9594007681253933,
+ "z": 0.0
+ },
+ {
+ "x": 192.16387314987745,
+ "y": -1.9595078712819658,
+ "z": 0.0
+ },
+ {
+ "x": 193.16737632886515,
+ "y": -1.9596149744385387,
+ "z": 0.0
+ },
+ {
+ "x": 194.17087950785287,
+ "y": -1.9597220775951116,
+ "z": 0.0
+ },
+ {
+ "x": 195.1743826868406,
+ "y": -1.9598291807516846,
+ "z": 0.0
+ },
+ {
+ "x": 196.1778858658283,
+ "y": -1.9599362839082572,
+ "z": 0.0
+ },
+ {
+ "x": 197.18138904481603,
+ "y": -1.96004338706483,
+ "z": 0.0
+ },
+ {
+ "x": 198.1848922238037,
+ "y": -1.9601504902214029,
+ "z": 0.0
+ },
+ {
+ "x": 199.18839540279143,
+ "y": -1.9602575933779758,
+ "z": 0.0
+ },
+ {
+ "x": 200.1918985817791,
+ "y": -1.9603646965345487,
+ "z": 0.0
+ },
+ {
+ "x": 201.19540176076683,
+ "y": -1.9604717996911212,
+ "z": 0.0
+ },
+ {
+ "x": 202.1989049397545,
+ "y": -1.960578902847694,
+ "z": 0.0
+ },
+ {
+ "x": 203.20240811874223,
+ "y": -1.960686006004267,
+ "z": 0.0
+ },
+ {
+ "x": 204.2059112977299,
+ "y": -1.96079310916084,
+ "z": 0.0
+ },
+ {
+ "x": 205.2094144767176,
+ "y": -1.9609002123174128,
+ "z": 0.0
+ },
+ {
+ "x": 206.2129176557053,
+ "y": -1.9610073154739853,
+ "z": 0.0
+ },
+ {
+ "x": 207.216420834693,
+ "y": -1.9611144186305582,
+ "z": 0.0
+ },
+ {
+ "x": 208.2199240136807,
+ "y": -1.9612215217871312,
+ "z": 0.0
+ },
+ {
+ "x": 209.2234271926684,
+ "y": -1.961328624943704,
+ "z": 0.0
+ },
+ {
+ "x": 210.2269303716561,
+ "y": -1.961435728100277,
+ "z": 0.0
+ },
+ {
+ "x": 211.2304335506438,
+ "y": -1.9615428312568495,
+ "z": 0.0
+ },
+ {
+ "x": 212.2339367296315,
+ "y": -1.9616499344134224,
+ "z": 0.0
+ },
+ {
+ "x": 213.2374399086192,
+ "y": -1.9617570375699953,
+ "z": 0.0
+ },
+ {
+ "x": 214.2409430876069,
+ "y": -1.9618641407265682,
+ "z": 0.0
+ },
+ {
+ "x": 215.2444462665946,
+ "y": -1.961971243883141,
+ "z": 0.0
+ },
+ {
+ "x": 216.2479494455823,
+ "y": -1.9620783470397136,
+ "z": 0.0
+ },
+ {
+ "x": 217.25145262457,
+ "y": -1.9621854501962865,
+ "z": 0.0
+ },
+ {
+ "x": 218.2549558035577,
+ "y": -1.9622925533528595,
+ "z": 0.0
+ },
+ {
+ "x": 219.2584589825454,
+ "y": -1.9623996565094324,
+ "z": 0.0
+ },
+ {
+ "x": 220.2619621615331,
+ "y": -1.9625067596660049,
+ "z": 0.0
+ },
+ {
+ "x": 221.2654653405208,
+ "y": -1.9626138628225778,
+ "z": 0.0
+ },
+ {
+ "x": 222.2689685195085,
+ "y": -1.9627209659791507,
+ "z": 0.0
+ },
+ {
+ "x": 223.2724716984962,
+ "y": -1.9628280691357236,
+ "z": 0.0
+ },
+ {
+ "x": 224.2759748774839,
+ "y": -1.9629351722922965,
+ "z": 0.0
+ },
+ {
+ "x": 225.2794780564716,
+ "y": -1.963042275448869,
+ "z": 0.0
+ },
+ {
+ "x": 226.2829812354593,
+ "y": -1.963149378605442,
+ "z": 0.0
+ },
+ {
+ "x": 227.286484414447,
+ "y": -1.9632564817620148,
+ "z": 0.0
+ },
+ {
+ "x": 228.2899875934347,
+ "y": -1.9633635849185878,
+ "z": 0.0
+ },
+ {
+ "x": 229.2934907724224,
+ "y": -1.9634706880751607,
+ "z": 0.0
+ },
+ {
+ "x": 230.2969939514101,
+ "y": -1.9635777912317331,
+ "z": 0.0
+ },
+ {
+ "x": 231.3004971303978,
+ "y": -1.963684894388306,
+ "z": 0.0
+ },
+ {
+ "x": 232.3040003093855,
+ "y": -1.963791997544879,
+ "z": 0.0
+ },
+ {
+ "x": 233.3075034883732,
+ "y": -1.963899100701452,
+ "z": 0.0
+ },
+ {
+ "x": 234.31100666736089,
+ "y": -1.9640062038580244,
+ "z": 0.0
+ },
+ {
+ "x": 235.31450984634859,
+ "y": -1.9641133070145973,
+ "z": 0.0
+ },
+ {
+ "x": 236.31801302533626,
+ "y": -1.9642204101711702,
+ "z": 0.0
+ },
+ {
+ "x": 237.32151620432398,
+ "y": -1.9643275133277431,
+ "z": 0.0
+ },
+ {
+ "x": 238.32501938331166,
+ "y": -1.964434616484316,
+ "z": 0.0
+ },
+ {
+ "x": 239.32852256229938,
+ "y": -1.9645417196408885,
+ "z": 0.0
+ },
+ {
+ "x": 240.33202574128705,
+ "y": -1.9646488227974614,
+ "z": 0.0
+ },
+ {
+ "x": 241.33552892027478,
+ "y": -1.9647559259540344,
+ "z": 0.0
+ },
+ {
+ "x": 242.33903209926245,
+ "y": -1.9648630291106073,
+ "z": 0.0
+ },
+ {
+ "x": 243.34253527825015,
+ "y": -1.9649701322671802,
+ "z": 0.0
+ },
+ {
+ "x": 244.34603845723785,
+ "y": -1.9650772354237527,
+ "z": 0.0
+ },
+ {
+ "x": 245.34954163622555,
+ "y": -1.9651843385803256,
+ "z": 0.0
+ },
+ {
+ "x": 246.35304481521325,
+ "y": -1.9652914417368985,
+ "z": 0.0
+ },
+ {
+ "x": 247.35654799420095,
+ "y": -1.9653985448934714,
+ "z": 0.0
+ },
+ {
+ "x": 248.36005117318865,
+ "y": -1.9655056480500444,
+ "z": 0.0
+ },
+ {
+ "x": 249.36355435217635,
+ "y": -1.9656127512066168,
+ "z": 0.0
+ },
+ {
+ "x": 250.36705753116405,
+ "y": -1.9657198543631897,
+ "z": 0.0
+ },
+ {
+ "x": 251.37056071015175,
+ "y": -1.9658269575197627,
+ "z": 0.0
+ },
+ {
+ "x": 252.37406388913945,
+ "y": -1.9659340606763356,
+ "z": 0.0
+ },
+ {
+ "x": 253.37756706812715,
+ "y": -1.966041163832908,
+ "z": 0.0
+ },
+ {
+ "x": 254.38107024711485,
+ "y": -1.966148266989481,
+ "z": 0.0
+ },
+ {
+ "x": 255.38457342610255,
+ "y": -1.966255370146054,
+ "z": 0.0
+ },
+ {
+ "x": 256.38807660509025,
+ "y": -1.9663624733026268,
+ "z": 0.0
+ },
+ {
+ "x": 257.3915797840779,
+ "y": -1.9664695764591997,
+ "z": 0.0
+ },
+ {
+ "x": 258.39508296306565,
+ "y": -1.9665766796157722,
+ "z": 0.0
+ },
+ {
+ "x": 259.3985861420533,
+ "y": -1.9666837827723451,
+ "z": 0.0
+ },
+ {
+ "x": 260.40208932104105,
+ "y": -1.966790885928918,
+ "z": 0.0
+ },
+ {
+ "x": 261.4055925000287,
+ "y": -1.966897989085491,
+ "z": 0.0
+ },
+ {
+ "x": 262.40909567901645,
+ "y": -1.9670050922420639,
+ "z": 0.0
+ },
+ {
+ "x": 263.4125988580042,
+ "y": -1.9671121953986364,
+ "z": 0.0
+ },
+ {
+ "x": 264.41610203699184,
+ "y": -1.9672192985552093,
+ "z": 0.0
+ },
+ {
+ "x": 265.4196052159796,
+ "y": -1.9673264017117822,
+ "z": 0.0
+ },
+ {
+ "x": 266.42310839496724,
+ "y": -1.967433504868355,
+ "z": 0.0
+ },
+ {
+ "x": 267.426611573955,
+ "y": -1.9675406080249278,
+ "z": 0.0
+ },
+ {
+ "x": 268.4301147529427,
+ "y": -1.9676477111815005,
+ "z": 0.0
+ },
+ {
+ "x": 269.43361793193037,
+ "y": -1.9677548143380734,
+ "z": 0.0
+ },
+ {
+ "x": 270.4371211109181,
+ "y": -1.9678619174946463,
+ "z": 0.0
+ },
+ {
+ "x": 271.44062428990577,
+ "y": -1.9679690206512193,
+ "z": 0.0
+ },
+ {
+ "x": 272.4441274688935,
+ "y": -1.9680761238077917,
+ "z": 0.0
+ },
+ {
+ "x": 273.4476306478812,
+ "y": -1.9681832269643647,
+ "z": 0.0
+ },
+ {
+ "x": 274.4511338268689,
+ "y": -1.9682903301209376,
+ "z": 0.0
+ },
+ {
+ "x": 275.4546370058566,
+ "y": -1.9683974332775105,
+ "z": 0.0
+ },
+ {
+ "x": 276.45814018484435,
+ "y": -1.9685045364340834,
+ "z": 0.0
+ },
+ {
+ "x": 277.461643363832,
+ "y": -1.9686116395906559,
+ "z": 0.0
+ },
+ {
+ "x": 278.46514654281975,
+ "y": -1.9687187427472288,
+ "z": 0.0
+ },
+ {
+ "x": 279.4686497218074,
+ "y": -1.9688258459038017,
+ "z": 0.0
+ },
+ {
+ "x": 280.47215290079515,
+ "y": -1.9689329490603746,
+ "z": 0.0
+ },
+ {
+ "x": 281.4756560797829,
+ "y": -1.9690400522169476,
+ "z": 0.0
+ },
+ {
+ "x": 282.47915925877055,
+ "y": -1.96914715537352,
+ "z": 0.0
+ },
+ {
+ "x": 283.4826624377583,
+ "y": -1.969254258530093,
+ "z": 0.0
+ },
+ {
+ "x": 284.48616561674595,
+ "y": -1.9693613616866659,
+ "z": 0.0
+ },
+ {
+ "x": 285.4896687957337,
+ "y": -1.9694684648432388,
+ "z": 0.0
+ },
+ {
+ "x": 286.4931719747214,
+ "y": -1.9695755679998117,
+ "z": 0.0
+ },
+ {
+ "x": 287.4966751537091,
+ "y": -1.9696826711563842,
+ "z": 0.0
+ },
+ {
+ "x": 288.5001783326968,
+ "y": -1.969789774312957,
+ "z": 0.0
+ },
+ {
+ "x": 289.50368151168453,
+ "y": -1.96989687746953,
+ "z": 0.0
+ },
+ {
+ "x": 290.5071239699698,
+ "y": -1.9700344366797367,
+ "z": 0.0
+ },
+ {
+ "x": 291.50986779320573,
+ "y": -1.970552697994256,
+ "z": 0.0
+ },
+ {
+ "x": 292.51334176180364,
+ "y": -1.9710857804400896,
+ "z": 0.0
+ },
+ {
+ "x": 293.5168448049064,
+ "y": -1.9716188781200372,
+ "z": 0.0
+ },
+ {
+ "x": 294.52034784800907,
+ "y": -1.972151975799984,
+ "z": 0.0
+ },
+ {
+ "x": 295.52385089111175,
+ "y": -1.9726850734799315,
+ "z": 0.0
+ },
+ {
+ "x": 296.5273539342145,
+ "y": -1.973218171159879,
+ "z": 0.0
+ },
+ {
+ "x": 297.53085697731717,
+ "y": -1.9737512688398258,
+ "z": 0.0
+ },
+ {
+ "x": 298.53436002041985,
+ "y": -1.974284366519773,
+ "z": 0.0
+ },
+ {
+ "x": 299.5378630635226,
+ "y": -1.9748174641997205,
+ "z": 0.0
+ },
+ {
+ "x": 300.5413661066253,
+ "y": -1.9753505618796672,
+ "z": 0.0
+ },
+ {
+ "x": 301.54486914972796,
+ "y": -1.9758836595596148,
+ "z": 0.0
+ },
+ {
+ "x": 302.5483721928307,
+ "y": -1.9764167572395623,
+ "z": 0.0
+ },
+ {
+ "x": 303.5518752359334,
+ "y": -1.976949854919509,
+ "z": 0.0
+ },
+ {
+ "x": 304.55537827903606,
+ "y": -1.9774829525994562,
+ "z": 0.0
+ },
+ {
+ "x": 305.5588813221388,
+ "y": -1.9780160502794037,
+ "z": 0.0
+ },
+ {
+ "x": 306.5623843652415,
+ "y": -1.9785491479593509,
+ "z": 0.0
+ },
+ {
+ "x": 307.56588740834417,
+ "y": -1.979082245639298,
+ "z": 0.0
+ },
+ {
+ "x": 308.5693904514469,
+ "y": -1.9796153433192456,
+ "z": 0.0
+ },
+ {
+ "x": 309.5728934945496,
+ "y": -1.9801484409991923,
+ "z": 0.0
+ },
+ {
+ "x": 310.5763965376523,
+ "y": -1.9806815386791394,
+ "z": 0.0
+ },
+ {
+ "x": 311.579899580755,
+ "y": -1.9812146363590875,
+ "z": 0.0
+ },
+ {
+ "x": 312.5834026238577,
+ "y": -1.9817477340390341,
+ "z": 0.0
+ },
+ {
+ "x": 313.5869056669604,
+ "y": -1.9822808317189813,
+ "z": 0.0
+ },
+ {
+ "x": 314.59040871006306,
+ "y": -1.9828139293989284,
+ "z": 0.0
+ },
+ {
+ "x": 315.5939117531658,
+ "y": -1.983347027078876,
+ "z": 0.0
+ },
+ {
+ "x": 316.5974147962685,
+ "y": -1.9838801247588231,
+ "z": 0.0
+ },
+ {
+ "x": 317.60091783937116,
+ "y": -1.9844132224387703,
+ "z": 0.0
+ },
+ {
+ "x": 318.6044208824739,
+ "y": -1.9849463201187179,
+ "z": 0.0
+ },
+ {
+ "x": 319.6079239255766,
+ "y": -1.9854794177986645,
+ "z": 0.0
+ },
+ {
+ "x": 320.61142696867927,
+ "y": -1.9860125154786117,
+ "z": 0.0
+ },
+ {
+ "x": 321.614930011782,
+ "y": -1.9865456131585593,
+ "z": 0.0
+ },
+ {
+ "x": 322.6184330548847,
+ "y": -1.9870787108385064,
+ "z": 0.0
+ },
+ {
+ "x": 323.6219360979874,
+ "y": -1.9876118085184535,
+ "z": 0.0
+ },
+ {
+ "x": 324.6254391410901,
+ "y": -1.9881449061984011,
+ "z": 0.0
+ },
+ {
+ "x": 325.6289421841928,
+ "y": -1.9886780038783478,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 9,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 325.63106713083204,
+ "y": 2.0113214316968344,
+ "z": 0.0
+ },
+ {
+ "x": 324.62756408772935,
+ "y": 2.011854529376782,
+ "z": 0.0
+ },
+ {
+ "x": 323.6240610446266,
+ "y": 2.012387627056729,
+ "z": 0.0
+ },
+ {
+ "x": 322.62055800152393,
+ "y": 2.0129207247366763,
+ "z": 0.0
+ },
+ {
+ "x": 321.61705495842125,
+ "y": 2.013453822416624,
+ "z": 0.0
+ },
+ {
+ "x": 320.6135519153185,
+ "y": 2.0139869200965705,
+ "z": 0.0
+ },
+ {
+ "x": 319.6100488722158,
+ "y": 2.0145200177765177,
+ "z": 0.0
+ },
+ {
+ "x": 318.60654582911314,
+ "y": 2.0150531154564657,
+ "z": 0.0
+ },
+ {
+ "x": 317.6030427860104,
+ "y": 2.0155862131364124,
+ "z": 0.0
+ },
+ {
+ "x": 316.5995397429077,
+ "y": 2.0161193108163595,
+ "z": 0.0
+ },
+ {
+ "x": 315.59603669980504,
+ "y": 2.016652408496307,
+ "z": 0.0
+ },
+ {
+ "x": 314.5925336567023,
+ "y": 2.017185506176254,
+ "z": 0.0
+ },
+ {
+ "x": 313.5890306135996,
+ "y": 2.0177186038562014,
+ "z": 0.0
+ },
+ {
+ "x": 312.58552757049694,
+ "y": 2.0182517015361485,
+ "z": 0.0
+ },
+ {
+ "x": 311.58202452739425,
+ "y": 2.018784799216096,
+ "z": 0.0
+ },
+ {
+ "x": 310.5785214842915,
+ "y": 2.019317896896043,
+ "z": 0.0
+ },
+ {
+ "x": 309.57501844118883,
+ "y": 2.01985099457599,
+ "z": 0.0
+ },
+ {
+ "x": 308.57151539808615,
+ "y": 2.020384092255938,
+ "z": 0.0
+ },
+ {
+ "x": 307.5680123549834,
+ "y": 2.0209171899358847,
+ "z": 0.0
+ },
+ {
+ "x": 306.5645093118807,
+ "y": 2.021450287615832,
+ "z": 0.0
+ },
+ {
+ "x": 305.56100626877804,
+ "y": 2.0219833852957794,
+ "z": 0.0
+ },
+ {
+ "x": 304.5575032256753,
+ "y": 2.022516482975726,
+ "z": 0.0
+ },
+ {
+ "x": 303.5540001825726,
+ "y": 2.023049580655673,
+ "z": 0.0
+ },
+ {
+ "x": 302.55049713946994,
+ "y": 2.023582678335621,
+ "z": 0.0
+ },
+ {
+ "x": 301.5469940963672,
+ "y": 2.024115776015568,
+ "z": 0.0
+ },
+ {
+ "x": 300.5434910532645,
+ "y": 2.024648873695515,
+ "z": 0.0
+ },
+ {
+ "x": 299.53998801016184,
+ "y": 2.0251819713754626,
+ "z": 0.0
+ },
+ {
+ "x": 298.5364849670591,
+ "y": 2.0257150690554093,
+ "z": 0.0
+ },
+ {
+ "x": 297.5329819239564,
+ "y": 2.026248166735357,
+ "z": 0.0
+ },
+ {
+ "x": 296.52947888085373,
+ "y": 2.0267812644153045,
+ "z": 0.0
+ },
+ {
+ "x": 295.525975837751,
+ "y": 2.027314362095251,
+ "z": 0.0
+ },
+ {
+ "x": 294.5224727946483,
+ "y": 2.0278474597751983,
+ "z": 0.0
+ },
+ {
+ "x": 293.5189697515456,
+ "y": 2.028380557455146,
+ "z": 0.0
+ },
+ {
+ "x": 292.5154667084429,
+ "y": 2.028913655135093,
+ "z": 0.0
+ },
+ {
+ "x": 291.51193459083544,
+ "y": 2.0294467680491537,
+ "z": 0.0
+ },
+ {
+ "x": 290.50767231546286,
+ "y": 2.0299655257349163,
+ "z": 0.0
+ },
+ {
+ "x": 289.5041084287415,
+ "y": 2.0301030997481986,
+ "z": 0.0
+ },
+ {
+ "x": 288.5006052497538,
+ "y": 2.030210202904771,
+ "z": 0.0
+ },
+ {
+ "x": 287.49710207076606,
+ "y": 2.030317306061344,
+ "z": 0.0
+ },
+ {
+ "x": 286.4935988917784,
+ "y": 2.030424409217917,
+ "z": 0.0
+ },
+ {
+ "x": 285.49009571279066,
+ "y": 2.03053151237449,
+ "z": 0.0
+ },
+ {
+ "x": 284.48659253380293,
+ "y": 2.0306386155310627,
+ "z": 0.0
+ },
+ {
+ "x": 283.48308935481526,
+ "y": 2.030745718687635,
+ "z": 0.0
+ },
+ {
+ "x": 282.47958617582754,
+ "y": 2.030852821844208,
+ "z": 0.0
+ },
+ {
+ "x": 281.47608299683986,
+ "y": 2.030959925000781,
+ "z": 0.0
+ },
+ {
+ "x": 280.47257981785214,
+ "y": 2.031067028157354,
+ "z": 0.0
+ },
+ {
+ "x": 279.4690766388644,
+ "y": 2.031174131313927,
+ "z": 0.0
+ },
+ {
+ "x": 278.46557345987674,
+ "y": 2.0312812344704994,
+ "z": 0.0
+ },
+ {
+ "x": 277.462070280889,
+ "y": 2.0313883376270723,
+ "z": 0.0
+ },
+ {
+ "x": 276.45856710190134,
+ "y": 2.031495440783645,
+ "z": 0.0
+ },
+ {
+ "x": 275.4550639229136,
+ "y": 2.031602543940218,
+ "z": 0.0
+ },
+ {
+ "x": 274.4515607439259,
+ "y": 2.0317096470967906,
+ "z": 0.0
+ },
+ {
+ "x": 273.4480575649382,
+ "y": 2.0318167502533635,
+ "z": 0.0
+ },
+ {
+ "x": 272.4445543859505,
+ "y": 2.0319238534099364,
+ "z": 0.0
+ },
+ {
+ "x": 271.44105120696275,
+ "y": 2.0320309565665093,
+ "z": 0.0
+ },
+ {
+ "x": 270.4375480279751,
+ "y": 2.0321380597230823,
+ "z": 0.0
+ },
+ {
+ "x": 269.43404484898736,
+ "y": 2.0322451628796547,
+ "z": 0.0
+ },
+ {
+ "x": 268.4305416699997,
+ "y": 2.0323522660362277,
+ "z": 0.0
+ },
+ {
+ "x": 267.42703849101196,
+ "y": 2.0324593691928006,
+ "z": 0.0
+ },
+ {
+ "x": 266.4235353120242,
+ "y": 2.0325664723493735,
+ "z": 0.0
+ },
+ {
+ "x": 265.42003213303656,
+ "y": 2.0326735755059464,
+ "z": 0.0
+ },
+ {
+ "x": 264.41652895404883,
+ "y": 2.032780678662519,
+ "z": 0.0
+ },
+ {
+ "x": 263.41302577506116,
+ "y": 2.032887781819092,
+ "z": 0.0
+ },
+ {
+ "x": 262.40952259607343,
+ "y": 2.0329948849756647,
+ "z": 0.0
+ },
+ {
+ "x": 261.4060194170857,
+ "y": 2.0331019881322376,
+ "z": 0.0
+ },
+ {
+ "x": 260.40251623809803,
+ "y": 2.0332090912888106,
+ "z": 0.0
+ },
+ {
+ "x": 259.3990130591103,
+ "y": 2.033316194445383,
+ "z": 0.0
+ },
+ {
+ "x": 258.39550988012263,
+ "y": 2.033423297601956,
+ "z": 0.0
+ },
+ {
+ "x": 257.3920067011349,
+ "y": 2.033530400758529,
+ "z": 0.0
+ },
+ {
+ "x": 256.38850352214723,
+ "y": 2.033637503915102,
+ "z": 0.0
+ },
+ {
+ "x": 255.38500034315953,
+ "y": 2.0337446070716743,
+ "z": 0.0
+ },
+ {
+ "x": 254.38149716417183,
+ "y": 2.033851710228247,
+ "z": 0.0
+ },
+ {
+ "x": 253.37799398518413,
+ "y": 2.03395881338482,
+ "z": 0.0
+ },
+ {
+ "x": 252.37449080619643,
+ "y": 2.034065916541393,
+ "z": 0.0
+ },
+ {
+ "x": 251.37098762720873,
+ "y": 2.034173019697966,
+ "z": 0.0
+ },
+ {
+ "x": 250.36748444822103,
+ "y": 2.0342801228545384,
+ "z": 0.0
+ },
+ {
+ "x": 249.36398126923334,
+ "y": 2.0343872260111113,
+ "z": 0.0
+ },
+ {
+ "x": 248.36047809024564,
+ "y": 2.0344943291676842,
+ "z": 0.0
+ },
+ {
+ "x": 247.35697491125794,
+ "y": 2.034601432324257,
+ "z": 0.0
+ },
+ {
+ "x": 246.35347173227024,
+ "y": 2.03470853548083,
+ "z": 0.0
+ },
+ {
+ "x": 245.34996855328254,
+ "y": 2.0348156386374026,
+ "z": 0.0
+ },
+ {
+ "x": 244.34646537429484,
+ "y": 2.0349227417939755,
+ "z": 0.0
+ },
+ {
+ "x": 243.34296219530714,
+ "y": 2.0350298449505484,
+ "z": 0.0
+ },
+ {
+ "x": 242.33945901631944,
+ "y": 2.0351369481071213,
+ "z": 0.0
+ },
+ {
+ "x": 241.33595583733177,
+ "y": 2.0352440512636942,
+ "z": 0.0
+ },
+ {
+ "x": 240.33245265834404,
+ "y": 2.0353511544202667,
+ "z": 0.0
+ },
+ {
+ "x": 239.32894947935637,
+ "y": 2.0354582575768396,
+ "z": 0.0
+ },
+ {
+ "x": 238.32544630036864,
+ "y": 2.0355653607334125,
+ "z": 0.0
+ },
+ {
+ "x": 237.32194312138097,
+ "y": 2.0356724638899855,
+ "z": 0.0
+ },
+ {
+ "x": 236.31843994239324,
+ "y": 2.035779567046558,
+ "z": 0.0
+ },
+ {
+ "x": 235.31493676340557,
+ "y": 2.035886670203131,
+ "z": 0.0
+ },
+ {
+ "x": 234.31143358441787,
+ "y": 2.0359937733597038,
+ "z": 0.0
+ },
+ {
+ "x": 233.30793040543017,
+ "y": 2.0361008765162767,
+ "z": 0.0
+ },
+ {
+ "x": 232.30442722644247,
+ "y": 2.0362079796728496,
+ "z": 0.0
+ },
+ {
+ "x": 231.30092404745477,
+ "y": 2.036315082829422,
+ "z": 0.0
+ },
+ {
+ "x": 230.29742086846707,
+ "y": 2.036422185985995,
+ "z": 0.0
+ },
+ {
+ "x": 229.29391768947937,
+ "y": 2.036529289142568,
+ "z": 0.0
+ },
+ {
+ "x": 228.29041451049167,
+ "y": 2.036636392299141,
+ "z": 0.0
+ },
+ {
+ "x": 227.28691133150397,
+ "y": 2.0367434954557138,
+ "z": 0.0
+ },
+ {
+ "x": 226.28340815251627,
+ "y": 2.0368505986122862,
+ "z": 0.0
+ },
+ {
+ "x": 225.27990497352857,
+ "y": 2.036957701768859,
+ "z": 0.0
+ },
+ {
+ "x": 224.27640179454087,
+ "y": 2.037064804925432,
+ "z": 0.0
+ },
+ {
+ "x": 223.27289861555317,
+ "y": 2.037171908082005,
+ "z": 0.0
+ },
+ {
+ "x": 222.26939543656547,
+ "y": 2.0372790112385775,
+ "z": 0.0
+ },
+ {
+ "x": 221.26589225757778,
+ "y": 2.0373861143951504,
+ "z": 0.0
+ },
+ {
+ "x": 220.26238907859008,
+ "y": 2.0374932175517233,
+ "z": 0.0
+ },
+ {
+ "x": 219.25888589960238,
+ "y": 2.037600320708296,
+ "z": 0.0
+ },
+ {
+ "x": 218.25538272061468,
+ "y": 2.037707423864869,
+ "z": 0.0
+ },
+ {
+ "x": 217.25187954162698,
+ "y": 2.0378145270214416,
+ "z": 0.0
+ },
+ {
+ "x": 216.24837636263928,
+ "y": 2.0379216301780145,
+ "z": 0.0
+ },
+ {
+ "x": 215.24487318365158,
+ "y": 2.0380287333345875,
+ "z": 0.0
+ },
+ {
+ "x": 214.24137000466388,
+ "y": 2.0381358364911604,
+ "z": 0.0
+ },
+ {
+ "x": 213.23786682567618,
+ "y": 2.0382429396477333,
+ "z": 0.0
+ },
+ {
+ "x": 212.23436364668848,
+ "y": 2.0383500428043058,
+ "z": 0.0
+ },
+ {
+ "x": 211.23086046770078,
+ "y": 2.0384571459608787,
+ "z": 0.0
+ },
+ {
+ "x": 210.22735728871308,
+ "y": 2.0385642491174516,
+ "z": 0.0
+ },
+ {
+ "x": 209.22385410972538,
+ "y": 2.0386713522740245,
+ "z": 0.0
+ },
+ {
+ "x": 208.22035093073768,
+ "y": 2.0387784554305974,
+ "z": 0.0
+ },
+ {
+ "x": 207.21684775174998,
+ "y": 2.03888555858717,
+ "z": 0.0
+ },
+ {
+ "x": 206.21334457276228,
+ "y": 2.038992661743743,
+ "z": 0.0
+ },
+ {
+ "x": 205.20984139377458,
+ "y": 2.0390997649003157,
+ "z": 0.0
+ },
+ {
+ "x": 204.20633821478688,
+ "y": 2.0392068680568887,
+ "z": 0.0
+ },
+ {
+ "x": 203.2028350357992,
+ "y": 2.039313971213461,
+ "z": 0.0
+ },
+ {
+ "x": 202.19933185681148,
+ "y": 2.039421074370034,
+ "z": 0.0
+ },
+ {
+ "x": 201.1958286778238,
+ "y": 2.039528177526607,
+ "z": 0.0
+ },
+ {
+ "x": 200.19232549883608,
+ "y": 2.03963528068318,
+ "z": 0.0
+ },
+ {
+ "x": 199.1888223198484,
+ "y": 2.039742383839753,
+ "z": 0.0
+ },
+ {
+ "x": 198.18531914086068,
+ "y": 2.0398494869963253,
+ "z": 0.0
+ },
+ {
+ "x": 197.181815961873,
+ "y": 2.039956590152898,
+ "z": 0.0
+ },
+ {
+ "x": 196.17831278288529,
+ "y": 2.040063693309471,
+ "z": 0.0
+ },
+ {
+ "x": 195.1748096038976,
+ "y": 2.040170796466044,
+ "z": 0.0
+ },
+ {
+ "x": 194.17130642490986,
+ "y": 2.040277899622617,
+ "z": 0.0
+ },
+ {
+ "x": 193.16780324592213,
+ "y": 2.0403850027791894,
+ "z": 0.0
+ },
+ {
+ "x": 192.16430006693443,
+ "y": 2.0404921059357624,
+ "z": 0.0
+ },
+ {
+ "x": 191.16079688794673,
+ "y": 2.0405992090923353,
+ "z": 0.0
+ },
+ {
+ "x": 190.15729370895903,
+ "y": 2.040706312248908,
+ "z": 0.0
+ },
+ {
+ "x": 189.15379052997127,
+ "y": 2.040813415405481,
+ "z": 0.0
+ },
+ {
+ "x": 188.15028735098358,
+ "y": 2.0409205185620536,
+ "z": 0.0
+ },
+ {
+ "x": 187.14678417199588,
+ "y": 2.0410276217186265,
+ "z": 0.0
+ },
+ {
+ "x": 186.14328099300818,
+ "y": 2.0411347248751994,
+ "z": 0.0
+ },
+ {
+ "x": 185.13977781402042,
+ "y": 2.0412418280317723,
+ "z": 0.0
+ },
+ {
+ "x": 184.13627463503272,
+ "y": 2.0413489311883453,
+ "z": 0.0
+ },
+ {
+ "x": 183.13277145604502,
+ "y": 2.0414560343449177,
+ "z": 0.0
+ },
+ {
+ "x": 182.12926827705732,
+ "y": 2.0415631375014907,
+ "z": 0.0
+ },
+ {
+ "x": 181.1257650980696,
+ "y": 2.0416702406580636,
+ "z": 0.0
+ },
+ {
+ "x": 180.12226191908186,
+ "y": 2.0417773438146365,
+ "z": 0.0
+ },
+ {
+ "x": 179.11875874009417,
+ "y": 2.041884446971209,
+ "z": 0.0
+ },
+ {
+ "x": 178.11525556110647,
+ "y": 2.041991550127782,
+ "z": 0.0
+ },
+ {
+ "x": 177.11175238211874,
+ "y": 2.042098653284355,
+ "z": 0.0
+ },
+ {
+ "x": 176.10824920313104,
+ "y": 2.0422057564409277,
+ "z": 0.0
+ },
+ {
+ "x": 175.1047460241433,
+ "y": 2.0423128595975006,
+ "z": 0.0
+ },
+ {
+ "x": 174.1012428451556,
+ "y": 2.042419962754073,
+ "z": 0.0
+ },
+ {
+ "x": 173.09773966616788,
+ "y": 2.042527065910646,
+ "z": 0.0
+ },
+ {
+ "x": 172.09423648718018,
+ "y": 2.042634169067219,
+ "z": 0.0
+ },
+ {
+ "x": 171.09073330819248,
+ "y": 2.042741272223792,
+ "z": 0.0
+ },
+ {
+ "x": 170.08723012920476,
+ "y": 2.042848375380365,
+ "z": 0.0
+ },
+ {
+ "x": 169.08372695021703,
+ "y": 2.0429554785369373,
+ "z": 0.0
+ },
+ {
+ "x": 168.08022377122933,
+ "y": 2.04306258169351,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 10,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 102.69023839464042,
+ "y": -3.9501270959538224,
+ "z": 0.0
+ },
+ {
+ "x": 103.72121398505429,
+ "y": -3.9500684091140976,
+ "z": 0.0
+ },
+ {
+ "x": 104.75153497744992,
+ "y": -3.9501784280806986,
+ "z": 0.0
+ },
+ {
+ "x": 105.78251058129288,
+ "y": -3.95028846334898,
+ "z": 0.0
+ },
+ {
+ "x": 106.81348618513584,
+ "y": -3.9503984986172616,
+ "z": 0.0
+ },
+ {
+ "x": 107.8444617889788,
+ "y": -3.950508533885543,
+ "z": 0.0
+ },
+ {
+ "x": 108.87543739282175,
+ "y": -3.9506185691538245,
+ "z": 0.0
+ },
+ {
+ "x": 109.90641299666471,
+ "y": -3.950728604422106,
+ "z": 0.0
+ },
+ {
+ "x": 110.93738860050767,
+ "y": -3.9508386396903874,
+ "z": 0.0
+ },
+ {
+ "x": 111.96836420435064,
+ "y": -3.950948674958669,
+ "z": 0.0
+ },
+ {
+ "x": 112.9993398081936,
+ "y": -3.95105871022695,
+ "z": 0.0
+ },
+ {
+ "x": 114.03031541203654,
+ "y": -3.9511687454952313,
+ "z": 0.0
+ },
+ {
+ "x": 115.0612910158795,
+ "y": -3.951278780763513,
+ "z": 0.0
+ },
+ {
+ "x": 116.09226661972247,
+ "y": -3.9513888160317943,
+ "z": 0.0
+ },
+ {
+ "x": 117.12324222356543,
+ "y": -3.9514988513000757,
+ "z": 0.0
+ },
+ {
+ "x": 118.15421782740839,
+ "y": -3.951608886568357,
+ "z": 0.0
+ },
+ {
+ "x": 119.18519343125135,
+ "y": -3.9517189218366386,
+ "z": 0.0
+ },
+ {
+ "x": 120.2161690350943,
+ "y": -3.95182895710492,
+ "z": 0.0
+ },
+ {
+ "x": 121.24714463893727,
+ "y": -3.951938992373201,
+ "z": 0.0
+ },
+ {
+ "x": 122.27812024278022,
+ "y": -3.9520490276414826,
+ "z": 0.0
+ },
+ {
+ "x": 123.30909584662318,
+ "y": -3.952159062909764,
+ "z": 0.0
+ },
+ {
+ "x": 124.34007145046614,
+ "y": -3.9522690981780455,
+ "z": 0.0
+ },
+ {
+ "x": 125.3710470543091,
+ "y": -3.952379133446327,
+ "z": 0.0
+ },
+ {
+ "x": 126.40202265815206,
+ "y": -3.9524891687146084,
+ "z": 0.0
+ },
+ {
+ "x": 127.43299826199502,
+ "y": -3.95259920398289,
+ "z": 0.0
+ },
+ {
+ "x": 128.46397386583797,
+ "y": -3.9527092392511713,
+ "z": 0.0
+ },
+ {
+ "x": 129.49494946968093,
+ "y": -3.9528192745194524,
+ "z": 0.0
+ },
+ {
+ "x": 130.5259250735239,
+ "y": -3.952929309787734,
+ "z": 0.0
+ },
+ {
+ "x": 131.55690067736685,
+ "y": -3.9530393450560153,
+ "z": 0.0
+ },
+ {
+ "x": 132.58787628120982,
+ "y": -3.9531493803242967,
+ "z": 0.0
+ },
+ {
+ "x": 133.61885188505278,
+ "y": -3.953259415592578,
+ "z": 0.0
+ },
+ {
+ "x": 134.64982748889574,
+ "y": -3.9533694508608597,
+ "z": 0.0
+ },
+ {
+ "x": 135.6808030927387,
+ "y": -3.953479486129141,
+ "z": 0.0
+ },
+ {
+ "x": 136.71177869658166,
+ "y": -3.9535895213974226,
+ "z": 0.0
+ },
+ {
+ "x": 137.74275430042462,
+ "y": -3.9536995566657036,
+ "z": 0.0
+ },
+ {
+ "x": 138.77372990426755,
+ "y": -3.953809591933985,
+ "z": 0.0
+ },
+ {
+ "x": 139.80470550811052,
+ "y": -3.9539196272022665,
+ "z": 0.0
+ },
+ {
+ "x": 140.83568111195348,
+ "y": -3.954029662470548,
+ "z": 0.0
+ },
+ {
+ "x": 141.86665671579644,
+ "y": -3.9541396977388295,
+ "z": 0.0
+ },
+ {
+ "x": 142.8976323196394,
+ "y": -3.954249733007111,
+ "z": 0.0
+ },
+ {
+ "x": 143.92860792348236,
+ "y": -3.9543597682753924,
+ "z": 0.0
+ },
+ {
+ "x": 144.95958352732532,
+ "y": -3.954469803543674,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 11,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 144.9604373614393,
+ "y": 4.045530150891783,
+ "z": 0.0
+ },
+ {
+ "x": 143.92946175759633,
+ "y": 4.045640186160065,
+ "z": 0.0
+ },
+ {
+ "x": 142.89848615375337,
+ "y": 4.045750221428346,
+ "z": 0.0
+ },
+ {
+ "x": 141.8675105499104,
+ "y": 4.045860256696628,
+ "z": 0.0
+ },
+ {
+ "x": 140.83653494606745,
+ "y": 4.045970291964909,
+ "z": 0.0
+ },
+ {
+ "x": 139.80555934222448,
+ "y": 4.04608032723319,
+ "z": 0.0
+ },
+ {
+ "x": 138.77458373838152,
+ "y": 4.046190362501472,
+ "z": 0.0
+ },
+ {
+ "x": 137.7436081345386,
+ "y": 4.046300397769753,
+ "z": 0.0
+ },
+ {
+ "x": 136.71263253069563,
+ "y": 4.046410433038035,
+ "z": 0.0
+ },
+ {
+ "x": 135.68165692685267,
+ "y": 4.046520468306316,
+ "z": 0.0
+ },
+ {
+ "x": 134.6506813230097,
+ "y": 4.0466305035745975,
+ "z": 0.0
+ },
+ {
+ "x": 133.61970571916675,
+ "y": 4.0467405388428785,
+ "z": 0.0
+ },
+ {
+ "x": 132.58873011532378,
+ "y": 4.04685057411116,
+ "z": 0.0
+ },
+ {
+ "x": 131.55775451148082,
+ "y": 4.0469606093794415,
+ "z": 0.0
+ },
+ {
+ "x": 130.52677890763786,
+ "y": 4.0470706446477225,
+ "z": 0.0
+ },
+ {
+ "x": 129.4958033037949,
+ "y": 4.047180679916004,
+ "z": 0.0
+ },
+ {
+ "x": 128.46482769995194,
+ "y": 4.047290715184285,
+ "z": 0.0
+ },
+ {
+ "x": 127.43385209610899,
+ "y": 4.047400750452567,
+ "z": 0.0
+ },
+ {
+ "x": 126.40287649226603,
+ "y": 4.047510785720848,
+ "z": 0.0
+ },
+ {
+ "x": 125.37190088842307,
+ "y": 4.04762082098913,
+ "z": 0.0
+ },
+ {
+ "x": 124.34092528458011,
+ "y": 4.047730856257411,
+ "z": 0.0
+ },
+ {
+ "x": 123.30994968073715,
+ "y": 4.047840891525692,
+ "z": 0.0
+ },
+ {
+ "x": 122.27897407689419,
+ "y": 4.047950926793974,
+ "z": 0.0
+ },
+ {
+ "x": 121.24799847305124,
+ "y": 4.048060962062255,
+ "z": 0.0
+ },
+ {
+ "x": 120.21702286920826,
+ "y": 4.048170997330537,
+ "z": 0.0
+ },
+ {
+ "x": 119.18604726536532,
+ "y": 4.048281032598818,
+ "z": 0.0
+ },
+ {
+ "x": 118.15507166152236,
+ "y": 4.0483910678671,
+ "z": 0.0
+ },
+ {
+ "x": 117.1240960576794,
+ "y": 4.048501103135381,
+ "z": 0.0
+ },
+ {
+ "x": 116.09312045383643,
+ "y": 4.048611138403662,
+ "z": 0.0
+ },
+ {
+ "x": 115.06214484999347,
+ "y": 4.048721173671944,
+ "z": 0.0
+ },
+ {
+ "x": 114.03116924615051,
+ "y": 4.048831208940225,
+ "z": 0.0
+ },
+ {
+ "x": 113.00019364230756,
+ "y": 4.048941244208507,
+ "z": 0.0
+ },
+ {
+ "x": 111.9692180384646,
+ "y": 4.049051279476788,
+ "z": 0.0
+ },
+ {
+ "x": 110.93824243462164,
+ "y": 4.04916131474507,
+ "z": 0.0
+ },
+ {
+ "x": 109.90726683077868,
+ "y": 4.049271350013351,
+ "z": 0.0
+ },
+ {
+ "x": 108.87629122693572,
+ "y": 4.049381385281633,
+ "z": 0.0
+ },
+ {
+ "x": 107.84531562309277,
+ "y": 4.049491420549914,
+ "z": 0.0
+ },
+ {
+ "x": 106.81434001924981,
+ "y": 4.049601455818195,
+ "z": 0.0
+ },
+ {
+ "x": 105.78336441540685,
+ "y": 4.049711491086477,
+ "z": 0.0
+ },
+ {
+ "x": 104.75238881156389,
+ "y": 4.049821526354758,
+ "z": 0.0
+ },
+ {
+ "x": 103.7207585962736,
+ "y": 4.04993157792472,
+ "z": 0.0
+ },
+ {
+ "x": 102.68978300585972,
+ "y": 4.049872891084994,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 12,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 144.9600104443823,
+ "y": 0.04553017367405473,
+ "z": 0.0
+ },
+ {
+ "x": 143.92903484053934,
+ "y": 0.045640208942336134,
+ "z": 0.0
+ },
+ {
+ "x": 142.89805923669638,
+ "y": 0.04575024421061754,
+ "z": 0.0
+ },
+ {
+ "x": 141.86708363285342,
+ "y": 0.045860279478898945,
+ "z": 0.0
+ },
+ {
+ "x": 140.83610802901046,
+ "y": 0.04597031474718035,
+ "z": 0.0
+ },
+ {
+ "x": 139.8051324251675,
+ "y": 0.046080350015461756,
+ "z": 0.0
+ },
+ {
+ "x": 138.77415682132454,
+ "y": 0.04619038528374317,
+ "z": 0.0
+ },
+ {
+ "x": 137.7431812174816,
+ "y": 0.04630042055202457,
+ "z": 0.0
+ },
+ {
+ "x": 136.71220561363864,
+ "y": 0.04641045582030597,
+ "z": 0.0
+ },
+ {
+ "x": 135.68123000979568,
+ "y": 0.046520491088587385,
+ "z": 0.0
+ },
+ {
+ "x": 134.65025440595272,
+ "y": 0.04663052635686878,
+ "z": 0.0
+ },
+ {
+ "x": 133.61927880210976,
+ "y": 0.04674056162515019,
+ "z": 0.0
+ },
+ {
+ "x": 132.5883031982668,
+ "y": 0.0468505968934316,
+ "z": 0.0
+ },
+ {
+ "x": 131.55732759442384,
+ "y": 0.046960632161713,
+ "z": 0.0
+ },
+ {
+ "x": 130.52635199058088,
+ "y": 0.047070667429994405,
+ "z": 0.0
+ },
+ {
+ "x": 129.49537638673792,
+ "y": 0.04718070269827582,
+ "z": 0.0
+ },
+ {
+ "x": 128.46440078289496,
+ "y": 0.04729073796655722,
+ "z": 0.0
+ },
+ {
+ "x": 127.43342517905201,
+ "y": 0.04740077323483862,
+ "z": 0.0
+ },
+ {
+ "x": 126.40244957520905,
+ "y": 0.047510808503120026,
+ "z": 0.0
+ },
+ {
+ "x": 125.37147397136609,
+ "y": 0.04762084377140144,
+ "z": 0.0
+ },
+ {
+ "x": 124.34049836752313,
+ "y": 0.047730879039682844,
+ "z": 0.0
+ },
+ {
+ "x": 123.30952276368016,
+ "y": 0.04784091430796424,
+ "z": 0.0
+ },
+ {
+ "x": 122.2785471598372,
+ "y": 0.047950949576245655,
+ "z": 0.0
+ },
+ {
+ "x": 121.24757155599426,
+ "y": 0.04806098484452706,
+ "z": 0.0
+ },
+ {
+ "x": 120.21659595215128,
+ "y": 0.048171020112808466,
+ "z": 0.0
+ },
+ {
+ "x": 119.18562034830833,
+ "y": 0.04828105538108987,
+ "z": 0.0
+ },
+ {
+ "x": 118.15464474446537,
+ "y": 0.04839109064937128,
+ "z": 0.0
+ },
+ {
+ "x": 117.12366914062241,
+ "y": 0.04850112591765268,
+ "z": 0.0
+ },
+ {
+ "x": 116.09269353677945,
+ "y": 0.04861116118593409,
+ "z": 0.0
+ },
+ {
+ "x": 115.06171793293649,
+ "y": 0.04872119645421549,
+ "z": 0.0
+ },
+ {
+ "x": 114.03074232909353,
+ "y": 0.0488312317224969,
+ "z": 0.0
+ },
+ {
+ "x": 112.99976672525058,
+ "y": 0.048941266990778304,
+ "z": 0.0
+ },
+ {
+ "x": 111.96879112140762,
+ "y": 0.04905130225905971,
+ "z": 0.0
+ },
+ {
+ "x": 110.93781551756466,
+ "y": 0.049161337527341115,
+ "z": 0.0
+ },
+ {
+ "x": 109.9068399137217,
+ "y": 0.04927137279562252,
+ "z": 0.0
+ },
+ {
+ "x": 108.87586430987874,
+ "y": 0.049381408063903925,
+ "z": 0.0
+ },
+ {
+ "x": 107.84488870603579,
+ "y": 0.04949144333218533,
+ "z": 0.0
+ },
+ {
+ "x": 106.81391310219283,
+ "y": 0.049601478600466736,
+ "z": 0.0
+ },
+ {
+ "x": 105.78293749834987,
+ "y": 0.04971151386874814,
+ "z": 0.0
+ },
+ {
+ "x": 104.7519618945069,
+ "y": 0.04982154913702955,
+ "z": 0.0
+ },
+ {
+ "x": 103.72098629066394,
+ "y": 0.04993158440531095,
+ "z": 0.0
+ },
+ {
+ "x": 102.69001070025007,
+ "y": 0.04987289756558597,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 13,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 102.69012454744524,
+ "y": -1.9501270991941182,
+ "z": 0.0
+ },
+ {
+ "x": 103.72110013785911,
+ "y": -1.9500684123543934,
+ "z": 0.0
+ },
+ {
+ "x": 104.75174843597841,
+ "y": -1.9501784394718344,
+ "z": 0.0
+ },
+ {
+ "x": 105.78272403982137,
+ "y": -1.950288474740116,
+ "z": 0.0
+ },
+ {
+ "x": 106.81369964366434,
+ "y": -1.9503985100083974,
+ "z": 0.0
+ },
+ {
+ "x": 107.8446752475073,
+ "y": -1.9505085452766788,
+ "z": 0.0
+ },
+ {
+ "x": 108.87565085135024,
+ "y": -1.9506185805449603,
+ "z": 0.0
+ },
+ {
+ "x": 109.9066264551932,
+ "y": -1.9507286158132418,
+ "z": 0.0
+ },
+ {
+ "x": 110.93760205903617,
+ "y": -1.9508386510815232,
+ "z": 0.0
+ },
+ {
+ "x": 111.96857766287913,
+ "y": -1.9509486863498047,
+ "z": 0.0
+ },
+ {
+ "x": 112.99955326672209,
+ "y": -1.9510587216180857,
+ "z": 0.0
+ },
+ {
+ "x": 114.03052887056504,
+ "y": -1.9511687568863672,
+ "z": 0.0
+ },
+ {
+ "x": 115.061504474408,
+ "y": -1.9512787921546486,
+ "z": 0.0
+ },
+ {
+ "x": 116.09248007825096,
+ "y": -1.95138882742293,
+ "z": 0.0
+ },
+ {
+ "x": 117.12345568209392,
+ "y": -1.9514988626912115,
+ "z": 0.0
+ },
+ {
+ "x": 118.15443128593688,
+ "y": -1.951608897959493,
+ "z": 0.0
+ },
+ {
+ "x": 119.18540688977984,
+ "y": -1.9517189332277745,
+ "z": 0.0
+ },
+ {
+ "x": 120.21638249362279,
+ "y": -1.951828968496056,
+ "z": 0.0
+ },
+ {
+ "x": 121.24735809746576,
+ "y": -1.951939003764337,
+ "z": 0.0
+ },
+ {
+ "x": 122.27833370130871,
+ "y": -1.9520490390326184,
+ "z": 0.0
+ },
+ {
+ "x": 123.30930930515167,
+ "y": -1.9521590743008999,
+ "z": 0.0
+ },
+ {
+ "x": 124.34028490899463,
+ "y": -1.9522691095691813,
+ "z": 0.0
+ },
+ {
+ "x": 125.3712605128376,
+ "y": -1.9523791448374628,
+ "z": 0.0
+ },
+ {
+ "x": 126.40223611668056,
+ "y": -1.9524891801057442,
+ "z": 0.0
+ },
+ {
+ "x": 127.43321172052352,
+ "y": -1.9525992153740257,
+ "z": 0.0
+ },
+ {
+ "x": 128.46418732436646,
+ "y": -1.9527092506423072,
+ "z": 0.0
+ },
+ {
+ "x": 129.49516292820942,
+ "y": -1.9528192859105882,
+ "z": 0.0
+ },
+ {
+ "x": 130.52613853205239,
+ "y": -1.9529293211788696,
+ "z": 0.0
+ },
+ {
+ "x": 131.55711413589535,
+ "y": -1.953039356447151,
+ "z": 0.0
+ },
+ {
+ "x": 132.5880897397383,
+ "y": -1.9531493917154326,
+ "z": 0.0
+ },
+ {
+ "x": 133.61906534358127,
+ "y": -1.953259426983714,
+ "z": 0.0
+ },
+ {
+ "x": 134.65004094742423,
+ "y": -1.9533694622519955,
+ "z": 0.0
+ },
+ {
+ "x": 135.6810165512672,
+ "y": -1.953479497520277,
+ "z": 0.0
+ },
+ {
+ "x": 136.71199215511015,
+ "y": -1.9535895327885584,
+ "z": 0.0
+ },
+ {
+ "x": 137.7429677589531,
+ "y": -1.9536995680568394,
+ "z": 0.0
+ },
+ {
+ "x": 138.77394336279605,
+ "y": -1.9538096033251209,
+ "z": 0.0
+ },
+ {
+ "x": 139.804918966639,
+ "y": -1.9539196385934023,
+ "z": 0.0
+ },
+ {
+ "x": 140.83589457048197,
+ "y": -1.9540296738616838,
+ "z": 0.0
+ },
+ {
+ "x": 141.86687017432493,
+ "y": -1.9541397091299653,
+ "z": 0.0
+ },
+ {
+ "x": 142.8978457781679,
+ "y": -1.9542497443982467,
+ "z": 0.0
+ },
+ {
+ "x": 143.92882138201085,
+ "y": -1.9543597796665282,
+ "z": 0.0
+ },
+ {
+ "x": 144.9597969858538,
+ "y": -1.9544698149348096,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 14,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 144.9602239029108,
+ "y": 2.045530162282919,
+ "z": 0.0
+ },
+ {
+ "x": 143.92924829906784,
+ "y": 2.0456401975512004,
+ "z": 0.0
+ },
+ {
+ "x": 142.89827269522488,
+ "y": 2.045750232819482,
+ "z": 0.0
+ },
+ {
+ "x": 141.86729709138191,
+ "y": 2.0458602680877633,
+ "z": 0.0
+ },
+ {
+ "x": 140.83632148753895,
+ "y": 2.0459703033560444,
+ "z": 0.0
+ },
+ {
+ "x": 139.805345883696,
+ "y": 2.046080338624326,
+ "z": 0.0
+ },
+ {
+ "x": 138.77437027985303,
+ "y": 2.0461903738926073,
+ "z": 0.0
+ },
+ {
+ "x": 137.7433946760101,
+ "y": 2.0463004091608887,
+ "z": 0.0
+ },
+ {
+ "x": 136.71241907216714,
+ "y": 2.04641044442917,
+ "z": 0.0
+ },
+ {
+ "x": 135.68144346832418,
+ "y": 2.0465204796974517,
+ "z": 0.0
+ },
+ {
+ "x": 134.65046786448121,
+ "y": 2.046630514965733,
+ "z": 0.0
+ },
+ {
+ "x": 133.61949226063825,
+ "y": 2.0467405502340146,
+ "z": 0.0
+ },
+ {
+ "x": 132.5885166567953,
+ "y": 2.0468505855022956,
+ "z": 0.0
+ },
+ {
+ "x": 131.55754105295233,
+ "y": 2.046960620770577,
+ "z": 0.0
+ },
+ {
+ "x": 130.52656544910937,
+ "y": 2.0470706560388585,
+ "z": 0.0
+ },
+ {
+ "x": 129.4955898452664,
+ "y": 2.04718069130714,
+ "z": 0.0
+ },
+ {
+ "x": 128.46461424142345,
+ "y": 2.0472907265754214,
+ "z": 0.0
+ },
+ {
+ "x": 127.4336386375805,
+ "y": 2.047400761843703,
+ "z": 0.0
+ },
+ {
+ "x": 126.40266303373754,
+ "y": 2.0475107971119844,
+ "z": 0.0
+ },
+ {
+ "x": 125.37168742989458,
+ "y": 2.047620832380266,
+ "z": 0.0
+ },
+ {
+ "x": 124.34071182605162,
+ "y": 2.047730867648547,
+ "z": 0.0
+ },
+ {
+ "x": 123.30973622220866,
+ "y": 2.0478409029168283,
+ "z": 0.0
+ },
+ {
+ "x": 122.2787606183657,
+ "y": 2.0479509381851098,
+ "z": 0.0
+ },
+ {
+ "x": 121.24778501452275,
+ "y": 2.048060973453391,
+ "z": 0.0
+ },
+ {
+ "x": 120.21680941067977,
+ "y": 2.0481710087216727,
+ "z": 0.0
+ },
+ {
+ "x": 119.18583380683683,
+ "y": 2.048281043989954,
+ "z": 0.0
+ },
+ {
+ "x": 118.15485820299386,
+ "y": 2.0483910792582356,
+ "z": 0.0
+ },
+ {
+ "x": 117.1238825991509,
+ "y": 2.048501114526517,
+ "z": 0.0
+ },
+ {
+ "x": 116.09290699530794,
+ "y": 2.048611149794798,
+ "z": 0.0
+ },
+ {
+ "x": 115.06193139146498,
+ "y": 2.0487211850630795,
+ "z": 0.0
+ },
+ {
+ "x": 114.03095578762202,
+ "y": 2.048831220331361,
+ "z": 0.0
+ },
+ {
+ "x": 112.99998018377907,
+ "y": 2.0489412555996425,
+ "z": 0.0
+ },
+ {
+ "x": 111.96900457993611,
+ "y": 2.049051290867924,
+ "z": 0.0
+ },
+ {
+ "x": 110.93802897609315,
+ "y": 2.0491613261362054,
+ "z": 0.0
+ },
+ {
+ "x": 109.90705337225019,
+ "y": 2.049271361404487,
+ "z": 0.0
+ },
+ {
+ "x": 108.87607776840723,
+ "y": 2.0493813966727683,
+ "z": 0.0
+ },
+ {
+ "x": 107.84510216456428,
+ "y": 2.0494914319410493,
+ "z": 0.0
+ },
+ {
+ "x": 106.81412656072132,
+ "y": 2.049601467209331,
+ "z": 0.0
+ },
+ {
+ "x": 105.78315095687836,
+ "y": 2.0497115024776122,
+ "z": 0.0
+ },
+ {
+ "x": 104.7521753530354,
+ "y": 2.0498215377458937,
+ "z": 0.0
+ },
+ {
+ "x": 103.72087244346878,
+ "y": 2.049931581165015,
+ "z": 0.0
+ },
+ {
+ "x": 102.6898968530549,
+ "y": 2.04987289432529,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 15,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 11.031303375477442,
+ "y": -3.97999978801159,
+ "z": 0.0
+ },
+ {
+ "x": 12.051452811327586,
+ "y": -3.9796673112888272,
+ "z": 0.0
+ },
+ {
+ "x": 13.07160224717773,
+ "y": -3.979334834566064,
+ "z": 0.0
+ },
+ {
+ "x": 14.091751683027873,
+ "y": -3.979002357843301,
+ "z": 0.0
+ },
+ {
+ "x": 15.111901118878016,
+ "y": -3.9786698811205383,
+ "z": 0.0
+ },
+ {
+ "x": 16.132050554728153,
+ "y": -3.978337404397776,
+ "z": 0.0
+ },
+ {
+ "x": 17.152199990578296,
+ "y": -3.9780049276750122,
+ "z": 0.0
+ },
+ {
+ "x": 18.17234942642844,
+ "y": -3.9776724509522494,
+ "z": 0.0
+ },
+ {
+ "x": 19.192498862278583,
+ "y": -3.977339974229486,
+ "z": 0.0
+ },
+ {
+ "x": 20.212648298128727,
+ "y": -3.9770074975067233,
+ "z": 0.0
+ },
+ {
+ "x": 21.23279773397887,
+ "y": -3.9766750207839605,
+ "z": 0.0
+ },
+ {
+ "x": 22.252947169829014,
+ "y": -3.9763425440611972,
+ "z": 0.0
+ },
+ {
+ "x": 23.273096605679157,
+ "y": -3.9760100673384344,
+ "z": 0.0
+ },
+ {
+ "x": 24.2932460415293,
+ "y": -3.9756775906156716,
+ "z": 0.0
+ },
+ {
+ "x": 25.313395477379444,
+ "y": -3.9753451138929083,
+ "z": 0.0
+ },
+ {
+ "x": 26.333544913229588,
+ "y": -3.9750126371701455,
+ "z": 0.0
+ },
+ {
+ "x": 27.35369434907973,
+ "y": -3.9746801604473823,
+ "z": 0.0
+ },
+ {
+ "x": 28.373843784929875,
+ "y": -3.9743476837246194,
+ "z": 0.0
+ },
+ {
+ "x": 29.39399322078002,
+ "y": -3.9740152070018566,
+ "z": 0.0
+ },
+ {
+ "x": 30.414142656630162,
+ "y": -3.9736827302790934,
+ "z": 0.0
+ },
+ {
+ "x": 31.434292092480312,
+ "y": -3.9733502535563305,
+ "z": 0.0
+ },
+ {
+ "x": 32.454441528330456,
+ "y": -3.9730177768335677,
+ "z": 0.0
+ },
+ {
+ "x": 33.4745909641806,
+ "y": -3.9726853001108045,
+ "z": 0.0
+ },
+ {
+ "x": 34.49474040003074,
+ "y": -3.9723528233880416,
+ "z": 0.0
+ },
+ {
+ "x": 35.514889835880886,
+ "y": -3.972020346665279,
+ "z": 0.0
+ },
+ {
+ "x": 36.53503927173103,
+ "y": -3.9716878699425155,
+ "z": 0.0
+ },
+ {
+ "x": 37.55518870758117,
+ "y": -3.9713553932197527,
+ "z": 0.0
+ },
+ {
+ "x": 38.57533814343132,
+ "y": -3.97102291649699,
+ "z": 0.0
+ },
+ {
+ "x": 39.59548757928146,
+ "y": -3.9706904397742266,
+ "z": 0.0
+ },
+ {
+ "x": 40.615637015131604,
+ "y": -3.970357963051464,
+ "z": 0.0
+ },
+ {
+ "x": 41.63578645098175,
+ "y": -3.970025486328701,
+ "z": 0.0
+ },
+ {
+ "x": 42.65593588683189,
+ "y": -3.9696930096059377,
+ "z": 0.0
+ },
+ {
+ "x": 43.676085322682034,
+ "y": -3.969360532883175,
+ "z": 0.0
+ },
+ {
+ "x": 44.69623475853218,
+ "y": -3.969028056160412,
+ "z": 0.0
+ },
+ {
+ "x": 45.71638419438232,
+ "y": -3.968695579437649,
+ "z": 0.0
+ },
+ {
+ "x": 46.736533630232465,
+ "y": -3.968363102714886,
+ "z": 0.0
+ },
+ {
+ "x": 47.75668306608261,
+ "y": -3.968030625992123,
+ "z": 0.0
+ },
+ {
+ "x": 48.77683250193275,
+ "y": -3.96769814926936,
+ "z": 0.0
+ },
+ {
+ "x": 49.796981937782895,
+ "y": -3.967365672546597,
+ "z": 0.0
+ },
+ {
+ "x": 50.81713137363304,
+ "y": -3.967033195823834,
+ "z": 0.0
+ },
+ {
+ "x": 51.83728080948318,
+ "y": -3.966700719101071,
+ "z": 0.0
+ },
+ {
+ "x": 52.857430245333326,
+ "y": -3.966368242378308,
+ "z": 0.0
+ },
+ {
+ "x": 53.87757968118347,
+ "y": -3.966035765655545,
+ "z": 0.0
+ },
+ {
+ "x": 54.89772911703361,
+ "y": -3.965703288932782,
+ "z": 0.0
+ },
+ {
+ "x": 55.91787855288376,
+ "y": -3.9653708122100193,
+ "z": 0.0
+ },
+ {
+ "x": 56.9380279887339,
+ "y": -3.965038335487256,
+ "z": 0.0
+ },
+ {
+ "x": 57.95817742458404,
+ "y": -3.964705858764493,
+ "z": 0.0
+ },
+ {
+ "x": 58.97832686043419,
+ "y": -3.9643733820417304,
+ "z": 0.0
+ },
+ {
+ "x": 59.99847629628433,
+ "y": -3.964040905318967,
+ "z": 0.0
+ },
+ {
+ "x": 61.018625732134474,
+ "y": -3.9637084285962043,
+ "z": 0.0
+ },
+ {
+ "x": 62.03877516798462,
+ "y": -3.9633759518734415,
+ "z": 0.0
+ },
+ {
+ "x": 63.05892460383476,
+ "y": -3.9630434751506782,
+ "z": 0.0
+ },
+ {
+ "x": 64.07907403968491,
+ "y": -3.9627109984279154,
+ "z": 0.0
+ },
+ {
+ "x": 65.09922347553506,
+ "y": -3.9623785217051526,
+ "z": 0.0
+ },
+ {
+ "x": 66.1193729113852,
+ "y": -3.9620460449823893,
+ "z": 0.0
+ },
+ {
+ "x": 67.13952234723534,
+ "y": -3.9617135682596265,
+ "z": 0.0
+ },
+ {
+ "x": 68.15967178308549,
+ "y": -3.9613810915368637,
+ "z": 0.0
+ },
+ {
+ "x": 69.17982121893563,
+ "y": -3.9610486148141004,
+ "z": 0.0
+ },
+ {
+ "x": 70.19997065478577,
+ "y": -3.9607161380913376,
+ "z": 0.0
+ },
+ {
+ "x": 71.22012009063592,
+ "y": -3.9603836613685743,
+ "z": 0.0
+ },
+ {
+ "x": 72.24026952648606,
+ "y": -3.9600511846458115,
+ "z": 0.0
+ },
+ {
+ "x": 73.2604189623362,
+ "y": -3.9597187079230487,
+ "z": 0.0
+ },
+ {
+ "x": 74.28056839818635,
+ "y": -3.9593862312002854,
+ "z": 0.0
+ },
+ {
+ "x": 75.30071783403649,
+ "y": -3.9590537544775226,
+ "z": 0.0
+ },
+ {
+ "x": 76.32086726988663,
+ "y": -3.95872127775476,
+ "z": 0.0
+ },
+ {
+ "x": 77.34101670573678,
+ "y": -3.9583888010319965,
+ "z": 0.0
+ },
+ {
+ "x": 78.36116614158692,
+ "y": -3.9580563243092337,
+ "z": 0.0
+ },
+ {
+ "x": 79.38131557743706,
+ "y": -3.957723847586471,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 16,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 79.3787082989861,
+ "y": 4.042275727544709,
+ "z": 0.0
+ },
+ {
+ "x": 78.35855886313595,
+ "y": 4.041943250821946,
+ "z": 0.0
+ },
+ {
+ "x": 77.33840942728581,
+ "y": 4.041610774099183,
+ "z": 0.0
+ },
+ {
+ "x": 76.31825999143567,
+ "y": 4.0412782973764205,
+ "z": 0.0
+ },
+ {
+ "x": 75.29811055558552,
+ "y": 4.040945820653657,
+ "z": 0.0
+ },
+ {
+ "x": 74.27796111973538,
+ "y": 4.040613343930894,
+ "z": 0.0
+ },
+ {
+ "x": 73.25781168388524,
+ "y": 4.040280867208131,
+ "z": 0.0
+ },
+ {
+ "x": 72.2376622480351,
+ "y": 4.039948390485368,
+ "z": 0.0
+ },
+ {
+ "x": 71.21751281218495,
+ "y": 4.0396159137626055,
+ "z": 0.0
+ },
+ {
+ "x": 70.1973633763348,
+ "y": 4.039283437039843,
+ "z": 0.0
+ },
+ {
+ "x": 69.17721394048466,
+ "y": 4.038950960317079,
+ "z": 0.0
+ },
+ {
+ "x": 68.15706450463452,
+ "y": 4.038618483594316,
+ "z": 0.0
+ },
+ {
+ "x": 67.13691506878438,
+ "y": 4.038286006871553,
+ "z": 0.0
+ },
+ {
+ "x": 66.11676563293423,
+ "y": 4.0379535301487905,
+ "z": 0.0
+ },
+ {
+ "x": 65.09661619708409,
+ "y": 4.037621053426028,
+ "z": 0.0
+ },
+ {
+ "x": 64.07646676123395,
+ "y": 4.037288576703265,
+ "z": 0.0
+ },
+ {
+ "x": 63.05631732538381,
+ "y": 4.036956099980501,
+ "z": 0.0
+ },
+ {
+ "x": 62.036167889533665,
+ "y": 4.036623623257738,
+ "z": 0.0
+ },
+ {
+ "x": 61.01601845368352,
+ "y": 4.036291146534976,
+ "z": 0.0
+ },
+ {
+ "x": 59.99586901783338,
+ "y": 4.035958669812213,
+ "z": 0.0
+ },
+ {
+ "x": 58.975719581983235,
+ "y": 4.03562619308945,
+ "z": 0.0
+ },
+ {
+ "x": 57.95557014613309,
+ "y": 4.035293716366686,
+ "z": 0.0
+ },
+ {
+ "x": 56.93542071028295,
+ "y": 4.034961239643923,
+ "z": 0.0
+ },
+ {
+ "x": 55.915271274432804,
+ "y": 4.034628762921161,
+ "z": 0.0
+ },
+ {
+ "x": 54.89512183858266,
+ "y": 4.034296286198398,
+ "z": 0.0
+ },
+ {
+ "x": 53.87497240273252,
+ "y": 4.033963809475635,
+ "z": 0.0
+ },
+ {
+ "x": 52.854822966882374,
+ "y": 4.033631332752872,
+ "z": 0.0
+ },
+ {
+ "x": 51.83467353103223,
+ "y": 4.033298856030108,
+ "z": 0.0
+ },
+ {
+ "x": 50.81452409518209,
+ "y": 4.032966379307346,
+ "z": 0.0
+ },
+ {
+ "x": 49.79437465933194,
+ "y": 4.032633902584583,
+ "z": 0.0
+ },
+ {
+ "x": 48.7742252234818,
+ "y": 4.03230142586182,
+ "z": 0.0
+ },
+ {
+ "x": 47.754075787631656,
+ "y": 4.031968949139057,
+ "z": 0.0
+ },
+ {
+ "x": 46.73392635178151,
+ "y": 4.031636472416294,
+ "z": 0.0
+ },
+ {
+ "x": 45.71377691593137,
+ "y": 4.031303995693531,
+ "z": 0.0
+ },
+ {
+ "x": 44.693627480081226,
+ "y": 4.030971518970768,
+ "z": 0.0
+ },
+ {
+ "x": 43.67347804423108,
+ "y": 4.030639042248005,
+ "z": 0.0
+ },
+ {
+ "x": 42.65332860838094,
+ "y": 4.030306565525242,
+ "z": 0.0
+ },
+ {
+ "x": 41.633179172530795,
+ "y": 4.029974088802479,
+ "z": 0.0
+ },
+ {
+ "x": 40.61302973668065,
+ "y": 4.0296416120797165,
+ "z": 0.0
+ },
+ {
+ "x": 39.59288030083051,
+ "y": 4.029309135356953,
+ "z": 0.0
+ },
+ {
+ "x": 38.572730864980365,
+ "y": 4.02897665863419,
+ "z": 0.0
+ },
+ {
+ "x": 37.55258142913022,
+ "y": 4.028644181911427,
+ "z": 0.0
+ },
+ {
+ "x": 36.53243199328008,
+ "y": 4.028311705188664,
+ "z": 0.0
+ },
+ {
+ "x": 35.512282557429934,
+ "y": 4.0279792284659015,
+ "z": 0.0
+ },
+ {
+ "x": 34.49213312157979,
+ "y": 4.027646751743138,
+ "z": 0.0
+ },
+ {
+ "x": 33.47198368572965,
+ "y": 4.027314275020375,
+ "z": 0.0
+ },
+ {
+ "x": 32.451834249879504,
+ "y": 4.026981798297612,
+ "z": 0.0
+ },
+ {
+ "x": 31.43168481402936,
+ "y": 4.026649321574849,
+ "z": 0.0
+ },
+ {
+ "x": 30.41153537817921,
+ "y": 4.0263168448520865,
+ "z": 0.0
+ },
+ {
+ "x": 29.391385942329066,
+ "y": 4.025984368129324,
+ "z": 0.0
+ },
+ {
+ "x": 28.371236506478922,
+ "y": 4.02565189140656,
+ "z": 0.0
+ },
+ {
+ "x": 27.35108707062878,
+ "y": 4.025319414683797,
+ "z": 0.0
+ },
+ {
+ "x": 26.330937634778635,
+ "y": 4.024986937961034,
+ "z": 0.0
+ },
+ {
+ "x": 25.310788198928492,
+ "y": 4.0246544612382715,
+ "z": 0.0
+ },
+ {
+ "x": 24.29063876307835,
+ "y": 4.024321984515509,
+ "z": 0.0
+ },
+ {
+ "x": 23.270489327228205,
+ "y": 4.023989507792746,
+ "z": 0.0
+ },
+ {
+ "x": 22.25033989137806,
+ "y": 4.023657031069982,
+ "z": 0.0
+ },
+ {
+ "x": 21.230190455527918,
+ "y": 4.023324554347219,
+ "z": 0.0
+ },
+ {
+ "x": 20.210041019677774,
+ "y": 4.0229920776244565,
+ "z": 0.0
+ },
+ {
+ "x": 19.18989158382763,
+ "y": 4.022659600901694,
+ "z": 0.0
+ },
+ {
+ "x": 18.169742147977487,
+ "y": 4.022327124178931,
+ "z": 0.0
+ },
+ {
+ "x": 17.149592712127344,
+ "y": 4.021994647456168,
+ "z": 0.0
+ },
+ {
+ "x": 16.1294432762772,
+ "y": 4.021662170733405,
+ "z": 0.0
+ },
+ {
+ "x": 15.109293840427064,
+ "y": 4.0213296940106416,
+ "z": 0.0
+ },
+ {
+ "x": 14.08914440457692,
+ "y": 4.020997217287879,
+ "z": 0.0
+ },
+ {
+ "x": 13.068994968726777,
+ "y": 4.020664740565116,
+ "z": 0.0
+ },
+ {
+ "x": 12.048845532876634,
+ "y": 4.020332263842353,
+ "z": 0.0
+ },
+ {
+ "x": 11.02869609702649,
+ "y": 4.019999787119589,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 17,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 79.38001193821158,
+ "y": 0.04227593997911919,
+ "z": 0.0
+ },
+ {
+ "x": 78.35986250236144,
+ "y": 0.041943463256356214,
+ "z": 0.0
+ },
+ {
+ "x": 77.3397130665113,
+ "y": 0.041610986533593235,
+ "z": 0.0
+ },
+ {
+ "x": 76.31956363066115,
+ "y": 0.04127850981083026,
+ "z": 0.0
+ },
+ {
+ "x": 75.299414194811,
+ "y": 0.04094603308806729,
+ "z": 0.0
+ },
+ {
+ "x": 74.27926475896086,
+ "y": 0.04061355636530431,
+ "z": 0.0
+ },
+ {
+ "x": 73.25911532311072,
+ "y": 0.04028107964254134,
+ "z": 0.0
+ },
+ {
+ "x": 72.23896588726058,
+ "y": 0.039948602919778364,
+ "z": 0.0
+ },
+ {
+ "x": 71.21881645141043,
+ "y": 0.039616126197015385,
+ "z": 0.0
+ },
+ {
+ "x": 70.19866701556029,
+ "y": 0.03928364947425241,
+ "z": 0.0
+ },
+ {
+ "x": 69.17851757971015,
+ "y": 0.03895117275148943,
+ "z": 0.0
+ },
+ {
+ "x": 68.15836814386,
+ "y": 0.03861869602872646,
+ "z": 0.0
+ },
+ {
+ "x": 67.13821870800986,
+ "y": 0.03828621930596349,
+ "z": 0.0
+ },
+ {
+ "x": 66.11806927215972,
+ "y": 0.037953742583200514,
+ "z": 0.0
+ },
+ {
+ "x": 65.09791983630957,
+ "y": 0.037621265860437535,
+ "z": 0.0
+ },
+ {
+ "x": 64.07777040045943,
+ "y": 0.03728878913767456,
+ "z": 0.0
+ },
+ {
+ "x": 63.057620964609285,
+ "y": 0.03695631241491158,
+ "z": 0.0
+ },
+ {
+ "x": 62.03747152875914,
+ "y": 0.03662383569214861,
+ "z": 0.0
+ },
+ {
+ "x": 61.017322092909,
+ "y": 0.03629135896938564,
+ "z": 0.0
+ },
+ {
+ "x": 59.997172657058854,
+ "y": 0.03595888224662266,
+ "z": 0.0
+ },
+ {
+ "x": 58.97702322120871,
+ "y": 0.035626405523859685,
+ "z": 0.0
+ },
+ {
+ "x": 57.95687378535857,
+ "y": 0.03529392880109671,
+ "z": 0.0
+ },
+ {
+ "x": 56.936724349508424,
+ "y": 0.03496145207833373,
+ "z": 0.0
+ },
+ {
+ "x": 55.91657491365828,
+ "y": 0.03462897535557076,
+ "z": 0.0
+ },
+ {
+ "x": 54.89642547780814,
+ "y": 0.03429649863280779,
+ "z": 0.0
+ },
+ {
+ "x": 53.87627604195799,
+ "y": 0.03396402191004481,
+ "z": 0.0
+ },
+ {
+ "x": 52.85612660610785,
+ "y": 0.033631545187281835,
+ "z": 0.0
+ },
+ {
+ "x": 51.835977170257706,
+ "y": 0.03329906846451886,
+ "z": 0.0
+ },
+ {
+ "x": 50.81582773440756,
+ "y": 0.03296659174175588,
+ "z": 0.0
+ },
+ {
+ "x": 49.79567829855742,
+ "y": 0.03263411501899291,
+ "z": 0.0
+ },
+ {
+ "x": 48.775528862707276,
+ "y": 0.03230163829622994,
+ "z": 0.0
+ },
+ {
+ "x": 47.75537942685713,
+ "y": 0.03196916157346696,
+ "z": 0.0
+ },
+ {
+ "x": 46.73522999100699,
+ "y": 0.031636684850703985,
+ "z": 0.0
+ },
+ {
+ "x": 45.715080555156845,
+ "y": 0.031304208127941005,
+ "z": 0.0
+ },
+ {
+ "x": 44.6949311193067,
+ "y": 0.030971731405178032,
+ "z": 0.0
+ },
+ {
+ "x": 43.67478168345656,
+ "y": 0.03063925468241506,
+ "z": 0.0
+ },
+ {
+ "x": 42.654632247606415,
+ "y": 0.030306777959652087,
+ "z": 0.0
+ },
+ {
+ "x": 41.63448281175627,
+ "y": 0.029974301236889107,
+ "z": 0.0
+ },
+ {
+ "x": 40.61433337590613,
+ "y": 0.029641824514126138,
+ "z": 0.0
+ },
+ {
+ "x": 39.594183940055984,
+ "y": 0.029309347791363162,
+ "z": 0.0
+ },
+ {
+ "x": 38.57403450420584,
+ "y": 0.028976871068600186,
+ "z": 0.0
+ },
+ {
+ "x": 37.5538850683557,
+ "y": 0.028644394345837213,
+ "z": 0.0
+ },
+ {
+ "x": 36.533735632505554,
+ "y": 0.028311917623074237,
+ "z": 0.0
+ },
+ {
+ "x": 35.51358619665541,
+ "y": 0.027979440900311257,
+ "z": 0.0
+ },
+ {
+ "x": 34.49343676080527,
+ "y": 0.027646964177548285,
+ "z": 0.0
+ },
+ {
+ "x": 33.47328732495512,
+ "y": 0.02731448745478531,
+ "z": 0.0
+ },
+ {
+ "x": 32.45313788910498,
+ "y": 0.026982010732022332,
+ "z": 0.0
+ },
+ {
+ "x": 31.432988453254836,
+ "y": 0.02664953400925936,
+ "z": 0.0
+ },
+ {
+ "x": 30.412839017404686,
+ "y": 0.02631705728649638,
+ "z": 0.0
+ },
+ {
+ "x": 29.392689581554542,
+ "y": 0.025984580563733407,
+ "z": 0.0
+ },
+ {
+ "x": 28.3725401457044,
+ "y": 0.02565210384097043,
+ "z": 0.0
+ },
+ {
+ "x": 27.352390709854255,
+ "y": 0.02531962711820746,
+ "z": 0.0
+ },
+ {
+ "x": 26.33224127400411,
+ "y": 0.024987150395444482,
+ "z": 0.0
+ },
+ {
+ "x": 25.312091838153968,
+ "y": 0.024654673672681506,
+ "z": 0.0
+ },
+ {
+ "x": 24.291942402303825,
+ "y": 0.024322196949918534,
+ "z": 0.0
+ },
+ {
+ "x": 23.27179296645368,
+ "y": 0.023989720227155554,
+ "z": 0.0
+ },
+ {
+ "x": 22.251643530603538,
+ "y": 0.023657243504392578,
+ "z": 0.0
+ },
+ {
+ "x": 21.231494094753394,
+ "y": 0.023324766781629605,
+ "z": 0.0
+ },
+ {
+ "x": 20.21134465890325,
+ "y": 0.02299229005886663,
+ "z": 0.0
+ },
+ {
+ "x": 19.191195223053107,
+ "y": 0.022659813336103656,
+ "z": 0.0
+ },
+ {
+ "x": 18.171045787202964,
+ "y": 0.02232733661334068,
+ "z": 0.0
+ },
+ {
+ "x": 17.15089635135282,
+ "y": 0.021994859890577707,
+ "z": 0.0
+ },
+ {
+ "x": 16.130746915502677,
+ "y": 0.02166238316781473,
+ "z": 0.0
+ },
+ {
+ "x": 15.11059747965254,
+ "y": 0.021329906445051755,
+ "z": 0.0
+ },
+ {
+ "x": 14.090448043802397,
+ "y": 0.020997429722288782,
+ "z": 0.0
+ },
+ {
+ "x": 13.070298607952253,
+ "y": 0.020664952999525806,
+ "z": 0.0
+ },
+ {
+ "x": 12.05014917210211,
+ "y": 0.02033247627676283,
+ "z": 0.0
+ },
+ {
+ "x": 11.029999736251966,
+ "y": 0.019999999553999857,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 18,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 11.030651555864704,
+ "y": -1.979999894228795,
+ "z": 0.0
+ },
+ {
+ "x": 12.050800991714848,
+ "y": -1.9796674175060323,
+ "z": 0.0
+ },
+ {
+ "x": 13.070950427564991,
+ "y": -1.979334940783269,
+ "z": 0.0
+ },
+ {
+ "x": 14.091099863415135,
+ "y": -1.9790024640605062,
+ "z": 0.0
+ },
+ {
+ "x": 15.111249299265278,
+ "y": -1.9786699873377434,
+ "z": 0.0
+ },
+ {
+ "x": 16.131398735115415,
+ "y": -1.9783375106149805,
+ "z": 0.0
+ },
+ {
+ "x": 17.151548170965558,
+ "y": -1.9780050338922173,
+ "z": 0.0
+ },
+ {
+ "x": 18.1716976068157,
+ "y": -1.9776725571694544,
+ "z": 0.0
+ },
+ {
+ "x": 19.191847042665845,
+ "y": -1.9773400804466912,
+ "z": 0.0
+ },
+ {
+ "x": 20.21199647851599,
+ "y": -1.9770076037239284,
+ "z": 0.0
+ },
+ {
+ "x": 21.232145914366132,
+ "y": -1.9766751270011655,
+ "z": 0.0
+ },
+ {
+ "x": 22.252295350216276,
+ "y": -1.9763426502784023,
+ "z": 0.0
+ },
+ {
+ "x": 23.27244478606642,
+ "y": -1.9760101735556395,
+ "z": 0.0
+ },
+ {
+ "x": 24.292594221916563,
+ "y": -1.9756776968328766,
+ "z": 0.0
+ },
+ {
+ "x": 25.312743657766706,
+ "y": -1.9753452201101134,
+ "z": 0.0
+ },
+ {
+ "x": 26.33289309361685,
+ "y": -1.9750127433873506,
+ "z": 0.0
+ },
+ {
+ "x": 27.353042529466993,
+ "y": -1.9746802666645873,
+ "z": 0.0
+ },
+ {
+ "x": 28.373191965317137,
+ "y": -1.9743477899418245,
+ "z": 0.0
+ },
+ {
+ "x": 29.39334140116728,
+ "y": -1.9740153132190617,
+ "z": 0.0
+ },
+ {
+ "x": 30.413490837017424,
+ "y": -1.9736828364962984,
+ "z": 0.0
+ },
+ {
+ "x": 31.433640272867574,
+ "y": -1.9733503597735356,
+ "z": 0.0
+ },
+ {
+ "x": 32.45378970871772,
+ "y": -1.9730178830507727,
+ "z": 0.0
+ },
+ {
+ "x": 33.473939144567865,
+ "y": -1.9726854063280095,
+ "z": 0.0
+ },
+ {
+ "x": 34.49408858041801,
+ "y": -1.9723529296052467,
+ "z": 0.0
+ },
+ {
+ "x": 35.51423801626815,
+ "y": -1.9720204528824838,
+ "z": 0.0
+ },
+ {
+ "x": 36.534387452118295,
+ "y": -1.9716879761597206,
+ "z": 0.0
+ },
+ {
+ "x": 37.55453688796844,
+ "y": -1.9713554994369578,
+ "z": 0.0
+ },
+ {
+ "x": 38.57468632381858,
+ "y": -1.971023022714195,
+ "z": 0.0
+ },
+ {
+ "x": 39.594835759668726,
+ "y": -1.9706905459914317,
+ "z": 0.0
+ },
+ {
+ "x": 40.61498519551887,
+ "y": -1.9703580692686689,
+ "z": 0.0
+ },
+ {
+ "x": 41.63513463136901,
+ "y": -1.970025592545906,
+ "z": 0.0
+ },
+ {
+ "x": 42.655284067219156,
+ "y": -1.9696931158231428,
+ "z": 0.0
+ },
+ {
+ "x": 43.6754335030693,
+ "y": -1.96936063910038,
+ "z": 0.0
+ },
+ {
+ "x": 44.69558293891944,
+ "y": -1.9690281623776171,
+ "z": 0.0
+ },
+ {
+ "x": 45.71573237476959,
+ "y": -1.9686956856548539,
+ "z": 0.0
+ },
+ {
+ "x": 46.73588181061973,
+ "y": -1.968363208932091,
+ "z": 0.0
+ },
+ {
+ "x": 47.756031246469874,
+ "y": -1.9680307322093282,
+ "z": 0.0
+ },
+ {
+ "x": 48.77618068232002,
+ "y": -1.967698255486565,
+ "z": 0.0
+ },
+ {
+ "x": 49.79633011817016,
+ "y": -1.9673657787638021,
+ "z": 0.0
+ },
+ {
+ "x": 50.816479554020304,
+ "y": -1.9670333020410389,
+ "z": 0.0
+ },
+ {
+ "x": 51.83662898987045,
+ "y": -1.966700825318276,
+ "z": 0.0
+ },
+ {
+ "x": 52.85677842572059,
+ "y": -1.9663683485955132,
+ "z": 0.0
+ },
+ {
+ "x": 53.876927861570735,
+ "y": -1.96603587187275,
+ "z": 0.0
+ },
+ {
+ "x": 54.89707729742088,
+ "y": -1.9657033951499872,
+ "z": 0.0
+ },
+ {
+ "x": 55.91722673327102,
+ "y": -1.9653709184272243,
+ "z": 0.0
+ },
+ {
+ "x": 56.937376169121166,
+ "y": -1.965038441704461,
+ "z": 0.0
+ },
+ {
+ "x": 57.95752560497131,
+ "y": -1.9647059649816982,
+ "z": 0.0
+ },
+ {
+ "x": 58.97767504082145,
+ "y": -1.9643734882589354,
+ "z": 0.0
+ },
+ {
+ "x": 59.997824476671596,
+ "y": -1.9640410115361722,
+ "z": 0.0
+ },
+ {
+ "x": 61.01797391252174,
+ "y": -1.9637085348134093,
+ "z": 0.0
+ },
+ {
+ "x": 62.03812334837188,
+ "y": -1.9633760580906465,
+ "z": 0.0
+ },
+ {
+ "x": 63.05827278422203,
+ "y": -1.9630435813678833,
+ "z": 0.0
+ },
+ {
+ "x": 64.07842222007217,
+ "y": -1.9627111046451204,
+ "z": 0.0
+ },
+ {
+ "x": 65.09857165592231,
+ "y": -1.9623786279223576,
+ "z": 0.0
+ },
+ {
+ "x": 66.11872109177246,
+ "y": -1.9620461511995944,
+ "z": 0.0
+ },
+ {
+ "x": 67.1388705276226,
+ "y": -1.9617136744768315,
+ "z": 0.0
+ },
+ {
+ "x": 68.15901996347274,
+ "y": -1.9613811977540687,
+ "z": 0.0
+ },
+ {
+ "x": 69.17916939932289,
+ "y": -1.9610487210313055,
+ "z": 0.0
+ },
+ {
+ "x": 70.19931883517303,
+ "y": -1.9607162443085426,
+ "z": 0.0
+ },
+ {
+ "x": 71.21946827102317,
+ "y": -1.9603837675857794,
+ "z": 0.0
+ },
+ {
+ "x": 72.23961770687332,
+ "y": -1.9600512908630165,
+ "z": 0.0
+ },
+ {
+ "x": 73.25976714272346,
+ "y": -1.9597188141402537,
+ "z": 0.0
+ },
+ {
+ "x": 74.2799165785736,
+ "y": -1.9593863374174905,
+ "z": 0.0
+ },
+ {
+ "x": 75.30006601442375,
+ "y": -1.9590538606947276,
+ "z": 0.0
+ },
+ {
+ "x": 76.32021545027389,
+ "y": -1.9587213839719648,
+ "z": 0.0
+ },
+ {
+ "x": 77.34036488612404,
+ "y": -1.9583889072492016,
+ "z": 0.0
+ },
+ {
+ "x": 78.36051432197418,
+ "y": -1.9580564305264387,
+ "z": 0.0
+ },
+ {
+ "x": 79.38066375782432,
+ "y": -1.957723953803676,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 19,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 79.37936011859884,
+ "y": 2.0422758337619142,
+ "z": 0.0
+ },
+ {
+ "x": 78.3592106827487,
+ "y": 2.041943357039151,
+ "z": 0.0
+ },
+ {
+ "x": 77.33906124689855,
+ "y": 2.041610880316388,
+ "z": 0.0
+ },
+ {
+ "x": 76.31891181104841,
+ "y": 2.0412784035936253,
+ "z": 0.0
+ },
+ {
+ "x": 75.29876237519827,
+ "y": 2.040945926870862,
+ "z": 0.0
+ },
+ {
+ "x": 74.27861293934812,
+ "y": 2.0406134501480993,
+ "z": 0.0
+ },
+ {
+ "x": 73.25846350349798,
+ "y": 2.0402809734253364,
+ "z": 0.0
+ },
+ {
+ "x": 72.23831406764783,
+ "y": 2.039948496702573,
+ "z": 0.0
+ },
+ {
+ "x": 71.21816463179769,
+ "y": 2.0396160199798103,
+ "z": 0.0
+ },
+ {
+ "x": 70.19801519594755,
+ "y": 2.0392835432570475,
+ "z": 0.0
+ },
+ {
+ "x": 69.1778657600974,
+ "y": 2.0389510665342843,
+ "z": 0.0
+ },
+ {
+ "x": 68.15771632424726,
+ "y": 2.0386185898115214,
+ "z": 0.0
+ },
+ {
+ "x": 67.13756688839712,
+ "y": 2.0382861130887586,
+ "z": 0.0
+ },
+ {
+ "x": 66.11741745254697,
+ "y": 2.0379536363659954,
+ "z": 0.0
+ },
+ {
+ "x": 65.09726801669683,
+ "y": 2.0376211596432325,
+ "z": 0.0
+ },
+ {
+ "x": 64.07711858084669,
+ "y": 2.0372886829204697,
+ "z": 0.0
+ },
+ {
+ "x": 63.05696914499654,
+ "y": 2.0369562061977065,
+ "z": 0.0
+ },
+ {
+ "x": 62.0368197091464,
+ "y": 2.0366237294749436,
+ "z": 0.0
+ },
+ {
+ "x": 61.016670273296256,
+ "y": 2.036291252752181,
+ "z": 0.0
+ },
+ {
+ "x": 59.99652083744611,
+ "y": 2.0359587760294175,
+ "z": 0.0
+ },
+ {
+ "x": 58.97637140159597,
+ "y": 2.0356262993066547,
+ "z": 0.0
+ },
+ {
+ "x": 57.956221965745826,
+ "y": 2.0352938225838915,
+ "z": 0.0
+ },
+ {
+ "x": 56.93607252989568,
+ "y": 2.0349613458611286,
+ "z": 0.0
+ },
+ {
+ "x": 55.91592309404554,
+ "y": 2.034628869138366,
+ "z": 0.0
+ },
+ {
+ "x": 54.895773658195395,
+ "y": 2.0342963924156026,
+ "z": 0.0
+ },
+ {
+ "x": 53.87562422234525,
+ "y": 2.0339639156928397,
+ "z": 0.0
+ },
+ {
+ "x": 52.85547478649511,
+ "y": 2.033631438970077,
+ "z": 0.0
+ },
+ {
+ "x": 51.835325350644965,
+ "y": 2.0332989622473137,
+ "z": 0.0
+ },
+ {
+ "x": 50.81517591479482,
+ "y": 2.032966485524551,
+ "z": 0.0
+ },
+ {
+ "x": 49.79502647894468,
+ "y": 2.032634008801788,
+ "z": 0.0
+ },
+ {
+ "x": 48.774877043094534,
+ "y": 2.0323015320790248,
+ "z": 0.0
+ },
+ {
+ "x": 47.75472760724439,
+ "y": 2.031969055356262,
+ "z": 0.0
+ },
+ {
+ "x": 46.73457817139425,
+ "y": 2.031636578633499,
+ "z": 0.0
+ },
+ {
+ "x": 45.714428735544104,
+ "y": 2.031304101910736,
+ "z": 0.0
+ },
+ {
+ "x": 44.69427929969396,
+ "y": 2.030971625187973,
+ "z": 0.0
+ },
+ {
+ "x": 43.67412986384382,
+ "y": 2.03063914846521,
+ "z": 0.0
+ },
+ {
+ "x": 42.65398042799367,
+ "y": 2.030306671742447,
+ "z": 0.0
+ },
+ {
+ "x": 41.63383099214353,
+ "y": 2.029974195019684,
+ "z": 0.0
+ },
+ {
+ "x": 40.613681556293386,
+ "y": 2.0296417182969213,
+ "z": 0.0
+ },
+ {
+ "x": 39.59353212044324,
+ "y": 2.029309241574158,
+ "z": 0.0
+ },
+ {
+ "x": 38.5733826845931,
+ "y": 2.028976764851395,
+ "z": 0.0
+ },
+ {
+ "x": 37.553233248742956,
+ "y": 2.0286442881286324,
+ "z": 0.0
+ },
+ {
+ "x": 36.53308381289281,
+ "y": 2.028311811405869,
+ "z": 0.0
+ },
+ {
+ "x": 35.51293437704267,
+ "y": 2.0279793346831063,
+ "z": 0.0
+ },
+ {
+ "x": 34.492784941192525,
+ "y": 2.027646857960343,
+ "z": 0.0
+ },
+ {
+ "x": 33.47263550534238,
+ "y": 2.0273143812375802,
+ "z": 0.0
+ },
+ {
+ "x": 32.45248606949224,
+ "y": 2.0269819045148174,
+ "z": 0.0
+ },
+ {
+ "x": 31.432336633642098,
+ "y": 2.026649427792054,
+ "z": 0.0
+ },
+ {
+ "x": 30.412187197791948,
+ "y": 2.0263169510692913,
+ "z": 0.0
+ },
+ {
+ "x": 29.392037761941804,
+ "y": 2.0259844743465285,
+ "z": 0.0
+ },
+ {
+ "x": 28.37188832609166,
+ "y": 2.0256519976237652,
+ "z": 0.0
+ },
+ {
+ "x": 27.351738890241517,
+ "y": 2.0253195209010024,
+ "z": 0.0
+ },
+ {
+ "x": 26.331589454391374,
+ "y": 2.0249870441782396,
+ "z": 0.0
+ },
+ {
+ "x": 25.31144001854123,
+ "y": 2.0246545674554763,
+ "z": 0.0
+ },
+ {
+ "x": 24.291290582691087,
+ "y": 2.0243220907327135,
+ "z": 0.0
+ },
+ {
+ "x": 23.271141146840943,
+ "y": 2.0239896140099507,
+ "z": 0.0
+ },
+ {
+ "x": 22.2509917109908,
+ "y": 2.0236571372871874,
+ "z": 0.0
+ },
+ {
+ "x": 21.230842275140656,
+ "y": 2.0233246605644246,
+ "z": 0.0
+ },
+ {
+ "x": 20.210692839290513,
+ "y": 2.022992183841662,
+ "z": 0.0
+ },
+ {
+ "x": 19.19054340344037,
+ "y": 2.0226597071188985,
+ "z": 0.0
+ },
+ {
+ "x": 18.170393967590226,
+ "y": 2.0223272303961357,
+ "z": 0.0
+ },
+ {
+ "x": 17.150244531740082,
+ "y": 2.021994753673373,
+ "z": 0.0
+ },
+ {
+ "x": 16.13009509588994,
+ "y": 2.02166227695061,
+ "z": 0.0
+ },
+ {
+ "x": 15.109945660039802,
+ "y": 2.021329800227847,
+ "z": 0.0
+ },
+ {
+ "x": 14.089796224189659,
+ "y": 2.0209973235050835,
+ "z": 0.0
+ },
+ {
+ "x": 13.069646788339515,
+ "y": 2.0206648467823207,
+ "z": 0.0
+ },
+ {
+ "x": 12.049497352489372,
+ "y": 2.020332370059558,
+ "z": 0.0
+ },
+ {
+ "x": 11.029347916639228,
+ "y": 2.0199998933367946,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 20,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 325.6417606480552,
+ "y": -127.51508546382411,
+ "z": 0.0
+ },
+ {
+ "x": 324.6362898963956,
+ "y": -127.5146362258154,
+ "z": 0.0
+ },
+ {
+ "x": 323.63081914473594,
+ "y": -127.51418698780671,
+ "z": 0.0
+ },
+ {
+ "x": 322.6253483930765,
+ "y": -127.513737749798,
+ "z": 0.0
+ },
+ {
+ "x": 321.6198776414169,
+ "y": -127.51328851178928,
+ "z": 0.0
+ },
+ {
+ "x": 320.61440688975733,
+ "y": -127.51283927378057,
+ "z": 0.0
+ },
+ {
+ "x": 319.60893613809776,
+ "y": -127.51239003577186,
+ "z": 0.0
+ },
+ {
+ "x": 318.6034653864382,
+ "y": -127.51194079776315,
+ "z": 0.0
+ },
+ {
+ "x": 317.5979946347786,
+ "y": -127.51149155975443,
+ "z": 0.0
+ },
+ {
+ "x": 316.592523883119,
+ "y": -127.51104232174572,
+ "z": 0.0
+ },
+ {
+ "x": 315.5870531314593,
+ "y": -127.51059308373704,
+ "z": 0.0
+ },
+ {
+ "x": 314.58158237979984,
+ "y": -127.51014384572832,
+ "z": 0.0
+ },
+ {
+ "x": 313.57611162814027,
+ "y": -127.50969460771961,
+ "z": 0.0
+ },
+ {
+ "x": 312.5706408764807,
+ "y": -127.5092453697109,
+ "z": 0.0
+ },
+ {
+ "x": 311.5651701248211,
+ "y": -127.50879613170218,
+ "z": 0.0
+ },
+ {
+ "x": 310.55969937316155,
+ "y": -127.50834689369347,
+ "z": 0.0
+ },
+ {
+ "x": 309.554228621502,
+ "y": -127.50789765568476,
+ "z": 0.0
+ },
+ {
+ "x": 308.5487578698423,
+ "y": -127.50744841767607,
+ "z": 0.0
+ },
+ {
+ "x": 307.54328711818283,
+ "y": -127.50699917966736,
+ "z": 0.0
+ },
+ {
+ "x": 306.53781636652326,
+ "y": -127.50654994165865,
+ "z": 0.0
+ },
+ {
+ "x": 305.5323456148637,
+ "y": -127.50610070364993,
+ "z": 0.0
+ },
+ {
+ "x": 304.5268748632041,
+ "y": -127.50565146564122,
+ "z": 0.0
+ },
+ {
+ "x": 303.5214041115445,
+ "y": -127.50520222763251,
+ "z": 0.0
+ },
+ {
+ "x": 302.5159333598849,
+ "y": -127.5047529896238,
+ "z": 0.0
+ },
+ {
+ "x": 301.51046260822534,
+ "y": -127.50430375161508,
+ "z": 0.0
+ },
+ {
+ "x": 300.50499185656565,
+ "y": -127.5038545136064,
+ "z": 0.0
+ },
+ {
+ "x": 299.4995211049062,
+ "y": -127.50340527559769,
+ "z": 0.0
+ },
+ {
+ "x": 298.4940503532466,
+ "y": -127.50295603758897,
+ "z": 0.0
+ },
+ {
+ "x": 297.48857960158705,
+ "y": -127.50250679958026,
+ "z": 0.0
+ },
+ {
+ "x": 296.4831088499275,
+ "y": -127.50205756157155,
+ "z": 0.0
+ },
+ {
+ "x": 295.4776380982679,
+ "y": -127.50160832356283,
+ "z": 0.0
+ },
+ {
+ "x": 294.47216734660833,
+ "y": -127.50115908555412,
+ "z": 0.0
+ },
+ {
+ "x": 293.46669659494864,
+ "y": -127.50070984754544,
+ "z": 0.0
+ },
+ {
+ "x": 292.4612258432892,
+ "y": -127.50026060953672,
+ "z": 0.0
+ },
+ {
+ "x": 291.4557550916296,
+ "y": -127.49981137152801,
+ "z": 0.0
+ },
+ {
+ "x": 290.45028433997,
+ "y": -127.4993621335193,
+ "z": 0.0
+ },
+ {
+ "x": 289.4448135883104,
+ "y": -127.49891289551059,
+ "z": 0.0
+ },
+ {
+ "x": 288.43934283665084,
+ "y": -127.49846365750187,
+ "z": 0.0
+ },
+ {
+ "x": 287.43387208499126,
+ "y": -127.49801441949316,
+ "z": 0.0
+ },
+ {
+ "x": 286.4284013333317,
+ "y": -127.49756518148445,
+ "z": 0.0
+ },
+ {
+ "x": 285.422930581672,
+ "y": -127.49711594347576,
+ "z": 0.0
+ },
+ {
+ "x": 284.41745983001255,
+ "y": -127.49666670546705,
+ "z": 0.0
+ },
+ {
+ "x": 283.411989078353,
+ "y": -127.49621746745834,
+ "z": 0.0
+ },
+ {
+ "x": 282.4065183266934,
+ "y": -127.49576822944962,
+ "z": 0.0
+ },
+ {
+ "x": 281.40104757503383,
+ "y": -127.49531899144091,
+ "z": 0.0
+ },
+ {
+ "x": 280.39557682337426,
+ "y": -127.4948697534322,
+ "z": 0.0
+ },
+ {
+ "x": 279.3901060717147,
+ "y": -127.49442051542349,
+ "z": 0.0
+ },
+ {
+ "x": 278.384635320055,
+ "y": -127.4939712774148,
+ "z": 0.0
+ },
+ {
+ "x": 277.3791645683955,
+ "y": -127.49352203940609,
+ "z": 0.0
+ },
+ {
+ "x": 276.3736938167359,
+ "y": -127.49307280139737,
+ "z": 0.0
+ },
+ {
+ "x": 275.36822306507634,
+ "y": -127.49262356338866,
+ "z": 0.0
+ },
+ {
+ "x": 274.36275231341676,
+ "y": -127.49217432537995,
+ "z": 0.0
+ },
+ {
+ "x": 273.3572815617572,
+ "y": -127.49172508737124,
+ "z": 0.0
+ },
+ {
+ "x": 272.3518108100976,
+ "y": -127.49127584936252,
+ "z": 0.0
+ },
+ {
+ "x": 271.34634005843805,
+ "y": -127.49082661135381,
+ "z": 0.0
+ },
+ {
+ "x": 270.34086930677836,
+ "y": -127.49037737334513,
+ "z": 0.0
+ },
+ {
+ "x": 269.3353985551189,
+ "y": -127.48992813533641,
+ "z": 0.0
+ },
+ {
+ "x": 268.3299278034593,
+ "y": -127.4894788973277,
+ "z": 0.0
+ },
+ {
+ "x": 267.32445705179975,
+ "y": -127.48902965931899,
+ "z": 0.0
+ },
+ {
+ "x": 266.3189863001402,
+ "y": -127.48858042131027,
+ "z": 0.0
+ },
+ {
+ "x": 265.31351554848055,
+ "y": -127.48813118330156,
+ "z": 0.0
+ },
+ {
+ "x": 264.308044796821,
+ "y": -127.48768194529285,
+ "z": 0.0
+ },
+ {
+ "x": 263.3025740451613,
+ "y": -127.48723270728416,
+ "z": 0.0
+ },
+ {
+ "x": 262.29710329350183,
+ "y": -127.48678346927545,
+ "z": 0.0
+ },
+ {
+ "x": 261.29163254184226,
+ "y": -127.48633423126674,
+ "z": 0.0
+ },
+ {
+ "x": 260.2861617901827,
+ "y": -127.48588499325803,
+ "z": 0.0
+ },
+ {
+ "x": 259.2806910385231,
+ "y": -127.48543575524931,
+ "z": 0.0
+ },
+ {
+ "x": 258.27522028686354,
+ "y": -127.4849865172406,
+ "z": 0.0
+ },
+ {
+ "x": 257.26974953520397,
+ "y": -127.48453727923189,
+ "z": 0.0
+ },
+ {
+ "x": 256.2642787835444,
+ "y": -127.48408804122317,
+ "z": 0.0
+ },
+ {
+ "x": 255.2588080318847,
+ "y": -127.48363880321449,
+ "z": 0.0
+ },
+ {
+ "x": 254.25333728022525,
+ "y": -127.48318956520578,
+ "z": 0.0
+ },
+ {
+ "x": 253.24786652856568,
+ "y": -127.48274032719706,
+ "z": 0.0
+ },
+ {
+ "x": 252.24239577690608,
+ "y": -127.48229108918835,
+ "z": 0.0
+ },
+ {
+ "x": 251.2369250252465,
+ "y": -127.48184185117964,
+ "z": 0.0
+ },
+ {
+ "x": 250.23145427358693,
+ "y": -127.48139261317093,
+ "z": 0.0
+ },
+ {
+ "x": 249.22598352192736,
+ "y": -127.48094337516221,
+ "z": 0.0
+ },
+ {
+ "x": 248.22051277026767,
+ "y": -127.48049413715353,
+ "z": 0.0
+ },
+ {
+ "x": 247.21504201860822,
+ "y": -127.48004489914481,
+ "z": 0.0
+ },
+ {
+ "x": 246.20957126694861,
+ "y": -127.4795956611361,
+ "z": 0.0
+ },
+ {
+ "x": 245.20410051528904,
+ "y": -127.47914642312739,
+ "z": 0.0
+ },
+ {
+ "x": 244.19862976362947,
+ "y": -127.47869718511868,
+ "z": 0.0
+ },
+ {
+ "x": 243.1931590119699,
+ "y": -127.47824794710996,
+ "z": 0.0
+ },
+ {
+ "x": 242.18768826031032,
+ "y": -127.47779870910125,
+ "z": 0.0
+ },
+ {
+ "x": 241.18221750865075,
+ "y": -127.47734947109254,
+ "z": 0.0
+ },
+ {
+ "x": 240.17674675699107,
+ "y": -127.47690023308385,
+ "z": 0.0
+ },
+ {
+ "x": 239.17127600533158,
+ "y": -127.47645099507514,
+ "z": 0.0
+ },
+ {
+ "x": 238.165805253672,
+ "y": -127.47600175706643,
+ "z": 0.0
+ },
+ {
+ "x": 237.16033450201243,
+ "y": -127.47555251905771,
+ "z": 0.0
+ },
+ {
+ "x": 236.15486375035286,
+ "y": -127.475103281049,
+ "z": 0.0
+ },
+ {
+ "x": 235.1493929986933,
+ "y": -127.47465404304029,
+ "z": 0.0
+ },
+ {
+ "x": 234.14392224703371,
+ "y": -127.47420480503158,
+ "z": 0.0
+ },
+ {
+ "x": 233.138451495374,
+ "y": -127.47375556702289,
+ "z": 0.0
+ },
+ {
+ "x": 232.13298074371454,
+ "y": -127.47330632901418,
+ "z": 0.0
+ },
+ {
+ "x": 231.12750999205497,
+ "y": -127.47285709100547,
+ "z": 0.0
+ },
+ {
+ "x": 230.1220392403954,
+ "y": -127.47240785299675,
+ "z": 0.0
+ },
+ {
+ "x": 229.1165684887358,
+ "y": -127.47195861498804,
+ "z": 0.0
+ },
+ {
+ "x": 228.1110977370762,
+ "y": -127.47150937697933,
+ "z": 0.0
+ },
+ {
+ "x": 227.10562698541662,
+ "y": -127.47106013897061,
+ "z": 0.0
+ },
+ {
+ "x": 226.10015623375702,
+ "y": -127.4706109009619,
+ "z": 0.0
+ },
+ {
+ "x": 225.0946854820973,
+ "y": -127.47016166295322,
+ "z": 0.0
+ },
+ {
+ "x": 224.08921473043785,
+ "y": -127.4697124249445,
+ "z": 0.0
+ },
+ {
+ "x": 223.08374397877824,
+ "y": -127.46926318693579,
+ "z": 0.0
+ },
+ {
+ "x": 222.07827322711867,
+ "y": -127.46881394892708,
+ "z": 0.0
+ },
+ {
+ "x": 221.07280247545907,
+ "y": -127.46836471091837,
+ "z": 0.0
+ },
+ {
+ "x": 220.06733172379947,
+ "y": -127.46791547290965,
+ "z": 0.0
+ },
+ {
+ "x": 219.0618609721399,
+ "y": -127.46746623490094,
+ "z": 0.0
+ },
+ {
+ "x": 218.05639022048018,
+ "y": -127.46701699689226,
+ "z": 0.0
+ },
+ {
+ "x": 217.0509194688207,
+ "y": -127.46656775888354,
+ "z": 0.0
+ },
+ {
+ "x": 216.04544871716112,
+ "y": -127.46611852087483,
+ "z": 0.0
+ },
+ {
+ "x": 215.03997796550152,
+ "y": -127.46566928286612,
+ "z": 0.0
+ },
+ {
+ "x": 214.03450721384192,
+ "y": -127.4652200448574,
+ "z": 0.0
+ },
+ {
+ "x": 213.02903646218235,
+ "y": -127.46477080684869,
+ "z": 0.0
+ },
+ {
+ "x": 212.02356571052275,
+ "y": -127.46432156883998,
+ "z": 0.0
+ },
+ {
+ "x": 211.01809495886314,
+ "y": -127.46387233083126,
+ "z": 0.0
+ },
+ {
+ "x": 210.01262420720346,
+ "y": -127.46342309282258,
+ "z": 0.0
+ },
+ {
+ "x": 209.00715345554397,
+ "y": -127.46297385481387,
+ "z": 0.0
+ },
+ {
+ "x": 208.00168270388437,
+ "y": -127.46252461680515,
+ "z": 0.0
+ },
+ {
+ "x": 206.9962119522248,
+ "y": -127.46207537879644,
+ "z": 0.0
+ },
+ {
+ "x": 205.9907412005652,
+ "y": -127.46162614078773,
+ "z": 0.0
+ },
+ {
+ "x": 204.9852704489056,
+ "y": -127.46117690277902,
+ "z": 0.0
+ },
+ {
+ "x": 203.97979969724602,
+ "y": -127.4607276647703,
+ "z": 0.0
+ },
+ {
+ "x": 202.9743289455863,
+ "y": -127.46027842676162,
+ "z": 0.0
+ },
+ {
+ "x": 201.96885819392682,
+ "y": -127.4598291887529,
+ "z": 0.0
+ },
+ {
+ "x": 200.96338744226725,
+ "y": -127.4593799507442,
+ "z": 0.0
+ },
+ {
+ "x": 199.95791669060765,
+ "y": -127.45893071273548,
+ "z": 0.0
+ },
+ {
+ "x": 198.95244593894805,
+ "y": -127.45848147472677,
+ "z": 0.0
+ },
+ {
+ "x": 197.94697518728847,
+ "y": -127.45803223671805,
+ "z": 0.0
+ },
+ {
+ "x": 196.94150443562887,
+ "y": -127.45758299870934,
+ "z": 0.0
+ },
+ {
+ "x": 195.93603368396927,
+ "y": -127.45713376070063,
+ "z": 0.0
+ },
+ {
+ "x": 194.93056293230958,
+ "y": -127.45668452269194,
+ "z": 0.0
+ },
+ {
+ "x": 193.9250921806501,
+ "y": -127.45623528468323,
+ "z": 0.0
+ },
+ {
+ "x": 192.9196214289905,
+ "y": -127.45578604667452,
+ "z": 0.0
+ },
+ {
+ "x": 191.91415067733092,
+ "y": -127.4553368086658,
+ "z": 0.0
+ },
+ {
+ "x": 190.90867992567132,
+ "y": -127.45488757065709,
+ "z": 0.0
+ },
+ {
+ "x": 189.90320917401175,
+ "y": -127.45443833264838,
+ "z": 0.0
+ },
+ {
+ "x": 188.89773842235215,
+ "y": -127.45398909463967,
+ "z": 0.0
+ },
+ {
+ "x": 187.89226767069243,
+ "y": -127.45353985663098,
+ "z": 0.0
+ },
+ {
+ "x": 186.88679691903297,
+ "y": -127.45309061862227,
+ "z": 0.0
+ },
+ {
+ "x": 185.88132616737337,
+ "y": -127.45264138061356,
+ "z": 0.0
+ },
+ {
+ "x": 184.87585541571377,
+ "y": -127.45219214260484,
+ "z": 0.0
+ },
+ {
+ "x": 183.8703846640542,
+ "y": -127.45174290459613,
+ "z": 0.0
+ },
+ {
+ "x": 182.8649139123946,
+ "y": -127.45129366658742,
+ "z": 0.0
+ },
+ {
+ "x": 181.859443160735,
+ "y": -127.4508444285787,
+ "z": 0.0
+ },
+ {
+ "x": 180.85397240907542,
+ "y": -127.45039519056999,
+ "z": 0.0
+ },
+ {
+ "x": 179.8485016574157,
+ "y": -127.44994595256131,
+ "z": 0.0
+ },
+ {
+ "x": 178.84303090575622,
+ "y": -127.4494967145526,
+ "z": 0.0
+ },
+ {
+ "x": 177.83756015409665,
+ "y": -127.44904747654388,
+ "z": 0.0
+ },
+ {
+ "x": 176.83208940243705,
+ "y": -127.44859823853517,
+ "z": 0.0
+ },
+ {
+ "x": 175.82661865077745,
+ "y": -127.44814900052646,
+ "z": 0.0
+ },
+ {
+ "x": 174.82114789911788,
+ "y": -127.44769976251774,
+ "z": 0.0
+ },
+ {
+ "x": 173.81567714745827,
+ "y": -127.44725052450903,
+ "z": 0.0
+ },
+ {
+ "x": 172.81020639579856,
+ "y": -127.44680128650035,
+ "z": 0.0
+ },
+ {
+ "x": 171.8047356441391,
+ "y": -127.44635204849163,
+ "z": 0.0
+ },
+ {
+ "x": 170.7992648924795,
+ "y": -127.44590281048292,
+ "z": 0.0
+ },
+ {
+ "x": 169.7937941408199,
+ "y": -127.44545357247421,
+ "z": 0.0
+ },
+ {
+ "x": 168.78832338916033,
+ "y": -127.4450043344655,
+ "z": 0.0
+ },
+ {
+ "x": 167.78285263750072,
+ "y": -127.44455509645678,
+ "z": 0.0
+ },
+ {
+ "x": 166.77738188584112,
+ "y": -127.44410585844807,
+ "z": 0.0
+ },
+ {
+ "x": 165.77191113418155,
+ "y": -127.44365662043936,
+ "z": 0.0
+ },
+ {
+ "x": 164.76644038252184,
+ "y": -127.44320738243067,
+ "z": 0.0
+ },
+ {
+ "x": 163.76096963086238,
+ "y": -127.44275814442196,
+ "z": 0.0
+ },
+ {
+ "x": 162.75549887920278,
+ "y": -127.44230890641325,
+ "z": 0.0
+ },
+ {
+ "x": 161.7500281275432,
+ "y": -127.44185966840453,
+ "z": 0.0
+ },
+ {
+ "x": 160.74455737588363,
+ "y": -127.44141043039582,
+ "z": 0.0
+ },
+ {
+ "x": 159.73908662422403,
+ "y": -127.4409611923871,
+ "z": 0.0
+ },
+ {
+ "x": 158.73361587256446,
+ "y": -127.4405119543784,
+ "z": 0.0
+ },
+ {
+ "x": 157.72814512090474,
+ "y": -127.44006271636971,
+ "z": 0.0
+ },
+ {
+ "x": 156.72267436924528,
+ "y": -127.439613478361,
+ "z": 0.0
+ },
+ {
+ "x": 155.7172036175857,
+ "y": -127.43916424035228,
+ "z": 0.0
+ },
+ {
+ "x": 154.7117328659261,
+ "y": -127.43871500234357,
+ "z": 0.0
+ },
+ {
+ "x": 153.70626211426654,
+ "y": -127.43826576433486,
+ "z": 0.0
+ },
+ {
+ "x": 152.70079136260694,
+ "y": -127.43781652632615,
+ "z": 0.0
+ },
+ {
+ "x": 151.69532061094736,
+ "y": -127.43736728831743,
+ "z": 0.0
+ },
+ {
+ "x": 150.6898498592878,
+ "y": -127.43691805030872,
+ "z": 0.0
+ },
+ {
+ "x": 149.68437910762808,
+ "y": -127.43646881230003,
+ "z": 0.0
+ },
+ {
+ "x": 148.67890835596862,
+ "y": -127.43601957429132,
+ "z": 0.0
+ },
+ {
+ "x": 147.67343760430902,
+ "y": -127.43557033628261,
+ "z": 0.0
+ },
+ {
+ "x": 146.66796685264944,
+ "y": -127.4351210982739,
+ "z": 0.0
+ },
+ {
+ "x": 145.66249610098987,
+ "y": -127.43467186026518,
+ "z": 0.0
+ },
+ {
+ "x": 144.65702534933027,
+ "y": -127.43422262225647,
+ "z": 0.0
+ },
+ {
+ "x": 143.6515545976707,
+ "y": -127.43377338424776,
+ "z": 0.0
+ },
+ {
+ "x": 142.64608384601098,
+ "y": -127.43332414623907,
+ "z": 0.0
+ },
+ {
+ "x": 141.64061309435152,
+ "y": -127.43287490823036,
+ "z": 0.0
+ },
+ {
+ "x": 140.63514234269192,
+ "y": -127.43242567022165,
+ "z": 0.0
+ },
+ {
+ "x": 139.62967159103235,
+ "y": -127.43197643221293,
+ "z": 0.0
+ },
+ {
+ "x": 138.62420083937278,
+ "y": -127.43152719420422,
+ "z": 0.0
+ },
+ {
+ "x": 137.61873008771317,
+ "y": -127.43107795619551,
+ "z": 0.0
+ },
+ {
+ "x": 136.6132593360536,
+ "y": -127.4306287181868,
+ "z": 0.0
+ },
+ {
+ "x": 135.607788584394,
+ "y": -127.43017948017808,
+ "z": 0.0
+ },
+ {
+ "x": 134.60231783273431,
+ "y": -127.4297302421694,
+ "z": 0.0
+ },
+ {
+ "x": 133.59684708107486,
+ "y": -127.42928100416069,
+ "z": 0.0
+ },
+ {
+ "x": 132.59137632941525,
+ "y": -127.42883176615197,
+ "z": 0.0
+ },
+ {
+ "x": 131.58590557775568,
+ "y": -127.42838252814326,
+ "z": 0.0
+ },
+ {
+ "x": 130.58043482609608,
+ "y": -127.42793329013455,
+ "z": 0.0
+ },
+ {
+ "x": 129.5749640744365,
+ "y": -127.42748405212583,
+ "z": 0.0
+ },
+ {
+ "x": 128.5694933227769,
+ "y": -127.42703481411712,
+ "z": 0.0
+ },
+ {
+ "x": 127.56402257111719,
+ "y": -127.42658557610844,
+ "z": 0.0
+ },
+ {
+ "x": 126.55855181945772,
+ "y": -127.42613633809972,
+ "z": 0.0
+ },
+ {
+ "x": 125.55308106779813,
+ "y": -127.42568710009101,
+ "z": 0.0
+ },
+ {
+ "x": 124.54761031613855,
+ "y": -127.4252378620823,
+ "z": 0.0
+ },
+ {
+ "x": 123.54213956447896,
+ "y": -127.42478862407359,
+ "z": 0.0
+ },
+ {
+ "x": 122.53666881281937,
+ "y": -127.42433938606487,
+ "z": 0.0
+ },
+ {
+ "x": 121.53119806115978,
+ "y": -127.42389014805616,
+ "z": 0.0
+ },
+ {
+ "x": 120.5257273095002,
+ "y": -127.42344091004745,
+ "z": 0.0
+ },
+ {
+ "x": 119.52025655784048,
+ "y": -127.42299167203876,
+ "z": 0.0
+ },
+ {
+ "x": 118.51478580618101,
+ "y": -127.42254243403005,
+ "z": 0.0
+ },
+ {
+ "x": 117.50931505452142,
+ "y": -127.42209319602134,
+ "z": 0.0
+ },
+ {
+ "x": 116.50384430286184,
+ "y": -127.42164395801262,
+ "z": 0.0
+ },
+ {
+ "x": 115.49837355120225,
+ "y": -127.42119472000391,
+ "z": 0.0
+ },
+ {
+ "x": 114.49290279954266,
+ "y": -127.4207454819952,
+ "z": 0.0
+ },
+ {
+ "x": 113.48743204788308,
+ "y": -127.42029624398648,
+ "z": 0.0
+ },
+ {
+ "x": 112.48196129622337,
+ "y": -127.4198470059778,
+ "z": 0.0
+ },
+ {
+ "x": 111.4764905445639,
+ "y": -127.41939776796909,
+ "z": 0.0
+ },
+ {
+ "x": 110.47101979290431,
+ "y": -127.41894852996037,
+ "z": 0.0
+ },
+ {
+ "x": 109.46554904124473,
+ "y": -127.41849929195166,
+ "z": 0.0
+ },
+ {
+ "x": 108.46007828958514,
+ "y": -127.41805005394295,
+ "z": 0.0
+ },
+ {
+ "x": 107.45460753792555,
+ "y": -127.41760081593424,
+ "z": 0.0
+ },
+ {
+ "x": 106.44913678626597,
+ "y": -127.41715157792552,
+ "z": 0.0
+ },
+ {
+ "x": 105.44366603460638,
+ "y": -127.41670233991681,
+ "z": 0.0
+ },
+ {
+ "x": 104.43819528294668,
+ "y": -127.41625310190813,
+ "z": 0.0
+ },
+ {
+ "x": 103.4327245312872,
+ "y": -127.41580386389941,
+ "z": 0.0
+ },
+ {
+ "x": 102.42725377962762,
+ "y": -127.4153546258907,
+ "z": 0.0
+ },
+ {
+ "x": 101.42178302796803,
+ "y": -127.41490538788199,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 21,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 101.4182086786346,
+ "y": -135.4149045893836,
+ "z": 0.0
+ },
+ {
+ "x": 102.42367943029419,
+ "y": -135.41535382739232,
+ "z": 0.0
+ },
+ {
+ "x": 103.42915018195377,
+ "y": -135.41580306540104,
+ "z": 0.0
+ },
+ {
+ "x": 104.43462093361347,
+ "y": -135.41625230340975,
+ "z": 0.0
+ },
+ {
+ "x": 105.44009168527295,
+ "y": -135.41670154141843,
+ "z": 0.0
+ },
+ {
+ "x": 106.44556243693253,
+ "y": -135.41715077942715,
+ "z": 0.0
+ },
+ {
+ "x": 107.45103318859212,
+ "y": -135.41760001743586,
+ "z": 0.0
+ },
+ {
+ "x": 108.45650394025171,
+ "y": -135.41804925544457,
+ "z": 0.0
+ },
+ {
+ "x": 109.4619746919113,
+ "y": -135.41849849345328,
+ "z": 0.0
+ },
+ {
+ "x": 110.46744544357088,
+ "y": -135.418947731462,
+ "z": 0.0
+ },
+ {
+ "x": 111.47291619523047,
+ "y": -135.4193969694707,
+ "z": 0.0
+ },
+ {
+ "x": 112.47838694689017,
+ "y": -135.41984620747942,
+ "z": 0.0
+ },
+ {
+ "x": 113.48385769854964,
+ "y": -135.4202954454881,
+ "z": 0.0
+ },
+ {
+ "x": 114.48932845020923,
+ "y": -135.42074468349682,
+ "z": 0.0
+ },
+ {
+ "x": 115.49479920186882,
+ "y": -135.42119392150553,
+ "z": 0.0
+ },
+ {
+ "x": 116.5002699535284,
+ "y": -135.42164315951425,
+ "z": 0.0
+ },
+ {
+ "x": 117.50574070518799,
+ "y": -135.42209239752296,
+ "z": 0.0
+ },
+ {
+ "x": 118.51121145684758,
+ "y": -135.42254163553167,
+ "z": 0.0
+ },
+ {
+ "x": 119.51668220850728,
+ "y": -135.42299087354039,
+ "z": 0.0
+ },
+ {
+ "x": 120.52215296016676,
+ "y": -135.42344011154907,
+ "z": 0.0
+ },
+ {
+ "x": 121.52762371182635,
+ "y": -135.42388934955778,
+ "z": 0.0
+ },
+ {
+ "x": 122.53309446348594,
+ "y": -135.4243385875665,
+ "z": 0.0
+ },
+ {
+ "x": 123.53856521514552,
+ "y": -135.4247878255752,
+ "z": 0.0
+ },
+ {
+ "x": 124.54403596680511,
+ "y": -135.42523706358392,
+ "z": 0.0
+ },
+ {
+ "x": 125.5495067184647,
+ "y": -135.42568630159263,
+ "z": 0.0
+ },
+ {
+ "x": 126.55497747012429,
+ "y": -135.42613553960135,
+ "z": 0.0
+ },
+ {
+ "x": 127.56044822178399,
+ "y": -135.42658477761006,
+ "z": 0.0
+ },
+ {
+ "x": 128.56591897344344,
+ "y": -135.42703401561874,
+ "z": 0.0
+ },
+ {
+ "x": 129.57138972510305,
+ "y": -135.42748325362746,
+ "z": 0.0
+ },
+ {
+ "x": 130.57686047676262,
+ "y": -135.42793249163617,
+ "z": 0.0
+ },
+ {
+ "x": 131.58233122842222,
+ "y": -135.42838172964488,
+ "z": 0.0
+ },
+ {
+ "x": 132.5878019800818,
+ "y": -135.4288309676536,
+ "z": 0.0
+ },
+ {
+ "x": 133.5932727317414,
+ "y": -135.4292802056623,
+ "z": 0.0
+ },
+ {
+ "x": 134.59874348340108,
+ "y": -135.42972944367102,
+ "z": 0.0
+ },
+ {
+ "x": 135.60421423506054,
+ "y": -135.4301786816797,
+ "z": 0.0
+ },
+ {
+ "x": 136.60968498672014,
+ "y": -135.43062791968842,
+ "z": 0.0
+ },
+ {
+ "x": 137.6151557383797,
+ "y": -135.43107715769713,
+ "z": 0.0
+ },
+ {
+ "x": 138.6206264900393,
+ "y": -135.43152639570584,
+ "z": 0.0
+ },
+ {
+ "x": 139.6260972416989,
+ "y": -135.43197563371456,
+ "z": 0.0
+ },
+ {
+ "x": 140.63156799335846,
+ "y": -135.43242487172327,
+ "z": 0.0
+ },
+ {
+ "x": 141.63703874501806,
+ "y": -135.43287410973198,
+ "z": 0.0
+ },
+ {
+ "x": 142.64250949667775,
+ "y": -135.4333233477407,
+ "z": 0.0
+ },
+ {
+ "x": 143.64798024833723,
+ "y": -135.43377258574938,
+ "z": 0.0
+ },
+ {
+ "x": 144.6534509999968,
+ "y": -135.4342218237581,
+ "z": 0.0
+ },
+ {
+ "x": 145.6589217516564,
+ "y": -135.4346710617668,
+ "z": 0.0
+ },
+ {
+ "x": 146.66439250331598,
+ "y": -135.43512029977552,
+ "z": 0.0
+ },
+ {
+ "x": 147.66986325497555,
+ "y": -135.43556953778423,
+ "z": 0.0
+ },
+ {
+ "x": 148.67533400663515,
+ "y": -135.43601877579295,
+ "z": 0.0
+ },
+ {
+ "x": 149.68080475829484,
+ "y": -135.43646801380166,
+ "z": 0.0
+ },
+ {
+ "x": 150.68627550995433,
+ "y": -135.43691725181034,
+ "z": 0.0
+ },
+ {
+ "x": 151.6917462616139,
+ "y": -135.43736648981906,
+ "z": 0.0
+ },
+ {
+ "x": 152.69721701327347,
+ "y": -135.43781572782777,
+ "z": 0.0
+ },
+ {
+ "x": 153.70268776493307,
+ "y": -135.43826496583648,
+ "z": 0.0
+ },
+ {
+ "x": 154.70815851659265,
+ "y": -135.4387142038452,
+ "z": 0.0
+ },
+ {
+ "x": 155.71362926825225,
+ "y": -135.4391634418539,
+ "z": 0.0
+ },
+ {
+ "x": 156.71910001991182,
+ "y": -135.43961267986262,
+ "z": 0.0
+ },
+ {
+ "x": 157.7245707715715,
+ "y": -135.44006191787133,
+ "z": 0.0
+ },
+ {
+ "x": 158.730041523231,
+ "y": -135.44051115588002,
+ "z": 0.0
+ },
+ {
+ "x": 159.73551227489057,
+ "y": -135.44096039388873,
+ "z": 0.0
+ },
+ {
+ "x": 160.74098302655017,
+ "y": -135.44140963189744,
+ "z": 0.0
+ },
+ {
+ "x": 161.74645377820974,
+ "y": -135.44185886990616,
+ "z": 0.0
+ },
+ {
+ "x": 162.7519245298693,
+ "y": -135.44230810791487,
+ "z": 0.0
+ },
+ {
+ "x": 163.75739528152891,
+ "y": -135.44275734592358,
+ "z": 0.0
+ },
+ {
+ "x": 164.7628660331886,
+ "y": -135.4432065839323,
+ "z": 0.0
+ },
+ {
+ "x": 165.7683367848481,
+ "y": -135.44365582194098,
+ "z": 0.0
+ },
+ {
+ "x": 166.77380753650766,
+ "y": -135.4441050599497,
+ "z": 0.0
+ },
+ {
+ "x": 167.77927828816726,
+ "y": -135.4445542979584,
+ "z": 0.0
+ },
+ {
+ "x": 168.78474903982686,
+ "y": -135.44500353596712,
+ "z": 0.0
+ },
+ {
+ "x": 169.79021979148644,
+ "y": -135.44545277397583,
+ "z": 0.0
+ },
+ {
+ "x": 170.79569054314604,
+ "y": -135.44590201198454,
+ "z": 0.0
+ },
+ {
+ "x": 171.80116129480564,
+ "y": -135.44635124999326,
+ "z": 0.0
+ },
+ {
+ "x": 172.80663204646532,
+ "y": -135.44680048800197,
+ "z": 0.0
+ },
+ {
+ "x": 173.8121027981248,
+ "y": -135.44724972601065,
+ "z": 0.0
+ },
+ {
+ "x": 174.8175735497844,
+ "y": -135.44769896401937,
+ "z": 0.0
+ },
+ {
+ "x": 175.82304430144399,
+ "y": -135.44814820202808,
+ "z": 0.0
+ },
+ {
+ "x": 176.8285150531036,
+ "y": -135.4485974400368,
+ "z": 0.0
+ },
+ {
+ "x": 177.8339858047632,
+ "y": -135.4490466780455,
+ "z": 0.0
+ },
+ {
+ "x": 178.83945655642276,
+ "y": -135.44949591605422,
+ "z": 0.0
+ },
+ {
+ "x": 179.84492730808248,
+ "y": -135.44994515406293,
+ "z": 0.0
+ },
+ {
+ "x": 180.85039805974196,
+ "y": -135.45039439207162,
+ "z": 0.0
+ },
+ {
+ "x": 181.85586881140154,
+ "y": -135.45084363008033,
+ "z": 0.0
+ },
+ {
+ "x": 182.86133956306114,
+ "y": -135.45129286808904,
+ "z": 0.0
+ },
+ {
+ "x": 183.86681031472074,
+ "y": -135.45174210609775,
+ "z": 0.0
+ },
+ {
+ "x": 184.8722810663803,
+ "y": -135.45219134410647,
+ "z": 0.0
+ },
+ {
+ "x": 185.8777518180399,
+ "y": -135.45264058211518,
+ "z": 0.0
+ },
+ {
+ "x": 186.8832225696995,
+ "y": -135.4530898201239,
+ "z": 0.0
+ },
+ {
+ "x": 187.8886933213592,
+ "y": -135.4535390581326,
+ "z": 0.0
+ },
+ {
+ "x": 188.8941640730187,
+ "y": -135.4539882961413,
+ "z": 0.0
+ },
+ {
+ "x": 189.8996348246783,
+ "y": -135.45443753415,
+ "z": 0.0
+ },
+ {
+ "x": 190.90510557633786,
+ "y": -135.45488677215872,
+ "z": 0.0
+ },
+ {
+ "x": 191.91057632799746,
+ "y": -135.45533601016743,
+ "z": 0.0
+ },
+ {
+ "x": 192.91604707965703,
+ "y": -135.45578524817614,
+ "z": 0.0
+ },
+ {
+ "x": 193.92151783131663,
+ "y": -135.45623448618485,
+ "z": 0.0
+ },
+ {
+ "x": 194.92698858297635,
+ "y": -135.45668372419357,
+ "z": 0.0
+ },
+ {
+ "x": 195.9324593346358,
+ "y": -135.45713296220225,
+ "z": 0.0
+ },
+ {
+ "x": 196.9379300862954,
+ "y": -135.45758220021096,
+ "z": 0.0
+ },
+ {
+ "x": 197.943400837955,
+ "y": -135.45803143821968,
+ "z": 0.0
+ },
+ {
+ "x": 198.94887158961458,
+ "y": -135.4584806762284,
+ "z": 0.0
+ },
+ {
+ "x": 199.95434234127418,
+ "y": -135.4589299142371,
+ "z": 0.0
+ },
+ {
+ "x": 200.95981309293379,
+ "y": -135.45937915224582,
+ "z": 0.0
+ },
+ {
+ "x": 201.96528384459336,
+ "y": -135.45982839025453,
+ "z": 0.0
+ },
+ {
+ "x": 202.97075459625307,
+ "y": -135.46027762826324,
+ "z": 0.0
+ },
+ {
+ "x": 203.97622534791256,
+ "y": -135.46072686627193,
+ "z": 0.0
+ },
+ {
+ "x": 204.98169609957213,
+ "y": -135.46117610428064,
+ "z": 0.0
+ },
+ {
+ "x": 205.98716685123173,
+ "y": -135.46162534228935,
+ "z": 0.0
+ },
+ {
+ "x": 206.99263760289134,
+ "y": -135.46207458029807,
+ "z": 0.0
+ },
+ {
+ "x": 207.9981083545509,
+ "y": -135.46252381830678,
+ "z": 0.0
+ },
+ {
+ "x": 209.0035791062105,
+ "y": -135.4629730563155,
+ "z": 0.0
+ },
+ {
+ "x": 210.00904985787022,
+ "y": -135.4634222943242,
+ "z": 0.0
+ },
+ {
+ "x": 211.01452060952968,
+ "y": -135.4638715323329,
+ "z": 0.0
+ },
+ {
+ "x": 212.01999136118928,
+ "y": -135.4643207703416,
+ "z": 0.0
+ },
+ {
+ "x": 213.02546211284888,
+ "y": -135.4647700083503,
+ "z": 0.0
+ },
+ {
+ "x": 214.03093286450846,
+ "y": -135.46521924635903,
+ "z": 0.0
+ },
+ {
+ "x": 215.03640361616806,
+ "y": -135.46566848436774,
+ "z": 0.0
+ },
+ {
+ "x": 216.04187436782766,
+ "y": -135.46611772237645,
+ "z": 0.0
+ },
+ {
+ "x": 217.04734511948723,
+ "y": -135.46656696038517,
+ "z": 0.0
+ },
+ {
+ "x": 218.05281587114695,
+ "y": -135.46701619839388,
+ "z": 0.0
+ },
+ {
+ "x": 219.05828662280643,
+ "y": -135.46746543640256,
+ "z": 0.0
+ },
+ {
+ "x": 220.063757374466,
+ "y": -135.46791467441128,
+ "z": 0.0
+ },
+ {
+ "x": 221.0692281261256,
+ "y": -135.46836391242,
+ "z": 0.0
+ },
+ {
+ "x": 222.0746988777852,
+ "y": -135.4688131504287,
+ "z": 0.0
+ },
+ {
+ "x": 223.08016962944478,
+ "y": -135.46926238843741,
+ "z": 0.0
+ },
+ {
+ "x": 224.08564038110438,
+ "y": -135.46971162644613,
+ "z": 0.0
+ },
+ {
+ "x": 225.09111113276407,
+ "y": -135.47016086445484,
+ "z": 0.0
+ },
+ {
+ "x": 226.09658188442356,
+ "y": -135.47061010246352,
+ "z": 0.0
+ },
+ {
+ "x": 227.10205263608316,
+ "y": -135.47105934047224,
+ "z": 0.0
+ },
+ {
+ "x": 228.10752338774273,
+ "y": -135.47150857848095,
+ "z": 0.0
+ },
+ {
+ "x": 229.11299413940233,
+ "y": -135.47195781648966,
+ "z": 0.0
+ },
+ {
+ "x": 230.11846489106193,
+ "y": -135.47240705449838,
+ "z": 0.0
+ },
+ {
+ "x": 231.1239356427215,
+ "y": -135.4728562925071,
+ "z": 0.0
+ },
+ {
+ "x": 232.12940639438108,
+ "y": -135.4733055305158,
+ "z": 0.0
+ },
+ {
+ "x": 233.13487714604076,
+ "y": -135.47375476852451,
+ "z": 0.0
+ },
+ {
+ "x": 234.14034789770025,
+ "y": -135.4742040065332,
+ "z": 0.0
+ },
+ {
+ "x": 235.14581864935982,
+ "y": -135.4746532445419,
+ "z": 0.0
+ },
+ {
+ "x": 236.1512894010194,
+ "y": -135.47510248255062,
+ "z": 0.0
+ },
+ {
+ "x": 237.15676015267897,
+ "y": -135.47555172055934,
+ "z": 0.0
+ },
+ {
+ "x": 238.16223090433854,
+ "y": -135.47600095856805,
+ "z": 0.0
+ },
+ {
+ "x": 239.16770165599812,
+ "y": -135.47645019657676,
+ "z": 0.0
+ },
+ {
+ "x": 240.17317240765783,
+ "y": -135.47689943458548,
+ "z": 0.0
+ },
+ {
+ "x": 241.1786431593173,
+ "y": -135.47734867259416,
+ "z": 0.0
+ },
+ {
+ "x": 242.18411391097686,
+ "y": -135.47779791060287,
+ "z": 0.0
+ },
+ {
+ "x": 243.18958466263643,
+ "y": -135.4782471486116,
+ "z": 0.0
+ },
+ {
+ "x": 244.195055414296,
+ "y": -135.4786963866203,
+ "z": 0.0
+ },
+ {
+ "x": 245.20052616595558,
+ "y": -135.479145624629,
+ "z": 0.0
+ },
+ {
+ "x": 246.20599691761515,
+ "y": -135.47959486263773,
+ "z": 0.0
+ },
+ {
+ "x": 247.21146766927475,
+ "y": -135.48004410064644,
+ "z": 0.0
+ },
+ {
+ "x": 248.21693842093444,
+ "y": -135.48049333865515,
+ "z": 0.0
+ },
+ {
+ "x": 249.2224091725939,
+ "y": -135.48094257666384,
+ "z": 0.0
+ },
+ {
+ "x": 250.22787992425347,
+ "y": -135.48139181467255,
+ "z": 0.0
+ },
+ {
+ "x": 251.23335067591304,
+ "y": -135.48184105268126,
+ "z": 0.0
+ },
+ {
+ "x": 252.23882142757262,
+ "y": -135.48229029068997,
+ "z": 0.0
+ },
+ {
+ "x": 253.24429217923222,
+ "y": -135.4827395286987,
+ "z": 0.0
+ },
+ {
+ "x": 254.2497629308918,
+ "y": -135.4831887667074,
+ "z": 0.0
+ },
+ {
+ "x": 255.25523368255148,
+ "y": -135.4836380047161,
+ "z": 0.0
+ },
+ {
+ "x": 256.26070443421094,
+ "y": -135.4840872427248,
+ "z": 0.0
+ },
+ {
+ "x": 257.2661751858705,
+ "y": -135.4845364807335,
+ "z": 0.0
+ },
+ {
+ "x": 258.2716459375301,
+ "y": -135.48498571874222,
+ "z": 0.0
+ },
+ {
+ "x": 259.27711668918965,
+ "y": -135.48543495675094,
+ "z": 0.0
+ },
+ {
+ "x": 260.2825874408492,
+ "y": -135.48588419475965,
+ "z": 0.0
+ },
+ {
+ "x": 261.2880581925088,
+ "y": -135.48633343276836,
+ "z": 0.0
+ },
+ {
+ "x": 262.2935289441684,
+ "y": -135.48678267077707,
+ "z": 0.0
+ },
+ {
+ "x": 263.29899969582806,
+ "y": -135.4872319087858,
+ "z": 0.0
+ },
+ {
+ "x": 264.3044704474875,
+ "y": -135.48768114679447,
+ "z": 0.0
+ },
+ {
+ "x": 265.3099411991471,
+ "y": -135.48813038480318,
+ "z": 0.0
+ },
+ {
+ "x": 266.3154119508067,
+ "y": -135.4885796228119,
+ "z": 0.0
+ },
+ {
+ "x": 267.3208827024663,
+ "y": -135.4890288608206,
+ "z": 0.0
+ },
+ {
+ "x": 268.32635345412587,
+ "y": -135.48947809882932,
+ "z": 0.0
+ },
+ {
+ "x": 269.33182420578544,
+ "y": -135.48992733683804,
+ "z": 0.0
+ },
+ {
+ "x": 270.3372949574451,
+ "y": -135.49037657484675,
+ "z": 0.0
+ },
+ {
+ "x": 271.3427657091046,
+ "y": -135.49082581285543,
+ "z": 0.0
+ },
+ {
+ "x": 272.34823646076416,
+ "y": -135.49127505086415,
+ "z": 0.0
+ },
+ {
+ "x": 273.3537072124237,
+ "y": -135.49172428887286,
+ "z": 0.0
+ },
+ {
+ "x": 274.3591779640833,
+ "y": -135.49217352688157,
+ "z": 0.0
+ },
+ {
+ "x": 275.3646487157429,
+ "y": -135.49262276489029,
+ "z": 0.0
+ },
+ {
+ "x": 276.37011946740245,
+ "y": -135.493072002899,
+ "z": 0.0
+ },
+ {
+ "x": 277.375590219062,
+ "y": -135.4935212409077,
+ "z": 0.0
+ },
+ {
+ "x": 278.38106097072176,
+ "y": -135.49397047891642,
+ "z": 0.0
+ },
+ {
+ "x": 279.3865317223812,
+ "y": -135.4944197169251,
+ "z": 0.0
+ },
+ {
+ "x": 280.3920024740408,
+ "y": -135.49486895493382,
+ "z": 0.0
+ },
+ {
+ "x": 281.39747322570037,
+ "y": -135.49531819294253,
+ "z": 0.0
+ },
+ {
+ "x": 282.40294397735994,
+ "y": -135.49576743095125,
+ "z": 0.0
+ },
+ {
+ "x": 283.4084147290195,
+ "y": -135.49621666895996,
+ "z": 0.0
+ },
+ {
+ "x": 284.4138854806791,
+ "y": -135.49666590696867,
+ "z": 0.0
+ },
+ {
+ "x": 285.41935623233877,
+ "y": -135.49711514497739,
+ "z": 0.0
+ },
+ {
+ "x": 286.42482698399823,
+ "y": -135.49756438298607,
+ "z": 0.0
+ },
+ {
+ "x": 287.4302977356578,
+ "y": -135.49801362099478,
+ "z": 0.0
+ },
+ {
+ "x": 288.4357684873174,
+ "y": -135.4984628590035,
+ "z": 0.0
+ },
+ {
+ "x": 289.44123923897695,
+ "y": -135.4989120970122,
+ "z": 0.0
+ },
+ {
+ "x": 290.4467099906365,
+ "y": -135.49936133502092,
+ "z": 0.0
+ },
+ {
+ "x": 291.45218074229615,
+ "y": -135.49981057302963,
+ "z": 0.0
+ },
+ {
+ "x": 292.4576514939557,
+ "y": -135.50025981103835,
+ "z": 0.0
+ },
+ {
+ "x": 293.4631222456154,
+ "y": -135.50070904904706,
+ "z": 0.0
+ },
+ {
+ "x": 294.46859299727487,
+ "y": -135.50115828705574,
+ "z": 0.0
+ },
+ {
+ "x": 295.47406374893444,
+ "y": -135.50160752506446,
+ "z": 0.0
+ },
+ {
+ "x": 296.479534500594,
+ "y": -135.50205676307317,
+ "z": 0.0
+ },
+ {
+ "x": 297.4850052522536,
+ "y": -135.50250600108188,
+ "z": 0.0
+ },
+ {
+ "x": 298.49047600391316,
+ "y": -135.5029552390906,
+ "z": 0.0
+ },
+ {
+ "x": 299.49594675557273,
+ "y": -135.5034044770993,
+ "z": 0.0
+ },
+ {
+ "x": 300.5014175072324,
+ "y": -135.50385371510802,
+ "z": 0.0
+ },
+ {
+ "x": 301.5068882588919,
+ "y": -135.5043029531167,
+ "z": 0.0
+ },
+ {
+ "x": 302.51235901055145,
+ "y": -135.50475219112542,
+ "z": 0.0
+ },
+ {
+ "x": 303.517829762211,
+ "y": -135.50520142913413,
+ "z": 0.0
+ },
+ {
+ "x": 304.52330051387065,
+ "y": -135.50565066714285,
+ "z": 0.0
+ },
+ {
+ "x": 305.5287712655302,
+ "y": -135.50609990515156,
+ "z": 0.0
+ },
+ {
+ "x": 306.5342420171898,
+ "y": -135.50654914316027,
+ "z": 0.0
+ },
+ {
+ "x": 307.53971276884937,
+ "y": -135.50699838116898,
+ "z": 0.0
+ },
+ {
+ "x": 308.54518352050906,
+ "y": -135.5074476191777,
+ "z": 0.0
+ },
+ {
+ "x": 309.5506542721685,
+ "y": -135.50789685718638,
+ "z": 0.0
+ },
+ {
+ "x": 310.5561250238281,
+ "y": -135.5083460951951,
+ "z": 0.0
+ },
+ {
+ "x": 311.56159577548766,
+ "y": -135.5087953332038,
+ "z": 0.0
+ },
+ {
+ "x": 312.56706652714723,
+ "y": -135.50924457121252,
+ "z": 0.0
+ },
+ {
+ "x": 313.5725372788068,
+ "y": -135.50969380922123,
+ "z": 0.0
+ },
+ {
+ "x": 314.5780080304664,
+ "y": -135.51014304722995,
+ "z": 0.0
+ },
+ {
+ "x": 315.58347878212606,
+ "y": -135.51059228523866,
+ "z": 0.0
+ },
+ {
+ "x": 316.5889495337855,
+ "y": -135.51104152324734,
+ "z": 0.0
+ },
+ {
+ "x": 317.59442028544515,
+ "y": -135.51149076125606,
+ "z": 0.0
+ },
+ {
+ "x": 318.5998910371047,
+ "y": -135.51193999926477,
+ "z": 0.0
+ },
+ {
+ "x": 319.6053617887643,
+ "y": -135.51238923727348,
+ "z": 0.0
+ },
+ {
+ "x": 320.61083254042387,
+ "y": -135.5128384752822,
+ "z": 0.0
+ },
+ {
+ "x": 321.61630329208344,
+ "y": -135.5132877132909,
+ "z": 0.0
+ },
+ {
+ "x": 322.621774043743,
+ "y": -135.51373695129962,
+ "z": 0.0
+ },
+ {
+ "x": 323.6272447954027,
+ "y": -135.51418618930833,
+ "z": 0.0
+ },
+ {
+ "x": 324.63271554706216,
+ "y": -135.51463542731702,
+ "z": 0.0
+ },
+ {
+ "x": 325.63818629872173,
+ "y": -135.51508466532573,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 22,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 101.41999585330132,
+ "y": -131.4149049886328,
+ "z": 0.0
+ },
+ {
+ "x": 102.4254666049609,
+ "y": -131.4153542266415,
+ "z": 0.0
+ },
+ {
+ "x": 103.43093735662049,
+ "y": -131.41580346465022,
+ "z": 0.0
+ },
+ {
+ "x": 104.43640810828008,
+ "y": -131.41625270265894,
+ "z": 0.0
+ },
+ {
+ "x": 105.44187885993966,
+ "y": -131.41670194066762,
+ "z": 0.0
+ },
+ {
+ "x": 106.44734961159925,
+ "y": -131.41715117867633,
+ "z": 0.0
+ },
+ {
+ "x": 107.45282036325884,
+ "y": -131.41760041668505,
+ "z": 0.0
+ },
+ {
+ "x": 108.45829111491842,
+ "y": -131.41804965469376,
+ "z": 0.0
+ },
+ {
+ "x": 109.46376186657801,
+ "y": -131.41849889270247,
+ "z": 0.0
+ },
+ {
+ "x": 110.4692326182376,
+ "y": -131.4189481307112,
+ "z": 0.0
+ },
+ {
+ "x": 111.47470336989718,
+ "y": -131.4193973687199,
+ "z": 0.0
+ },
+ {
+ "x": 112.48017412155677,
+ "y": -131.4198466067286,
+ "z": 0.0
+ },
+ {
+ "x": 113.48564487321636,
+ "y": -131.4202958447373,
+ "z": 0.0
+ },
+ {
+ "x": 114.49111562487595,
+ "y": -131.420745082746,
+ "z": 0.0
+ },
+ {
+ "x": 115.49658637653553,
+ "y": -131.42119432075472,
+ "z": 0.0
+ },
+ {
+ "x": 116.50205712819512,
+ "y": -131.42164355876344,
+ "z": 0.0
+ },
+ {
+ "x": 117.5075278798547,
+ "y": -131.42209279677215,
+ "z": 0.0
+ },
+ {
+ "x": 118.5129986315143,
+ "y": -131.42254203478086,
+ "z": 0.0
+ },
+ {
+ "x": 119.51846938317388,
+ "y": -131.42299127278957,
+ "z": 0.0
+ },
+ {
+ "x": 120.52394013483348,
+ "y": -131.42344051079826,
+ "z": 0.0
+ },
+ {
+ "x": 121.52941088649307,
+ "y": -131.42388974880697,
+ "z": 0.0
+ },
+ {
+ "x": 122.53488163815265,
+ "y": -131.42433898681568,
+ "z": 0.0
+ },
+ {
+ "x": 123.54035238981224,
+ "y": -131.4247882248244,
+ "z": 0.0
+ },
+ {
+ "x": 124.54582314147183,
+ "y": -131.4252374628331,
+ "z": 0.0
+ },
+ {
+ "x": 125.55129389313142,
+ "y": -131.42568670084182,
+ "z": 0.0
+ },
+ {
+ "x": 126.556764644791,
+ "y": -131.42613593885054,
+ "z": 0.0
+ },
+ {
+ "x": 127.56223539645059,
+ "y": -131.42658517685925,
+ "z": 0.0
+ },
+ {
+ "x": 128.56770614811018,
+ "y": -131.42703441486793,
+ "z": 0.0
+ },
+ {
+ "x": 129.57317689976978,
+ "y": -131.42748365287665,
+ "z": 0.0
+ },
+ {
+ "x": 130.57864765142935,
+ "y": -131.42793289088536,
+ "z": 0.0
+ },
+ {
+ "x": 131.58411840308895,
+ "y": -131.42838212889407,
+ "z": 0.0
+ },
+ {
+ "x": 132.58958915474852,
+ "y": -131.42883136690278,
+ "z": 0.0
+ },
+ {
+ "x": 133.59505990640812,
+ "y": -131.4292806049115,
+ "z": 0.0
+ },
+ {
+ "x": 134.6005306580677,
+ "y": -131.4297298429202,
+ "z": 0.0
+ },
+ {
+ "x": 135.60600140972727,
+ "y": -131.4301790809289,
+ "z": 0.0
+ },
+ {
+ "x": 136.61147216138687,
+ "y": -131.4306283189376,
+ "z": 0.0
+ },
+ {
+ "x": 137.61694291304644,
+ "y": -131.43107755694632,
+ "z": 0.0
+ },
+ {
+ "x": 138.62241366470604,
+ "y": -131.43152679495503,
+ "z": 0.0
+ },
+ {
+ "x": 139.62788441636562,
+ "y": -131.43197603296375,
+ "z": 0.0
+ },
+ {
+ "x": 140.6333551680252,
+ "y": -131.43242527097246,
+ "z": 0.0
+ },
+ {
+ "x": 141.6388259196848,
+ "y": -131.43287450898117,
+ "z": 0.0
+ },
+ {
+ "x": 142.64429667134436,
+ "y": -131.43332374698988,
+ "z": 0.0
+ },
+ {
+ "x": 143.64976742300396,
+ "y": -131.43377298499857,
+ "z": 0.0
+ },
+ {
+ "x": 144.65523817466354,
+ "y": -131.43422222300728,
+ "z": 0.0
+ },
+ {
+ "x": 145.66070892632314,
+ "y": -131.434671461016,
+ "z": 0.0
+ },
+ {
+ "x": 146.6661796779827,
+ "y": -131.4351206990247,
+ "z": 0.0
+ },
+ {
+ "x": 147.67165042964228,
+ "y": -131.43556993703342,
+ "z": 0.0
+ },
+ {
+ "x": 148.67712118130189,
+ "y": -131.43601917504213,
+ "z": 0.0
+ },
+ {
+ "x": 149.68259193296146,
+ "y": -131.43646841305085,
+ "z": 0.0
+ },
+ {
+ "x": 150.68806268462106,
+ "y": -131.43691765105953,
+ "z": 0.0
+ },
+ {
+ "x": 151.69353343628063,
+ "y": -131.43736688906824,
+ "z": 0.0
+ },
+ {
+ "x": 152.6990041879402,
+ "y": -131.43781612707696,
+ "z": 0.0
+ },
+ {
+ "x": 153.7044749395998,
+ "y": -131.43826536508567,
+ "z": 0.0
+ },
+ {
+ "x": 154.70994569125938,
+ "y": -131.43871460309438,
+ "z": 0.0
+ },
+ {
+ "x": 155.71541644291898,
+ "y": -131.4391638411031,
+ "z": 0.0
+ },
+ {
+ "x": 156.72088719457855,
+ "y": -131.4396130791118,
+ "z": 0.0
+ },
+ {
+ "x": 157.72635794623812,
+ "y": -131.44006231712052,
+ "z": 0.0
+ },
+ {
+ "x": 158.73182869789773,
+ "y": -131.4405115551292,
+ "z": 0.0
+ },
+ {
+ "x": 159.7372994495573,
+ "y": -131.44096079313792,
+ "z": 0.0
+ },
+ {
+ "x": 160.7427702012169,
+ "y": -131.44141003114663,
+ "z": 0.0
+ },
+ {
+ "x": 161.74824095287647,
+ "y": -131.44185926915534,
+ "z": 0.0
+ },
+ {
+ "x": 162.75371170453604,
+ "y": -131.44230850716406,
+ "z": 0.0
+ },
+ {
+ "x": 163.75918245619565,
+ "y": -131.44275774517277,
+ "z": 0.0
+ },
+ {
+ "x": 164.76465320785522,
+ "y": -131.44320698318148,
+ "z": 0.0
+ },
+ {
+ "x": 165.77012395951482,
+ "y": -131.44365622119017,
+ "z": 0.0
+ },
+ {
+ "x": 166.7755947111744,
+ "y": -131.44410545919888,
+ "z": 0.0
+ },
+ {
+ "x": 167.781065462834,
+ "y": -131.4445546972076,
+ "z": 0.0
+ },
+ {
+ "x": 168.7865362144936,
+ "y": -131.4450039352163,
+ "z": 0.0
+ },
+ {
+ "x": 169.79200696615317,
+ "y": -131.44545317322502,
+ "z": 0.0
+ },
+ {
+ "x": 170.79747771781277,
+ "y": -131.44590241123373,
+ "z": 0.0
+ },
+ {
+ "x": 171.80294846947237,
+ "y": -131.44635164924244,
+ "z": 0.0
+ },
+ {
+ "x": 172.80841922113194,
+ "y": -131.44680088725116,
+ "z": 0.0
+ },
+ {
+ "x": 173.81388997279154,
+ "y": -131.44725012525984,
+ "z": 0.0
+ },
+ {
+ "x": 174.81936072445114,
+ "y": -131.44769936326855,
+ "z": 0.0
+ },
+ {
+ "x": 175.82483147611072,
+ "y": -131.44814860127727,
+ "z": 0.0
+ },
+ {
+ "x": 176.83030222777032,
+ "y": -131.44859783928598,
+ "z": 0.0
+ },
+ {
+ "x": 177.83577297942992,
+ "y": -131.4490470772947,
+ "z": 0.0
+ },
+ {
+ "x": 178.8412437310895,
+ "y": -131.4494963153034,
+ "z": 0.0
+ },
+ {
+ "x": 179.8467144827491,
+ "y": -131.44994555331212,
+ "z": 0.0
+ },
+ {
+ "x": 180.8521852344087,
+ "y": -131.4503947913208,
+ "z": 0.0
+ },
+ {
+ "x": 181.85765598606827,
+ "y": -131.45084402932952,
+ "z": 0.0
+ },
+ {
+ "x": 182.86312673772787,
+ "y": -131.45129326733823,
+ "z": 0.0
+ },
+ {
+ "x": 183.86859748938747,
+ "y": -131.45174250534694,
+ "z": 0.0
+ },
+ {
+ "x": 184.87406824104704,
+ "y": -131.45219174335566,
+ "z": 0.0
+ },
+ {
+ "x": 185.87953899270664,
+ "y": -131.45264098136437,
+ "z": 0.0
+ },
+ {
+ "x": 186.88500974436624,
+ "y": -131.45309021937308,
+ "z": 0.0
+ },
+ {
+ "x": 187.89048049602582,
+ "y": -131.4535394573818,
+ "z": 0.0
+ },
+ {
+ "x": 188.89595124768542,
+ "y": -131.45398869539048,
+ "z": 0.0
+ },
+ {
+ "x": 189.90142199934502,
+ "y": -131.4544379333992,
+ "z": 0.0
+ },
+ {
+ "x": 190.9068927510046,
+ "y": -131.4548871714079,
+ "z": 0.0
+ },
+ {
+ "x": 191.9123635026642,
+ "y": -131.45533640941662,
+ "z": 0.0
+ },
+ {
+ "x": 192.91783425432376,
+ "y": -131.45578564742533,
+ "z": 0.0
+ },
+ {
+ "x": 193.92330500598337,
+ "y": -131.45623488543404,
+ "z": 0.0
+ },
+ {
+ "x": 194.92877575764297,
+ "y": -131.45668412344276,
+ "z": 0.0
+ },
+ {
+ "x": 195.93424650930254,
+ "y": -131.45713336145144,
+ "z": 0.0
+ },
+ {
+ "x": 196.93971726096214,
+ "y": -131.45758259946015,
+ "z": 0.0
+ },
+ {
+ "x": 197.94518801262174,
+ "y": -131.45803183746887,
+ "z": 0.0
+ },
+ {
+ "x": 198.95065876428131,
+ "y": -131.45848107547758,
+ "z": 0.0
+ },
+ {
+ "x": 199.95612951594092,
+ "y": -131.4589303134863,
+ "z": 0.0
+ },
+ {
+ "x": 200.96160026760052,
+ "y": -131.459379551495,
+ "z": 0.0
+ },
+ {
+ "x": 201.9670710192601,
+ "y": -131.45982878950372,
+ "z": 0.0
+ },
+ {
+ "x": 202.9725417709197,
+ "y": -131.46027802751243,
+ "z": 0.0
+ },
+ {
+ "x": 203.9780125225793,
+ "y": -131.46072726552111,
+ "z": 0.0
+ },
+ {
+ "x": 204.98348327423886,
+ "y": -131.46117650352983,
+ "z": 0.0
+ },
+ {
+ "x": 205.98895402589847,
+ "y": -131.46162574153854,
+ "z": 0.0
+ },
+ {
+ "x": 206.99442477755807,
+ "y": -131.46207497954725,
+ "z": 0.0
+ },
+ {
+ "x": 207.99989552921764,
+ "y": -131.46252421755597,
+ "z": 0.0
+ },
+ {
+ "x": 209.00536628087724,
+ "y": -131.46297345556468,
+ "z": 0.0
+ },
+ {
+ "x": 210.01083703253684,
+ "y": -131.4634226935734,
+ "z": 0.0
+ },
+ {
+ "x": 211.0163077841964,
+ "y": -131.46387193158208,
+ "z": 0.0
+ },
+ {
+ "x": 212.02177853585601,
+ "y": -131.4643211695908,
+ "z": 0.0
+ },
+ {
+ "x": 213.02724928751562,
+ "y": -131.4647704075995,
+ "z": 0.0
+ },
+ {
+ "x": 214.0327200391752,
+ "y": -131.46521964560822,
+ "z": 0.0
+ },
+ {
+ "x": 215.0381907908348,
+ "y": -131.46566888361693,
+ "z": 0.0
+ },
+ {
+ "x": 216.0436615424944,
+ "y": -131.46611812162564,
+ "z": 0.0
+ },
+ {
+ "x": 217.04913229415396,
+ "y": -131.46656735963435,
+ "z": 0.0
+ },
+ {
+ "x": 218.05460304581356,
+ "y": -131.46701659764307,
+ "z": 0.0
+ },
+ {
+ "x": 219.06007379747317,
+ "y": -131.46746583565175,
+ "z": 0.0
+ },
+ {
+ "x": 220.06554454913274,
+ "y": -131.46791507366046,
+ "z": 0.0
+ },
+ {
+ "x": 221.07101530079234,
+ "y": -131.46836431166918,
+ "z": 0.0
+ },
+ {
+ "x": 222.07648605245194,
+ "y": -131.4688135496779,
+ "z": 0.0
+ },
+ {
+ "x": 223.0819568041115,
+ "y": -131.4692627876866,
+ "z": 0.0
+ },
+ {
+ "x": 224.08742755577111,
+ "y": -131.46971202569532,
+ "z": 0.0
+ },
+ {
+ "x": 225.0928983074307,
+ "y": -131.47016126370403,
+ "z": 0.0
+ },
+ {
+ "x": 226.0983690590903,
+ "y": -131.4706105017127,
+ "z": 0.0
+ },
+ {
+ "x": 227.1038398107499,
+ "y": -131.47105973972143,
+ "z": 0.0
+ },
+ {
+ "x": 228.10931056240946,
+ "y": -131.47150897773014,
+ "z": 0.0
+ },
+ {
+ "x": 229.11478131406906,
+ "y": -131.47195821573885,
+ "z": 0.0
+ },
+ {
+ "x": 230.12025206572866,
+ "y": -131.47240745374756,
+ "z": 0.0
+ },
+ {
+ "x": 231.12572281738824,
+ "y": -131.47285669175628,
+ "z": 0.0
+ },
+ {
+ "x": 232.1311935690478,
+ "y": -131.473305929765,
+ "z": 0.0
+ },
+ {
+ "x": 233.13666432070738,
+ "y": -131.4737551677737,
+ "z": 0.0
+ },
+ {
+ "x": 234.14213507236698,
+ "y": -131.4742044057824,
+ "z": 0.0
+ },
+ {
+ "x": 235.14760582402656,
+ "y": -131.4746536437911,
+ "z": 0.0
+ },
+ {
+ "x": 236.15307657568613,
+ "y": -131.4751028817998,
+ "z": 0.0
+ },
+ {
+ "x": 237.1585473273457,
+ "y": -131.47555211980853,
+ "z": 0.0
+ },
+ {
+ "x": 238.16401807900527,
+ "y": -131.47600135781724,
+ "z": 0.0
+ },
+ {
+ "x": 239.16948883066485,
+ "y": -131.47645059582595,
+ "z": 0.0
+ },
+ {
+ "x": 240.17495958232445,
+ "y": -131.47689983383466,
+ "z": 0.0
+ },
+ {
+ "x": 241.18043033398402,
+ "y": -131.47734907184335,
+ "z": 0.0
+ },
+ {
+ "x": 242.1859010856436,
+ "y": -131.47779830985206,
+ "z": 0.0
+ },
+ {
+ "x": 243.19137183730317,
+ "y": -131.47824754786078,
+ "z": 0.0
+ },
+ {
+ "x": 244.19684258896274,
+ "y": -131.4786967858695,
+ "z": 0.0
+ },
+ {
+ "x": 245.2023133406223,
+ "y": -131.4791460238782,
+ "z": 0.0
+ },
+ {
+ "x": 246.20778409228188,
+ "y": -131.4795952618869,
+ "z": 0.0
+ },
+ {
+ "x": 247.21325484394148,
+ "y": -131.48004449989563,
+ "z": 0.0
+ },
+ {
+ "x": 248.21872559560106,
+ "y": -131.48049373790434,
+ "z": 0.0
+ },
+ {
+ "x": 249.22419634726063,
+ "y": -131.48094297591302,
+ "z": 0.0
+ },
+ {
+ "x": 250.2296670989202,
+ "y": -131.48139221392174,
+ "z": 0.0
+ },
+ {
+ "x": 251.23513785057978,
+ "y": -131.48184145193045,
+ "z": 0.0
+ },
+ {
+ "x": 252.24060860223935,
+ "y": -131.48229068993916,
+ "z": 0.0
+ },
+ {
+ "x": 253.24607935389895,
+ "y": -131.48273992794788,
+ "z": 0.0
+ },
+ {
+ "x": 254.25155010555852,
+ "y": -131.4831891659566,
+ "z": 0.0
+ },
+ {
+ "x": 255.2570208572181,
+ "y": -131.4836384039653,
+ "z": 0.0
+ },
+ {
+ "x": 256.26249160887767,
+ "y": -131.48408764197399,
+ "z": 0.0
+ },
+ {
+ "x": 257.26796236053724,
+ "y": -131.4845368799827,
+ "z": 0.0
+ },
+ {
+ "x": 258.2734331121968,
+ "y": -131.4849861179914,
+ "z": 0.0
+ },
+ {
+ "x": 259.2789038638564,
+ "y": -131.48543535600012,
+ "z": 0.0
+ },
+ {
+ "x": 260.28437461551596,
+ "y": -131.48588459400884,
+ "z": 0.0
+ },
+ {
+ "x": 261.28984536717553,
+ "y": -131.48633383201755,
+ "z": 0.0
+ },
+ {
+ "x": 262.2953161188351,
+ "y": -131.48678307002626,
+ "z": 0.0
+ },
+ {
+ "x": 263.3007868704947,
+ "y": -131.48723230803498,
+ "z": 0.0
+ },
+ {
+ "x": 264.30625762215425,
+ "y": -131.48768154604366,
+ "z": 0.0
+ },
+ {
+ "x": 265.3117283738138,
+ "y": -131.48813078405237,
+ "z": 0.0
+ },
+ {
+ "x": 266.31719912547345,
+ "y": -131.4885800220611,
+ "z": 0.0
+ },
+ {
+ "x": 267.322669877133,
+ "y": -131.4890292600698,
+ "z": 0.0
+ },
+ {
+ "x": 268.3281406287926,
+ "y": -131.4894784980785,
+ "z": 0.0
+ },
+ {
+ "x": 269.33361138045217,
+ "y": -131.48992773608722,
+ "z": 0.0
+ },
+ {
+ "x": 270.33908213211174,
+ "y": -131.49037697409594,
+ "z": 0.0
+ },
+ {
+ "x": 271.3445528837713,
+ "y": -131.49082621210462,
+ "z": 0.0
+ },
+ {
+ "x": 272.3500236354309,
+ "y": -131.49127545011333,
+ "z": 0.0
+ },
+ {
+ "x": 273.35549438709046,
+ "y": -131.49172468812205,
+ "z": 0.0
+ },
+ {
+ "x": 274.36096513875003,
+ "y": -131.49217392613076,
+ "z": 0.0
+ },
+ {
+ "x": 275.3664358904096,
+ "y": -131.49262316413947,
+ "z": 0.0
+ },
+ {
+ "x": 276.3719066420692,
+ "y": -131.4930724021482,
+ "z": 0.0
+ },
+ {
+ "x": 277.37737739372875,
+ "y": -131.4935216401569,
+ "z": 0.0
+ },
+ {
+ "x": 278.3828481453884,
+ "y": -131.4939708781656,
+ "z": 0.0
+ },
+ {
+ "x": 279.38831889704795,
+ "y": -131.4944201161743,
+ "z": 0.0
+ },
+ {
+ "x": 280.3937896487075,
+ "y": -131.494869354183,
+ "z": 0.0
+ },
+ {
+ "x": 281.3992604003671,
+ "y": -131.49531859219172,
+ "z": 0.0
+ },
+ {
+ "x": 282.40473115202667,
+ "y": -131.49576783020044,
+ "z": 0.0
+ },
+ {
+ "x": 283.41020190368624,
+ "y": -131.49621706820915,
+ "z": 0.0
+ },
+ {
+ "x": 284.4156726553458,
+ "y": -131.49666630621786,
+ "z": 0.0
+ },
+ {
+ "x": 285.4211434070054,
+ "y": -131.49711554422657,
+ "z": 0.0
+ },
+ {
+ "x": 286.42661415866496,
+ "y": -131.49756478223526,
+ "z": 0.0
+ },
+ {
+ "x": 287.43208491032453,
+ "y": -131.49801402024397,
+ "z": 0.0
+ },
+ {
+ "x": 288.4375556619841,
+ "y": -131.49846325825268,
+ "z": 0.0
+ },
+ {
+ "x": 289.4430264136437,
+ "y": -131.4989124962614,
+ "z": 0.0
+ },
+ {
+ "x": 290.44849716530325,
+ "y": -131.4993617342701,
+ "z": 0.0
+ },
+ {
+ "x": 291.4539679169629,
+ "y": -131.49981097227882,
+ "z": 0.0
+ },
+ {
+ "x": 292.45943866862245,
+ "y": -131.50026021028754,
+ "z": 0.0
+ },
+ {
+ "x": 293.464909420282,
+ "y": -131.50070944829625,
+ "z": 0.0
+ },
+ {
+ "x": 294.4703801719416,
+ "y": -131.50115868630493,
+ "z": 0.0
+ },
+ {
+ "x": 295.4758509236012,
+ "y": -131.50160792431365,
+ "z": 0.0
+ },
+ {
+ "x": 296.48132167526074,
+ "y": -131.50205716232236,
+ "z": 0.0
+ },
+ {
+ "x": 297.4867924269203,
+ "y": -131.50250640033107,
+ "z": 0.0
+ },
+ {
+ "x": 298.4922631785799,
+ "y": -131.50295563833978,
+ "z": 0.0
+ },
+ {
+ "x": 299.49773393023946,
+ "y": -131.5034048763485,
+ "z": 0.0
+ },
+ {
+ "x": 300.50320468189904,
+ "y": -131.5038541143572,
+ "z": 0.0
+ },
+ {
+ "x": 301.5086754335586,
+ "y": -131.5043033523659,
+ "z": 0.0
+ },
+ {
+ "x": 302.5141461852182,
+ "y": -131.5047525903746,
+ "z": 0.0
+ },
+ {
+ "x": 303.51961693687775,
+ "y": -131.50520182838332,
+ "z": 0.0
+ },
+ {
+ "x": 304.5250876885374,
+ "y": -131.50565106639203,
+ "z": 0.0
+ },
+ {
+ "x": 305.53055844019696,
+ "y": -131.50610030440075,
+ "z": 0.0
+ },
+ {
+ "x": 306.5360291918565,
+ "y": -131.50654954240946,
+ "z": 0.0
+ },
+ {
+ "x": 307.5414999435161,
+ "y": -131.50699878041817,
+ "z": 0.0
+ },
+ {
+ "x": 308.5469706951757,
+ "y": -131.50744801842689,
+ "z": 0.0
+ },
+ {
+ "x": 309.55244144683525,
+ "y": -131.50789725643557,
+ "z": 0.0
+ },
+ {
+ "x": 310.5579121984948,
+ "y": -131.50834649444428,
+ "z": 0.0
+ },
+ {
+ "x": 311.5633829501544,
+ "y": -131.508795732453,
+ "z": 0.0
+ },
+ {
+ "x": 312.56885370181396,
+ "y": -131.5092449704617,
+ "z": 0.0
+ },
+ {
+ "x": 313.57432445347354,
+ "y": -131.50969420847042,
+ "z": 0.0
+ },
+ {
+ "x": 314.5797952051331,
+ "y": -131.51014344647913,
+ "z": 0.0
+ },
+ {
+ "x": 315.5852659567927,
+ "y": -131.51059268448785,
+ "z": 0.0
+ },
+ {
+ "x": 316.59073670845225,
+ "y": -131.51104192249653,
+ "z": 0.0
+ },
+ {
+ "x": 317.5962074601119,
+ "y": -131.51149116050524,
+ "z": 0.0
+ },
+ {
+ "x": 318.60167821177146,
+ "y": -131.51194039851396,
+ "z": 0.0
+ },
+ {
+ "x": 319.60714896343103,
+ "y": -131.51238963652267,
+ "z": 0.0
+ },
+ {
+ "x": 320.6126197150906,
+ "y": -131.51283887453138,
+ "z": 0.0
+ },
+ {
+ "x": 321.6180904667502,
+ "y": -131.5132881125401,
+ "z": 0.0
+ },
+ {
+ "x": 322.62356121840975,
+ "y": -131.5137373505488,
+ "z": 0.0
+ },
+ {
+ "x": 323.6290319700693,
+ "y": -131.51418658855752,
+ "z": 0.0
+ },
+ {
+ "x": 324.6345027217289,
+ "y": -131.5146358265662,
+ "z": 0.0
+ },
+ {
+ "x": 325.63997347338847,
+ "y": -131.51508506457492,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 23,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 325.6408670607218,
+ "y": -129.5150852641995,
+ "z": 0.0
+ },
+ {
+ "x": 324.63539630906223,
+ "y": -129.5146360261908,
+ "z": 0.0
+ },
+ {
+ "x": 323.62992555740266,
+ "y": -129.51418678818212,
+ "z": 0.0
+ },
+ {
+ "x": 322.6244548057431,
+ "y": -129.5137375501734,
+ "z": 0.0
+ },
+ {
+ "x": 321.6189840540835,
+ "y": -129.5132883121647,
+ "z": 0.0
+ },
+ {
+ "x": 320.61351330242394,
+ "y": -129.51283907415598,
+ "z": 0.0
+ },
+ {
+ "x": 319.60804255076437,
+ "y": -129.51238983614726,
+ "z": 0.0
+ },
+ {
+ "x": 318.6025717991048,
+ "y": -129.51194059813855,
+ "z": 0.0
+ },
+ {
+ "x": 317.5971010474452,
+ "y": -129.51149136012984,
+ "z": 0.0
+ },
+ {
+ "x": 316.59163029578565,
+ "y": -129.51104212212113,
+ "z": 0.0
+ },
+ {
+ "x": 315.58615954412596,
+ "y": -129.51059288411244,
+ "z": 0.0
+ },
+ {
+ "x": 314.5806887924665,
+ "y": -129.51014364610373,
+ "z": 0.0
+ },
+ {
+ "x": 313.57521804080693,
+ "y": -129.50969440809502,
+ "z": 0.0
+ },
+ {
+ "x": 312.56974728914736,
+ "y": -129.5092451700863,
+ "z": 0.0
+ },
+ {
+ "x": 311.5642765374878,
+ "y": -129.5087959320776,
+ "z": 0.0
+ },
+ {
+ "x": 310.5588057858282,
+ "y": -129.50834669406888,
+ "z": 0.0
+ },
+ {
+ "x": 309.55333503416864,
+ "y": -129.50789745606016,
+ "z": 0.0
+ },
+ {
+ "x": 308.54786428250895,
+ "y": -129.50744821805148,
+ "z": 0.0
+ },
+ {
+ "x": 307.5423935308495,
+ "y": -129.50699898004277,
+ "z": 0.0
+ },
+ {
+ "x": 306.5369227791899,
+ "y": -129.50654974203405,
+ "z": 0.0
+ },
+ {
+ "x": 305.53145202753035,
+ "y": -129.50610050402534,
+ "z": 0.0
+ },
+ {
+ "x": 304.5259812758708,
+ "y": -129.50565126601663,
+ "z": 0.0
+ },
+ {
+ "x": 303.5205105242111,
+ "y": -129.50520202800791,
+ "z": 0.0
+ },
+ {
+ "x": 302.5150397725515,
+ "y": -129.5047527899992,
+ "z": 0.0
+ },
+ {
+ "x": 301.50956902089195,
+ "y": -129.5043035519905,
+ "z": 0.0
+ },
+ {
+ "x": 300.5040982692324,
+ "y": -129.5038543139818,
+ "z": 0.0
+ },
+ {
+ "x": 299.4986275175728,
+ "y": -129.5034050759731,
+ "z": 0.0
+ },
+ {
+ "x": 298.4931567659132,
+ "y": -129.50295583796438,
+ "z": 0.0
+ },
+ {
+ "x": 297.48768601425365,
+ "y": -129.50250659995567,
+ "z": 0.0
+ },
+ {
+ "x": 296.4822152625941,
+ "y": -129.50205736194695,
+ "z": 0.0
+ },
+ {
+ "x": 295.4767445109345,
+ "y": -129.50160812393824,
+ "z": 0.0
+ },
+ {
+ "x": 294.47127375927494,
+ "y": -129.50115888592953,
+ "z": 0.0
+ },
+ {
+ "x": 293.46580300761536,
+ "y": -129.50070964792084,
+ "z": 0.0
+ },
+ {
+ "x": 292.4603322559558,
+ "y": -129.50026040991213,
+ "z": 0.0
+ },
+ {
+ "x": 291.4548615042962,
+ "y": -129.49981117190342,
+ "z": 0.0
+ },
+ {
+ "x": 290.44939075263665,
+ "y": -129.4993619338947,
+ "z": 0.0
+ },
+ {
+ "x": 289.4439200009771,
+ "y": -129.498912695886,
+ "z": 0.0
+ },
+ {
+ "x": 288.4384492493175,
+ "y": -129.49846345787728,
+ "z": 0.0
+ },
+ {
+ "x": 287.4329784976579,
+ "y": -129.49801421986857,
+ "z": 0.0
+ },
+ {
+ "x": 286.42750774599835,
+ "y": -129.49756498185985,
+ "z": 0.0
+ },
+ {
+ "x": 285.42203699433867,
+ "y": -129.49711574385117,
+ "z": 0.0
+ },
+ {
+ "x": 284.4165662426792,
+ "y": -129.49666650584246,
+ "z": 0.0
+ },
+ {
+ "x": 283.41109549101964,
+ "y": -129.49621726783374,
+ "z": 0.0
+ },
+ {
+ "x": 282.40562473936006,
+ "y": -129.49576802982503,
+ "z": 0.0
+ },
+ {
+ "x": 281.4001539877005,
+ "y": -129.49531879181632,
+ "z": 0.0
+ },
+ {
+ "x": 280.3946832360409,
+ "y": -129.4948695538076,
+ "z": 0.0
+ },
+ {
+ "x": 279.38921248438135,
+ "y": -129.4944203157989,
+ "z": 0.0
+ },
+ {
+ "x": 278.38374173272166,
+ "y": -129.4939710777902,
+ "z": 0.0
+ },
+ {
+ "x": 277.3782709810621,
+ "y": -129.4935218397815,
+ "z": 0.0
+ },
+ {
+ "x": 276.3728002294025,
+ "y": -129.49307260177278,
+ "z": 0.0
+ },
+ {
+ "x": 275.36732947774294,
+ "y": -129.49262336376407,
+ "z": 0.0
+ },
+ {
+ "x": 274.36185872608337,
+ "y": -129.49217412575535,
+ "z": 0.0
+ },
+ {
+ "x": 273.3563879744238,
+ "y": -129.49172488774664,
+ "z": 0.0
+ },
+ {
+ "x": 272.3509172227642,
+ "y": -129.49127564973793,
+ "z": 0.0
+ },
+ {
+ "x": 271.34544647110465,
+ "y": -129.49082641172922,
+ "z": 0.0
+ },
+ {
+ "x": 270.3399757194451,
+ "y": -129.49037717372053,
+ "z": 0.0
+ },
+ {
+ "x": 269.3345049677855,
+ "y": -129.48992793571182,
+ "z": 0.0
+ },
+ {
+ "x": 268.32903421612593,
+ "y": -129.4894786977031,
+ "z": 0.0
+ },
+ {
+ "x": 267.32356346446636,
+ "y": -129.4890294596944,
+ "z": 0.0
+ },
+ {
+ "x": 266.3180927128068,
+ "y": -129.48858022168568,
+ "z": 0.0
+ },
+ {
+ "x": 265.3126219611472,
+ "y": -129.48813098367697,
+ "z": 0.0
+ },
+ {
+ "x": 264.30715120948764,
+ "y": -129.48768174566825,
+ "z": 0.0
+ },
+ {
+ "x": 263.30168045782796,
+ "y": -129.48723250765957,
+ "z": 0.0
+ },
+ {
+ "x": 262.2962097061685,
+ "y": -129.48678326965086,
+ "z": 0.0
+ },
+ {
+ "x": 261.2907389545089,
+ "y": -129.48633403164214,
+ "z": 0.0
+ },
+ {
+ "x": 260.28526820284935,
+ "y": -129.48588479363343,
+ "z": 0.0
+ },
+ {
+ "x": 259.2797974511898,
+ "y": -129.48543555562472,
+ "z": 0.0
+ },
+ {
+ "x": 258.2743266995302,
+ "y": -129.484986317616,
+ "z": 0.0
+ },
+ {
+ "x": 257.26885594787063,
+ "y": -129.4845370796073,
+ "z": 0.0
+ },
+ {
+ "x": 256.26338519621106,
+ "y": -129.48408784159858,
+ "z": 0.0
+ },
+ {
+ "x": 255.2579144445514,
+ "y": -129.4836386035899,
+ "z": 0.0
+ },
+ {
+ "x": 254.2524436928919,
+ "y": -129.48318936558118,
+ "z": 0.0
+ },
+ {
+ "x": 253.24697294123231,
+ "y": -129.48274012757247,
+ "z": 0.0
+ },
+ {
+ "x": 252.2415021895727,
+ "y": -129.48229088956376,
+ "z": 0.0
+ },
+ {
+ "x": 251.23603143791314,
+ "y": -129.48184165155504,
+ "z": 0.0
+ },
+ {
+ "x": 250.23056068625357,
+ "y": -129.48139241354633,
+ "z": 0.0
+ },
+ {
+ "x": 249.225089934594,
+ "y": -129.48094317553762,
+ "z": 0.0
+ },
+ {
+ "x": 248.21961918293437,
+ "y": -129.48049393752893,
+ "z": 0.0
+ },
+ {
+ "x": 247.21414843127485,
+ "y": -129.48004469952022,
+ "z": 0.0
+ },
+ {
+ "x": 246.20867767961525,
+ "y": -129.4795954615115,
+ "z": 0.0
+ },
+ {
+ "x": 245.20320692795568,
+ "y": -129.4791462235028,
+ "z": 0.0
+ },
+ {
+ "x": 244.1977361762961,
+ "y": -129.47869698549408,
+ "z": 0.0
+ },
+ {
+ "x": 243.19226542463653,
+ "y": -129.47824774748537,
+ "z": 0.0
+ },
+ {
+ "x": 242.18679467297696,
+ "y": -129.47779850947666,
+ "z": 0.0
+ },
+ {
+ "x": 241.1813239213174,
+ "y": -129.47734927146794,
+ "z": 0.0
+ },
+ {
+ "x": 240.17585316965776,
+ "y": -129.47690003345926,
+ "z": 0.0
+ },
+ {
+ "x": 239.1703824179982,
+ "y": -129.47645079545055,
+ "z": 0.0
+ },
+ {
+ "x": 238.16491166633864,
+ "y": -129.47600155744183,
+ "z": 0.0
+ },
+ {
+ "x": 237.15944091467907,
+ "y": -129.47555231943312,
+ "z": 0.0
+ },
+ {
+ "x": 236.1539701630195,
+ "y": -129.4751030814244,
+ "z": 0.0
+ },
+ {
+ "x": 235.14849941135992,
+ "y": -129.4746538434157,
+ "z": 0.0
+ },
+ {
+ "x": 234.14302865970035,
+ "y": -129.47420460540698,
+ "z": 0.0
+ },
+ {
+ "x": 233.1375579080407,
+ "y": -129.4737553673983,
+ "z": 0.0
+ },
+ {
+ "x": 232.13208715638117,
+ "y": -129.47330612938958,
+ "z": 0.0
+ },
+ {
+ "x": 231.1266164047216,
+ "y": -129.47285689138087,
+ "z": 0.0
+ },
+ {
+ "x": 230.12114565306203,
+ "y": -129.47240765337216,
+ "z": 0.0
+ },
+ {
+ "x": 229.11567490140243,
+ "y": -129.47195841536345,
+ "z": 0.0
+ },
+ {
+ "x": 228.11020414974283,
+ "y": -129.47150917735473,
+ "z": 0.0
+ },
+ {
+ "x": 227.10473339808325,
+ "y": -129.47105993934602,
+ "z": 0.0
+ },
+ {
+ "x": 226.09926264642365,
+ "y": -129.4706107013373,
+ "z": 0.0
+ },
+ {
+ "x": 225.093791894764,
+ "y": -129.47016146332862,
+ "z": 0.0
+ },
+ {
+ "x": 224.08832114310448,
+ "y": -129.4697122253199,
+ "z": 0.0
+ },
+ {
+ "x": 223.08285039144488,
+ "y": -129.4692629873112,
+ "z": 0.0
+ },
+ {
+ "x": 222.0773796397853,
+ "y": -129.46881374930248,
+ "z": 0.0
+ },
+ {
+ "x": 221.0719088881257,
+ "y": -129.46836451129377,
+ "z": 0.0
+ },
+ {
+ "x": 220.0664381364661,
+ "y": -129.46791527328506,
+ "z": 0.0
+ },
+ {
+ "x": 219.06096738480653,
+ "y": -129.46746603527635,
+ "z": 0.0
+ },
+ {
+ "x": 218.05549663314687,
+ "y": -129.46701679726766,
+ "z": 0.0
+ },
+ {
+ "x": 217.05002588148733,
+ "y": -129.46656755925895,
+ "z": 0.0
+ },
+ {
+ "x": 216.04455512982776,
+ "y": -129.46611832125024,
+ "z": 0.0
+ },
+ {
+ "x": 215.03908437816816,
+ "y": -129.46566908324152,
+ "z": 0.0
+ },
+ {
+ "x": 214.03361362650855,
+ "y": -129.4652198452328,
+ "z": 0.0
+ },
+ {
+ "x": 213.02814287484898,
+ "y": -129.4647706072241,
+ "z": 0.0
+ },
+ {
+ "x": 212.02267212318938,
+ "y": -129.46432136921538,
+ "z": 0.0
+ },
+ {
+ "x": 211.01720137152978,
+ "y": -129.46387213120667,
+ "z": 0.0
+ },
+ {
+ "x": 210.01173061987015,
+ "y": -129.463422893198,
+ "z": 0.0
+ },
+ {
+ "x": 209.0062598682106,
+ "y": -129.46297365518927,
+ "z": 0.0
+ },
+ {
+ "x": 208.000789116551,
+ "y": -129.46252441718056,
+ "z": 0.0
+ },
+ {
+ "x": 206.99531836489143,
+ "y": -129.46207517917185,
+ "z": 0.0
+ },
+ {
+ "x": 205.98984761323183,
+ "y": -129.46162594116313,
+ "z": 0.0
+ },
+ {
+ "x": 204.98437686157223,
+ "y": -129.46117670315442,
+ "z": 0.0
+ },
+ {
+ "x": 203.97890610991266,
+ "y": -129.4607274651457,
+ "z": 0.0
+ },
+ {
+ "x": 202.973435358253,
+ "y": -129.46027822713702,
+ "z": 0.0
+ },
+ {
+ "x": 201.96796460659345,
+ "y": -129.4598289891283,
+ "z": 0.0
+ },
+ {
+ "x": 200.96249385493388,
+ "y": -129.4593797511196,
+ "z": 0.0
+ },
+ {
+ "x": 199.95702310327428,
+ "y": -129.4589305131109,
+ "z": 0.0
+ },
+ {
+ "x": 198.95155235161468,
+ "y": -129.45848127510217,
+ "z": 0.0
+ },
+ {
+ "x": 197.9460815999551,
+ "y": -129.45803203709346,
+ "z": 0.0
+ },
+ {
+ "x": 196.9406108482955,
+ "y": -129.45758279908475,
+ "z": 0.0
+ },
+ {
+ "x": 195.9351400966359,
+ "y": -129.45713356107603,
+ "z": 0.0
+ },
+ {
+ "x": 194.92966934497628,
+ "y": -129.45668432306735,
+ "z": 0.0
+ },
+ {
+ "x": 193.92419859331673,
+ "y": -129.45623508505864,
+ "z": 0.0
+ },
+ {
+ "x": 192.91872784165713,
+ "y": -129.45578584704992,
+ "z": 0.0
+ },
+ {
+ "x": 191.91325708999756,
+ "y": -129.4553366090412,
+ "z": 0.0
+ },
+ {
+ "x": 190.90778633833796,
+ "y": -129.4548873710325,
+ "z": 0.0
+ },
+ {
+ "x": 189.90231558667838,
+ "y": -129.45443813302379,
+ "z": 0.0
+ },
+ {
+ "x": 188.89684483501878,
+ "y": -129.45398889501507,
+ "z": 0.0
+ },
+ {
+ "x": 187.89137408335912,
+ "y": -129.4535396570064,
+ "z": 0.0
+ },
+ {
+ "x": 186.8859033316996,
+ "y": -129.45309041899768,
+ "z": 0.0
+ },
+ {
+ "x": 185.88043258004,
+ "y": -129.45264118098896,
+ "z": 0.0
+ },
+ {
+ "x": 184.8749618283804,
+ "y": -129.45219194298025,
+ "z": 0.0
+ },
+ {
+ "x": 183.86949107672083,
+ "y": -129.45174270497154,
+ "z": 0.0
+ },
+ {
+ "x": 182.86402032506123,
+ "y": -129.45129346696282,
+ "z": 0.0
+ },
+ {
+ "x": 181.85854957340163,
+ "y": -129.4508442289541,
+ "z": 0.0
+ },
+ {
+ "x": 180.85307882174206,
+ "y": -129.4503949909454,
+ "z": 0.0
+ },
+ {
+ "x": 179.8476080700824,
+ "y": -129.4499457529367,
+ "z": 0.0
+ },
+ {
+ "x": 178.84213731842286,
+ "y": -129.449496514928,
+ "z": 0.0
+ },
+ {
+ "x": 177.83666656676328,
+ "y": -129.4490472769193,
+ "z": 0.0
+ },
+ {
+ "x": 176.83119581510368,
+ "y": -129.44859803891057,
+ "z": 0.0
+ },
+ {
+ "x": 175.82572506344408,
+ "y": -129.44814880090186,
+ "z": 0.0
+ },
+ {
+ "x": 174.8202543117845,
+ "y": -129.44769956289315,
+ "z": 0.0
+ },
+ {
+ "x": 173.8147835601249,
+ "y": -129.44725032488444,
+ "z": 0.0
+ },
+ {
+ "x": 172.80931280846525,
+ "y": -129.44680108687575,
+ "z": 0.0
+ },
+ {
+ "x": 171.80384205680573,
+ "y": -129.44635184886704,
+ "z": 0.0
+ },
+ {
+ "x": 170.79837130514613,
+ "y": -129.44590261085833,
+ "z": 0.0
+ },
+ {
+ "x": 169.79290055348653,
+ "y": -129.4454533728496,
+ "z": 0.0
+ },
+ {
+ "x": 168.78742980182696,
+ "y": -129.4450041348409,
+ "z": 0.0
+ },
+ {
+ "x": 167.78195905016736,
+ "y": -129.4445548968322,
+ "z": 0.0
+ },
+ {
+ "x": 166.77648829850776,
+ "y": -129.44410565882347,
+ "z": 0.0
+ },
+ {
+ "x": 165.77101754684819,
+ "y": -129.44365642081476,
+ "z": 0.0
+ },
+ {
+ "x": 164.76554679518853,
+ "y": -129.44320718280608,
+ "z": 0.0
+ },
+ {
+ "x": 163.760076043529,
+ "y": -129.44275794479736,
+ "z": 0.0
+ },
+ {
+ "x": 162.7546052918694,
+ "y": -129.44230870678865,
+ "z": 0.0
+ },
+ {
+ "x": 161.74913454020984,
+ "y": -129.44185946877994,
+ "z": 0.0
+ },
+ {
+ "x": 160.74366378855026,
+ "y": -129.44141023077123,
+ "z": 0.0
+ },
+ {
+ "x": 159.73819303689066,
+ "y": -129.4409609927625,
+ "z": 0.0
+ },
+ {
+ "x": 158.7327222852311,
+ "y": -129.4405117547538,
+ "z": 0.0
+ },
+ {
+ "x": 157.72725153357143,
+ "y": -129.44006251674512,
+ "z": 0.0
+ },
+ {
+ "x": 156.72178078191192,
+ "y": -129.4396132787364,
+ "z": 0.0
+ },
+ {
+ "x": 155.71631003025234,
+ "y": -129.4391640407277,
+ "z": 0.0
+ },
+ {
+ "x": 154.71083927859274,
+ "y": -129.43871480271898,
+ "z": 0.0
+ },
+ {
+ "x": 153.70536852693317,
+ "y": -129.43826556471026,
+ "z": 0.0
+ },
+ {
+ "x": 152.69989777527357,
+ "y": -129.43781632670155,
+ "z": 0.0
+ },
+ {
+ "x": 151.694427023614,
+ "y": -129.43736708869284,
+ "z": 0.0
+ },
+ {
+ "x": 150.68895627195442,
+ "y": -129.43691785068413,
+ "z": 0.0
+ },
+ {
+ "x": 149.68348552029477,
+ "y": -129.43646861267544,
+ "z": 0.0
+ },
+ {
+ "x": 148.67801476863525,
+ "y": -129.43601937466673,
+ "z": 0.0
+ },
+ {
+ "x": 147.67254401697565,
+ "y": -129.43557013665801,
+ "z": 0.0
+ },
+ {
+ "x": 146.66707326531608,
+ "y": -129.4351208986493,
+ "z": 0.0
+ },
+ {
+ "x": 145.6616025136565,
+ "y": -129.4346716606406,
+ "z": 0.0
+ },
+ {
+ "x": 144.6561317619969,
+ "y": -129.43422242263188,
+ "z": 0.0
+ },
+ {
+ "x": 143.65066101033733,
+ "y": -129.43377318462316,
+ "z": 0.0
+ },
+ {
+ "x": 142.64519025867767,
+ "y": -129.43332394661448,
+ "z": 0.0
+ },
+ {
+ "x": 141.63971950701816,
+ "y": -129.43287470860577,
+ "z": 0.0
+ },
+ {
+ "x": 140.63424875535856,
+ "y": -129.43242547059705,
+ "z": 0.0
+ },
+ {
+ "x": 139.62877800369898,
+ "y": -129.43197623258834,
+ "z": 0.0
+ },
+ {
+ "x": 138.6233072520394,
+ "y": -129.43152699457963,
+ "z": 0.0
+ },
+ {
+ "x": 137.6178365003798,
+ "y": -129.43107775657091,
+ "z": 0.0
+ },
+ {
+ "x": 136.61236574872024,
+ "y": -129.4306285185622,
+ "z": 0.0
+ },
+ {
+ "x": 135.60689499706064,
+ "y": -129.4301792805535,
+ "z": 0.0
+ },
+ {
+ "x": 134.601424245401,
+ "y": -129.4297300425448,
+ "z": 0.0
+ },
+ {
+ "x": 133.5959534937415,
+ "y": -129.4292808045361,
+ "z": 0.0
+ },
+ {
+ "x": 132.5904827420819,
+ "y": -129.42883156652738,
+ "z": 0.0
+ },
+ {
+ "x": 131.58501199042232,
+ "y": -129.42838232851867,
+ "z": 0.0
+ },
+ {
+ "x": 130.57954123876272,
+ "y": -129.42793309050995,
+ "z": 0.0
+ },
+ {
+ "x": 129.57407048710314,
+ "y": -129.42748385250124,
+ "z": 0.0
+ },
+ {
+ "x": 128.56859973544354,
+ "y": -129.42703461449253,
+ "z": 0.0
+ },
+ {
+ "x": 127.56312898378388,
+ "y": -129.42658537648384,
+ "z": 0.0
+ },
+ {
+ "x": 126.55765823212437,
+ "y": -129.42613613847513,
+ "z": 0.0
+ },
+ {
+ "x": 125.55218748046477,
+ "y": -129.42568690046642,
+ "z": 0.0
+ },
+ {
+ "x": 124.5467167288052,
+ "y": -129.4252376624577,
+ "z": 0.0
+ },
+ {
+ "x": 123.54124597714559,
+ "y": -129.424788424449,
+ "z": 0.0
+ },
+ {
+ "x": 122.53577522548602,
+ "y": -129.42433918644028,
+ "z": 0.0
+ },
+ {
+ "x": 121.53030447382642,
+ "y": -129.42388994843157,
+ "z": 0.0
+ },
+ {
+ "x": 120.52483372216685,
+ "y": -129.42344071042285,
+ "z": 0.0
+ },
+ {
+ "x": 119.51936297050719,
+ "y": -129.42299147241417,
+ "z": 0.0
+ },
+ {
+ "x": 118.51389221884764,
+ "y": -129.42254223440546,
+ "z": 0.0
+ },
+ {
+ "x": 117.50842146718807,
+ "y": -129.42209299639674,
+ "z": 0.0
+ },
+ {
+ "x": 116.50295071552847,
+ "y": -129.42164375838803,
+ "z": 0.0
+ },
+ {
+ "x": 115.4974799638689,
+ "y": -129.42119452037932,
+ "z": 0.0
+ },
+ {
+ "x": 114.4920092122093,
+ "y": -129.4207452823706,
+ "z": 0.0
+ },
+ {
+ "x": 113.48653846054972,
+ "y": -129.4202960443619,
+ "z": 0.0
+ },
+ {
+ "x": 112.48106770889007,
+ "y": -129.4198468063532,
+ "z": 0.0
+ },
+ {
+ "x": 111.47559695723055,
+ "y": -129.4193975683445,
+ "z": 0.0
+ },
+ {
+ "x": 110.47012620557095,
+ "y": -129.41894833033578,
+ "z": 0.0
+ },
+ {
+ "x": 109.46465545391138,
+ "y": -129.41849909232707,
+ "z": 0.0
+ },
+ {
+ "x": 108.45918470225178,
+ "y": -129.41804985431835,
+ "z": 0.0
+ },
+ {
+ "x": 107.4537139505922,
+ "y": -129.41760061630964,
+ "z": 0.0
+ },
+ {
+ "x": 106.4482431989326,
+ "y": -129.41715137830093,
+ "z": 0.0
+ },
+ {
+ "x": 105.44277244727303,
+ "y": -129.41670214029222,
+ "z": 0.0
+ },
+ {
+ "x": 104.43730169561337,
+ "y": -129.41625290228353,
+ "z": 0.0
+ },
+ {
+ "x": 103.43183094395386,
+ "y": -129.41580366427482,
+ "z": 0.0
+ },
+ {
+ "x": 102.42636019229425,
+ "y": -129.4153544262661,
+ "z": 0.0
+ },
+ {
+ "x": 101.42088944063468,
+ "y": -129.4149051882574,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 24,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 101.41910226596795,
+ "y": -133.4149047890082,
+ "z": 0.0
+ },
+ {
+ "x": 102.42457301762755,
+ "y": -133.41535402701692,
+ "z": 0.0
+ },
+ {
+ "x": 103.43004376928712,
+ "y": -133.41580326502563,
+ "z": 0.0
+ },
+ {
+ "x": 104.43551452094678,
+ "y": -133.41625250303434,
+ "z": 0.0
+ },
+ {
+ "x": 105.4409852726063,
+ "y": -133.41670174104303,
+ "z": 0.0
+ },
+ {
+ "x": 106.4464560242659,
+ "y": -133.41715097905174,
+ "z": 0.0
+ },
+ {
+ "x": 107.45192677592547,
+ "y": -133.41760021706045,
+ "z": 0.0
+ },
+ {
+ "x": 108.45739752758507,
+ "y": -133.41804945506917,
+ "z": 0.0
+ },
+ {
+ "x": 109.46286827924465,
+ "y": -133.41849869307788,
+ "z": 0.0
+ },
+ {
+ "x": 110.46833903090425,
+ "y": -133.4189479310866,
+ "z": 0.0
+ },
+ {
+ "x": 111.47380978256382,
+ "y": -133.4193971690953,
+ "z": 0.0
+ },
+ {
+ "x": 112.47928053422348,
+ "y": -133.41984640710402,
+ "z": 0.0
+ },
+ {
+ "x": 113.484751285883,
+ "y": -133.4202956451127,
+ "z": 0.0
+ },
+ {
+ "x": 114.4902220375426,
+ "y": -133.42074488312142,
+ "z": 0.0
+ },
+ {
+ "x": 115.49569278920217,
+ "y": -133.42119412113013,
+ "z": 0.0
+ },
+ {
+ "x": 116.50116354086177,
+ "y": -133.42164335913884,
+ "z": 0.0
+ },
+ {
+ "x": 117.50663429252134,
+ "y": -133.42209259714755,
+ "z": 0.0
+ },
+ {
+ "x": 118.51210504418094,
+ "y": -133.42254183515627,
+ "z": 0.0
+ },
+ {
+ "x": 119.51757579584057,
+ "y": -133.42299107316498,
+ "z": 0.0
+ },
+ {
+ "x": 120.52304654750012,
+ "y": -133.42344031117366,
+ "z": 0.0
+ },
+ {
+ "x": 121.52851729915972,
+ "y": -133.42388954918238,
+ "z": 0.0
+ },
+ {
+ "x": 122.53398805081929,
+ "y": -133.4243387871911,
+ "z": 0.0
+ },
+ {
+ "x": 123.53945880247889,
+ "y": -133.4247880251998,
+ "z": 0.0
+ },
+ {
+ "x": 124.54492955413846,
+ "y": -133.42523726320852,
+ "z": 0.0
+ },
+ {
+ "x": 125.55040030579806,
+ "y": -133.42568650121723,
+ "z": 0.0
+ },
+ {
+ "x": 126.55587105745764,
+ "y": -133.42613573922594,
+ "z": 0.0
+ },
+ {
+ "x": 127.5613418091173,
+ "y": -133.42658497723465,
+ "z": 0.0
+ },
+ {
+ "x": 128.5668125607768,
+ "y": -133.42703421524334,
+ "z": 0.0
+ },
+ {
+ "x": 129.5722833124364,
+ "y": -133.42748345325205,
+ "z": 0.0
+ },
+ {
+ "x": 130.57775406409598,
+ "y": -133.42793269126076,
+ "z": 0.0
+ },
+ {
+ "x": 131.58322481575559,
+ "y": -133.42838192926948,
+ "z": 0.0
+ },
+ {
+ "x": 132.58869556741516,
+ "y": -133.4288311672782,
+ "z": 0.0
+ },
+ {
+ "x": 133.59416631907476,
+ "y": -133.4292804052869,
+ "z": 0.0
+ },
+ {
+ "x": 134.5996370707344,
+ "y": -133.42972964329562,
+ "z": 0.0
+ },
+ {
+ "x": 135.6051078223939,
+ "y": -133.4301788813043,
+ "z": 0.0
+ },
+ {
+ "x": 136.6105785740535,
+ "y": -133.430628119313,
+ "z": 0.0
+ },
+ {
+ "x": 137.61604932571308,
+ "y": -133.43107735732173,
+ "z": 0.0
+ },
+ {
+ "x": 138.62152007737268,
+ "y": -133.43152659533044,
+ "z": 0.0
+ },
+ {
+ "x": 139.62699082903225,
+ "y": -133.43197583333915,
+ "z": 0.0
+ },
+ {
+ "x": 140.63246158069182,
+ "y": -133.43242507134786,
+ "z": 0.0
+ },
+ {
+ "x": 141.63793233235143,
+ "y": -133.43287430935658,
+ "z": 0.0
+ },
+ {
+ "x": 142.64340308401106,
+ "y": -133.4333235473653,
+ "z": 0.0
+ },
+ {
+ "x": 143.6488738356706,
+ "y": -133.43377278537398,
+ "z": 0.0
+ },
+ {
+ "x": 144.65434458733017,
+ "y": -133.4342220233827,
+ "z": 0.0
+ },
+ {
+ "x": 145.65981533898977,
+ "y": -133.4346712613914,
+ "z": 0.0
+ },
+ {
+ "x": 146.66528609064935,
+ "y": -133.4351204994001,
+ "z": 0.0
+ },
+ {
+ "x": 147.67075684230892,
+ "y": -133.43556973740883,
+ "z": 0.0
+ },
+ {
+ "x": 148.67622759396852,
+ "y": -133.43601897541754,
+ "z": 0.0
+ },
+ {
+ "x": 149.68169834562815,
+ "y": -133.43646821342625,
+ "z": 0.0
+ },
+ {
+ "x": 150.6871690972877,
+ "y": -133.43691745143494,
+ "z": 0.0
+ },
+ {
+ "x": 151.69263984894727,
+ "y": -133.43736668944365,
+ "z": 0.0
+ },
+ {
+ "x": 152.69811060060684,
+ "y": -133.43781592745236,
+ "z": 0.0
+ },
+ {
+ "x": 153.70358135226644,
+ "y": -133.43826516546108,
+ "z": 0.0
+ },
+ {
+ "x": 154.709052103926,
+ "y": -133.4387144034698,
+ "z": 0.0
+ },
+ {
+ "x": 155.7145228555856,
+ "y": -133.4391636414785,
+ "z": 0.0
+ },
+ {
+ "x": 156.7199936072452,
+ "y": -133.4396128794872,
+ "z": 0.0
+ },
+ {
+ "x": 157.72546435890482,
+ "y": -133.44006211749593,
+ "z": 0.0
+ },
+ {
+ "x": 158.73093511056436,
+ "y": -133.4405113555046,
+ "z": 0.0
+ },
+ {
+ "x": 159.73640586222393,
+ "y": -133.44096059351332,
+ "z": 0.0
+ },
+ {
+ "x": 160.74187661388353,
+ "y": -133.44140983152204,
+ "z": 0.0
+ },
+ {
+ "x": 161.7473473655431,
+ "y": -133.44185906953075,
+ "z": 0.0
+ },
+ {
+ "x": 162.75281811720268,
+ "y": -133.44230830753946,
+ "z": 0.0
+ },
+ {
+ "x": 163.75828886886228,
+ "y": -133.44275754554818,
+ "z": 0.0
+ },
+ {
+ "x": 164.7637596205219,
+ "y": -133.4432067835569,
+ "z": 0.0
+ },
+ {
+ "x": 165.76923037218145,
+ "y": -133.44365602156557,
+ "z": 0.0
+ },
+ {
+ "x": 166.77470112384103,
+ "y": -133.4441052595743,
+ "z": 0.0
+ },
+ {
+ "x": 167.78017187550063,
+ "y": -133.444554497583,
+ "z": 0.0
+ },
+ {
+ "x": 168.78564262716023,
+ "y": -133.4450037355917,
+ "z": 0.0
+ },
+ {
+ "x": 169.7911133788198,
+ "y": -133.44545297360042,
+ "z": 0.0
+ },
+ {
+ "x": 170.7965841304794,
+ "y": -133.44590221160914,
+ "z": 0.0
+ },
+ {
+ "x": 171.802054882139,
+ "y": -133.44635144961785,
+ "z": 0.0
+ },
+ {
+ "x": 172.80752563379863,
+ "y": -133.44680068762656,
+ "z": 0.0
+ },
+ {
+ "x": 173.81299638545818,
+ "y": -133.44724992563525,
+ "z": 0.0
+ },
+ {
+ "x": 174.81846713711778,
+ "y": -133.44769916364396,
+ "z": 0.0
+ },
+ {
+ "x": 175.82393788877735,
+ "y": -133.44814840165267,
+ "z": 0.0
+ },
+ {
+ "x": 176.82940864043695,
+ "y": -133.4485976396614,
+ "z": 0.0
+ },
+ {
+ "x": 177.83487939209655,
+ "y": -133.4490468776701,
+ "z": 0.0
+ },
+ {
+ "x": 178.84035014375613,
+ "y": -133.4494961156788,
+ "z": 0.0
+ },
+ {
+ "x": 179.84582089541578,
+ "y": -133.44994535368753,
+ "z": 0.0
+ },
+ {
+ "x": 180.85129164707533,
+ "y": -133.4503945916962,
+ "z": 0.0
+ },
+ {
+ "x": 181.8567623987349,
+ "y": -133.45084382970492,
+ "z": 0.0
+ },
+ {
+ "x": 182.8622331503945,
+ "y": -133.45129306771364,
+ "z": 0.0
+ },
+ {
+ "x": 183.8677039020541,
+ "y": -133.45174230572235,
+ "z": 0.0
+ },
+ {
+ "x": 184.87317465371368,
+ "y": -133.45219154373106,
+ "z": 0.0
+ },
+ {
+ "x": 185.87864540537328,
+ "y": -133.45264078173977,
+ "z": 0.0
+ },
+ {
+ "x": 186.88411615703288,
+ "y": -133.4530900197485,
+ "z": 0.0
+ },
+ {
+ "x": 187.8895869086925,
+ "y": -133.4535392577572,
+ "z": 0.0
+ },
+ {
+ "x": 188.89505766035205,
+ "y": -133.45398849576588,
+ "z": 0.0
+ },
+ {
+ "x": 189.90052841201165,
+ "y": -133.4544377337746,
+ "z": 0.0
+ },
+ {
+ "x": 190.90599916367123,
+ "y": -133.4548869717833,
+ "z": 0.0
+ },
+ {
+ "x": 191.91146991533083,
+ "y": -133.45533620979202,
+ "z": 0.0
+ },
+ {
+ "x": 192.9169406669904,
+ "y": -133.45578544780074,
+ "z": 0.0
+ },
+ {
+ "x": 193.92241141865,
+ "y": -133.45623468580945,
+ "z": 0.0
+ },
+ {
+ "x": 194.92788217030966,
+ "y": -133.45668392381816,
+ "z": 0.0
+ },
+ {
+ "x": 195.93335292196917,
+ "y": -133.45713316182685,
+ "z": 0.0
+ },
+ {
+ "x": 196.93882367362878,
+ "y": -133.45758239983556,
+ "z": 0.0
+ },
+ {
+ "x": 197.94429442528838,
+ "y": -133.45803163784427,
+ "z": 0.0
+ },
+ {
+ "x": 198.94976517694795,
+ "y": -133.45848087585298,
+ "z": 0.0
+ },
+ {
+ "x": 199.95523592860755,
+ "y": -133.4589301138617,
+ "z": 0.0
+ },
+ {
+ "x": 200.96070668026715,
+ "y": -133.4593793518704,
+ "z": 0.0
+ },
+ {
+ "x": 201.96617743192672,
+ "y": -133.45982858987912,
+ "z": 0.0
+ },
+ {
+ "x": 202.97164818358638,
+ "y": -133.46027782788784,
+ "z": 0.0
+ },
+ {
+ "x": 203.97711893524593,
+ "y": -133.46072706589652,
+ "z": 0.0
+ },
+ {
+ "x": 204.9825896869055,
+ "y": -133.46117630390523,
+ "z": 0.0
+ },
+ {
+ "x": 205.9880604385651,
+ "y": -133.46162554191395,
+ "z": 0.0
+ },
+ {
+ "x": 206.9935311902247,
+ "y": -133.46207477992266,
+ "z": 0.0
+ },
+ {
+ "x": 207.99900194188427,
+ "y": -133.46252401793137,
+ "z": 0.0
+ },
+ {
+ "x": 209.00447269354387,
+ "y": -133.46297325594008,
+ "z": 0.0
+ },
+ {
+ "x": 210.00994344520353,
+ "y": -133.4634224939488,
+ "z": 0.0
+ },
+ {
+ "x": 211.01541419686305,
+ "y": -133.46387173195748,
+ "z": 0.0
+ },
+ {
+ "x": 212.02088494852265,
+ "y": -133.4643209699662,
+ "z": 0.0
+ },
+ {
+ "x": 213.02635570018225,
+ "y": -133.4647702079749,
+ "z": 0.0
+ },
+ {
+ "x": 214.03182645184182,
+ "y": -133.46521944598362,
+ "z": 0.0
+ },
+ {
+ "x": 215.03729720350142,
+ "y": -133.46566868399233,
+ "z": 0.0
+ },
+ {
+ "x": 216.04276795516103,
+ "y": -133.46611792200105,
+ "z": 0.0
+ },
+ {
+ "x": 217.0482387068206,
+ "y": -133.46656716000976,
+ "z": 0.0
+ },
+ {
+ "x": 218.05370945848026,
+ "y": -133.46701639801847,
+ "z": 0.0
+ },
+ {
+ "x": 219.0591802101398,
+ "y": -133.46746563602716,
+ "z": 0.0
+ },
+ {
+ "x": 220.06465096179937,
+ "y": -133.46791487403587,
+ "z": 0.0
+ },
+ {
+ "x": 221.07012171345897,
+ "y": -133.46836411204458,
+ "z": 0.0
+ },
+ {
+ "x": 222.07559246511858,
+ "y": -133.4688133500533,
+ "z": 0.0
+ },
+ {
+ "x": 223.08106321677815,
+ "y": -133.469262588062,
+ "z": 0.0
+ },
+ {
+ "x": 224.08653396843775,
+ "y": -133.46971182607072,
+ "z": 0.0
+ },
+ {
+ "x": 225.09200472009738,
+ "y": -133.47016106407943,
+ "z": 0.0
+ },
+ {
+ "x": 226.09747547175692,
+ "y": -133.47061030208812,
+ "z": 0.0
+ },
+ {
+ "x": 227.10294622341652,
+ "y": -133.47105954009683,
+ "z": 0.0
+ },
+ {
+ "x": 228.1084169750761,
+ "y": -133.47150877810554,
+ "z": 0.0
+ },
+ {
+ "x": 229.1138877267357,
+ "y": -133.47195801611426,
+ "z": 0.0
+ },
+ {
+ "x": 230.1193584783953,
+ "y": -133.47240725412297,
+ "z": 0.0
+ },
+ {
+ "x": 231.12482923005487,
+ "y": -133.47285649213168,
+ "z": 0.0
+ },
+ {
+ "x": 232.13029998171444,
+ "y": -133.4733057301404,
+ "z": 0.0
+ },
+ {
+ "x": 233.13577073337407,
+ "y": -133.4737549681491,
+ "z": 0.0
+ },
+ {
+ "x": 234.14124148503362,
+ "y": -133.4742042061578,
+ "z": 0.0
+ },
+ {
+ "x": 235.1467122366932,
+ "y": -133.4746534441665,
+ "z": 0.0
+ },
+ {
+ "x": 236.15218298835276,
+ "y": -133.47510268217522,
+ "z": 0.0
+ },
+ {
+ "x": 237.15765374001234,
+ "y": -133.47555192018393,
+ "z": 0.0
+ },
+ {
+ "x": 238.1631244916719,
+ "y": -133.47600115819264,
+ "z": 0.0
+ },
+ {
+ "x": 239.16859524333148,
+ "y": -133.47645039620136,
+ "z": 0.0
+ },
+ {
+ "x": 240.17406599499114,
+ "y": -133.47689963421007,
+ "z": 0.0
+ },
+ {
+ "x": 241.17953674665065,
+ "y": -133.47734887221876,
+ "z": 0.0
+ },
+ {
+ "x": 242.18500749831023,
+ "y": -133.47779811022747,
+ "z": 0.0
+ },
+ {
+ "x": 243.1904782499698,
+ "y": -133.47824734823618,
+ "z": 0.0
+ },
+ {
+ "x": 244.19594900162937,
+ "y": -133.4786965862449,
+ "z": 0.0
+ },
+ {
+ "x": 245.20141975328895,
+ "y": -133.4791458242536,
+ "z": 0.0
+ },
+ {
+ "x": 246.20689050494852,
+ "y": -133.47959506226232,
+ "z": 0.0
+ },
+ {
+ "x": 247.21236125660812,
+ "y": -133.48004430027103,
+ "z": 0.0
+ },
+ {
+ "x": 248.21783200826775,
+ "y": -133.48049353827975,
+ "z": 0.0
+ },
+ {
+ "x": 249.22330275992726,
+ "y": -133.48094277628843,
+ "z": 0.0
+ },
+ {
+ "x": 250.22877351158684,
+ "y": -133.48139201429714,
+ "z": 0.0
+ },
+ {
+ "x": 251.2342442632464,
+ "y": -133.48184125230586,
+ "z": 0.0
+ },
+ {
+ "x": 252.23971501490598,
+ "y": -133.48229049031457,
+ "z": 0.0
+ },
+ {
+ "x": 253.24518576656558,
+ "y": -133.48273972832328,
+ "z": 0.0
+ },
+ {
+ "x": 254.25065651822516,
+ "y": -133.483188966332,
+ "z": 0.0
+ },
+ {
+ "x": 255.2561272698848,
+ "y": -133.4836382043407,
+ "z": 0.0
+ },
+ {
+ "x": 256.2615980215443,
+ "y": -133.4840874423494,
+ "z": 0.0
+ },
+ {
+ "x": 257.26706877320385,
+ "y": -133.4845366803581,
+ "z": 0.0
+ },
+ {
+ "x": 258.2725395248634,
+ "y": -133.48498591836682,
+ "z": 0.0
+ },
+ {
+ "x": 259.278010276523,
+ "y": -133.48543515637553,
+ "z": 0.0
+ },
+ {
+ "x": 260.28348102818256,
+ "y": -133.48588439438424,
+ "z": 0.0
+ },
+ {
+ "x": 261.28895177984214,
+ "y": -133.48633363239296,
+ "z": 0.0
+ },
+ {
+ "x": 262.2944225315017,
+ "y": -133.48678287040167,
+ "z": 0.0
+ },
+ {
+ "x": 263.2998932831614,
+ "y": -133.48723210841038,
+ "z": 0.0
+ },
+ {
+ "x": 264.30536403482085,
+ "y": -133.48768134641907,
+ "z": 0.0
+ },
+ {
+ "x": 265.3108347864804,
+ "y": -133.48813058442778,
+ "z": 0.0
+ },
+ {
+ "x": 266.3163055381401,
+ "y": -133.4885798224365,
+ "z": 0.0
+ },
+ {
+ "x": 267.3217762897997,
+ "y": -133.4890290604452,
+ "z": 0.0
+ },
+ {
+ "x": 268.32724704145926,
+ "y": -133.48947829845392,
+ "z": 0.0
+ },
+ {
+ "x": 269.33271779311883,
+ "y": -133.48992753646263,
+ "z": 0.0
+ },
+ {
+ "x": 270.3381885447784,
+ "y": -133.49037677447134,
+ "z": 0.0
+ },
+ {
+ "x": 271.343659296438,
+ "y": -133.49082601248003,
+ "z": 0.0
+ },
+ {
+ "x": 272.34913004809755,
+ "y": -133.49127525048874,
+ "z": 0.0
+ },
+ {
+ "x": 273.3546007997571,
+ "y": -133.49172448849745,
+ "z": 0.0
+ },
+ {
+ "x": 274.3600715514167,
+ "y": -133.49217372650617,
+ "z": 0.0
+ },
+ {
+ "x": 275.36554230307627,
+ "y": -133.49262296451488,
+ "z": 0.0
+ },
+ {
+ "x": 276.37101305473584,
+ "y": -133.4930722025236,
+ "z": 0.0
+ },
+ {
+ "x": 277.3764838063954,
+ "y": -133.4935214405323,
+ "z": 0.0
+ },
+ {
+ "x": 278.3819545580551,
+ "y": -133.49397067854102,
+ "z": 0.0
+ },
+ {
+ "x": 279.38742530971456,
+ "y": -133.4944199165497,
+ "z": 0.0
+ },
+ {
+ "x": 280.39289606137413,
+ "y": -133.49486915455842,
+ "z": 0.0
+ },
+ {
+ "x": 281.3983668130337,
+ "y": -133.49531839256713,
+ "z": 0.0
+ },
+ {
+ "x": 282.4038375646933,
+ "y": -133.49576763057584,
+ "z": 0.0
+ },
+ {
+ "x": 283.40930831635285,
+ "y": -133.49621686858455,
+ "z": 0.0
+ },
+ {
+ "x": 284.4147790680124,
+ "y": -133.49666610659327,
+ "z": 0.0
+ },
+ {
+ "x": 285.4202498196721,
+ "y": -133.49711534460198,
+ "z": 0.0
+ },
+ {
+ "x": 286.42572057133157,
+ "y": -133.49756458261066,
+ "z": 0.0
+ },
+ {
+ "x": 287.43119132299114,
+ "y": -133.49801382061938,
+ "z": 0.0
+ },
+ {
+ "x": 288.4366620746507,
+ "y": -133.4984630586281,
+ "z": 0.0
+ },
+ {
+ "x": 289.4421328263103,
+ "y": -133.4989122966368,
+ "z": 0.0
+ },
+ {
+ "x": 290.44760357796986,
+ "y": -133.49936153464552,
+ "z": 0.0
+ },
+ {
+ "x": 291.45307432962954,
+ "y": -133.49981077265423,
+ "z": 0.0
+ },
+ {
+ "x": 292.4585450812891,
+ "y": -133.50026001066294,
+ "z": 0.0
+ },
+ {
+ "x": 293.4640158329487,
+ "y": -133.50070924867165,
+ "z": 0.0
+ },
+ {
+ "x": 294.46948658460826,
+ "y": -133.50115848668034,
+ "z": 0.0
+ },
+ {
+ "x": 295.47495733626783,
+ "y": -133.50160772468905,
+ "z": 0.0
+ },
+ {
+ "x": 296.4804280879274,
+ "y": -133.50205696269776,
+ "z": 0.0
+ },
+ {
+ "x": 297.485898839587,
+ "y": -133.50250620070648,
+ "z": 0.0
+ },
+ {
+ "x": 298.49136959124655,
+ "y": -133.5029554387152,
+ "z": 0.0
+ },
+ {
+ "x": 299.4968403429061,
+ "y": -133.5034046767239,
+ "z": 0.0
+ },
+ {
+ "x": 300.5023110945657,
+ "y": -133.50385391473262,
+ "z": 0.0
+ },
+ {
+ "x": 301.50778184622527,
+ "y": -133.5043031527413,
+ "z": 0.0
+ },
+ {
+ "x": 302.51325259788484,
+ "y": -133.50475239075,
+ "z": 0.0
+ },
+ {
+ "x": 303.5187233495444,
+ "y": -133.50520162875873,
+ "z": 0.0
+ },
+ {
+ "x": 304.524194101204,
+ "y": -133.50565086676744,
+ "z": 0.0
+ },
+ {
+ "x": 305.52966485286356,
+ "y": -133.50610010477615,
+ "z": 0.0
+ },
+ {
+ "x": 306.53513560452313,
+ "y": -133.50654934278487,
+ "z": 0.0
+ },
+ {
+ "x": 307.5406063561827,
+ "y": -133.50699858079358,
+ "z": 0.0
+ },
+ {
+ "x": 308.5460771078424,
+ "y": -133.5074478188023,
+ "z": 0.0
+ },
+ {
+ "x": 309.55154785950185,
+ "y": -133.50789705681098,
+ "z": 0.0
+ },
+ {
+ "x": 310.5570186111614,
+ "y": -133.5083462948197,
+ "z": 0.0
+ },
+ {
+ "x": 311.562489362821,
+ "y": -133.5087955328284,
+ "z": 0.0
+ },
+ {
+ "x": 312.56796011448057,
+ "y": -133.5092447708371,
+ "z": 0.0
+ },
+ {
+ "x": 313.57343086614014,
+ "y": -133.50969400884583,
+ "z": 0.0
+ },
+ {
+ "x": 314.5789016177997,
+ "y": -133.51014324685454,
+ "z": 0.0
+ },
+ {
+ "x": 315.5843723694594,
+ "y": -133.51059248486325,
+ "z": 0.0
+ },
+ {
+ "x": 316.58984312111886,
+ "y": -133.51104172287194,
+ "z": 0.0
+ },
+ {
+ "x": 317.59531387277855,
+ "y": -133.51149096088065,
+ "z": 0.0
+ },
+ {
+ "x": 318.6007846244381,
+ "y": -133.51194019888936,
+ "z": 0.0
+ },
+ {
+ "x": 319.6062553760977,
+ "y": -133.51238943689808,
+ "z": 0.0
+ },
+ {
+ "x": 320.61172612775727,
+ "y": -133.5128386749068,
+ "z": 0.0
+ },
+ {
+ "x": 321.61719687941684,
+ "y": -133.5132879129155,
+ "z": 0.0
+ },
+ {
+ "x": 322.6226676310764,
+ "y": -133.51373715092421,
+ "z": 0.0
+ },
+ {
+ "x": 323.628138382736,
+ "y": -133.51418638893293,
+ "z": 0.0
+ },
+ {
+ "x": 324.63360913439556,
+ "y": -133.5146356269416,
+ "z": 0.0
+ },
+ {
+ "x": 325.63907988605513,
+ "y": -133.51508486495032,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 25,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 79.64213303769317,
+ "y": -324.57727938928275,
+ "z": 0.0
+ },
+ {
+ "x": 78.6330027477079,
+ "y": -324.5767387981524,
+ "z": 0.0
+ },
+ {
+ "x": 77.62387245772217,
+ "y": -324.5761982070222,
+ "z": 0.0
+ },
+ {
+ "x": 76.61474216773736,
+ "y": -324.5756576158918,
+ "z": 0.0
+ },
+ {
+ "x": 75.60561187775163,
+ "y": -324.5751170247616,
+ "z": 0.0
+ },
+ {
+ "x": 74.59648158776682,
+ "y": -324.57457643363125,
+ "z": 0.0
+ },
+ {
+ "x": 73.58735129778131,
+ "y": -324.57403584250096,
+ "z": 0.0
+ },
+ {
+ "x": 72.57822100779582,
+ "y": -324.57349525137073,
+ "z": 0.0
+ },
+ {
+ "x": 71.569090717811,
+ "y": -324.5729546602404,
+ "z": 0.0
+ },
+ {
+ "x": 70.5599604278255,
+ "y": -324.5724140691101,
+ "z": 0.0
+ },
+ {
+ "x": 69.55083013784022,
+ "y": -324.5718734779798,
+ "z": 0.0
+ },
+ {
+ "x": 68.54169984785494,
+ "y": -324.5713328868495,
+ "z": 0.0
+ },
+ {
+ "x": 67.53256955786968,
+ "y": -324.57079229571923,
+ "z": 0.0
+ },
+ {
+ "x": 66.5234392678844,
+ "y": -324.57025170458894,
+ "z": 0.0
+ },
+ {
+ "x": 65.51430897789913,
+ "y": -324.56971111345865,
+ "z": 0.0
+ },
+ {
+ "x": 64.50517868791385,
+ "y": -324.56917052232836,
+ "z": 0.0
+ },
+ {
+ "x": 63.496048397928575,
+ "y": -324.5686299311981,
+ "z": 0.0
+ },
+ {
+ "x": 62.486918107943296,
+ "y": -324.5680893400678,
+ "z": 0.0
+ },
+ {
+ "x": 61.477787817958024,
+ "y": -324.5675487489375,
+ "z": 0.0
+ },
+ {
+ "x": 60.468657527972745,
+ "y": -324.5670081578072,
+ "z": 0.0
+ },
+ {
+ "x": 59.45952723798747,
+ "y": -324.5664675666769,
+ "z": 0.0
+ },
+ {
+ "x": 58.450396948002194,
+ "y": -324.56592697554663,
+ "z": 0.0
+ },
+ {
+ "x": 57.441266658016914,
+ "y": -324.56538638441634,
+ "z": 0.0
+ },
+ {
+ "x": 56.43213636803164,
+ "y": -324.56484579328605,
+ "z": 0.0
+ },
+ {
+ "x": 55.42300607804658,
+ "y": -324.5643052021557,
+ "z": 0.0
+ },
+ {
+ "x": 54.41387578806109,
+ "y": -324.5637646110254,
+ "z": 0.0
+ },
+ {
+ "x": 53.404745498075584,
+ "y": -324.5632240198952,
+ "z": 0.0
+ },
+ {
+ "x": 52.39561520809054,
+ "y": -324.5626834287649,
+ "z": 0.0
+ },
+ {
+ "x": 51.38648491810525,
+ "y": -324.5621428376346,
+ "z": 0.0
+ },
+ {
+ "x": 50.37735462812019,
+ "y": -324.56160224650426,
+ "z": 0.0
+ },
+ {
+ "x": 49.368224338134695,
+ "y": -324.561061655374,
+ "z": 0.0
+ },
+ {
+ "x": 48.35909404814919,
+ "y": -324.56052106424374,
+ "z": 0.0
+ },
+ {
+ "x": 47.349963758164144,
+ "y": -324.55998047311346,
+ "z": 0.0
+ },
+ {
+ "x": 46.340833468179085,
+ "y": -324.5594398819831,
+ "z": 0.0
+ },
+ {
+ "x": 45.33170317819359,
+ "y": -324.5588992908528,
+ "z": 0.0
+ },
+ {
+ "x": 44.32257288820831,
+ "y": -324.55835869972253,
+ "z": 0.0
+ },
+ {
+ "x": 43.31344259822304,
+ "y": -324.55781810859224,
+ "z": 0.0
+ },
+ {
+ "x": 42.30431230823776,
+ "y": -324.55727751746196,
+ "z": 0.0
+ },
+ {
+ "x": 41.29518201825249,
+ "y": -324.55673692633167,
+ "z": 0.0
+ },
+ {
+ "x": 40.28605172826721,
+ "y": -324.5561963352014,
+ "z": 0.0
+ },
+ {
+ "x": 39.27692143828194,
+ "y": -324.5556557440711,
+ "z": 0.0
+ },
+ {
+ "x": 38.26779114829666,
+ "y": -324.5551151529408,
+ "z": 0.0
+ },
+ {
+ "x": 37.25866085831138,
+ "y": -324.5545745618105,
+ "z": 0.0
+ },
+ {
+ "x": 36.24953056832611,
+ "y": -324.5540339706802,
+ "z": 0.0
+ },
+ {
+ "x": 35.24040027834083,
+ "y": -324.55349337954993,
+ "z": 0.0
+ },
+ {
+ "x": 34.23126998835556,
+ "y": -324.55295278841965,
+ "z": 0.0
+ },
+ {
+ "x": 33.22213969837028,
+ "y": -324.55241219728936,
+ "z": 0.0
+ },
+ {
+ "x": 32.213009408385,
+ "y": -324.55187160615907,
+ "z": 0.0
+ },
+ {
+ "x": 31.203879118399723,
+ "y": -324.5513310150288,
+ "z": 0.0
+ },
+ {
+ "x": 30.19474882841467,
+ "y": -324.55079042389843,
+ "z": 0.0
+ },
+ {
+ "x": 29.185618538428944,
+ "y": -324.5502498327682,
+ "z": 0.0
+ },
+ {
+ "x": 28.176488248443892,
+ "y": -324.5497092416379,
+ "z": 0.0
+ },
+ {
+ "x": 27.167357958458613,
+ "y": -324.5491686505076,
+ "z": 0.0
+ },
+ {
+ "x": 26.158227668473337,
+ "y": -324.54862805937734,
+ "z": 0.0
+ },
+ {
+ "x": 25.14909737848829,
+ "y": -324.548087468247,
+ "z": 0.0
+ },
+ {
+ "x": 24.139967088502562,
+ "y": -324.54754687711676,
+ "z": 0.0
+ },
+ {
+ "x": 23.130836798517738,
+ "y": -324.5470062859864,
+ "z": 0.0
+ },
+ {
+ "x": 22.121706508532235,
+ "y": -324.5464656948561,
+ "z": 0.0
+ },
+ {
+ "x": 21.11257621854673,
+ "y": -324.5459251037259,
+ "z": 0.0
+ },
+ {
+ "x": 20.103445928561907,
+ "y": -324.54538451259555,
+ "z": 0.0
+ },
+ {
+ "x": 19.094315638576404,
+ "y": -324.54484392146526,
+ "z": 0.0
+ },
+ {
+ "x": 18.08518534859113,
+ "y": -324.54430333033497,
+ "z": 0.0
+ },
+ {
+ "x": 17.076055058605853,
+ "y": -324.5437627392047,
+ "z": 0.0
+ },
+ {
+ "x": 16.06692476862035,
+ "y": -324.54322214807445,
+ "z": 0.0
+ },
+ {
+ "x": 15.057794478635525,
+ "y": -324.5426815569441,
+ "z": 0.0
+ },
+ {
+ "x": 14.048664188650024,
+ "y": -324.5421409658138,
+ "z": 0.0
+ },
+ {
+ "x": 13.039533898664747,
+ "y": -324.5416003746835,
+ "z": 0.0
+ },
+ {
+ "x": 12.030403608679471,
+ "y": -324.54105978355324,
+ "z": 0.0
+ },
+ {
+ "x": 11.021273318694194,
+ "y": -324.54051919242295,
+ "z": 0.0
+ },
+ {
+ "x": 10.012143028708918,
+ "y": -324.53997860129266,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 26,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 10.007857429054754,
+ "y": -332.53997745339484,
+ "z": 0.0
+ },
+ {
+ "x": 11.01698771904003,
+ "y": -332.54051804452513,
+ "z": 0.0
+ },
+ {
+ "x": 12.026118009025307,
+ "y": -332.5410586356554,
+ "z": 0.0
+ },
+ {
+ "x": 13.035248299010583,
+ "y": -332.5415992267857,
+ "z": 0.0
+ },
+ {
+ "x": 14.04437858899586,
+ "y": -332.542139817916,
+ "z": 0.0
+ },
+ {
+ "x": 15.05350887898091,
+ "y": -332.5426804090463,
+ "z": 0.0
+ },
+ {
+ "x": 16.062639168966637,
+ "y": -332.54322100017663,
+ "z": 0.0
+ },
+ {
+ "x": 17.071769458951692,
+ "y": -332.54376159130686,
+ "z": 0.0
+ },
+ {
+ "x": 18.080899748936968,
+ "y": -332.54430218243715,
+ "z": 0.0
+ },
+ {
+ "x": 19.090030038922244,
+ "y": -332.54484277356744,
+ "z": 0.0
+ },
+ {
+ "x": 20.099160328907292,
+ "y": -332.5453833646977,
+ "z": 0.0
+ },
+ {
+ "x": 21.10829061889302,
+ "y": -332.5459239558281,
+ "z": 0.0
+ },
+ {
+ "x": 22.117420908878074,
+ "y": -332.5464645469583,
+ "z": 0.0
+ },
+ {
+ "x": 23.126551198863122,
+ "y": -332.5470051380886,
+ "z": 0.0
+ },
+ {
+ "x": 24.13568148884885,
+ "y": -332.54754572921894,
+ "z": 0.0
+ },
+ {
+ "x": 25.144811778833674,
+ "y": -332.54808632034917,
+ "z": 0.0
+ },
+ {
+ "x": 26.153942068819177,
+ "y": -332.5486269114795,
+ "z": 0.0
+ },
+ {
+ "x": 27.163072358804452,
+ "y": -332.5491675026098,
+ "z": 0.0
+ },
+ {
+ "x": 28.17220264878973,
+ "y": -332.5497080937401,
+ "z": 0.0
+ },
+ {
+ "x": 29.18133293877523,
+ "y": -332.5502486848704,
+ "z": 0.0
+ },
+ {
+ "x": 30.190463228760056,
+ "y": -332.5507892760006,
+ "z": 0.0
+ },
+ {
+ "x": 31.199593518745562,
+ "y": -332.55132986713096,
+ "z": 0.0
+ },
+ {
+ "x": 32.20872380873083,
+ "y": -332.55187045826125,
+ "z": 0.0
+ },
+ {
+ "x": 33.21785409871611,
+ "y": -332.55241104939154,
+ "z": 0.0
+ },
+ {
+ "x": 34.22698438870139,
+ "y": -332.5529516405218,
+ "z": 0.0
+ },
+ {
+ "x": 35.23611467868666,
+ "y": -332.5534922316521,
+ "z": 0.0
+ },
+ {
+ "x": 36.24524496867194,
+ "y": -332.5540328227824,
+ "z": 0.0
+ },
+ {
+ "x": 37.25437525865721,
+ "y": -332.5545734139127,
+ "z": 0.0
+ },
+ {
+ "x": 38.26350554864249,
+ "y": -332.555114005043,
+ "z": 0.0
+ },
+ {
+ "x": 39.27263583862777,
+ "y": -332.55565459617327,
+ "z": 0.0
+ },
+ {
+ "x": 40.28176612861304,
+ "y": -332.55619518730356,
+ "z": 0.0
+ },
+ {
+ "x": 41.29089641859832,
+ "y": -332.55673577843385,
+ "z": 0.0
+ },
+ {
+ "x": 42.300026708583594,
+ "y": -332.55727636956414,
+ "z": 0.0
+ },
+ {
+ "x": 43.309156998568874,
+ "y": -332.5578169606944,
+ "z": 0.0
+ },
+ {
+ "x": 44.318287288554146,
+ "y": -332.5583575518247,
+ "z": 0.0
+ },
+ {
+ "x": 45.327417578539425,
+ "y": -332.558898142955,
+ "z": 0.0
+ },
+ {
+ "x": 46.33654786852448,
+ "y": -332.5594387340853,
+ "z": 0.0
+ },
+ {
+ "x": 47.345678158509976,
+ "y": -332.55997932521564,
+ "z": 0.0
+ },
+ {
+ "x": 48.354808448495476,
+ "y": -332.5605199163459,
+ "z": 0.0
+ },
+ {
+ "x": 49.36393873848053,
+ "y": -332.56106050747616,
+ "z": 0.0
+ },
+ {
+ "x": 50.37306902846558,
+ "y": -332.56160109860645,
+ "z": 0.0
+ },
+ {
+ "x": 51.382199318451086,
+ "y": -332.5621416897368,
+ "z": 0.0
+ },
+ {
+ "x": 52.39132960843637,
+ "y": -332.5626822808671,
+ "z": 0.0
+ },
+ {
+ "x": 53.40045989842187,
+ "y": -332.56322287199737,
+ "z": 0.0
+ },
+ {
+ "x": 54.40959018840692,
+ "y": -332.5637634631276,
+ "z": 0.0
+ },
+ {
+ "x": 55.418720478391975,
+ "y": -332.5643040542579,
+ "z": 0.0
+ },
+ {
+ "x": 56.427850768377475,
+ "y": -332.56484464538823,
+ "z": 0.0
+ },
+ {
+ "x": 57.43698105836275,
+ "y": -332.5653852365185,
+ "z": 0.0
+ },
+ {
+ "x": 58.446111348348026,
+ "y": -332.5659258276488,
+ "z": 0.0
+ },
+ {
+ "x": 59.455241638333305,
+ "y": -332.5664664187791,
+ "z": 0.0
+ },
+ {
+ "x": 60.46437192831858,
+ "y": -332.5670070099094,
+ "z": 0.0
+ },
+ {
+ "x": 61.47350221830386,
+ "y": -332.5675476010397,
+ "z": 0.0
+ },
+ {
+ "x": 62.48263250828913,
+ "y": -332.56808819216997,
+ "z": 0.0
+ },
+ {
+ "x": 63.49176279827441,
+ "y": -332.56862878330026,
+ "z": 0.0
+ },
+ {
+ "x": 64.50089308825969,
+ "y": -332.56916937443054,
+ "z": 0.0
+ },
+ {
+ "x": 65.51002337824497,
+ "y": -332.56970996556083,
+ "z": 0.0
+ },
+ {
+ "x": 66.51915366823023,
+ "y": -332.5702505566911,
+ "z": 0.0
+ },
+ {
+ "x": 67.52828395821551,
+ "y": -332.5707911478214,
+ "z": 0.0
+ },
+ {
+ "x": 68.53741424820078,
+ "y": -332.5713317389517,
+ "z": 0.0
+ },
+ {
+ "x": 69.54654453818605,
+ "y": -332.571872330082,
+ "z": 0.0
+ },
+ {
+ "x": 70.55567482817133,
+ "y": -332.5724129212123,
+ "z": 0.0
+ },
+ {
+ "x": 71.56480511815637,
+ "y": -332.57295351234256,
+ "z": 0.0
+ },
+ {
+ "x": 72.5739354081421,
+ "y": -332.5734941034729,
+ "z": 0.0
+ },
+ {
+ "x": 73.58306569812714,
+ "y": -332.57403469460314,
+ "z": 0.0
+ },
+ {
+ "x": 74.5921959881122,
+ "y": -332.57457528573343,
+ "z": 0.0
+ },
+ {
+ "x": 75.60132627809791,
+ "y": -332.5751158768638,
+ "z": 0.0
+ },
+ {
+ "x": 76.61045656808274,
+ "y": -332.575656467994,
+ "z": 0.0
+ },
+ {
+ "x": 77.61958685806846,
+ "y": -332.57619705912435,
+ "z": 0.0
+ },
+ {
+ "x": 78.62871714805328,
+ "y": -332.5767376502546,
+ "z": 0.0
+ },
+ {
+ "x": 79.63784743803855,
+ "y": -332.57727824138493,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 27,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 10.010000228881836,
+ "y": -328.53997802734375,
+ "z": 0.0
+ },
+ {
+ "x": 11.019130518867112,
+ "y": -328.54051861847404,
+ "z": 0.0
+ },
+ {
+ "x": 12.028260808852389,
+ "y": -328.5410592096043,
+ "z": 0.0
+ },
+ {
+ "x": 13.037391098837665,
+ "y": -328.5415998007346,
+ "z": 0.0
+ },
+ {
+ "x": 14.046521388822942,
+ "y": -328.5421403918649,
+ "z": 0.0
+ },
+ {
+ "x": 15.055651678808218,
+ "y": -328.5426809829952,
+ "z": 0.0
+ },
+ {
+ "x": 16.064781968793493,
+ "y": -328.54322157412554,
+ "z": 0.0
+ },
+ {
+ "x": 17.073912258778773,
+ "y": -328.54376216525577,
+ "z": 0.0
+ },
+ {
+ "x": 18.08304254876405,
+ "y": -328.54430275638606,
+ "z": 0.0
+ },
+ {
+ "x": 19.092172838749324,
+ "y": -328.54484334751635,
+ "z": 0.0
+ },
+ {
+ "x": 20.1013031287346,
+ "y": -328.54538393864664,
+ "z": 0.0
+ },
+ {
+ "x": 21.110433418719875,
+ "y": -328.545924529777,
+ "z": 0.0
+ },
+ {
+ "x": 22.119563708705154,
+ "y": -328.5464651209072,
+ "z": 0.0
+ },
+ {
+ "x": 23.12869399869043,
+ "y": -328.5470057120375,
+ "z": 0.0
+ },
+ {
+ "x": 24.137824288675706,
+ "y": -328.54754630316785,
+ "z": 0.0
+ },
+ {
+ "x": 25.14695457866098,
+ "y": -328.5480868942981,
+ "z": 0.0
+ },
+ {
+ "x": 26.156084868646257,
+ "y": -328.5486274854284,
+ "z": 0.0
+ },
+ {
+ "x": 27.165215158631533,
+ "y": -328.5491680765587,
+ "z": 0.0
+ },
+ {
+ "x": 28.174345448616812,
+ "y": -328.549708667689,
+ "z": 0.0
+ },
+ {
+ "x": 29.183475738602088,
+ "y": -328.5502492588193,
+ "z": 0.0
+ },
+ {
+ "x": 30.192606028587363,
+ "y": -328.5507898499495,
+ "z": 0.0
+ },
+ {
+ "x": 31.201736318572642,
+ "y": -328.55133044107987,
+ "z": 0.0
+ },
+ {
+ "x": 32.210866608557915,
+ "y": -328.55187103221016,
+ "z": 0.0
+ },
+ {
+ "x": 33.219996898543194,
+ "y": -328.55241162334045,
+ "z": 0.0
+ },
+ {
+ "x": 34.22912718852847,
+ "y": -328.55295221447074,
+ "z": 0.0
+ },
+ {
+ "x": 35.238257478513745,
+ "y": -328.553492805601,
+ "z": 0.0
+ },
+ {
+ "x": 36.247387768499024,
+ "y": -328.5540333967313,
+ "z": 0.0
+ },
+ {
+ "x": 37.256518058484296,
+ "y": -328.5545739878616,
+ "z": 0.0
+ },
+ {
+ "x": 38.265648348469576,
+ "y": -328.5551145789919,
+ "z": 0.0
+ },
+ {
+ "x": 39.274778638454855,
+ "y": -328.5556551701222,
+ "z": 0.0
+ },
+ {
+ "x": 40.28390892844013,
+ "y": -328.55619576125247,
+ "z": 0.0
+ },
+ {
+ "x": 41.293039218425406,
+ "y": -328.55673635238276,
+ "z": 0.0
+ },
+ {
+ "x": 42.30216950841068,
+ "y": -328.55727694351305,
+ "z": 0.0
+ },
+ {
+ "x": 43.31129979839596,
+ "y": -328.55781753464333,
+ "z": 0.0
+ },
+ {
+ "x": 44.32043008838123,
+ "y": -328.5583581257736,
+ "z": 0.0
+ },
+ {
+ "x": 45.32956037836651,
+ "y": -328.5588987169039,
+ "z": 0.0
+ },
+ {
+ "x": 46.33869066835178,
+ "y": -328.5594393080342,
+ "z": 0.0
+ },
+ {
+ "x": 47.34782095833706,
+ "y": -328.55997989916455,
+ "z": 0.0
+ },
+ {
+ "x": 48.35695124832233,
+ "y": -328.56052049029483,
+ "z": 0.0
+ },
+ {
+ "x": 49.36608153830761,
+ "y": -328.56106108142507,
+ "z": 0.0
+ },
+ {
+ "x": 50.37521182829288,
+ "y": -328.56160167255535,
+ "z": 0.0
+ },
+ {
+ "x": 51.38434211827817,
+ "y": -328.5621422636857,
+ "z": 0.0
+ },
+ {
+ "x": 52.393472408263456,
+ "y": -328.562682854816,
+ "z": 0.0
+ },
+ {
+ "x": 53.40260269824873,
+ "y": -328.5632234459463,
+ "z": 0.0
+ },
+ {
+ "x": 54.41173298823401,
+ "y": -328.5637640370765,
+ "z": 0.0
+ },
+ {
+ "x": 55.42086327821928,
+ "y": -328.5643046282068,
+ "z": 0.0
+ },
+ {
+ "x": 56.42999356820456,
+ "y": -328.56484521933714,
+ "z": 0.0
+ },
+ {
+ "x": 57.43912385818983,
+ "y": -328.56538581046743,
+ "z": 0.0
+ },
+ {
+ "x": 58.44825414817511,
+ "y": -328.5659264015977,
+ "z": 0.0
+ },
+ {
+ "x": 59.45738443816039,
+ "y": -328.566466992728,
+ "z": 0.0
+ },
+ {
+ "x": 60.46651472814566,
+ "y": -328.5670075838583,
+ "z": 0.0
+ },
+ {
+ "x": 61.47564501813094,
+ "y": -328.5675481749886,
+ "z": 0.0
+ },
+ {
+ "x": 62.48477530811621,
+ "y": -328.5680887661189,
+ "z": 0.0
+ },
+ {
+ "x": 63.49390559810149,
+ "y": -328.56862935724916,
+ "z": 0.0
+ },
+ {
+ "x": 64.50303588808677,
+ "y": -328.56916994837945,
+ "z": 0.0
+ },
+ {
+ "x": 65.51216617807205,
+ "y": -328.56971053950974,
+ "z": 0.0
+ },
+ {
+ "x": 66.52129646805732,
+ "y": -328.57025113064003,
+ "z": 0.0
+ },
+ {
+ "x": 67.5304267580426,
+ "y": -328.5707917217703,
+ "z": 0.0
+ },
+ {
+ "x": 68.53955704802786,
+ "y": -328.5713323129006,
+ "z": 0.0
+ },
+ {
+ "x": 69.54868733801314,
+ "y": -328.5718729040309,
+ "z": 0.0
+ },
+ {
+ "x": 70.55781762799842,
+ "y": -328.5724134951612,
+ "z": 0.0
+ },
+ {
+ "x": 71.56694791798368,
+ "y": -328.5729540862915,
+ "z": 0.0
+ },
+ {
+ "x": 72.57607820796896,
+ "y": -328.5734946774218,
+ "z": 0.0
+ },
+ {
+ "x": 73.58520849795423,
+ "y": -328.57403526855205,
+ "z": 0.0
+ },
+ {
+ "x": 74.5943387879395,
+ "y": -328.57457585968234,
+ "z": 0.0
+ },
+ {
+ "x": 75.60346907792477,
+ "y": -328.5751164508127,
+ "z": 0.0
+ },
+ {
+ "x": 76.61259936791005,
+ "y": -328.5756570419429,
+ "z": 0.0
+ },
+ {
+ "x": 77.62172965789532,
+ "y": -328.57619763307326,
+ "z": 0.0
+ },
+ {
+ "x": 78.6308599478806,
+ "y": -328.5767382242035,
+ "z": 0.0
+ },
+ {
+ "x": 79.63999023786586,
+ "y": -328.57727881533384,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 28,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 79.64106163777952,
+ "y": -326.5772791023083,
+ "z": 0.0
+ },
+ {
+ "x": 78.63193134779425,
+ "y": -326.57673851117795,
+ "z": 0.0
+ },
+ {
+ "x": 77.62280105780874,
+ "y": -326.5761979200477,
+ "z": 0.0
+ },
+ {
+ "x": 76.6136707678237,
+ "y": -326.5756573289174,
+ "z": 0.0
+ },
+ {
+ "x": 75.6045404778382,
+ "y": -326.57511673778714,
+ "z": 0.0
+ },
+ {
+ "x": 74.59541018785316,
+ "y": -326.5745761466568,
+ "z": 0.0
+ },
+ {
+ "x": 73.58627989786777,
+ "y": -326.5740355555265,
+ "z": 0.0
+ },
+ {
+ "x": 72.57714960788239,
+ "y": -326.5734949643963,
+ "z": 0.0
+ },
+ {
+ "x": 71.56801931789734,
+ "y": -326.57295437326593,
+ "z": 0.0
+ },
+ {
+ "x": 70.55888902791196,
+ "y": -326.57241378213564,
+ "z": 0.0
+ },
+ {
+ "x": 69.54975873792668,
+ "y": -326.57187319100535,
+ "z": 0.0
+ },
+ {
+ "x": 68.5406284479414,
+ "y": -326.57133259987506,
+ "z": 0.0
+ },
+ {
+ "x": 67.53149815795614,
+ "y": -326.5707920087448,
+ "z": 0.0
+ },
+ {
+ "x": 66.52236786797086,
+ "y": -326.5702514176145,
+ "z": 0.0
+ },
+ {
+ "x": 65.51323757798559,
+ "y": -326.5697108264842,
+ "z": 0.0
+ },
+ {
+ "x": 64.50410728800031,
+ "y": -326.5691702353539,
+ "z": 0.0
+ },
+ {
+ "x": 63.494976998015034,
+ "y": -326.5686296442236,
+ "z": 0.0
+ },
+ {
+ "x": 62.485846708029754,
+ "y": -326.56808905309333,
+ "z": 0.0
+ },
+ {
+ "x": 61.47671641804448,
+ "y": -326.56754846196304,
+ "z": 0.0
+ },
+ {
+ "x": 60.4675861280592,
+ "y": -326.56700787083275,
+ "z": 0.0
+ },
+ {
+ "x": 59.45845583807393,
+ "y": -326.56646727970247,
+ "z": 0.0
+ },
+ {
+ "x": 58.44932554808865,
+ "y": -326.5659266885722,
+ "z": 0.0
+ },
+ {
+ "x": 57.44019525810337,
+ "y": -326.5653860974419,
+ "z": 0.0
+ },
+ {
+ "x": 56.4310649681181,
+ "y": -326.5648455063116,
+ "z": 0.0
+ },
+ {
+ "x": 55.42193467813293,
+ "y": -326.56430491518125,
+ "z": 0.0
+ },
+ {
+ "x": 54.41280438814755,
+ "y": -326.56376432405096,
+ "z": 0.0
+ },
+ {
+ "x": 53.403674098162156,
+ "y": -326.56322373292073,
+ "z": 0.0
+ },
+ {
+ "x": 52.394543808177,
+ "y": -326.56268314179044,
+ "z": 0.0
+ },
+ {
+ "x": 51.38541351819171,
+ "y": -326.56214255066016,
+ "z": 0.0
+ },
+ {
+ "x": 50.37628322820653,
+ "y": -326.5616019595298,
+ "z": 0.0
+ },
+ {
+ "x": 49.36715293822115,
+ "y": -326.5610613683995,
+ "z": 0.0
+ },
+ {
+ "x": 48.35802264823576,
+ "y": -326.5605207772693,
+ "z": 0.0
+ },
+ {
+ "x": 47.3488923582506,
+ "y": -326.559980186139,
+ "z": 0.0
+ },
+ {
+ "x": 46.33976206826543,
+ "y": -326.55943959500866,
+ "z": 0.0
+ },
+ {
+ "x": 45.33063177828005,
+ "y": -326.55889900387837,
+ "z": 0.0
+ },
+ {
+ "x": 44.32150148829477,
+ "y": -326.5583584127481,
+ "z": 0.0
+ },
+ {
+ "x": 43.3123711983095,
+ "y": -326.5578178216178,
+ "z": 0.0
+ },
+ {
+ "x": 42.30324090832422,
+ "y": -326.5572772304875,
+ "z": 0.0
+ },
+ {
+ "x": 41.29411061833895,
+ "y": -326.5567366393572,
+ "z": 0.0
+ },
+ {
+ "x": 40.28498032835367,
+ "y": -326.5561960482269,
+ "z": 0.0
+ },
+ {
+ "x": 39.2758500383684,
+ "y": -326.55565545709663,
+ "z": 0.0
+ },
+ {
+ "x": 38.26671974838312,
+ "y": -326.55511486596635,
+ "z": 0.0
+ },
+ {
+ "x": 37.25758945839784,
+ "y": -326.55457427483606,
+ "z": 0.0
+ },
+ {
+ "x": 36.248459168412566,
+ "y": -326.55403368370577,
+ "z": 0.0
+ },
+ {
+ "x": 35.23932887842729,
+ "y": -326.5534930925755,
+ "z": 0.0
+ },
+ {
+ "x": 34.230198588442015,
+ "y": -326.5529525014452,
+ "z": 0.0
+ },
+ {
+ "x": 33.221068298456736,
+ "y": -326.5524119103149,
+ "z": 0.0
+ },
+ {
+ "x": 32.211938008471456,
+ "y": -326.5518713191846,
+ "z": 0.0
+ },
+ {
+ "x": 31.202807718486184,
+ "y": -326.5513307280543,
+ "z": 0.0
+ },
+ {
+ "x": 30.19367742850102,
+ "y": -326.550790136924,
+ "z": 0.0
+ },
+ {
+ "x": 29.184547138515516,
+ "y": -326.55024954579375,
+ "z": 0.0
+ },
+ {
+ "x": 28.175416848530354,
+ "y": -326.54970895466346,
+ "z": 0.0
+ },
+ {
+ "x": 27.166286558545075,
+ "y": -326.54916836353317,
+ "z": 0.0
+ },
+ {
+ "x": 26.157156268559795,
+ "y": -326.5486277724029,
+ "z": 0.0
+ },
+ {
+ "x": 25.148025978574637,
+ "y": -326.54808718127254,
+ "z": 0.0
+ },
+ {
+ "x": 24.138895688589134,
+ "y": -326.5475465901423,
+ "z": 0.0
+ },
+ {
+ "x": 23.129765398604086,
+ "y": -326.54700599901196,
+ "z": 0.0
+ },
+ {
+ "x": 22.120635108618693,
+ "y": -326.54646540788167,
+ "z": 0.0
+ },
+ {
+ "x": 21.111504818633303,
+ "y": -326.54592481675144,
+ "z": 0.0
+ },
+ {
+ "x": 20.102374528648255,
+ "y": -326.5453842256211,
+ "z": 0.0
+ },
+ {
+ "x": 19.093244238662862,
+ "y": -326.5448436344908,
+ "z": 0.0
+ },
+ {
+ "x": 18.08411394867759,
+ "y": -326.5443030433605,
+ "z": 0.0
+ },
+ {
+ "x": 17.07498365869231,
+ "y": -326.5437624522302,
+ "z": 0.0
+ },
+ {
+ "x": 16.06585336870692,
+ "y": -326.5432218611,
+ "z": 0.0
+ },
+ {
+ "x": 15.056723078721872,
+ "y": -326.54268126996965,
+ "z": 0.0
+ },
+ {
+ "x": 14.047592788736484,
+ "y": -326.54214067883936,
+ "z": 0.0
+ },
+ {
+ "x": 13.038462498751205,
+ "y": -326.54160008770907,
+ "z": 0.0
+ },
+ {
+ "x": 12.02933220876593,
+ "y": -326.5410594965788,
+ "z": 0.0
+ },
+ {
+ "x": 11.020201918780653,
+ "y": -326.5405189054485,
+ "z": 0.0
+ },
+ {
+ "x": 10.011071628795378,
+ "y": -326.5399783143182,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 29,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 10.008928828968294,
+ "y": -330.5399777403693,
+ "z": 0.0
+ },
+ {
+ "x": 11.01805911895357,
+ "y": -330.5405183314996,
+ "z": 0.0
+ },
+ {
+ "x": 12.027189408938849,
+ "y": -330.5410589226299,
+ "z": 0.0
+ },
+ {
+ "x": 13.036319698924125,
+ "y": -330.54159951376016,
+ "z": 0.0
+ },
+ {
+ "x": 14.0454499889094,
+ "y": -330.54214010489045,
+ "z": 0.0
+ },
+ {
+ "x": 15.054580278894564,
+ "y": -330.54268069602074,
+ "z": 0.0
+ },
+ {
+ "x": 16.063710568880065,
+ "y": -330.5432212871511,
+ "z": 0.0
+ },
+ {
+ "x": 17.072840858865234,
+ "y": -330.5437618782813,
+ "z": 0.0
+ },
+ {
+ "x": 18.081971148850506,
+ "y": -330.5443024694116,
+ "z": 0.0
+ },
+ {
+ "x": 19.091101438835786,
+ "y": -330.5448430605419,
+ "z": 0.0
+ },
+ {
+ "x": 20.100231728820944,
+ "y": -330.5453836516722,
+ "z": 0.0
+ },
+ {
+ "x": 21.109362018806447,
+ "y": -330.5459242428025,
+ "z": 0.0
+ },
+ {
+ "x": 22.118492308791616,
+ "y": -330.54646483393276,
+ "z": 0.0
+ },
+ {
+ "x": 23.127622598776775,
+ "y": -330.54700542506305,
+ "z": 0.0
+ },
+ {
+ "x": 24.136752888762278,
+ "y": -330.5475460161934,
+ "z": 0.0
+ },
+ {
+ "x": 25.145883178747326,
+ "y": -330.5480866073236,
+ "z": 0.0
+ },
+ {
+ "x": 26.15501346873272,
+ "y": -330.54862719845397,
+ "z": 0.0
+ },
+ {
+ "x": 27.16414375871799,
+ "y": -330.54916778958426,
+ "z": 0.0
+ },
+ {
+ "x": 28.17327404870327,
+ "y": -330.54970838071455,
+ "z": 0.0
+ },
+ {
+ "x": 29.18240433868866,
+ "y": -330.55024897184484,
+ "z": 0.0
+ },
+ {
+ "x": 30.191534628673708,
+ "y": -330.55078956297507,
+ "z": 0.0
+ },
+ {
+ "x": 31.2006649186591,
+ "y": -330.5513301541054,
+ "z": 0.0
+ },
+ {
+ "x": 32.20979520864437,
+ "y": -330.5518707452357,
+ "z": 0.0
+ },
+ {
+ "x": 33.21892549862965,
+ "y": -330.552411336366,
+ "z": 0.0
+ },
+ {
+ "x": 34.22805578861493,
+ "y": -330.5529519274963,
+ "z": 0.0
+ },
+ {
+ "x": 35.2371860786002,
+ "y": -330.55349251862657,
+ "z": 0.0
+ },
+ {
+ "x": 36.24631636858548,
+ "y": -330.55403310975686,
+ "z": 0.0
+ },
+ {
+ "x": 37.255446658570754,
+ "y": -330.55457370088715,
+ "z": 0.0
+ },
+ {
+ "x": 38.264576948556034,
+ "y": -330.55511429201744,
+ "z": 0.0
+ },
+ {
+ "x": 39.27370723854131,
+ "y": -330.5556548831477,
+ "z": 0.0
+ },
+ {
+ "x": 40.282837528526585,
+ "y": -330.556195474278,
+ "z": 0.0
+ },
+ {
+ "x": 41.291967818511864,
+ "y": -330.5567360654083,
+ "z": 0.0
+ },
+ {
+ "x": 42.301098108497136,
+ "y": -330.5572766565386,
+ "z": 0.0
+ },
+ {
+ "x": 43.310228398482415,
+ "y": -330.5578172476689,
+ "z": 0.0
+ },
+ {
+ "x": 44.31935868846769,
+ "y": -330.55835783879917,
+ "z": 0.0
+ },
+ {
+ "x": 45.32848897845297,
+ "y": -330.55889842992946,
+ "z": 0.0
+ },
+ {
+ "x": 46.33761926843813,
+ "y": -330.55943902105975,
+ "z": 0.0
+ },
+ {
+ "x": 47.34674955842352,
+ "y": -330.5599796121901,
+ "z": 0.0
+ },
+ {
+ "x": 48.355879848408904,
+ "y": -330.5605202033204,
+ "z": 0.0
+ },
+ {
+ "x": 49.36501013839407,
+ "y": -330.5610607944506,
+ "z": 0.0
+ },
+ {
+ "x": 50.374140428379235,
+ "y": -330.5616013855809,
+ "z": 0.0
+ },
+ {
+ "x": 51.38327071836463,
+ "y": -330.56214197671125,
+ "z": 0.0
+ },
+ {
+ "x": 52.392401008349914,
+ "y": -330.56268256784153,
+ "z": 0.0
+ },
+ {
+ "x": 53.4015312983353,
+ "y": -330.5632231589718,
+ "z": 0.0
+ },
+ {
+ "x": 54.410661588320465,
+ "y": -330.56376375010205,
+ "z": 0.0
+ },
+ {
+ "x": 55.41979187830563,
+ "y": -330.56430434123234,
+ "z": 0.0
+ },
+ {
+ "x": 56.42892216829102,
+ "y": -330.5648449323627,
+ "z": 0.0
+ },
+ {
+ "x": 57.43805245827629,
+ "y": -330.565385523493,
+ "z": 0.0
+ },
+ {
+ "x": 58.44718274826157,
+ "y": -330.56592611462327,
+ "z": 0.0
+ },
+ {
+ "x": 59.45631303824685,
+ "y": -330.56646670575356,
+ "z": 0.0
+ },
+ {
+ "x": 60.46544332823212,
+ "y": -330.56700729688384,
+ "z": 0.0
+ },
+ {
+ "x": 61.4745736182174,
+ "y": -330.56754788801413,
+ "z": 0.0
+ },
+ {
+ "x": 62.48370390820267,
+ "y": -330.5680884791444,
+ "z": 0.0
+ },
+ {
+ "x": 63.49283419818795,
+ "y": -330.5686290702747,
+ "z": 0.0
+ },
+ {
+ "x": 64.50196448817323,
+ "y": -330.569169661405,
+ "z": 0.0
+ },
+ {
+ "x": 65.51109477815851,
+ "y": -330.5697102525353,
+ "z": 0.0
+ },
+ {
+ "x": 66.52022506814377,
+ "y": -330.5702508436656,
+ "z": 0.0
+ },
+ {
+ "x": 67.52935535812905,
+ "y": -330.57079143479586,
+ "z": 0.0
+ },
+ {
+ "x": 68.53848564811432,
+ "y": -330.57133202592615,
+ "z": 0.0
+ },
+ {
+ "x": 69.5476159380996,
+ "y": -330.57187261705644,
+ "z": 0.0
+ },
+ {
+ "x": 70.55674622808488,
+ "y": -330.57241320818673,
+ "z": 0.0
+ },
+ {
+ "x": 71.56587651807003,
+ "y": -330.572953799317,
+ "z": 0.0
+ },
+ {
+ "x": 72.57500680805553,
+ "y": -330.57349439044737,
+ "z": 0.0
+ },
+ {
+ "x": 73.58413709804069,
+ "y": -330.5740349815776,
+ "z": 0.0
+ },
+ {
+ "x": 74.59326738802585,
+ "y": -330.5745755727079,
+ "z": 0.0
+ },
+ {
+ "x": 75.60239767801134,
+ "y": -330.57511616383823,
+ "z": 0.0
+ },
+ {
+ "x": 76.6115279679964,
+ "y": -330.57565675496846,
+ "z": 0.0
+ },
+ {
+ "x": 77.62065825798189,
+ "y": -330.5761973460988,
+ "z": 0.0
+ },
+ {
+ "x": 78.62978854796694,
+ "y": -330.57673793722904,
+ "z": 0.0
+ },
+ {
+ "x": 79.6389188379522,
+ "y": -330.5772785283594,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 30,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 325.71998576749917,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 324.7150530320806,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 323.7101202966621,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 322.70518756124363,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 321.7002548258251,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 320.69532209040653,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 319.69038935498804,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 318.6854566195695,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 317.68052388415094,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 316.67559114873245,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 315.67065841331396,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 314.6657256778954,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 313.66079294247686,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 312.65586020705837,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 311.6509274716398,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 310.64599473622127,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 309.6410620008028,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 308.6361292653843,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 307.63119652996573,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 306.6262637945472,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 305.6213310591287,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 304.61639832371014,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 303.6114655882916,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 302.6065328528731,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 301.6016001174546,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 300.59666738203606,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 299.5917346466175,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 298.586801911199,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 297.58186917578047,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 296.5769364403619,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 295.5720037049434,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 294.56707096952493,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 293.5621382341064,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 292.55720549868784,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 291.55227276326934,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 290.54734839213904,
+ "y": -324.6099832501986,
+ "z": 0.0
+ },
+ {
+ "x": 289.54283147550484,
+ "y": -324.6098767052554,
+ "z": 0.0
+ },
+ {
+ "x": 288.53790172978063,
+ "y": -324.60976938847693,
+ "z": 0.0
+ },
+ {
+ "x": 287.5329690000928,
+ "y": -324.6096620713808,
+ "z": 0.0
+ },
+ {
+ "x": 286.528036270404,
+ "y": -324.6095547542848,
+ "z": 0.0
+ },
+ {
+ "x": 285.52310354071574,
+ "y": -324.60944743718875,
+ "z": 0.0
+ },
+ {
+ "x": 284.5181708110277,
+ "y": -324.60934012009267,
+ "z": 0.0
+ },
+ {
+ "x": 283.51323808133935,
+ "y": -324.6092328029966,
+ "z": 0.0
+ },
+ {
+ "x": 282.5083053516508,
+ "y": -324.60912548590056,
+ "z": 0.0
+ },
+ {
+ "x": 281.50337262196274,
+ "y": -324.6090181688045,
+ "z": 0.0
+ },
+ {
+ "x": 280.49843989227446,
+ "y": -324.6089108517084,
+ "z": 0.0
+ },
+ {
+ "x": 279.4935071625859,
+ "y": -324.6088035346124,
+ "z": 0.0
+ },
+ {
+ "x": 278.48857443289785,
+ "y": -324.6086962175163,
+ "z": 0.0
+ },
+ {
+ "x": 277.48364170320957,
+ "y": -324.6085889004202,
+ "z": 0.0
+ },
+ {
+ "x": 276.478708973521,
+ "y": -324.6084815833242,
+ "z": 0.0
+ },
+ {
+ "x": 275.4737762438329,
+ "y": -324.6083742662281,
+ "z": 0.0
+ },
+ {
+ "x": 274.4688435141444,
+ "y": -324.6082669491321,
+ "z": 0.0
+ },
+ {
+ "x": 273.46391078445635,
+ "y": -324.608159632036,
+ "z": 0.0
+ },
+ {
+ "x": 272.4589780547678,
+ "y": -324.60805231494,
+ "z": 0.0
+ },
+ {
+ "x": 271.45404532507973,
+ "y": -324.6079449978439,
+ "z": 0.0
+ },
+ {
+ "x": 270.44911259539145,
+ "y": -324.6078376807478,
+ "z": 0.0
+ },
+ {
+ "x": 269.4441798657029,
+ "y": -324.6077303636518,
+ "z": 0.0
+ },
+ {
+ "x": 268.4392471360148,
+ "y": -324.6076230465557,
+ "z": 0.0
+ },
+ {
+ "x": 267.4343144063265,
+ "y": -324.60751572945964,
+ "z": 0.0
+ },
+ {
+ "x": 266.429381676638,
+ "y": -324.6074084123636,
+ "z": 0.0
+ },
+ {
+ "x": 265.4244489469499,
+ "y": -324.60730109526753,
+ "z": 0.0
+ },
+ {
+ "x": 264.4195162172616,
+ "y": -324.60719377817145,
+ "z": 0.0
+ },
+ {
+ "x": 263.4145834875731,
+ "y": -324.6070864610754,
+ "z": 0.0
+ },
+ {
+ "x": 262.409650757885,
+ "y": -324.60697914397934,
+ "z": 0.0
+ },
+ {
+ "x": 261.40471802819644,
+ "y": -324.6068718268833,
+ "z": 0.0
+ },
+ {
+ "x": 260.3997852985084,
+ "y": -324.60676450978724,
+ "z": 0.0
+ },
+ {
+ "x": 259.3948525688201,
+ "y": -324.60665719269116,
+ "z": 0.0
+ },
+ {
+ "x": 258.38991983913155,
+ "y": -324.60654987559514,
+ "z": 0.0
+ },
+ {
+ "x": 257.3849871094435,
+ "y": -324.60644255849905,
+ "z": 0.0
+ },
+ {
+ "x": 256.380054379755,
+ "y": -324.60633524140303,
+ "z": 0.0
+ },
+ {
+ "x": 255.37512165006692,
+ "y": -324.60622792430695,
+ "z": 0.0
+ },
+ {
+ "x": 254.37018892037858,
+ "y": -324.60612060721087,
+ "z": 0.0
+ },
+ {
+ "x": 253.36525619069005,
+ "y": -324.60601329011484,
+ "z": 0.0
+ },
+ {
+ "x": 252.360323461002,
+ "y": -324.60590597301876,
+ "z": 0.0
+ },
+ {
+ "x": 251.35539073131346,
+ "y": -324.60579865592274,
+ "z": 0.0
+ },
+ {
+ "x": 250.35045800162538,
+ "y": -324.60569133882666,
+ "z": 0.0
+ },
+ {
+ "x": 249.3455252719371,
+ "y": -324.6055840217306,
+ "z": 0.0
+ },
+ {
+ "x": 248.34059254224857,
+ "y": -324.60547670463455,
+ "z": 0.0
+ },
+ {
+ "x": 247.33565981256046,
+ "y": -324.6053693875385,
+ "z": 0.0
+ },
+ {
+ "x": 246.3307270828722,
+ "y": -324.6052620704424,
+ "z": 0.0
+ },
+ {
+ "x": 245.32579435318365,
+ "y": -324.60515475334637,
+ "z": 0.0
+ },
+ {
+ "x": 244.32086162349557,
+ "y": -324.6050474362503,
+ "z": 0.0
+ },
+ {
+ "x": 243.31592889380727,
+ "y": -324.6049401191542,
+ "z": 0.0
+ },
+ {
+ "x": 242.31099616411876,
+ "y": -324.6048328020582,
+ "z": 0.0
+ },
+ {
+ "x": 241.30606343443046,
+ "y": -324.60472548496216,
+ "z": 0.0
+ },
+ {
+ "x": 240.30113070474235,
+ "y": -324.6046181678661,
+ "z": 0.0
+ },
+ {
+ "x": 239.29619797505407,
+ "y": -324.60451085077,
+ "z": 0.0
+ },
+ {
+ "x": 238.29126524536554,
+ "y": -324.604403533674,
+ "z": 0.0
+ },
+ {
+ "x": 237.28633251567746,
+ "y": -324.6042962165779,
+ "z": 0.0
+ },
+ {
+ "x": 236.28139978598918,
+ "y": -324.6041888994818,
+ "z": 0.0
+ },
+ {
+ "x": 235.27646705630065,
+ "y": -324.6040815823858,
+ "z": 0.0
+ },
+ {
+ "x": 234.27153432661257,
+ "y": -324.6039742652897,
+ "z": 0.0
+ },
+ {
+ "x": 233.26660159692423,
+ "y": -324.6038669481936,
+ "z": 0.0
+ },
+ {
+ "x": 232.26166886723573,
+ "y": -324.6037596310976,
+ "z": 0.0
+ },
+ {
+ "x": 231.25673613754742,
+ "y": -324.6036523140016,
+ "z": 0.0
+ },
+ {
+ "x": 230.25180340785957,
+ "y": -324.60354499690544,
+ "z": 0.0
+ },
+ {
+ "x": 229.24687067817084,
+ "y": -324.6034376798094,
+ "z": 0.0
+ },
+ {
+ "x": 228.2419379484825,
+ "y": -324.6033303627134,
+ "z": 0.0
+ },
+ {
+ "x": 227.23700521879465,
+ "y": -324.60322304561726,
+ "z": 0.0
+ },
+ {
+ "x": 226.2320724891059,
+ "y": -324.60311572852123,
+ "z": 0.0
+ },
+ {
+ "x": 225.22713975941755,
+ "y": -324.6030084114252,
+ "z": 0.0
+ },
+ {
+ "x": 224.22220702972947,
+ "y": -324.6029010943291,
+ "z": 0.0
+ },
+ {
+ "x": 223.21727430004114,
+ "y": -324.60279377723305,
+ "z": 0.0
+ },
+ {
+ "x": 222.2123415703526,
+ "y": -324.602686460137,
+ "z": 0.0
+ },
+ {
+ "x": 221.20740884066453,
+ "y": -324.60257914304094,
+ "z": 0.0
+ },
+ {
+ "x": 220.2024761109762,
+ "y": -324.60247182594486,
+ "z": 0.0
+ },
+ {
+ "x": 219.19754338128766,
+ "y": -324.60236450884884,
+ "z": 0.0
+ },
+ {
+ "x": 218.19261065159935,
+ "y": -324.6022571917528,
+ "z": 0.0
+ },
+ {
+ "x": 217.18767792191147,
+ "y": -324.6021498746567,
+ "z": 0.0
+ },
+ {
+ "x": 216.1827451922227,
+ "y": -324.60204255756065,
+ "z": 0.0
+ },
+ {
+ "x": 215.1778124625344,
+ "y": -324.6019352404646,
+ "z": 0.0
+ },
+ {
+ "x": 214.17287973284655,
+ "y": -324.6018279233685,
+ "z": 0.0
+ },
+ {
+ "x": 213.16794700315776,
+ "y": -324.60172060627247,
+ "z": 0.0
+ },
+ {
+ "x": 212.16301427346946,
+ "y": -324.60161328917644,
+ "z": 0.0
+ },
+ {
+ "x": 211.15808154378138,
+ "y": -324.60150597208036,
+ "z": 0.0
+ },
+ {
+ "x": 210.15314881409304,
+ "y": -324.6013986549843,
+ "z": 0.0
+ },
+ {
+ "x": 209.1482160844045,
+ "y": -324.60129133788826,
+ "z": 0.0
+ },
+ {
+ "x": 208.1432833547162,
+ "y": -324.60118402079223,
+ "z": 0.0
+ },
+ {
+ "x": 207.13835062502832,
+ "y": -324.6010767036961,
+ "z": 0.0
+ },
+ {
+ "x": 206.13341789533956,
+ "y": -324.60096938660007,
+ "z": 0.0
+ },
+ {
+ "x": 205.12848516565123,
+ "y": -324.60086206950405,
+ "z": 0.0
+ },
+ {
+ "x": 204.12355243596338,
+ "y": -324.6007547524079,
+ "z": 0.0
+ },
+ {
+ "x": 203.11861970627461,
+ "y": -324.6006474353119,
+ "z": 0.0
+ },
+ {
+ "x": 202.11368697658628,
+ "y": -324.60054011821586,
+ "z": 0.0
+ },
+ {
+ "x": 201.1087542468982,
+ "y": -324.6004328011198,
+ "z": 0.0
+ },
+ {
+ "x": 200.1038215172099,
+ "y": -324.6003254840237,
+ "z": 0.0
+ },
+ {
+ "x": 199.09888878752133,
+ "y": -324.6002181669277,
+ "z": 0.0
+ },
+ {
+ "x": 198.09395605783325,
+ "y": -324.6001108498316,
+ "z": 0.0
+ },
+ {
+ "x": 197.08902332814495,
+ "y": -324.6000035327355,
+ "z": 0.0
+ },
+ {
+ "x": 196.08409059845638,
+ "y": -324.5998962156395,
+ "z": 0.0
+ },
+ {
+ "x": 195.0791578687683,
+ "y": -324.5997888985434,
+ "z": 0.0
+ },
+ {
+ "x": 194.07422513908,
+ "y": -324.5996815814473,
+ "z": 0.0
+ },
+ {
+ "x": 193.06929240939147,
+ "y": -324.5995742643513,
+ "z": 0.0
+ },
+ {
+ "x": 192.06435967970313,
+ "y": -324.5994669472553,
+ "z": 0.0
+ },
+ {
+ "x": 191.05942695001505,
+ "y": -324.5993596301592,
+ "z": 0.0
+ },
+ {
+ "x": 190.05449422032672,
+ "y": -324.5992523130631,
+ "z": 0.0
+ },
+ {
+ "x": 189.04956149063818,
+ "y": -324.5991449959671,
+ "z": 0.0
+ },
+ {
+ "x": 188.0446287609501,
+ "y": -324.599037678871,
+ "z": 0.0
+ },
+ {
+ "x": 187.03969603126177,
+ "y": -324.59893036177493,
+ "z": 0.0
+ },
+ {
+ "x": 186.03476330157324,
+ "y": -324.5988230446789,
+ "z": 0.0
+ },
+ {
+ "x": 185.02983057188513,
+ "y": -324.5987157275828,
+ "z": 0.0
+ },
+ {
+ "x": 184.02489784219682,
+ "y": -324.59860841048675,
+ "z": 0.0
+ },
+ {
+ "x": 183.0199651125083,
+ "y": -324.5985010933907,
+ "z": 0.0
+ },
+ {
+ "x": 182.01503238282018,
+ "y": -324.59839377629464,
+ "z": 0.0
+ },
+ {
+ "x": 181.01009965313187,
+ "y": -324.59828645919856,
+ "z": 0.0
+ },
+ {
+ "x": 180.00516692344334,
+ "y": -324.59817914210254,
+ "z": 0.0
+ },
+ {
+ "x": 179.00023419375526,
+ "y": -324.59807182500646,
+ "z": 0.0
+ },
+ {
+ "x": 177.99530146406693,
+ "y": -324.5979645079104,
+ "z": 0.0
+ },
+ {
+ "x": 176.9903687343784,
+ "y": -324.59785719081435,
+ "z": 0.0
+ },
+ {
+ "x": 175.9854360046901,
+ "y": -324.5977498737183,
+ "z": 0.0
+ },
+ {
+ "x": 174.98050327500198,
+ "y": -324.59764255662225,
+ "z": 0.0
+ },
+ {
+ "x": 173.97557054531367,
+ "y": -324.59753523952617,
+ "z": 0.0
+ },
+ {
+ "x": 172.97063781562514,
+ "y": -324.59742792243014,
+ "z": 0.0
+ },
+ {
+ "x": 171.96570508593703,
+ "y": -324.59732060533406,
+ "z": 0.0
+ },
+ {
+ "x": 170.96077235624873,
+ "y": -324.597213288238,
+ "z": 0.0
+ },
+ {
+ "x": 169.95583962656016,
+ "y": -324.59710597114196,
+ "z": 0.0
+ },
+ {
+ "x": 168.95090689687208,
+ "y": -324.5969986540459,
+ "z": 0.0
+ },
+ {
+ "x": 167.94597416718378,
+ "y": -324.5968913369498,
+ "z": 0.0
+ },
+ {
+ "x": 166.94104143749522,
+ "y": -324.59678401985377,
+ "z": 0.0
+ },
+ {
+ "x": 165.93610870780714,
+ "y": -324.5966767027577,
+ "z": 0.0
+ },
+ {
+ "x": 164.9311759781186,
+ "y": -324.59656938566167,
+ "z": 0.0
+ },
+ {
+ "x": 163.92624324843052,
+ "y": -324.5964620685656,
+ "z": 0.0
+ },
+ {
+ "x": 162.92131051874222,
+ "y": -324.5963547514695,
+ "z": 0.0
+ },
+ {
+ "x": 161.91637778905368,
+ "y": -324.5962474343735,
+ "z": 0.0
+ },
+ {
+ "x": 160.9114450593656,
+ "y": -324.5961401172774,
+ "z": 0.0
+ },
+ {
+ "x": 159.90651232967707,
+ "y": -324.5960328001814,
+ "z": 0.0
+ },
+ {
+ "x": 158.901579599989,
+ "y": -324.5959254830853,
+ "z": 0.0
+ },
+ {
+ "x": 157.89664687030069,
+ "y": -324.5958181659892,
+ "z": 0.0
+ },
+ {
+ "x": 156.89171414061212,
+ "y": -324.5957108488932,
+ "z": 0.0
+ },
+ {
+ "x": 155.88678141092404,
+ "y": -324.5956035317971,
+ "z": 0.0
+ },
+ {
+ "x": 154.8818486812355,
+ "y": -324.5954962147011,
+ "z": 0.0
+ },
+ {
+ "x": 153.87691595154743,
+ "y": -324.595388897605,
+ "z": 0.0
+ },
+ {
+ "x": 152.87198322185913,
+ "y": -324.5952815805089,
+ "z": 0.0
+ },
+ {
+ "x": 151.8670504921706,
+ "y": -324.5951742634129,
+ "z": 0.0
+ },
+ {
+ "x": 150.8621177624825,
+ "y": -324.5950669463168,
+ "z": 0.0
+ },
+ {
+ "x": 149.8571850327942,
+ "y": -324.59495962922074,
+ "z": 0.0
+ },
+ {
+ "x": 148.85225230310567,
+ "y": -324.5948523121247,
+ "z": 0.0
+ },
+ {
+ "x": 147.8473195734176,
+ "y": -324.59474499502863,
+ "z": 0.0
+ },
+ {
+ "x": 146.84238684372926,
+ "y": -324.59463767793255,
+ "z": 0.0
+ },
+ {
+ "x": 145.83745411404072,
+ "y": -324.59453036083653,
+ "z": 0.0
+ },
+ {
+ "x": 144.83252138435242,
+ "y": -324.5944230437405,
+ "z": 0.0
+ },
+ {
+ "x": 143.82758865466434,
+ "y": -324.5943157266444,
+ "z": 0.0
+ },
+ {
+ "x": 142.82265592497603,
+ "y": -324.59420840954834,
+ "z": 0.0
+ },
+ {
+ "x": 141.8177231952875,
+ "y": -324.5941010924523,
+ "z": 0.0
+ },
+ {
+ "x": 140.81279046559942,
+ "y": -324.59399377535624,
+ "z": 0.0
+ },
+ {
+ "x": 139.8078577359111,
+ "y": -324.59388645826016,
+ "z": 0.0
+ },
+ {
+ "x": 138.80292500622258,
+ "y": -324.59377914116413,
+ "z": 0.0
+ },
+ {
+ "x": 137.7979922765345,
+ "y": -324.59367182406805,
+ "z": 0.0
+ },
+ {
+ "x": 136.7930595468462,
+ "y": -324.593564506972,
+ "z": 0.0
+ },
+ {
+ "x": 135.78812681715763,
+ "y": -324.59345718987595,
+ "z": 0.0
+ },
+ {
+ "x": 134.78319408746958,
+ "y": -324.59334987277987,
+ "z": 0.0
+ },
+ {
+ "x": 133.77826135778125,
+ "y": -324.5932425556838,
+ "z": 0.0
+ },
+ {
+ "x": 132.7733286280927,
+ "y": -324.59313523858776,
+ "z": 0.0
+ },
+ {
+ "x": 131.7683958984044,
+ "y": -324.59302792149174,
+ "z": 0.0
+ },
+ {
+ "x": 130.76346316871656,
+ "y": -324.5929206043956,
+ "z": 0.0
+ },
+ {
+ "x": 129.7585304390278,
+ "y": -324.5928132872996,
+ "z": 0.0
+ },
+ {
+ "x": 128.75359770933946,
+ "y": -324.59270597020355,
+ "z": 0.0
+ },
+ {
+ "x": 127.74866497965138,
+ "y": -324.5925986531075,
+ "z": 0.0
+ },
+ {
+ "x": 126.74373224996307,
+ "y": -324.5924913360114,
+ "z": 0.0
+ },
+ {
+ "x": 125.73879952027453,
+ "y": -324.59238401891537,
+ "z": 0.0
+ },
+ {
+ "x": 124.73386679058645,
+ "y": -324.5922767018193,
+ "z": 0.0
+ },
+ {
+ "x": 123.72893406089814,
+ "y": -324.5921693847232,
+ "z": 0.0
+ },
+ {
+ "x": 122.72400133120959,
+ "y": -324.5920620676272,
+ "z": 0.0
+ },
+ {
+ "x": 121.71906860152127,
+ "y": -324.59195475053116,
+ "z": 0.0
+ },
+ {
+ "x": 120.71413587183342,
+ "y": -324.591847433435,
+ "z": 0.0
+ },
+ {
+ "x": 119.70920314214466,
+ "y": -324.591740116339,
+ "z": 0.0
+ },
+ {
+ "x": 118.70427041245634,
+ "y": -324.591632799243,
+ "z": 0.0
+ },
+ {
+ "x": 117.69933768276849,
+ "y": -324.59152548214684,
+ "z": 0.0
+ },
+ {
+ "x": 116.69440495307973,
+ "y": -324.5914181650508,
+ "z": 0.0
+ },
+ {
+ "x": 115.6894722233914,
+ "y": -324.5913108479548,
+ "z": 0.0
+ },
+ {
+ "x": 114.68453949370333,
+ "y": -324.5912035308587,
+ "z": 0.0
+ },
+ {
+ "x": 113.67960676401502,
+ "y": -324.5910962137626,
+ "z": 0.0
+ },
+ {
+ "x": 112.67467403432649,
+ "y": -324.5909888966666,
+ "z": 0.0
+ },
+ {
+ "x": 111.66974130463817,
+ "y": -324.5908815795706,
+ "z": 0.0
+ },
+ {
+ "x": 110.66480857495031,
+ "y": -324.59077426247444,
+ "z": 0.0
+ },
+ {
+ "x": 109.65987584526155,
+ "y": -324.5906669453784,
+ "z": 0.0
+ },
+ {
+ "x": 108.65494311557323,
+ "y": -324.5905596282824,
+ "z": 0.0
+ },
+ {
+ "x": 107.65001038588538,
+ "y": -324.59045231118625,
+ "z": 0.0
+ },
+ {
+ "x": 106.64507765619662,
+ "y": -324.59034499409023,
+ "z": 0.0
+ },
+ {
+ "x": 105.6401449265083,
+ "y": -324.5902376769942,
+ "z": 0.0
+ },
+ {
+ "x": 104.63521219682022,
+ "y": -324.5901303598981,
+ "z": 0.0
+ },
+ {
+ "x": 103.63027946713191,
+ "y": -324.59002304280204,
+ "z": 0.0
+ },
+ {
+ "x": 102.62663591823683,
+ "y": -324.58959221099286,
+ "z": 0.0
+ },
+ {
+ "x": 101.62212988384367,
+ "y": -324.5890540743326,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 31,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 101.61784428418933,
+ "y": -332.58905292643476,
+ "z": 0.0
+ },
+ {
+ "x": 102.62320343224319,
+ "y": -332.58959147462036,
+ "z": 0.0
+ },
+ {
+ "x": 103.62942514451072,
+ "y": -332.5900229971853,
+ "z": 0.0
+ },
+ {
+ "x": 104.63435787419903,
+ "y": -332.5901303142814,
+ "z": 0.0
+ },
+ {
+ "x": 105.63929060388756,
+ "y": -332.5902376313775,
+ "z": 0.0
+ },
+ {
+ "x": 106.64422333357588,
+ "y": -332.5903449484735,
+ "z": 0.0
+ },
+ {
+ "x": 107.64915606326373,
+ "y": -332.5904522655695,
+ "z": 0.0
+ },
+ {
+ "x": 108.65408879295249,
+ "y": -332.59055958266566,
+ "z": 0.0
+ },
+ {
+ "x": 109.65902152264081,
+ "y": -332.5906668997617,
+ "z": 0.0
+ },
+ {
+ "x": 110.66395425232867,
+ "y": -332.5907742168577,
+ "z": 0.0
+ },
+ {
+ "x": 111.66888698201743,
+ "y": -332.59088153395385,
+ "z": 0.0
+ },
+ {
+ "x": 112.67381971170575,
+ "y": -332.5909888510499,
+ "z": 0.0
+ },
+ {
+ "x": 113.67875244139383,
+ "y": -332.5910961681459,
+ "z": 0.0
+ },
+ {
+ "x": 114.68368517108213,
+ "y": -332.591203485242,
+ "z": 0.0
+ },
+ {
+ "x": 115.68861790077067,
+ "y": -332.59131080233806,
+ "z": 0.0
+ },
+ {
+ "x": 116.69355063045899,
+ "y": -332.5914181194341,
+ "z": 0.0
+ },
+ {
+ "x": 117.69848336014684,
+ "y": -332.5915254365301,
+ "z": 0.0
+ },
+ {
+ "x": 118.7034160898356,
+ "y": -332.59163275362624,
+ "z": 0.0
+ },
+ {
+ "x": 119.70834881952392,
+ "y": -332.59174007072227,
+ "z": 0.0
+ },
+ {
+ "x": 120.71328154921177,
+ "y": -332.5918473878183,
+ "z": 0.0
+ },
+ {
+ "x": 121.71821427890053,
+ "y": -332.59195470491443,
+ "z": 0.0
+ },
+ {
+ "x": 122.72314700858885,
+ "y": -332.59206202201045,
+ "z": 0.0
+ },
+ {
+ "x": 123.72807973827695,
+ "y": -332.5921693391065,
+ "z": 0.0
+ },
+ {
+ "x": 124.73301246796525,
+ "y": -332.59227665620256,
+ "z": 0.0
+ },
+ {
+ "x": 125.73794519765379,
+ "y": -332.59238397329864,
+ "z": 0.0
+ },
+ {
+ "x": 126.74287792734188,
+ "y": -332.59249129039466,
+ "z": 0.0
+ },
+ {
+ "x": 127.74781065703019,
+ "y": -332.59259860749074,
+ "z": 0.0
+ },
+ {
+ "x": 128.75274338671872,
+ "y": -332.5927059245868,
+ "z": 0.0
+ },
+ {
+ "x": 129.75767611640705,
+ "y": -332.59281324168285,
+ "z": 0.0
+ },
+ {
+ "x": 130.7626088460949,
+ "y": -332.59292055877887,
+ "z": 0.0
+ },
+ {
+ "x": 131.76754157578367,
+ "y": -332.593027875875,
+ "z": 0.0
+ },
+ {
+ "x": 132.77247430547197,
+ "y": -332.59313519297103,
+ "z": 0.0
+ },
+ {
+ "x": 133.77740703516005,
+ "y": -332.59324251006706,
+ "z": 0.0
+ },
+ {
+ "x": 134.7823397648484,
+ "y": -332.59334982716314,
+ "z": 0.0
+ },
+ {
+ "x": 135.7872724945369,
+ "y": -332.5934571442592,
+ "z": 0.0
+ },
+ {
+ "x": 136.792205224225,
+ "y": -332.59356446135524,
+ "z": 0.0
+ },
+ {
+ "x": 137.7971379539133,
+ "y": -332.5936717784513,
+ "z": 0.0
+ },
+ {
+ "x": 138.80207068360184,
+ "y": -332.5937790955474,
+ "z": 0.0
+ },
+ {
+ "x": 139.80700341328992,
+ "y": -332.5938864126434,
+ "z": 0.0
+ },
+ {
+ "x": 140.81193614297823,
+ "y": -332.5939937297395,
+ "z": 0.0
+ },
+ {
+ "x": 141.81686887266676,
+ "y": -332.5941010468356,
+ "z": 0.0
+ },
+ {
+ "x": 142.82180160235484,
+ "y": -332.5942083639316,
+ "z": 0.0
+ },
+ {
+ "x": 143.82673433204315,
+ "y": -332.5943156810277,
+ "z": 0.0
+ },
+ {
+ "x": 144.83166706173168,
+ "y": -332.5944229981238,
+ "z": 0.0
+ },
+ {
+ "x": 145.83659979141999,
+ "y": -332.5945303152198,
+ "z": 0.0
+ },
+ {
+ "x": 146.84153252110806,
+ "y": -332.5946376323158,
+ "z": 0.0
+ },
+ {
+ "x": 147.8464652507964,
+ "y": -332.5947449494119,
+ "z": 0.0
+ },
+ {
+ "x": 148.85139798048493,
+ "y": -332.594852266508,
+ "z": 0.0
+ },
+ {
+ "x": 149.856330710173,
+ "y": -332.594959583604,
+ "z": 0.0
+ },
+ {
+ "x": 150.86126343986132,
+ "y": -332.5950669007001,
+ "z": 0.0
+ },
+ {
+ "x": 151.86619616954985,
+ "y": -332.59517421779617,
+ "z": 0.0
+ },
+ {
+ "x": 152.87112889923793,
+ "y": -332.5952815348922,
+ "z": 0.0
+ },
+ {
+ "x": 153.87606162892624,
+ "y": -332.5953888519883,
+ "z": 0.0
+ },
+ {
+ "x": 154.88099435861477,
+ "y": -332.59549616908436,
+ "z": 0.0
+ },
+ {
+ "x": 155.88592708830285,
+ "y": -332.5956034861804,
+ "z": 0.0
+ },
+ {
+ "x": 156.89085981799138,
+ "y": -332.59571080327646,
+ "z": 0.0
+ },
+ {
+ "x": 157.8957925476795,
+ "y": -332.5958181203725,
+ "z": 0.0
+ },
+ {
+ "x": 158.9007252773678,
+ "y": -332.59592543746857,
+ "z": 0.0
+ },
+ {
+ "x": 159.90565800705633,
+ "y": -332.59603275456465,
+ "z": 0.0
+ },
+ {
+ "x": 160.9105907367444,
+ "y": -332.59614007166067,
+ "z": 0.0
+ },
+ {
+ "x": 161.91552346643294,
+ "y": -332.59624738875675,
+ "z": 0.0
+ },
+ {
+ "x": 162.92045619612102,
+ "y": -332.5963547058528,
+ "z": 0.0
+ },
+ {
+ "x": 163.92538892580933,
+ "y": -332.59646202294886,
+ "z": 0.0
+ },
+ {
+ "x": 164.93032165549786,
+ "y": -332.59656934004494,
+ "z": 0.0
+ },
+ {
+ "x": 165.93525438518594,
+ "y": -332.59667665714096,
+ "z": 0.0
+ },
+ {
+ "x": 166.94018711487448,
+ "y": -332.59678397423704,
+ "z": 0.0
+ },
+ {
+ "x": 167.94511984456258,
+ "y": -332.59689129133307,
+ "z": 0.0
+ },
+ {
+ "x": 168.9500525742509,
+ "y": -332.59699860842915,
+ "z": 0.0
+ },
+ {
+ "x": 169.95498530393942,
+ "y": -332.5971059255252,
+ "z": 0.0
+ },
+ {
+ "x": 170.95991803362753,
+ "y": -332.59721324262125,
+ "z": 0.0
+ },
+ {
+ "x": 171.96485076331584,
+ "y": -332.59732055971733,
+ "z": 0.0
+ },
+ {
+ "x": 172.9697834930044,
+ "y": -332.5974278768134,
+ "z": 0.0
+ },
+ {
+ "x": 173.97471622269248,
+ "y": -332.59753519390944,
+ "z": 0.0
+ },
+ {
+ "x": 174.97964895238078,
+ "y": -332.5976425110055,
+ "z": 0.0
+ },
+ {
+ "x": 175.98458168206935,
+ "y": -332.5977498281016,
+ "z": 0.0
+ },
+ {
+ "x": 176.98951441175765,
+ "y": -332.5978571451976,
+ "z": 0.0
+ },
+ {
+ "x": 177.99444714144573,
+ "y": -332.59796446229365,
+ "z": 0.0
+ },
+ {
+ "x": 178.99937987113407,
+ "y": -332.5980717793897,
+ "z": 0.0
+ },
+ {
+ "x": 180.0043126008226,
+ "y": -332.5981790964858,
+ "z": 0.0
+ },
+ {
+ "x": 181.00924533051068,
+ "y": -332.59828641358183,
+ "z": 0.0
+ },
+ {
+ "x": 182.014178060199,
+ "y": -332.5983937306779,
+ "z": 0.0
+ },
+ {
+ "x": 183.01911078988755,
+ "y": -332.598501047774,
+ "z": 0.0
+ },
+ {
+ "x": 184.02404351957563,
+ "y": -332.59860836487,
+ "z": 0.0
+ },
+ {
+ "x": 185.02897624926393,
+ "y": -332.5987156819661,
+ "z": 0.0
+ },
+ {
+ "x": 186.0339089789525,
+ "y": -332.5988229990622,
+ "z": 0.0
+ },
+ {
+ "x": 187.03884170864058,
+ "y": -332.5989303161582,
+ "z": 0.0
+ },
+ {
+ "x": 188.0437744383289,
+ "y": -332.5990376332543,
+ "z": 0.0
+ },
+ {
+ "x": 189.04870716801744,
+ "y": -332.59914495035036,
+ "z": 0.0
+ },
+ {
+ "x": 190.05363989770552,
+ "y": -332.5992522674464,
+ "z": 0.0
+ },
+ {
+ "x": 191.05857262739386,
+ "y": -332.59935958454247,
+ "z": 0.0
+ },
+ {
+ "x": 192.0635053570824,
+ "y": -332.59946690163855,
+ "z": 0.0
+ },
+ {
+ "x": 193.06843808677073,
+ "y": -332.5995742187346,
+ "z": 0.0
+ },
+ {
+ "x": 194.0733708164588,
+ "y": -332.5996815358306,
+ "z": 0.0
+ },
+ {
+ "x": 195.0783035461471,
+ "y": -332.5997888529267,
+ "z": 0.0
+ },
+ {
+ "x": 196.08323627583565,
+ "y": -332.59989617002276,
+ "z": 0.0
+ },
+ {
+ "x": 197.08816900552375,
+ "y": -332.6000034871188,
+ "z": 0.0
+ },
+ {
+ "x": 198.09310173521206,
+ "y": -332.60011080421486,
+ "z": 0.0
+ },
+ {
+ "x": 199.0980344649006,
+ "y": -332.60021812131095,
+ "z": 0.0
+ },
+ {
+ "x": 200.1029671945887,
+ "y": -332.60032543840697,
+ "z": 0.0
+ },
+ {
+ "x": 201.107899924277,
+ "y": -332.60043275550305,
+ "z": 0.0
+ },
+ {
+ "x": 202.11283265396554,
+ "y": -332.60054007259913,
+ "z": 0.0
+ },
+ {
+ "x": 203.11776538365388,
+ "y": -332.60064738969515,
+ "z": 0.0
+ },
+ {
+ "x": 204.12269811334173,
+ "y": -332.6007547067912,
+ "z": 0.0
+ },
+ {
+ "x": 205.1276308430305,
+ "y": -332.6008620238873,
+ "z": 0.0
+ },
+ {
+ "x": 206.13256357271882,
+ "y": -332.60096934098334,
+ "z": 0.0
+ },
+ {
+ "x": 207.13749630240667,
+ "y": -332.60107665807936,
+ "z": 0.0
+ },
+ {
+ "x": 208.14242903209546,
+ "y": -332.6011839751755,
+ "z": 0.0
+ },
+ {
+ "x": 209.14736176178377,
+ "y": -332.6012912922715,
+ "z": 0.0
+ },
+ {
+ "x": 210.15229449147185,
+ "y": -332.60139860936755,
+ "z": 0.0
+ },
+ {
+ "x": 211.15722722116018,
+ "y": -332.60150592646363,
+ "z": 0.0
+ },
+ {
+ "x": 212.16215995084872,
+ "y": -332.6016132435597,
+ "z": 0.0
+ },
+ {
+ "x": 213.16709268053702,
+ "y": -332.60172056065574,
+ "z": 0.0
+ },
+ {
+ "x": 214.1720254102249,
+ "y": -332.60182787775176,
+ "z": 0.0
+ },
+ {
+ "x": 215.17695813991367,
+ "y": -332.6019351948479,
+ "z": 0.0
+ },
+ {
+ "x": 216.18189086960197,
+ "y": -332.6020425119439,
+ "z": 0.0
+ },
+ {
+ "x": 217.18682359928982,
+ "y": -332.60214982903994,
+ "z": 0.0
+ },
+ {
+ "x": 218.1917563289786,
+ "y": -332.6022571461361,
+ "z": 0.0
+ },
+ {
+ "x": 219.19668905866692,
+ "y": -332.6023644632321,
+ "z": 0.0
+ },
+ {
+ "x": 220.201621788355,
+ "y": -332.60247178032813,
+ "z": 0.0
+ },
+ {
+ "x": 221.20655451804333,
+ "y": -332.6025790974242,
+ "z": 0.0
+ },
+ {
+ "x": 222.21148724773187,
+ "y": -332.6026864145203,
+ "z": 0.0
+ },
+ {
+ "x": 223.21641997741995,
+ "y": -332.6027937316163,
+ "z": 0.0
+ },
+ {
+ "x": 224.22135270710828,
+ "y": -332.6029010487124,
+ "z": 0.0
+ },
+ {
+ "x": 225.22628543679681,
+ "y": -332.6030083658085,
+ "z": 0.0
+ },
+ {
+ "x": 226.23121816648515,
+ "y": -332.6031156829045,
+ "z": 0.0
+ },
+ {
+ "x": 227.236150896173,
+ "y": -332.6032230000005,
+ "z": 0.0
+ },
+ {
+ "x": 228.24108362586176,
+ "y": -332.60333031709666,
+ "z": 0.0
+ },
+ {
+ "x": 229.2460163555501,
+ "y": -332.6034376341927,
+ "z": 0.0
+ },
+ {
+ "x": 230.25094908523792,
+ "y": -332.6035449512887,
+ "z": 0.0
+ },
+ {
+ "x": 231.25588181492668,
+ "y": -332.60365226838485,
+ "z": 0.0
+ },
+ {
+ "x": 232.260814544615,
+ "y": -332.6037595854809,
+ "z": 0.0
+ },
+ {
+ "x": 233.26574727430304,
+ "y": -332.6038669025769,
+ "z": 0.0
+ },
+ {
+ "x": 234.27068000399137,
+ "y": -332.603974219673,
+ "z": 0.0
+ },
+ {
+ "x": 235.2756127336799,
+ "y": -332.60408153676906,
+ "z": 0.0
+ },
+ {
+ "x": 236.280545463368,
+ "y": -332.6041888538651,
+ "z": 0.0
+ },
+ {
+ "x": 237.28547819305626,
+ "y": -332.60429617096116,
+ "z": 0.0
+ },
+ {
+ "x": 238.2904109227448,
+ "y": -332.60440348805724,
+ "z": 0.0
+ },
+ {
+ "x": 239.29534365243288,
+ "y": -332.60451080515327,
+ "z": 0.0
+ },
+ {
+ "x": 240.30027638212115,
+ "y": -332.60461812224935,
+ "z": 0.0
+ },
+ {
+ "x": 241.30520911180972,
+ "y": -332.60472543934543,
+ "z": 0.0
+ },
+ {
+ "x": 242.31014184149802,
+ "y": -332.60483275644145,
+ "z": 0.0
+ },
+ {
+ "x": 243.31507457118607,
+ "y": -332.6049400735375,
+ "z": 0.0
+ },
+ {
+ "x": 244.32000730087438,
+ "y": -332.60504739063356,
+ "z": 0.0
+ },
+ {
+ "x": 245.3249400305629,
+ "y": -332.60515470772964,
+ "z": 0.0
+ },
+ {
+ "x": 246.329872760251,
+ "y": -332.60526202482566,
+ "z": 0.0
+ },
+ {
+ "x": 247.33480548993927,
+ "y": -332.60536934192174,
+ "z": 0.0
+ },
+ {
+ "x": 248.33973821962783,
+ "y": -332.6054766590178,
+ "z": 0.0
+ },
+ {
+ "x": 249.3446709493159,
+ "y": -332.60558397611385,
+ "z": 0.0
+ },
+ {
+ "x": 250.3496036790042,
+ "y": -332.60569129320993,
+ "z": 0.0
+ },
+ {
+ "x": 251.35453640869272,
+ "y": -332.605798610306,
+ "z": 0.0
+ },
+ {
+ "x": 252.3594691383808,
+ "y": -332.60590592740203,
+ "z": 0.0
+ },
+ {
+ "x": 253.3644018680693,
+ "y": -332.6060132444981,
+ "z": 0.0
+ },
+ {
+ "x": 254.3693345977574,
+ "y": -332.60612056159414,
+ "z": 0.0
+ },
+ {
+ "x": 255.37426732744572,
+ "y": -332.6062278786902,
+ "z": 0.0
+ },
+ {
+ "x": 256.37920005713426,
+ "y": -332.6063351957863,
+ "z": 0.0
+ },
+ {
+ "x": 257.3841327868223,
+ "y": -332.6064425128823,
+ "z": 0.0
+ },
+ {
+ "x": 258.3890655165108,
+ "y": -332.6065498299784,
+ "z": 0.0
+ },
+ {
+ "x": 259.3939982461989,
+ "y": -332.60665714707443,
+ "z": 0.0
+ },
+ {
+ "x": 260.3989309758872,
+ "y": -332.6067644641705,
+ "z": 0.0
+ },
+ {
+ "x": 261.4038637055757,
+ "y": -332.6068717812666,
+ "z": 0.0
+ },
+ {
+ "x": 262.4087964352638,
+ "y": -332.6069790983626,
+ "z": 0.0
+ },
+ {
+ "x": 263.4137291649524,
+ "y": -332.6070864154587,
+ "z": 0.0
+ },
+ {
+ "x": 264.4186618946404,
+ "y": -332.6071937325547,
+ "z": 0.0
+ },
+ {
+ "x": 265.4235946243287,
+ "y": -332.6073010496508,
+ "z": 0.0
+ },
+ {
+ "x": 266.42852735401726,
+ "y": -332.6074083667469,
+ "z": 0.0
+ },
+ {
+ "x": 267.4334600837053,
+ "y": -332.6075156838429,
+ "z": 0.0
+ },
+ {
+ "x": 268.4383928133936,
+ "y": -332.607623000939,
+ "z": 0.0
+ },
+ {
+ "x": 269.44332554308215,
+ "y": -332.60773031803507,
+ "z": 0.0
+ },
+ {
+ "x": 270.44825827277026,
+ "y": -332.6078376351311,
+ "z": 0.0
+ },
+ {
+ "x": 271.45319100245854,
+ "y": -332.6079449522272,
+ "z": 0.0
+ },
+ {
+ "x": 272.45812373214704,
+ "y": -332.60805226932325,
+ "z": 0.0
+ },
+ {
+ "x": 273.46305646183515,
+ "y": -332.6081595864193,
+ "z": 0.0
+ },
+ {
+ "x": 274.46798919152366,
+ "y": -332.60826690351536,
+ "z": 0.0
+ },
+ {
+ "x": 275.4729219212117,
+ "y": -332.6083742206114,
+ "z": 0.0
+ },
+ {
+ "x": 276.47785465090027,
+ "y": -332.60848153770746,
+ "z": 0.0
+ },
+ {
+ "x": 277.4827873805884,
+ "y": -332.6085888548035,
+ "z": 0.0
+ },
+ {
+ "x": 278.48772011027665,
+ "y": -332.60869617189957,
+ "z": 0.0
+ },
+ {
+ "x": 279.49265283996516,
+ "y": -332.60880348899565,
+ "z": 0.0
+ },
+ {
+ "x": 280.49758556965327,
+ "y": -332.60891080609167,
+ "z": 0.0
+ },
+ {
+ "x": 281.50251829934155,
+ "y": -332.60901812318775,
+ "z": 0.0
+ },
+ {
+ "x": 282.50745102903005,
+ "y": -332.60912544028383,
+ "z": 0.0
+ },
+ {
+ "x": 283.51238375871816,
+ "y": -332.60923275737986,
+ "z": 0.0
+ },
+ {
+ "x": 284.5173164884065,
+ "y": -332.60934007447594,
+ "z": 0.0
+ },
+ {
+ "x": 285.522249218095,
+ "y": -332.609447391572,
+ "z": 0.0
+ },
+ {
+ "x": 286.5271819477833,
+ "y": -332.60955470866804,
+ "z": 0.0
+ },
+ {
+ "x": 287.53211467747116,
+ "y": -332.60966202576407,
+ "z": 0.0
+ },
+ {
+ "x": 288.5370474071599,
+ "y": -332.6097693428602,
+ "z": 0.0
+ },
+ {
+ "x": 289.54198312081223,
+ "y": -332.6098766602738,
+ "z": 0.0
+ },
+ {
+ "x": 290.54733166367475,
+ "y": -332.6099832501811,
+ "z": 0.0
+ },
+ {
+ "x": 291.55227276326934,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 292.55720549868784,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 293.5621382341064,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 294.56707096952493,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 295.5720037049434,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 296.5769364403619,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 297.58186917578047,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 298.586801911199,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 299.5917346466175,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 300.59666738203606,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 301.6016001174546,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 302.6065328528731,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 303.6114655882916,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 304.61639832371014,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 305.6213310591287,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 306.6262637945472,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 307.63119652996573,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 308.6361292653843,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 309.6410620008028,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 310.64599473622127,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 311.6509274716398,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 312.65586020705837,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 313.66079294247686,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 314.6657256778954,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 315.67065841331396,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 316.67559114873245,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 317.68052388415094,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 318.6854566195695,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 319.69038935498804,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 320.69532209040653,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 321.7002548258251,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 322.70518756124363,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 323.7101202966621,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 324.7150530320806,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 325.71998576749917,
+ "y": -332.6099853515625,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 32,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 101.6199870840165,
+ "y": -328.58905350038367,
+ "z": 0.0
+ },
+ {
+ "x": 102.62491967524001,
+ "y": -328.5895918428066,
+ "z": 0.0
+ },
+ {
+ "x": 103.62985230582132,
+ "y": -328.5900230199937,
+ "z": 0.0
+ },
+ {
+ "x": 104.63478503550962,
+ "y": -328.59013033708976,
+ "z": 0.0
+ },
+ {
+ "x": 105.63971776519793,
+ "y": -328.59023765418584,
+ "z": 0.0
+ },
+ {
+ "x": 106.64465049488625,
+ "y": -328.59034497128187,
+ "z": 0.0
+ },
+ {
+ "x": 107.64958322457456,
+ "y": -328.5904522883779,
+ "z": 0.0
+ },
+ {
+ "x": 108.65451595426286,
+ "y": -328.590559605474,
+ "z": 0.0
+ },
+ {
+ "x": 109.65944868395118,
+ "y": -328.59066692257005,
+ "z": 0.0
+ },
+ {
+ "x": 110.66438141363949,
+ "y": -328.5907742396661,
+ "z": 0.0
+ },
+ {
+ "x": 111.6693141433278,
+ "y": -328.5908815567622,
+ "z": 0.0
+ },
+ {
+ "x": 112.67424687301612,
+ "y": -328.59098887385824,
+ "z": 0.0
+ },
+ {
+ "x": 113.67917960270442,
+ "y": -328.59109619095426,
+ "z": 0.0
+ },
+ {
+ "x": 114.68411233239273,
+ "y": -328.59120350805034,
+ "z": 0.0
+ },
+ {
+ "x": 115.68904506208104,
+ "y": -328.5913108251464,
+ "z": 0.0
+ },
+ {
+ "x": 116.69397779176936,
+ "y": -328.59141814224245,
+ "z": 0.0
+ },
+ {
+ "x": 117.69891052145766,
+ "y": -328.59152545933847,
+ "z": 0.0
+ },
+ {
+ "x": 118.70384325114597,
+ "y": -328.5916327764346,
+ "z": 0.0
+ },
+ {
+ "x": 119.70877598083429,
+ "y": -328.59174009353063,
+ "z": 0.0
+ },
+ {
+ "x": 120.7137087105226,
+ "y": -328.59184741062666,
+ "z": 0.0
+ },
+ {
+ "x": 121.7186414402109,
+ "y": -328.5919547277228,
+ "z": 0.0
+ },
+ {
+ "x": 122.72357416989922,
+ "y": -328.5920620448188,
+ "z": 0.0
+ },
+ {
+ "x": 123.72850689958754,
+ "y": -328.59216936191484,
+ "z": 0.0
+ },
+ {
+ "x": 124.73343962927585,
+ "y": -328.5922766790109,
+ "z": 0.0
+ },
+ {
+ "x": 125.73837235896416,
+ "y": -328.592383996107,
+ "z": 0.0
+ },
+ {
+ "x": 126.74330508865248,
+ "y": -328.592491313203,
+ "z": 0.0
+ },
+ {
+ "x": 127.74823781834078,
+ "y": -328.5925986302991,
+ "z": 0.0
+ },
+ {
+ "x": 128.7531705480291,
+ "y": -328.5927059473952,
+ "z": 0.0
+ },
+ {
+ "x": 129.75810327771742,
+ "y": -328.5928132644912,
+ "z": 0.0
+ },
+ {
+ "x": 130.76303600740573,
+ "y": -328.59292058158724,
+ "z": 0.0
+ },
+ {
+ "x": 131.76796873709404,
+ "y": -328.5930278986834,
+ "z": 0.0
+ },
+ {
+ "x": 132.77290146678234,
+ "y": -328.5931352157794,
+ "z": 0.0
+ },
+ {
+ "x": 133.77783419647065,
+ "y": -328.5932425328754,
+ "z": 0.0
+ },
+ {
+ "x": 134.78276692615898,
+ "y": -328.5933498499715,
+ "z": 0.0
+ },
+ {
+ "x": 135.78769965584726,
+ "y": -328.5934571670676,
+ "z": 0.0
+ },
+ {
+ "x": 136.7926323855356,
+ "y": -328.5935644841636,
+ "z": 0.0
+ },
+ {
+ "x": 137.7975651152239,
+ "y": -328.5936718012597,
+ "z": 0.0
+ },
+ {
+ "x": 138.8024978449122,
+ "y": -328.59377911835577,
+ "z": 0.0
+ },
+ {
+ "x": 139.80743057460052,
+ "y": -328.5938864354518,
+ "z": 0.0
+ },
+ {
+ "x": 140.81236330428882,
+ "y": -328.5939937525479,
+ "z": 0.0
+ },
+ {
+ "x": 141.81729603397713,
+ "y": -328.59410106964395,
+ "z": 0.0
+ },
+ {
+ "x": 142.82222876366544,
+ "y": -328.59420838674,
+ "z": 0.0
+ },
+ {
+ "x": 143.82716149335374,
+ "y": -328.59431570383606,
+ "z": 0.0
+ },
+ {
+ "x": 144.83209422304205,
+ "y": -328.59442302093214,
+ "z": 0.0
+ },
+ {
+ "x": 145.83702695273035,
+ "y": -328.59453033802816,
+ "z": 0.0
+ },
+ {
+ "x": 146.84195968241866,
+ "y": -328.5946376551242,
+ "z": 0.0
+ },
+ {
+ "x": 147.846892412107,
+ "y": -328.59474497222027,
+ "z": 0.0
+ },
+ {
+ "x": 148.8518251417953,
+ "y": -328.59485228931635,
+ "z": 0.0
+ },
+ {
+ "x": 149.8567578714836,
+ "y": -328.5949596064124,
+ "z": 0.0
+ },
+ {
+ "x": 150.86169060117192,
+ "y": -328.59506692350845,
+ "z": 0.0
+ },
+ {
+ "x": 151.86662333086022,
+ "y": -328.59517424060454,
+ "z": 0.0
+ },
+ {
+ "x": 152.87155606054853,
+ "y": -328.59528155770056,
+ "z": 0.0
+ },
+ {
+ "x": 153.87648879023683,
+ "y": -328.59538887479664,
+ "z": 0.0
+ },
+ {
+ "x": 154.88142151992514,
+ "y": -328.5954961918927,
+ "z": 0.0
+ },
+ {
+ "x": 155.88635424961345,
+ "y": -328.59560350898875,
+ "z": 0.0
+ },
+ {
+ "x": 156.89128697930175,
+ "y": -328.5957108260848,
+ "z": 0.0
+ },
+ {
+ "x": 157.8962197089901,
+ "y": -328.59581814318085,
+ "z": 0.0
+ },
+ {
+ "x": 158.9011524386784,
+ "y": -328.59592546027693,
+ "z": 0.0
+ },
+ {
+ "x": 159.9060851683667,
+ "y": -328.596032777373,
+ "z": 0.0
+ },
+ {
+ "x": 160.911017898055,
+ "y": -328.59614009446904,
+ "z": 0.0
+ },
+ {
+ "x": 161.9159506277433,
+ "y": -328.5962474115651,
+ "z": 0.0
+ },
+ {
+ "x": 162.92088335743162,
+ "y": -328.59635472866114,
+ "z": 0.0
+ },
+ {
+ "x": 163.92581608711993,
+ "y": -328.5964620457572,
+ "z": 0.0
+ },
+ {
+ "x": 164.93074881680823,
+ "y": -328.5965693628533,
+ "z": 0.0
+ },
+ {
+ "x": 165.93568154649654,
+ "y": -328.5966766799493,
+ "z": 0.0
+ },
+ {
+ "x": 166.94061427618485,
+ "y": -328.5967839970454,
+ "z": 0.0
+ },
+ {
+ "x": 167.94554700587318,
+ "y": -328.59689131414143,
+ "z": 0.0
+ },
+ {
+ "x": 168.9504797355615,
+ "y": -328.5969986312375,
+ "z": 0.0
+ },
+ {
+ "x": 169.9554124652498,
+ "y": -328.5971059483336,
+ "z": 0.0
+ },
+ {
+ "x": 170.96034519493813,
+ "y": -328.5972132654296,
+ "z": 0.0
+ },
+ {
+ "x": 171.96527792462643,
+ "y": -328.5973205825257,
+ "z": 0.0
+ },
+ {
+ "x": 172.97021065431477,
+ "y": -328.5974278996218,
+ "z": 0.0
+ },
+ {
+ "x": 173.97514338400308,
+ "y": -328.5975352167178,
+ "z": 0.0
+ },
+ {
+ "x": 174.98007611369138,
+ "y": -328.5976425338139,
+ "z": 0.0
+ },
+ {
+ "x": 175.98500884337972,
+ "y": -328.59774985090996,
+ "z": 0.0
+ },
+ {
+ "x": 176.98994157306802,
+ "y": -328.597857168006,
+ "z": 0.0
+ },
+ {
+ "x": 177.99487430275633,
+ "y": -328.597964485102,
+ "z": 0.0
+ },
+ {
+ "x": 178.99980703244466,
+ "y": -328.5980718021981,
+ "z": 0.0
+ },
+ {
+ "x": 180.00473976213297,
+ "y": -328.5981791192942,
+ "z": 0.0
+ },
+ {
+ "x": 181.00967249182128,
+ "y": -328.5982864363902,
+ "z": 0.0
+ },
+ {
+ "x": 182.01460522150958,
+ "y": -328.5983937534863,
+ "z": 0.0
+ },
+ {
+ "x": 183.01953795119792,
+ "y": -328.59850107058236,
+ "z": 0.0
+ },
+ {
+ "x": 184.02447068088622,
+ "y": -328.5986083876784,
+ "z": 0.0
+ },
+ {
+ "x": 185.02940341057453,
+ "y": -328.59871570477446,
+ "z": 0.0
+ },
+ {
+ "x": 186.03433614026287,
+ "y": -328.59882302187054,
+ "z": 0.0
+ },
+ {
+ "x": 187.03926886995117,
+ "y": -328.59893033896657,
+ "z": 0.0
+ },
+ {
+ "x": 188.0442015996395,
+ "y": -328.59903765606265,
+ "z": 0.0
+ },
+ {
+ "x": 189.0491343293278,
+ "y": -328.59914497315873,
+ "z": 0.0
+ },
+ {
+ "x": 190.05406705901612,
+ "y": -328.59925229025475,
+ "z": 0.0
+ },
+ {
+ "x": 191.05899978870445,
+ "y": -328.59935960735083,
+ "z": 0.0
+ },
+ {
+ "x": 192.06393251839276,
+ "y": -328.5994669244469,
+ "z": 0.0
+ },
+ {
+ "x": 193.0688652480811,
+ "y": -328.59957424154294,
+ "z": 0.0
+ },
+ {
+ "x": 194.0737979777694,
+ "y": -328.59968155863896,
+ "z": 0.0
+ },
+ {
+ "x": 195.0787307074577,
+ "y": -328.59978887573504,
+ "z": 0.0
+ },
+ {
+ "x": 196.08366343714601,
+ "y": -328.5998961928311,
+ "z": 0.0
+ },
+ {
+ "x": 197.08859616683435,
+ "y": -328.60000350992715,
+ "z": 0.0
+ },
+ {
+ "x": 198.09352889652266,
+ "y": -328.60011082702323,
+ "z": 0.0
+ },
+ {
+ "x": 199.09846162621096,
+ "y": -328.6002181441193,
+ "z": 0.0
+ },
+ {
+ "x": 200.1033943558993,
+ "y": -328.60032546121533,
+ "z": 0.0
+ },
+ {
+ "x": 201.1083270855876,
+ "y": -328.6004327783114,
+ "z": 0.0
+ },
+ {
+ "x": 202.1132598152759,
+ "y": -328.6005400954075,
+ "z": 0.0
+ },
+ {
+ "x": 203.11819254496424,
+ "y": -328.6006474125035,
+ "z": 0.0
+ },
+ {
+ "x": 204.12312527465255,
+ "y": -328.60075472959954,
+ "z": 0.0
+ },
+ {
+ "x": 205.12805800434086,
+ "y": -328.6008620466957,
+ "z": 0.0
+ },
+ {
+ "x": 206.1329907340292,
+ "y": -328.6009693637917,
+ "z": 0.0
+ },
+ {
+ "x": 207.1379234637175,
+ "y": -328.60107668088773,
+ "z": 0.0
+ },
+ {
+ "x": 208.14285619340583,
+ "y": -328.60118399798387,
+ "z": 0.0
+ },
+ {
+ "x": 209.14778892309414,
+ "y": -328.6012913150799,
+ "z": 0.0
+ },
+ {
+ "x": 210.15272165278245,
+ "y": -328.6013986321759,
+ "z": 0.0
+ },
+ {
+ "x": 211.15765438247078,
+ "y": -328.601505949272,
+ "z": 0.0
+ },
+ {
+ "x": 212.1625871121591,
+ "y": -328.6016132663681,
+ "z": 0.0
+ },
+ {
+ "x": 213.1675198418474,
+ "y": -328.6017205834641,
+ "z": 0.0
+ },
+ {
+ "x": 214.17245257153573,
+ "y": -328.6018279005601,
+ "z": 0.0
+ },
+ {
+ "x": 215.17738530122404,
+ "y": -328.60193521765626,
+ "z": 0.0
+ },
+ {
+ "x": 216.18231803091234,
+ "y": -328.6020425347523,
+ "z": 0.0
+ },
+ {
+ "x": 217.18725076060065,
+ "y": -328.6021498518483,
+ "z": 0.0
+ },
+ {
+ "x": 218.19218349028898,
+ "y": -328.60225716894445,
+ "z": 0.0
+ },
+ {
+ "x": 219.1971162199773,
+ "y": -328.60236448604047,
+ "z": 0.0
+ },
+ {
+ "x": 220.2020489496656,
+ "y": -328.6024718031365,
+ "z": 0.0
+ },
+ {
+ "x": 221.20698167935393,
+ "y": -328.6025791202326,
+ "z": 0.0
+ },
+ {
+ "x": 222.21191440904224,
+ "y": -328.60268643732866,
+ "z": 0.0
+ },
+ {
+ "x": 223.21684713873054,
+ "y": -328.6027937544247,
+ "z": 0.0
+ },
+ {
+ "x": 224.22177986841888,
+ "y": -328.60290107152076,
+ "z": 0.0
+ },
+ {
+ "x": 225.22671259810718,
+ "y": -328.60300838861684,
+ "z": 0.0
+ },
+ {
+ "x": 226.23164532779552,
+ "y": -328.60311570571287,
+ "z": 0.0
+ },
+ {
+ "x": 227.23657805748383,
+ "y": -328.6032230228089,
+ "z": 0.0
+ },
+ {
+ "x": 228.24151078717213,
+ "y": -328.603330339905,
+ "z": 0.0
+ },
+ {
+ "x": 229.24644351686047,
+ "y": -328.60343765700105,
+ "z": 0.0
+ },
+ {
+ "x": 230.25137624654874,
+ "y": -328.6035449740971,
+ "z": 0.0
+ },
+ {
+ "x": 231.25630897623705,
+ "y": -328.6036522911932,
+ "z": 0.0
+ },
+ {
+ "x": 232.26124170592536,
+ "y": -328.60375960828924,
+ "z": 0.0
+ },
+ {
+ "x": 233.26617443561364,
+ "y": -328.60386692538526,
+ "z": 0.0
+ },
+ {
+ "x": 234.27110716530197,
+ "y": -328.60397424248134,
+ "z": 0.0
+ },
+ {
+ "x": 235.27603989499028,
+ "y": -328.6040815595774,
+ "z": 0.0
+ },
+ {
+ "x": 236.28097262467858,
+ "y": -328.60418887667345,
+ "z": 0.0
+ },
+ {
+ "x": 237.28590535436686,
+ "y": -328.6042961937695,
+ "z": 0.0
+ },
+ {
+ "x": 238.29083808405517,
+ "y": -328.6044035108656,
+ "z": 0.0
+ },
+ {
+ "x": 239.29577081374347,
+ "y": -328.60451082796163,
+ "z": 0.0
+ },
+ {
+ "x": 240.30070354343175,
+ "y": -328.6046181450577,
+ "z": 0.0
+ },
+ {
+ "x": 241.3056362731201,
+ "y": -328.6047254621538,
+ "z": 0.0
+ },
+ {
+ "x": 242.3105690028084,
+ "y": -328.6048327792498,
+ "z": 0.0
+ },
+ {
+ "x": 243.31550173249667,
+ "y": -328.60494009634584,
+ "z": 0.0
+ },
+ {
+ "x": 244.32043446218498,
+ "y": -328.6050474134419,
+ "z": 0.0
+ },
+ {
+ "x": 245.32536719187328,
+ "y": -328.605154730538,
+ "z": 0.0
+ },
+ {
+ "x": 246.3302999215616,
+ "y": -328.605262047634,
+ "z": 0.0
+ },
+ {
+ "x": 247.33523265124987,
+ "y": -328.6053693647301,
+ "z": 0.0
+ },
+ {
+ "x": 248.3401653809382,
+ "y": -328.6054766818262,
+ "z": 0.0
+ },
+ {
+ "x": 249.3450981106265,
+ "y": -328.6055839989222,
+ "z": 0.0
+ },
+ {
+ "x": 250.3500308403148,
+ "y": -328.6056913160183,
+ "z": 0.0
+ },
+ {
+ "x": 251.3549635700031,
+ "y": -328.6057986331144,
+ "z": 0.0
+ },
+ {
+ "x": 252.3598962996914,
+ "y": -328.6059059502104,
+ "z": 0.0
+ },
+ {
+ "x": 253.36482902937968,
+ "y": -328.6060132673065,
+ "z": 0.0
+ },
+ {
+ "x": 254.36976175906798,
+ "y": -328.6061205844025,
+ "z": 0.0
+ },
+ {
+ "x": 255.37469448875632,
+ "y": -328.6062279014986,
+ "z": 0.0
+ },
+ {
+ "x": 256.3796272184446,
+ "y": -328.60633521859467,
+ "z": 0.0
+ },
+ {
+ "x": 257.3845599481329,
+ "y": -328.6064425356907,
+ "z": 0.0
+ },
+ {
+ "x": 258.3894926778212,
+ "y": -328.60654985278677,
+ "z": 0.0
+ },
+ {
+ "x": 259.3944254075095,
+ "y": -328.6066571698828,
+ "z": 0.0
+ },
+ {
+ "x": 260.3993581371978,
+ "y": -328.6067644869789,
+ "z": 0.0
+ },
+ {
+ "x": 261.4042908668861,
+ "y": -328.60687180407496,
+ "z": 0.0
+ },
+ {
+ "x": 262.4092235965744,
+ "y": -328.606979121171,
+ "z": 0.0
+ },
+ {
+ "x": 263.41415632626274,
+ "y": -328.60708643826706,
+ "z": 0.0
+ },
+ {
+ "x": 264.419089055951,
+ "y": -328.6071937553631,
+ "z": 0.0
+ },
+ {
+ "x": 265.4240217856393,
+ "y": -328.60730107245917,
+ "z": 0.0
+ },
+ {
+ "x": 266.42895451532763,
+ "y": -328.60740838955525,
+ "z": 0.0
+ },
+ {
+ "x": 267.4338872450159,
+ "y": -328.60751570665127,
+ "z": 0.0
+ },
+ {
+ "x": 268.4388199747042,
+ "y": -328.60762302374735,
+ "z": 0.0
+ },
+ {
+ "x": 269.4437527043925,
+ "y": -328.60773034084343,
+ "z": 0.0
+ },
+ {
+ "x": 270.44868543408086,
+ "y": -328.60783765793946,
+ "z": 0.0
+ },
+ {
+ "x": 271.45361816376914,
+ "y": -328.60794497503554,
+ "z": 0.0
+ },
+ {
+ "x": 272.4585508934574,
+ "y": -328.6080522921316,
+ "z": 0.0
+ },
+ {
+ "x": 273.46348362314575,
+ "y": -328.60815960922764,
+ "z": 0.0
+ },
+ {
+ "x": 274.468416352834,
+ "y": -328.6082669263237,
+ "z": 0.0
+ },
+ {
+ "x": 275.4733490825223,
+ "y": -328.60837424341975,
+ "z": 0.0
+ },
+ {
+ "x": 276.47828181221064,
+ "y": -328.6084815605158,
+ "z": 0.0
+ },
+ {
+ "x": 277.483214541899,
+ "y": -328.60858887761185,
+ "z": 0.0
+ },
+ {
+ "x": 278.48814727158725,
+ "y": -328.60869619470793,
+ "z": 0.0
+ },
+ {
+ "x": 279.49308000127553,
+ "y": -328.608803511804,
+ "z": 0.0
+ },
+ {
+ "x": 280.49801273096386,
+ "y": -328.60891082890004,
+ "z": 0.0
+ },
+ {
+ "x": 281.50294546065214,
+ "y": -328.6090181459961,
+ "z": 0.0
+ },
+ {
+ "x": 282.5078781903404,
+ "y": -328.6091254630922,
+ "z": 0.0
+ },
+ {
+ "x": 283.51281092002876,
+ "y": -328.6092327801882,
+ "z": 0.0
+ },
+ {
+ "x": 284.5177436497171,
+ "y": -328.6093400972843,
+ "z": 0.0
+ },
+ {
+ "x": 285.52267637940537,
+ "y": -328.6094474143804,
+ "z": 0.0
+ },
+ {
+ "x": 286.52760910909365,
+ "y": -328.6095547314764,
+ "z": 0.0
+ },
+ {
+ "x": 287.532541838782,
+ "y": -328.60966204857243,
+ "z": 0.0
+ },
+ {
+ "x": 288.53747456847026,
+ "y": -328.60976936566857,
+ "z": 0.0
+ },
+ {
+ "x": 289.54240729815854,
+ "y": -328.6098766827646,
+ "z": 0.0
+ },
+ {
+ "x": 290.5473400279069,
+ "y": -328.6099832501898,
+ "z": 0.0
+ },
+ {
+ "x": 291.55227276326934,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 292.55720549868784,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 293.5621382341064,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 294.56707096952493,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 295.5720037049434,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 296.5769364403619,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 297.58186917578047,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 298.586801911199,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 299.5917346466175,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 300.59666738203606,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 301.6016001174546,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 302.6065328528731,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 303.6114655882916,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 304.61639832371014,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 305.6213310591287,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 306.6262637945472,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 307.63119652996573,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 308.6361292653843,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 309.6410620008028,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 310.64599473622127,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 311.6509274716398,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 312.65586020705837,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 313.66079294247686,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 314.6657256778954,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 315.67065841331396,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 316.67559114873245,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 317.68052388415094,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 318.6854566195695,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 319.69038935498804,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 320.69532209040653,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 321.7002548258251,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 322.70518756124363,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 323.7101202966621,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 324.7150530320806,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 325.71998576749917,
+ "y": -328.6099853515625,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 33,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 325.71998576749917,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 324.7150530320806,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 323.7101202966621,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 322.70518756124363,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 321.7002548258251,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 320.69532209040653,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 319.69038935498804,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 318.6854566195695,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 317.68052388415094,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 316.67559114873245,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 315.67065841331396,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 314.6657256778954,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 313.66079294247686,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 312.65586020705837,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 311.6509274716398,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 310.64599473622127,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 309.6410620008028,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 308.6361292653843,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 307.63119652996573,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 306.6262637945472,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 305.6213310591287,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 304.61639832371014,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 303.6114655882916,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 302.6065328528731,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 301.6016001174546,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 300.59666738203606,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 299.5917346466175,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 298.586801911199,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 297.58186917578047,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 296.5769364403619,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 295.5720037049434,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 294.56707096952493,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 293.5621382341064,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 292.55720549868784,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 291.55227276326934,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 290.54734421002297,
+ "y": -326.6099832501942,
+ "z": 0.0
+ },
+ {
+ "x": 289.5426193868317,
+ "y": -326.60987669401,
+ "z": 0.0
+ },
+ {
+ "x": 288.5376881491254,
+ "y": -326.6097693770728,
+ "z": 0.0
+ },
+ {
+ "x": 287.5327554194374,
+ "y": -326.6096620599766,
+ "z": 0.0
+ },
+ {
+ "x": 286.52782268974886,
+ "y": -326.6095547428806,
+ "z": 0.0
+ },
+ {
+ "x": 285.5228899600605,
+ "y": -326.60944742578454,
+ "z": 0.0
+ },
+ {
+ "x": 284.5179572303724,
+ "y": -326.60934010868846,
+ "z": 0.0
+ },
+ {
+ "x": 283.5130245006841,
+ "y": -326.6092327915924,
+ "z": 0.0
+ },
+ {
+ "x": 282.50809177099563,
+ "y": -326.6091254744964,
+ "z": 0.0
+ },
+ {
+ "x": 281.5031590413074,
+ "y": -326.6090181574003,
+ "z": 0.0
+ },
+ {
+ "x": 280.4982263116192,
+ "y": -326.60891084030425,
+ "z": 0.0
+ },
+ {
+ "x": 279.49329358193074,
+ "y": -326.60880352320817,
+ "z": 0.0
+ },
+ {
+ "x": 278.4883608522425,
+ "y": -326.6086962061121,
+ "z": 0.0
+ },
+ {
+ "x": 277.4834281225543,
+ "y": -326.608588889016,
+ "z": 0.0
+ },
+ {
+ "x": 276.47849539286585,
+ "y": -326.60848157192004,
+ "z": 0.0
+ },
+ {
+ "x": 275.47356266317763,
+ "y": -326.60837425482396,
+ "z": 0.0
+ },
+ {
+ "x": 274.4686299334892,
+ "y": -326.6082669377279,
+ "z": 0.0
+ },
+ {
+ "x": 273.4636972038011,
+ "y": -326.6081596206318,
+ "z": 0.0
+ },
+ {
+ "x": 272.4587644741126,
+ "y": -326.6080523035358,
+ "z": 0.0
+ },
+ {
+ "x": 271.4538317444244,
+ "y": -326.60794498643975,
+ "z": 0.0
+ },
+ {
+ "x": 270.4488990147362,
+ "y": -326.60783766934367,
+ "z": 0.0
+ },
+ {
+ "x": 269.44396628504774,
+ "y": -326.6077303522476,
+ "z": 0.0
+ },
+ {
+ "x": 268.4390335553595,
+ "y": -326.6076230351515,
+ "z": 0.0
+ },
+ {
+ "x": 267.4341008256712,
+ "y": -326.6075157180554,
+ "z": 0.0
+ },
+ {
+ "x": 266.42916809598285,
+ "y": -326.60740840095946,
+ "z": 0.0
+ },
+ {
+ "x": 265.4242353662946,
+ "y": -326.6073010838634,
+ "z": 0.0
+ },
+ {
+ "x": 264.4193026366063,
+ "y": -326.6071937667673,
+ "z": 0.0
+ },
+ {
+ "x": 263.41436990691795,
+ "y": -326.6070864496712,
+ "z": 0.0
+ },
+ {
+ "x": 262.40943717722973,
+ "y": -326.60697913257513,
+ "z": 0.0
+ },
+ {
+ "x": 261.4045044475413,
+ "y": -326.60687181547917,
+ "z": 0.0
+ },
+ {
+ "x": 260.39957171785306,
+ "y": -326.6067644983831,
+ "z": 0.0
+ },
+ {
+ "x": 259.39463898816484,
+ "y": -326.606657181287,
+ "z": 0.0
+ },
+ {
+ "x": 258.3897062584764,
+ "y": -326.6065498641909,
+ "z": 0.0
+ },
+ {
+ "x": 257.3847735287882,
+ "y": -326.60644254709484,
+ "z": 0.0
+ },
+ {
+ "x": 256.37984079909984,
+ "y": -326.6063352299989,
+ "z": 0.0
+ },
+ {
+ "x": 255.37490806941162,
+ "y": -326.6062279129028,
+ "z": 0.0
+ },
+ {
+ "x": 254.36997533972328,
+ "y": -326.6061205958067,
+ "z": 0.0
+ },
+ {
+ "x": 253.36504261003486,
+ "y": -326.60601327871063,
+ "z": 0.0
+ },
+ {
+ "x": 252.3601098803467,
+ "y": -326.60590596161455,
+ "z": 0.0
+ },
+ {
+ "x": 251.35517715065828,
+ "y": -326.6057986445186,
+ "z": 0.0
+ },
+ {
+ "x": 250.35024442097009,
+ "y": -326.6056913274225,
+ "z": 0.0
+ },
+ {
+ "x": 249.3453116912818,
+ "y": -326.6055840103264,
+ "z": 0.0
+ },
+ {
+ "x": 248.3403789615934,
+ "y": -326.60547669323034,
+ "z": 0.0
+ },
+ {
+ "x": 247.33544623190517,
+ "y": -326.60536937613426,
+ "z": 0.0
+ },
+ {
+ "x": 246.3305135022169,
+ "y": -326.6052620590382,
+ "z": 0.0
+ },
+ {
+ "x": 245.32558077252847,
+ "y": -326.6051547419422,
+ "z": 0.0
+ },
+ {
+ "x": 244.32064804284028,
+ "y": -326.60504742484613,
+ "z": 0.0
+ },
+ {
+ "x": 243.31571531315197,
+ "y": -326.60494010775005,
+ "z": 0.0
+ },
+ {
+ "x": 242.31078258346358,
+ "y": -326.604832790654,
+ "z": 0.0
+ },
+ {
+ "x": 241.30584985377527,
+ "y": -326.604725473558,
+ "z": 0.0
+ },
+ {
+ "x": 240.30091712408705,
+ "y": -326.6046181564619,
+ "z": 0.0
+ },
+ {
+ "x": 239.29598439439877,
+ "y": -326.60451083936584,
+ "z": 0.0
+ },
+ {
+ "x": 238.29105166471035,
+ "y": -326.60440352226976,
+ "z": 0.0
+ },
+ {
+ "x": 237.28611893502216,
+ "y": -326.6042962051737,
+ "z": 0.0
+ },
+ {
+ "x": 236.28118620533388,
+ "y": -326.6041888880776,
+ "z": 0.0
+ },
+ {
+ "x": 235.27625347564546,
+ "y": -326.60408157098163,
+ "z": 0.0
+ },
+ {
+ "x": 234.27132074595727,
+ "y": -326.60397425388555,
+ "z": 0.0
+ },
+ {
+ "x": 233.26638801626893,
+ "y": -326.6038669367895,
+ "z": 0.0
+ },
+ {
+ "x": 232.26145528658054,
+ "y": -326.6037596196934,
+ "z": 0.0
+ },
+ {
+ "x": 231.25652255689224,
+ "y": -326.6036523025974,
+ "z": 0.0
+ },
+ {
+ "x": 230.25158982720416,
+ "y": -326.60354498550123,
+ "z": 0.0
+ },
+ {
+ "x": 229.24665709751565,
+ "y": -326.60343766840526,
+ "z": 0.0
+ },
+ {
+ "x": 228.24172436782732,
+ "y": -326.6033303513092,
+ "z": 0.0
+ },
+ {
+ "x": 227.23679163813924,
+ "y": -326.6032230342131,
+ "z": 0.0
+ },
+ {
+ "x": 226.2318589084507,
+ "y": -326.603115717117,
+ "z": 0.0
+ },
+ {
+ "x": 225.22692617876237,
+ "y": -326.60300840002105,
+ "z": 0.0
+ },
+ {
+ "x": 224.22199344907418,
+ "y": -326.602901082925,
+ "z": 0.0
+ },
+ {
+ "x": 223.21706071938584,
+ "y": -326.6027937658289,
+ "z": 0.0
+ },
+ {
+ "x": 222.21212798969742,
+ "y": -326.6026864487328,
+ "z": 0.0
+ },
+ {
+ "x": 221.20719526000923,
+ "y": -326.60257913163673,
+ "z": 0.0
+ },
+ {
+ "x": 220.2022625303209,
+ "y": -326.60247181454065,
+ "z": 0.0
+ },
+ {
+ "x": 219.19732980063247,
+ "y": -326.6023644974447,
+ "z": 0.0
+ },
+ {
+ "x": 218.19239707094417,
+ "y": -326.6022571803486,
+ "z": 0.0
+ },
+ {
+ "x": 217.18746434125606,
+ "y": -326.6021498632525,
+ "z": 0.0
+ },
+ {
+ "x": 216.18253161156753,
+ "y": -326.60204254615644,
+ "z": 0.0
+ },
+ {
+ "x": 215.17759888187922,
+ "y": -326.6019352290605,
+ "z": 0.0
+ },
+ {
+ "x": 214.17266615219114,
+ "y": -326.6018279119643,
+ "z": 0.0
+ },
+ {
+ "x": 213.16773342250258,
+ "y": -326.6017205948683,
+ "z": 0.0
+ },
+ {
+ "x": 212.16280069281427,
+ "y": -326.60161327777223,
+ "z": 0.0
+ },
+ {
+ "x": 211.15786796312608,
+ "y": -326.60150596067615,
+ "z": 0.0
+ },
+ {
+ "x": 210.15293523343774,
+ "y": -326.60139864358007,
+ "z": 0.0
+ },
+ {
+ "x": 209.14800250374932,
+ "y": -326.6012913264841,
+ "z": 0.0
+ },
+ {
+ "x": 208.14306977406102,
+ "y": -326.601184009388,
+ "z": 0.0
+ },
+ {
+ "x": 207.1381370443729,
+ "y": -326.60107669229194,
+ "z": 0.0
+ },
+ {
+ "x": 206.13320431468438,
+ "y": -326.60096937519586,
+ "z": 0.0
+ },
+ {
+ "x": 205.12827158499604,
+ "y": -326.6008620580999,
+ "z": 0.0
+ },
+ {
+ "x": 204.12333885530796,
+ "y": -326.6007547410037,
+ "z": 0.0
+ },
+ {
+ "x": 203.11840612561943,
+ "y": -326.60064742390773,
+ "z": 0.0
+ },
+ {
+ "x": 202.1134733959311,
+ "y": -326.60054010681165,
+ "z": 0.0
+ },
+ {
+ "x": 201.1085406662429,
+ "y": -326.60043278971557,
+ "z": 0.0
+ },
+ {
+ "x": 200.1036079365546,
+ "y": -326.6003254726195,
+ "z": 0.0
+ },
+ {
+ "x": 199.09867520686615,
+ "y": -326.6002181555235,
+ "z": 0.0
+ },
+ {
+ "x": 198.09374247717795,
+ "y": -326.60011083842744,
+ "z": 0.0
+ },
+ {
+ "x": 197.08880974748965,
+ "y": -326.60000352133136,
+ "z": 0.0
+ },
+ {
+ "x": 196.0838770178012,
+ "y": -326.5998962042353,
+ "z": 0.0
+ },
+ {
+ "x": 195.078944288113,
+ "y": -326.5997888871392,
+ "z": 0.0
+ },
+ {
+ "x": 194.0740115584247,
+ "y": -326.5996815700431,
+ "z": 0.0
+ },
+ {
+ "x": 193.06907882873628,
+ "y": -326.59957425294715,
+ "z": 0.0
+ },
+ {
+ "x": 192.06414609904795,
+ "y": -326.59946693585107,
+ "z": 0.0
+ },
+ {
+ "x": 191.05921336935975,
+ "y": -326.599359618755,
+ "z": 0.0
+ },
+ {
+ "x": 190.05428063967142,
+ "y": -326.5992523016589,
+ "z": 0.0
+ },
+ {
+ "x": 189.049347909983,
+ "y": -326.59914498456294,
+ "z": 0.0
+ },
+ {
+ "x": 188.0444151802948,
+ "y": -326.59903766746686,
+ "z": 0.0
+ },
+ {
+ "x": 187.03948245060647,
+ "y": -326.5989303503708,
+ "z": 0.0
+ },
+ {
+ "x": 186.03454972091805,
+ "y": -326.5988230332747,
+ "z": 0.0
+ },
+ {
+ "x": 185.02961699122983,
+ "y": -326.5987157161786,
+ "z": 0.0
+ },
+ {
+ "x": 184.02468426154152,
+ "y": -326.59860839908254,
+ "z": 0.0
+ },
+ {
+ "x": 183.0197515318531,
+ "y": -326.59850108198657,
+ "z": 0.0
+ },
+ {
+ "x": 182.01481880216488,
+ "y": -326.5983937648905,
+ "z": 0.0
+ },
+ {
+ "x": 181.00988607247658,
+ "y": -326.5982864477944,
+ "z": 0.0
+ },
+ {
+ "x": 180.00495334278816,
+ "y": -326.5981791306983,
+ "z": 0.0
+ },
+ {
+ "x": 179.00002061309996,
+ "y": -326.59807181360225,
+ "z": 0.0
+ },
+ {
+ "x": 177.99508788341163,
+ "y": -326.59796449650617,
+ "z": 0.0
+ },
+ {
+ "x": 176.9901551537232,
+ "y": -326.5978571794102,
+ "z": 0.0
+ },
+ {
+ "x": 175.9852224240349,
+ "y": -326.5977498623141,
+ "z": 0.0
+ },
+ {
+ "x": 174.98028969434668,
+ "y": -326.59764254521804,
+ "z": 0.0
+ },
+ {
+ "x": 173.97535696465837,
+ "y": -326.59753522812196,
+ "z": 0.0
+ },
+ {
+ "x": 172.97042423496995,
+ "y": -326.597427911026,
+ "z": 0.0
+ },
+ {
+ "x": 171.96549150528173,
+ "y": -326.5973205939299,
+ "z": 0.0
+ },
+ {
+ "x": 170.96055877559343,
+ "y": -326.5972132768338,
+ "z": 0.0
+ },
+ {
+ "x": 169.95562604590498,
+ "y": -326.59710595973775,
+ "z": 0.0
+ },
+ {
+ "x": 168.95069331621679,
+ "y": -326.59699864264167,
+ "z": 0.0
+ },
+ {
+ "x": 167.94576058652848,
+ "y": -326.5968913255456,
+ "z": 0.0
+ },
+ {
+ "x": 166.94082785684003,
+ "y": -326.5967840084496,
+ "z": 0.0
+ },
+ {
+ "x": 165.93589512715184,
+ "y": -326.59667669135354,
+ "z": 0.0
+ },
+ {
+ "x": 164.93096239746342,
+ "y": -326.59656937425746,
+ "z": 0.0
+ },
+ {
+ "x": 163.92602966777523,
+ "y": -326.5964620571614,
+ "z": 0.0
+ },
+ {
+ "x": 162.92109693808692,
+ "y": -326.5963547400653,
+ "z": 0.0
+ },
+ {
+ "x": 161.9161642083985,
+ "y": -326.5962474229693,
+ "z": 0.0
+ },
+ {
+ "x": 160.9112314787103,
+ "y": -326.59614010587325,
+ "z": 0.0
+ },
+ {
+ "x": 159.9062987490219,
+ "y": -326.59603278877717,
+ "z": 0.0
+ },
+ {
+ "x": 158.9013660193337,
+ "y": -326.5959254716811,
+ "z": 0.0
+ },
+ {
+ "x": 157.8964332896454,
+ "y": -326.595818154585,
+ "z": 0.0
+ },
+ {
+ "x": 156.89150055995694,
+ "y": -326.59571083748904,
+ "z": 0.0
+ },
+ {
+ "x": 155.88656783026875,
+ "y": -326.59560352039296,
+ "z": 0.0
+ },
+ {
+ "x": 154.88163510058033,
+ "y": -326.5954962032969,
+ "z": 0.0
+ },
+ {
+ "x": 153.87670237089213,
+ "y": -326.5953888862008,
+ "z": 0.0
+ },
+ {
+ "x": 152.87176964120383,
+ "y": -326.5952815691047,
+ "z": 0.0
+ },
+ {
+ "x": 151.8668369115154,
+ "y": -326.59517425200875,
+ "z": 0.0
+ },
+ {
+ "x": 150.8619041818272,
+ "y": -326.59506693491267,
+ "z": 0.0
+ },
+ {
+ "x": 149.8569714521389,
+ "y": -326.5949596178166,
+ "z": 0.0
+ },
+ {
+ "x": 148.8520387224505,
+ "y": -326.5948523007205,
+ "z": 0.0
+ },
+ {
+ "x": 147.8471059927623,
+ "y": -326.5947449836244,
+ "z": 0.0
+ },
+ {
+ "x": 146.84217326307396,
+ "y": -326.59463766652834,
+ "z": 0.0
+ },
+ {
+ "x": 145.83724053338554,
+ "y": -326.5945303494324,
+ "z": 0.0
+ },
+ {
+ "x": 144.83230780369723,
+ "y": -326.5944230323363,
+ "z": 0.0
+ },
+ {
+ "x": 143.82737507400904,
+ "y": -326.5943157152402,
+ "z": 0.0
+ },
+ {
+ "x": 142.82244234432073,
+ "y": -326.59420839814413,
+ "z": 0.0
+ },
+ {
+ "x": 141.8175096146323,
+ "y": -326.59410108104817,
+ "z": 0.0
+ },
+ {
+ "x": 140.81257688494412,
+ "y": -326.5939937639521,
+ "z": 0.0
+ },
+ {
+ "x": 139.80764415525582,
+ "y": -326.593886446856,
+ "z": 0.0
+ },
+ {
+ "x": 138.8027114255674,
+ "y": -326.5937791297599,
+ "z": 0.0
+ },
+ {
+ "x": 137.7977786958792,
+ "y": -326.59367181266384,
+ "z": 0.0
+ },
+ {
+ "x": 136.7928459661909,
+ "y": -326.59356449556776,
+ "z": 0.0
+ },
+ {
+ "x": 135.78791323650245,
+ "y": -326.5934571784718,
+ "z": 0.0
+ },
+ {
+ "x": 134.78298050681428,
+ "y": -326.5933498613757,
+ "z": 0.0
+ },
+ {
+ "x": 133.77804777712595,
+ "y": -326.59324254427963,
+ "z": 0.0
+ },
+ {
+ "x": 132.77311504743753,
+ "y": -326.59313522718355,
+ "z": 0.0
+ },
+ {
+ "x": 131.76818231774922,
+ "y": -326.5930279100876,
+ "z": 0.0
+ },
+ {
+ "x": 130.76324958806114,
+ "y": -326.5929205929914,
+ "z": 0.0
+ },
+ {
+ "x": 129.7583168583726,
+ "y": -326.5928132758954,
+ "z": 0.0
+ },
+ {
+ "x": 128.75338412868427,
+ "y": -326.59270595879934,
+ "z": 0.0
+ },
+ {
+ "x": 127.74845139899608,
+ "y": -326.59259864170326,
+ "z": 0.0
+ },
+ {
+ "x": 126.74351866930778,
+ "y": -326.5924913246072,
+ "z": 0.0
+ },
+ {
+ "x": 125.73858593961934,
+ "y": -326.5923840075112,
+ "z": 0.0
+ },
+ {
+ "x": 124.73365320993115,
+ "y": -326.59227669041513,
+ "z": 0.0
+ },
+ {
+ "x": 123.72872048024284,
+ "y": -326.59216937331905,
+ "z": 0.0
+ },
+ {
+ "x": 122.72378775055441,
+ "y": -326.59206205622297,
+ "z": 0.0
+ },
+ {
+ "x": 121.71885502086609,
+ "y": -326.591954739127,
+ "z": 0.0
+ },
+ {
+ "x": 120.71392229117801,
+ "y": -326.5918474220308,
+ "z": 0.0
+ },
+ {
+ "x": 119.70898956148947,
+ "y": -326.59174010493484,
+ "z": 0.0
+ },
+ {
+ "x": 118.70405683180115,
+ "y": -326.59163278783876,
+ "z": 0.0
+ },
+ {
+ "x": 117.69912410211307,
+ "y": -326.5915254707427,
+ "z": 0.0
+ },
+ {
+ "x": 116.69419137242454,
+ "y": -326.5914181536466,
+ "z": 0.0
+ },
+ {
+ "x": 115.68925864273622,
+ "y": -326.59131083655063,
+ "z": 0.0
+ },
+ {
+ "x": 114.68432591304803,
+ "y": -326.59120351945455,
+ "z": 0.0
+ },
+ {
+ "x": 113.67939318335972,
+ "y": -326.5910962023585,
+ "z": 0.0
+ },
+ {
+ "x": 112.6744604536713,
+ "y": -326.5909888852624,
+ "z": 0.0
+ },
+ {
+ "x": 111.66952772398298,
+ "y": -326.5908815681664,
+ "z": 0.0
+ },
+ {
+ "x": 110.6645949942949,
+ "y": -326.59077425107023,
+ "z": 0.0
+ },
+ {
+ "x": 109.65966226460637,
+ "y": -326.59066693397426,
+ "z": 0.0
+ },
+ {
+ "x": 108.65472953491805,
+ "y": -326.5905596168782,
+ "z": 0.0
+ },
+ {
+ "x": 107.64979680522997,
+ "y": -326.5904522997821,
+ "z": 0.0
+ },
+ {
+ "x": 106.64486407554143,
+ "y": -326.590344982686,
+ "z": 0.0
+ },
+ {
+ "x": 105.63993134585311,
+ "y": -326.59023766559005,
+ "z": 0.0
+ },
+ {
+ "x": 104.63499861616492,
+ "y": -326.590130348494,
+ "z": 0.0
+ },
+ {
+ "x": 103.63006588647661,
+ "y": -326.5900230313979,
+ "z": 0.0
+ },
+ {
+ "x": 102.62577779673842,
+ "y": -326.5895920268997,
+ "z": 0.0
+ },
+ {
+ "x": 101.62105848393009,
+ "y": -326.5890537873581,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 34,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 101.61891568410292,
+ "y": -330.5890532134092,
+ "z": 0.0
+ },
+ {
+ "x": 102.6240615537416,
+ "y": -330.5895916587135,
+ "z": 0.0
+ },
+ {
+ "x": 103.62963872516602,
+ "y": -330.59002300858947,
+ "z": 0.0
+ },
+ {
+ "x": 104.63457145485432,
+ "y": -330.59013032568555,
+ "z": 0.0
+ },
+ {
+ "x": 105.63950418454274,
+ "y": -330.59023764278163,
+ "z": 0.0
+ },
+ {
+ "x": 106.64443691423106,
+ "y": -330.5903449598777,
+ "z": 0.0
+ },
+ {
+ "x": 107.64936964391914,
+ "y": -330.5904522769737,
+ "z": 0.0
+ },
+ {
+ "x": 108.65430237360768,
+ "y": -330.5905595940699,
+ "z": 0.0
+ },
+ {
+ "x": 109.659235103296,
+ "y": -330.59066691116584,
+ "z": 0.0
+ },
+ {
+ "x": 110.66416783298408,
+ "y": -330.5907742282619,
+ "z": 0.0
+ },
+ {
+ "x": 111.66910056267261,
+ "y": -330.590881545358,
+ "z": 0.0
+ },
+ {
+ "x": 112.67403329236093,
+ "y": -330.5909888624541,
+ "z": 0.0
+ },
+ {
+ "x": 113.67896602204912,
+ "y": -330.59109617955005,
+ "z": 0.0
+ },
+ {
+ "x": 114.68389875173743,
+ "y": -330.59120349664613,
+ "z": 0.0
+ },
+ {
+ "x": 115.68883148142585,
+ "y": -330.5913108137422,
+ "z": 0.0
+ },
+ {
+ "x": 116.69376421111417,
+ "y": -330.5914181308383,
+ "z": 0.0
+ },
+ {
+ "x": 117.69869694080225,
+ "y": -330.59152544793426,
+ "z": 0.0
+ },
+ {
+ "x": 118.70362967049078,
+ "y": -330.59163276503045,
+ "z": 0.0
+ },
+ {
+ "x": 119.7085624001791,
+ "y": -330.5917400821264,
+ "z": 0.0
+ },
+ {
+ "x": 120.71349512986718,
+ "y": -330.5918473992225,
+ "z": 0.0
+ },
+ {
+ "x": 121.71842785955572,
+ "y": -330.5919547163186,
+ "z": 0.0
+ },
+ {
+ "x": 122.72336058924404,
+ "y": -330.59206203341466,
+ "z": 0.0
+ },
+ {
+ "x": 123.72829331893224,
+ "y": -330.59216935051063,
+ "z": 0.0
+ },
+ {
+ "x": 124.73322604862055,
+ "y": -330.5922766676067,
+ "z": 0.0
+ },
+ {
+ "x": 125.73815877830897,
+ "y": -330.5923839847028,
+ "z": 0.0
+ },
+ {
+ "x": 126.74309150799718,
+ "y": -330.5924913017989,
+ "z": 0.0
+ },
+ {
+ "x": 127.74802423768548,
+ "y": -330.59259861889495,
+ "z": 0.0
+ },
+ {
+ "x": 128.7529569673739,
+ "y": -330.59270593599103,
+ "z": 0.0
+ },
+ {
+ "x": 129.75788969706224,
+ "y": -330.592813253087,
+ "z": 0.0
+ },
+ {
+ "x": 130.76282242675032,
+ "y": -330.5929205701831,
+ "z": 0.0
+ },
+ {
+ "x": 131.76775515643885,
+ "y": -330.59302788727916,
+ "z": 0.0
+ },
+ {
+ "x": 132.77268788612716,
+ "y": -330.59313520437524,
+ "z": 0.0
+ },
+ {
+ "x": 133.77762061581535,
+ "y": -330.5932425214712,
+ "z": 0.0
+ },
+ {
+ "x": 134.7825533455037,
+ "y": -330.5933498385673,
+ "z": 0.0
+ },
+ {
+ "x": 135.78748607519208,
+ "y": -330.5934571556634,
+ "z": 0.0
+ },
+ {
+ "x": 136.7924188048803,
+ "y": -330.59356447275945,
+ "z": 0.0
+ },
+ {
+ "x": 137.7973515345686,
+ "y": -330.59367178985553,
+ "z": 0.0
+ },
+ {
+ "x": 138.80228426425703,
+ "y": -330.5937791069516,
+ "z": 0.0
+ },
+ {
+ "x": 139.80721699394522,
+ "y": -330.5938864240476,
+ "z": 0.0
+ },
+ {
+ "x": 140.81214972363352,
+ "y": -330.59399374114366,
+ "z": 0.0
+ },
+ {
+ "x": 141.81708245332194,
+ "y": -330.59410105823974,
+ "z": 0.0
+ },
+ {
+ "x": 142.82201518301014,
+ "y": -330.5942083753358,
+ "z": 0.0
+ },
+ {
+ "x": 143.82694791269844,
+ "y": -330.5943156924319,
+ "z": 0.0
+ },
+ {
+ "x": 144.83188064238686,
+ "y": -330.594423009528,
+ "z": 0.0
+ },
+ {
+ "x": 145.83681337207517,
+ "y": -330.59453032662395,
+ "z": 0.0
+ },
+ {
+ "x": 146.84174610176336,
+ "y": -330.59463764372003,
+ "z": 0.0
+ },
+ {
+ "x": 147.8466788314517,
+ "y": -330.5947449608161,
+ "z": 0.0
+ },
+ {
+ "x": 148.85161156114012,
+ "y": -330.5948522779122,
+ "z": 0.0
+ },
+ {
+ "x": 149.8565442908283,
+ "y": -330.59495959500816,
+ "z": 0.0
+ },
+ {
+ "x": 150.86147702051662,
+ "y": -330.59506691210424,
+ "z": 0.0
+ },
+ {
+ "x": 151.86640975020504,
+ "y": -330.5951742292003,
+ "z": 0.0
+ },
+ {
+ "x": 152.87134247989323,
+ "y": -330.5952815462964,
+ "z": 0.0
+ },
+ {
+ "x": 153.87627520958154,
+ "y": -330.5953888633925,
+ "z": 0.0
+ },
+ {
+ "x": 154.88120793926996,
+ "y": -330.59549618048857,
+ "z": 0.0
+ },
+ {
+ "x": 155.88614066895815,
+ "y": -330.59560349758453,
+ "z": 0.0
+ },
+ {
+ "x": 156.89107339864657,
+ "y": -330.5957108146806,
+ "z": 0.0
+ },
+ {
+ "x": 157.8960061283348,
+ "y": -330.5958181317767,
+ "z": 0.0
+ },
+ {
+ "x": 158.9009388580231,
+ "y": -330.5959254488728,
+ "z": 0.0
+ },
+ {
+ "x": 159.90587158771152,
+ "y": -330.59603276596886,
+ "z": 0.0
+ },
+ {
+ "x": 160.9108043173997,
+ "y": -330.5961400830648,
+ "z": 0.0
+ },
+ {
+ "x": 161.91573704708813,
+ "y": -330.5962474001609,
+ "z": 0.0
+ },
+ {
+ "x": 162.92066977677632,
+ "y": -330.596354717257,
+ "z": 0.0
+ },
+ {
+ "x": 163.92560250646463,
+ "y": -330.59646203435307,
+ "z": 0.0
+ },
+ {
+ "x": 164.93053523615305,
+ "y": -330.59656935144915,
+ "z": 0.0
+ },
+ {
+ "x": 165.93546796584124,
+ "y": -330.5966766685451,
+ "z": 0.0
+ },
+ {
+ "x": 166.94040069552966,
+ "y": -330.5967839856412,
+ "z": 0.0
+ },
+ {
+ "x": 167.94533342521788,
+ "y": -330.5968913027373,
+ "z": 0.0
+ },
+ {
+ "x": 168.9502661549062,
+ "y": -330.59699861983336,
+ "z": 0.0
+ },
+ {
+ "x": 169.9551988845946,
+ "y": -330.59710593692944,
+ "z": 0.0
+ },
+ {
+ "x": 170.96013161428283,
+ "y": -330.5972132540254,
+ "z": 0.0
+ },
+ {
+ "x": 171.96506434397114,
+ "y": -330.5973205711215,
+ "z": 0.0
+ },
+ {
+ "x": 172.96999707365958,
+ "y": -330.59742788821757,
+ "z": 0.0
+ },
+ {
+ "x": 173.97492980334778,
+ "y": -330.59753520531365,
+ "z": 0.0
+ },
+ {
+ "x": 174.97986253303608,
+ "y": -330.5976425224097,
+ "z": 0.0
+ },
+ {
+ "x": 175.98479526272453,
+ "y": -330.5977498395058,
+ "z": 0.0
+ },
+ {
+ "x": 176.98972799241284,
+ "y": -330.5978571566018,
+ "z": 0.0
+ },
+ {
+ "x": 177.99466072210103,
+ "y": -330.59796447369786,
+ "z": 0.0
+ },
+ {
+ "x": 178.99959345178937,
+ "y": -330.59807179079394,
+ "z": 0.0
+ },
+ {
+ "x": 180.0045261814778,
+ "y": -330.59817910789,
+ "z": 0.0
+ },
+ {
+ "x": 181.00945891116598,
+ "y": -330.598286424986,
+ "z": 0.0
+ },
+ {
+ "x": 182.01439164085429,
+ "y": -330.59839374208207,
+ "z": 0.0
+ },
+ {
+ "x": 183.01932437054273,
+ "y": -330.59850105917815,
+ "z": 0.0
+ },
+ {
+ "x": 184.02425710023093,
+ "y": -330.5986083762742,
+ "z": 0.0
+ },
+ {
+ "x": 185.02918982991923,
+ "y": -330.5987156933703,
+ "z": 0.0
+ },
+ {
+ "x": 186.03412255960768,
+ "y": -330.5988230104664,
+ "z": 0.0
+ },
+ {
+ "x": 187.03905528929587,
+ "y": -330.59893032756236,
+ "z": 0.0
+ },
+ {
+ "x": 188.0439880189842,
+ "y": -330.59903764465844,
+ "z": 0.0
+ },
+ {
+ "x": 189.04892074867263,
+ "y": -330.5991449617545,
+ "z": 0.0
+ },
+ {
+ "x": 190.05385347836082,
+ "y": -330.5992522788506,
+ "z": 0.0
+ },
+ {
+ "x": 191.05878620804916,
+ "y": -330.5993595959467,
+ "z": 0.0
+ },
+ {
+ "x": 192.06371893773758,
+ "y": -330.59946691304276,
+ "z": 0.0
+ },
+ {
+ "x": 193.0686516674259,
+ "y": -330.5995742301387,
+ "z": 0.0
+ },
+ {
+ "x": 194.0735843971141,
+ "y": -330.5996815472348,
+ "z": 0.0
+ },
+ {
+ "x": 195.0785171268024,
+ "y": -330.5997888643309,
+ "z": 0.0
+ },
+ {
+ "x": 196.08344985649083,
+ "y": -330.59989618142697,
+ "z": 0.0
+ },
+ {
+ "x": 197.08838258617905,
+ "y": -330.60000349852294,
+ "z": 0.0
+ },
+ {
+ "x": 198.09331531586736,
+ "y": -330.600110815619,
+ "z": 0.0
+ },
+ {
+ "x": 199.09824804555578,
+ "y": -330.6002181327151,
+ "z": 0.0
+ },
+ {
+ "x": 200.103180775244,
+ "y": -330.6003254498112,
+ "z": 0.0
+ },
+ {
+ "x": 201.1081135049323,
+ "y": -330.60043276690726,
+ "z": 0.0
+ },
+ {
+ "x": 202.11304623462073,
+ "y": -330.60054008400334,
+ "z": 0.0
+ },
+ {
+ "x": 203.11797896430906,
+ "y": -330.6006474010993,
+ "z": 0.0
+ },
+ {
+ "x": 204.12291169399714,
+ "y": -330.6007547181954,
+ "z": 0.0
+ },
+ {
+ "x": 205.12784442368567,
+ "y": -330.60086203529147,
+ "z": 0.0
+ },
+ {
+ "x": 206.132777153374,
+ "y": -330.60096935238755,
+ "z": 0.0
+ },
+ {
+ "x": 207.1377098830621,
+ "y": -330.6010766694835,
+ "z": 0.0
+ },
+ {
+ "x": 208.14264261275065,
+ "y": -330.6011839865797,
+ "z": 0.0
+ },
+ {
+ "x": 209.14757534243896,
+ "y": -330.6012913036757,
+ "z": 0.0
+ },
+ {
+ "x": 210.15250807212715,
+ "y": -330.60139862077176,
+ "z": 0.0
+ },
+ {
+ "x": 211.15744080181548,
+ "y": -330.60150593786784,
+ "z": 0.0
+ },
+ {
+ "x": 212.1623735315039,
+ "y": -330.6016132549639,
+ "z": 0.0
+ },
+ {
+ "x": 213.1673062611922,
+ "y": -330.6017205720599,
+ "z": 0.0
+ },
+ {
+ "x": 214.17223899088032,
+ "y": -330.60182788915597,
+ "z": 0.0
+ },
+ {
+ "x": 215.17717172056885,
+ "y": -330.60193520625205,
+ "z": 0.0
+ },
+ {
+ "x": 216.18210445025716,
+ "y": -330.60204252334813,
+ "z": 0.0
+ },
+ {
+ "x": 217.18703717994524,
+ "y": -330.6021498404441,
+ "z": 0.0
+ },
+ {
+ "x": 218.1919699096338,
+ "y": -330.6022571575403,
+ "z": 0.0
+ },
+ {
+ "x": 219.1969026393221,
+ "y": -330.60236447463626,
+ "z": 0.0
+ },
+ {
+ "x": 220.2018353690103,
+ "y": -330.60247179173234,
+ "z": 0.0
+ },
+ {
+ "x": 221.20676809869863,
+ "y": -330.6025791088284,
+ "z": 0.0
+ },
+ {
+ "x": 222.21170082838705,
+ "y": -330.6026864259245,
+ "z": 0.0
+ },
+ {
+ "x": 223.21663355807524,
+ "y": -330.60279374302047,
+ "z": 0.0
+ },
+ {
+ "x": 224.22156628776358,
+ "y": -330.60290106011655,
+ "z": 0.0
+ },
+ {
+ "x": 225.226499017452,
+ "y": -330.60300837721263,
+ "z": 0.0
+ },
+ {
+ "x": 226.23143174714033,
+ "y": -330.6031156943087,
+ "z": 0.0
+ },
+ {
+ "x": 227.2363644768284,
+ "y": -330.6032230114047,
+ "z": 0.0
+ },
+ {
+ "x": 228.24129720651695,
+ "y": -330.6033303285009,
+ "z": 0.0
+ },
+ {
+ "x": 229.24622993620528,
+ "y": -330.60343764559684,
+ "z": 0.0
+ },
+ {
+ "x": 230.25116266589333,
+ "y": -330.6035449626929,
+ "z": 0.0
+ },
+ {
+ "x": 231.25609539558187,
+ "y": -330.603652279789,
+ "z": 0.0
+ },
+ {
+ "x": 232.26102812527017,
+ "y": -330.6037595968851,
+ "z": 0.0
+ },
+ {
+ "x": 233.26596085495834,
+ "y": -330.60386691398105,
+ "z": 0.0
+ },
+ {
+ "x": 234.27089358464667,
+ "y": -330.60397423107713,
+ "z": 0.0
+ },
+ {
+ "x": 235.2758263143351,
+ "y": -330.6040815481732,
+ "z": 0.0
+ },
+ {
+ "x": 236.28075904402328,
+ "y": -330.6041888652693,
+ "z": 0.0
+ },
+ {
+ "x": 237.28569177371156,
+ "y": -330.6042961823654,
+ "z": 0.0
+ },
+ {
+ "x": 238.29062450339998,
+ "y": -330.60440349946145,
+ "z": 0.0
+ },
+ {
+ "x": 239.29555723308818,
+ "y": -330.6045108165574,
+ "z": 0.0
+ },
+ {
+ "x": 240.30048996277645,
+ "y": -330.6046181336535,
+ "z": 0.0
+ },
+ {
+ "x": 241.3054226924649,
+ "y": -330.6047254507496,
+ "z": 0.0
+ },
+ {
+ "x": 242.3103554221532,
+ "y": -330.60483276784566,
+ "z": 0.0
+ },
+ {
+ "x": 243.31528815184137,
+ "y": -330.60494008494163,
+ "z": 0.0
+ },
+ {
+ "x": 244.32022088152968,
+ "y": -330.6050474020377,
+ "z": 0.0
+ },
+ {
+ "x": 245.3251536112181,
+ "y": -330.6051547191338,
+ "z": 0.0
+ },
+ {
+ "x": 246.3300863409063,
+ "y": -330.6052620362299,
+ "z": 0.0
+ },
+ {
+ "x": 247.33501907059457,
+ "y": -330.60536935332595,
+ "z": 0.0
+ },
+ {
+ "x": 248.33995180028302,
+ "y": -330.60547667042204,
+ "z": 0.0
+ },
+ {
+ "x": 249.3448845299712,
+ "y": -330.605583987518,
+ "z": 0.0
+ },
+ {
+ "x": 250.3498172596595,
+ "y": -330.6056913046141,
+ "z": 0.0
+ },
+ {
+ "x": 251.3547499893479,
+ "y": -330.60579862171016,
+ "z": 0.0
+ },
+ {
+ "x": 252.3596827190361,
+ "y": -330.60590593880625,
+ "z": 0.0
+ },
+ {
+ "x": 253.3646154487245,
+ "y": -330.6060132559023,
+ "z": 0.0
+ },
+ {
+ "x": 254.36954817841269,
+ "y": -330.6061205729983,
+ "z": 0.0
+ },
+ {
+ "x": 255.37448090810102,
+ "y": -330.6062278900944,
+ "z": 0.0
+ },
+ {
+ "x": 256.3794136377894,
+ "y": -330.60633520719045,
+ "z": 0.0
+ },
+ {
+ "x": 257.38434636747763,
+ "y": -330.60644252428654,
+ "z": 0.0
+ },
+ {
+ "x": 258.38927909716597,
+ "y": -330.6065498413826,
+ "z": 0.0
+ },
+ {
+ "x": 259.3942118268542,
+ "y": -330.6066571584786,
+ "z": 0.0
+ },
+ {
+ "x": 260.3991445565425,
+ "y": -330.60676447557466,
+ "z": 0.0
+ },
+ {
+ "x": 261.40407728623086,
+ "y": -330.60687179267074,
+ "z": 0.0
+ },
+ {
+ "x": 262.4090100159191,
+ "y": -330.6069791097668,
+ "z": 0.0
+ },
+ {
+ "x": 263.4139427456075,
+ "y": -330.6070864268629,
+ "z": 0.0
+ },
+ {
+ "x": 264.41887547529575,
+ "y": -330.6071937439589,
+ "z": 0.0
+ },
+ {
+ "x": 265.42380820498397,
+ "y": -330.60730106105495,
+ "z": 0.0
+ },
+ {
+ "x": 266.4287409346724,
+ "y": -330.60740837815104,
+ "z": 0.0
+ },
+ {
+ "x": 267.43367366436064,
+ "y": -330.6075156952471,
+ "z": 0.0
+ },
+ {
+ "x": 268.43860639404886,
+ "y": -330.6076230123432,
+ "z": 0.0
+ },
+ {
+ "x": 269.4435391237373,
+ "y": -330.6077303294393,
+ "z": 0.0
+ },
+ {
+ "x": 270.44847185342553,
+ "y": -330.60783764653524,
+ "z": 0.0
+ },
+ {
+ "x": 271.45340458311387,
+ "y": -330.6079449636313,
+ "z": 0.0
+ },
+ {
+ "x": 272.4583373128022,
+ "y": -330.6080522807274,
+ "z": 0.0
+ },
+ {
+ "x": 273.4632700424904,
+ "y": -330.6081595978235,
+ "z": 0.0
+ },
+ {
+ "x": 274.46820277217887,
+ "y": -330.60826691491957,
+ "z": 0.0
+ },
+ {
+ "x": 275.473135501867,
+ "y": -330.60837423201554,
+ "z": 0.0
+ },
+ {
+ "x": 276.4780682315554,
+ "y": -330.6084815491116,
+ "z": 0.0
+ },
+ {
+ "x": 277.48300096124365,
+ "y": -330.6085888662077,
+ "z": 0.0
+ },
+ {
+ "x": 278.487933690932,
+ "y": -330.6086961833038,
+ "z": 0.0
+ },
+ {
+ "x": 279.4928664206203,
+ "y": -330.60880350039986,
+ "z": 0.0
+ },
+ {
+ "x": 280.49779915030854,
+ "y": -330.6089108174958,
+ "z": 0.0
+ },
+ {
+ "x": 281.5027318799969,
+ "y": -330.6090181345919,
+ "z": 0.0
+ },
+ {
+ "x": 282.5076646096852,
+ "y": -330.609125451688,
+ "z": 0.0
+ },
+ {
+ "x": 283.51259733937343,
+ "y": -330.60923276878407,
+ "z": 0.0
+ },
+ {
+ "x": 284.51753006906176,
+ "y": -330.60934008588015,
+ "z": 0.0
+ },
+ {
+ "x": 285.5224627987502,
+ "y": -330.60944740297623,
+ "z": 0.0
+ },
+ {
+ "x": 286.52739552843843,
+ "y": -330.6095547200722,
+ "z": 0.0
+ },
+ {
+ "x": 287.53232825812654,
+ "y": -330.6096620371683,
+ "z": 0.0
+ },
+ {
+ "x": 288.5372609878151,
+ "y": -330.60976935426436,
+ "z": 0.0
+ },
+ {
+ "x": 289.5421952094854,
+ "y": -330.6098766715192,
+ "z": 0.0
+ },
+ {
+ "x": 290.5473358457908,
+ "y": -330.60998325018545,
+ "z": 0.0
+ },
+ {
+ "x": 291.55227276326934,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 292.55720549868784,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 293.5621382341064,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 294.56707096952493,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 295.5720037049434,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 296.5769364403619,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 297.58186917578047,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 298.586801911199,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 299.5917346466175,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 300.59666738203606,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 301.6016001174546,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 302.6065328528731,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 303.6114655882916,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 304.61639832371014,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 305.6213310591287,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 306.6262637945472,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 307.63119652996573,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 308.6361292653843,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 309.6410620008028,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 310.64599473622127,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 311.6509274716398,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 312.65586020705837,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 313.66079294247686,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 314.6657256778954,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 315.67065841331396,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 316.67559114873245,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 317.68052388415094,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 318.6854566195695,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 319.69038935498804,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 320.69532209040653,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 321.7002548258251,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 322.70518756124363,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 323.7101202966621,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 324.7150530320806,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 325.71998576749917,
+ "y": -330.6099853515625,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 35,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 384.07998657059636,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 383.0414151190793,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 382.0028436675622,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 380.9642722160452,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 379.92570076452813,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 378.88712931301103,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 377.848557861494,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 376.80998640997694,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 375.77141495845984,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 374.7328435069428,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 373.69427205542576,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 372.6557006039087,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 371.6171291523916,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 370.57855770087457,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 369.5399862493575,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 368.5014147978404,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 367.4628433463234,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 366.42427189480634,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 365.38570044328924,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 364.3471289917722,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 363.30855754025515,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 362.26998608873805,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 361.231414637221,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 360.19284318570396,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 359.15427173418686,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 358.1157002826698,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 357.0771288311528,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 356.0385573796357,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 354.99998592811863,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 353.9614144766016,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 352.92284302508455,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 351.88427157356745,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 350.8457001220504,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 349.80712867053336,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 348.76855721901626,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 347.7299857674992,
+ "y": -324.6099853515625,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 36,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 347.7299857674992,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 348.76855721901626,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 349.80712867053336,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 350.8457001220504,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 351.88427157356745,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 352.92284302508455,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 353.9614144766016,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 354.99998592811863,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 356.0385573796357,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 357.0771288311528,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 358.1157002826698,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 359.15427173418686,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 360.19284318570396,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 361.231414637221,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 362.26998608873805,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 363.30855754025515,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 364.3471289917722,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 365.38570044328924,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 366.42427189480634,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 367.4628433463234,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 368.5014147978404,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 369.5399862493575,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 370.57855770087457,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 371.6171291523916,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 372.6557006039087,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 373.69427205542576,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 374.7328435069428,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 375.77141495845984,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 376.80998640997694,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 377.848557861494,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 378.88712931301103,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 379.92570076452813,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 380.9642722160452,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 382.0028436675622,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 383.0414151190793,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 384.07998657059636,
+ "y": -332.6099853515625,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 37,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 347.7299857674992,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 348.76855721901626,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 349.80712867053336,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 350.8457001220504,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 351.88427157356745,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 352.92284302508455,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 353.9614144766016,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 354.99998592811863,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 356.0385573796357,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 357.0771288311528,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 358.1157002826698,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 359.15427173418686,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 360.19284318570396,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 361.231414637221,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 362.26998608873805,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 363.30855754025515,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 364.3471289917722,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 365.38570044328924,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 366.42427189480634,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 367.4628433463234,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 368.5014147978404,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 369.5399862493575,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 370.57855770087457,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 371.6171291523916,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 372.6557006039087,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 373.69427205542576,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 374.7328435069428,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 375.77141495845984,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 376.80998640997694,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 377.848557861494,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 378.88712931301103,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 379.92570076452813,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 380.9642722160452,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 382.0028436675622,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 383.0414151190793,
+ "y": -328.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 384.07998657059636,
+ "y": -328.6099853515625,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 38,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 384.07998657059636,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 383.0414151190793,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 382.0028436675622,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 380.9642722160452,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 379.92570076452813,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 378.88712931301103,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 377.848557861494,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 376.80998640997694,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 375.77141495845984,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 374.7328435069428,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 373.69427205542576,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 372.6557006039087,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 371.6171291523916,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 370.57855770087457,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 369.5399862493575,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 368.5014147978404,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 367.4628433463234,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 366.42427189480634,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 365.38570044328924,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 364.3471289917722,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 363.30855754025515,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 362.26998608873805,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 361.231414637221,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 360.19284318570396,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 359.15427173418686,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 358.1157002826698,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 357.0771288311528,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 356.0385573796357,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 354.99998592811863,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 353.9614144766016,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 352.92284302508455,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 351.88427157356745,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 350.8457001220504,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 349.80712867053336,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 348.76855721901626,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 347.7299857674992,
+ "y": -326.6099853515625,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 39,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 347.7299857674992,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 348.76855721901626,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 349.80712867053336,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 350.8457001220504,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 351.88427157356745,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 352.92284302508455,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 353.9614144766016,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 354.99998592811863,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 356.0385573796357,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 357.0771288311528,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 358.1157002826698,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 359.15427173418686,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 360.19284318570396,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 361.231414637221,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 362.26998608873805,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 363.30855754025515,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 364.3471289917722,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 365.38570044328924,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 366.42427189480634,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 367.4628433463234,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 368.5014147978404,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 369.5399862493575,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 370.57855770087457,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 371.6171291523916,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 372.6557006039087,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 373.69427205542576,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 374.7328435069428,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 375.77141495845984,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 376.80998640997694,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 377.848557861494,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 378.88712931301103,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 379.92570076452813,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 380.9642722160452,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 382.0028436675622,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 383.0414151190793,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 384.07998657059636,
+ "y": -330.6099853515625,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 40,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 390.380007762646,
+ "y": -9.845199567387848,
+ "z": 0.0
+ },
+ {
+ "x": 390.3788050944489,
+ "y": -10.847439245752769,
+ "z": 0.0
+ },
+ {
+ "x": 390.3776024262517,
+ "y": -11.849678924117207,
+ "z": 0.0
+ },
+ {
+ "x": 390.3763997580546,
+ "y": -12.85191860248258,
+ "z": 0.0
+ },
+ {
+ "x": 390.3751970898575,
+ "y": -13.854158280847502,
+ "z": 0.0
+ },
+ {
+ "x": 390.3739944216603,
+ "y": -14.856397959211929,
+ "z": 0.0
+ },
+ {
+ "x": 390.3727917534632,
+ "y": -15.8586376375773,
+ "z": 0.0
+ },
+ {
+ "x": 390.37158908526607,
+ "y": -16.860877315941995,
+ "z": 0.0
+ },
+ {
+ "x": 390.3703864170689,
+ "y": -17.86311699430688,
+ "z": 0.0
+ },
+ {
+ "x": 390.3691837488718,
+ "y": -18.865356672671986,
+ "z": 0.0
+ },
+ {
+ "x": 390.36798108067467,
+ "y": -19.86759635103667,
+ "z": 0.0
+ },
+ {
+ "x": 390.3667784124775,
+ "y": -20.86983602940159,
+ "z": 0.0
+ },
+ {
+ "x": 390.36557574428036,
+ "y": -21.872075707766566,
+ "z": 0.0
+ },
+ {
+ "x": 390.36437307608327,
+ "y": -22.87431538613169,
+ "z": 0.0
+ },
+ {
+ "x": 390.3631704078861,
+ "y": -23.876555064496372,
+ "z": 0.0
+ },
+ {
+ "x": 390.36196773968896,
+ "y": -24.87879474286126,
+ "z": 0.0
+ },
+ {
+ "x": 390.36076507149187,
+ "y": -25.88103442122636,
+ "z": 0.0
+ },
+ {
+ "x": 390.3595624032947,
+ "y": -26.883274099591002,
+ "z": 0.0
+ },
+ {
+ "x": 390.35835973509757,
+ "y": -27.885513777955907,
+ "z": 0.0
+ },
+ {
+ "x": 390.35715706690047,
+ "y": -28.887753456321025,
+ "z": 0.0
+ },
+ {
+ "x": 390.3559543987033,
+ "y": -29.889993134685668,
+ "z": 0.0
+ },
+ {
+ "x": 390.35475173050617,
+ "y": -30.89223281305054,
+ "z": 0.0
+ },
+ {
+ "x": 390.35354906230907,
+ "y": -31.89447249141564,
+ "z": 0.0
+ },
+ {
+ "x": 390.3523463941119,
+ "y": -32.89671216978028,
+ "z": 0.0
+ },
+ {
+ "x": 390.35114372591477,
+ "y": -33.89895184814515,
+ "z": 0.0
+ },
+ {
+ "x": 390.3499410577176,
+ "y": -34.90119152651005,
+ "z": 0.0
+ },
+ {
+ "x": 390.34873838952046,
+ "y": -35.90343120487495,
+ "z": 0.0
+ },
+ {
+ "x": 390.34753572132337,
+ "y": -36.90567088324007,
+ "z": 0.0
+ },
+ {
+ "x": 390.3463330531262,
+ "y": -37.907910561604744,
+ "z": 0.0
+ },
+ {
+ "x": 390.34513038492906,
+ "y": -38.91015023996968,
+ "z": 0.0
+ },
+ {
+ "x": 390.34392771673197,
+ "y": -39.912389918334775,
+ "z": 0.0
+ },
+ {
+ "x": 390.3427250485348,
+ "y": -40.91462959669942,
+ "z": 0.0
+ },
+ {
+ "x": 390.34152238033766,
+ "y": -41.91686927506429,
+ "z": 0.0
+ },
+ {
+ "x": 390.34031971214057,
+ "y": -42.919108953429394,
+ "z": 0.0
+ },
+ {
+ "x": 390.3391170439434,
+ "y": -43.92134863179405,
+ "z": 0.0
+ },
+ {
+ "x": 390.33791437574627,
+ "y": -44.923588310158955,
+ "z": 0.0
+ },
+ {
+ "x": 390.33671170754917,
+ "y": -45.92582798852408,
+ "z": 0.0
+ },
+ {
+ "x": 390.335509039352,
+ "y": -46.92806766688876,
+ "z": 0.0
+ },
+ {
+ "x": 390.33430637115487,
+ "y": -47.93030734525364,
+ "z": 0.0
+ },
+ {
+ "x": 390.3331037029577,
+ "y": -48.93254702361856,
+ "z": 0.0
+ },
+ {
+ "x": 390.3319010347606,
+ "y": -49.934786701983654,
+ "z": 0.0
+ },
+ {
+ "x": 390.33069836656347,
+ "y": -50.93702638034831,
+ "z": 0.0
+ },
+ {
+ "x": 390.3294956983663,
+ "y": -51.93926605871323,
+ "z": 0.0
+ },
+ {
+ "x": 390.3282930301692,
+ "y": -52.94150573707833,
+ "z": 0.0
+ },
+ {
+ "x": 390.327090361972,
+ "y": -53.94374541544286,
+ "z": 0.0
+ },
+ {
+ "x": 390.3258876937749,
+ "y": -54.94598509380819,
+ "z": 0.0
+ },
+ {
+ "x": 390.3246850255778,
+ "y": -55.948224772173106,
+ "z": 0.0
+ },
+ {
+ "x": 390.3234823573806,
+ "y": -56.95046445053753,
+ "z": 0.0
+ },
+ {
+ "x": 390.3222796891835,
+ "y": -57.95270412890285,
+ "z": 0.0
+ },
+ {
+ "x": 390.32107702098637,
+ "y": -58.954943807267554,
+ "z": 0.0
+ },
+ {
+ "x": 390.3198743527892,
+ "y": -59.95718348563243,
+ "z": 0.0
+ },
+ {
+ "x": 390.3186716845921,
+ "y": -60.95942316399757,
+ "z": 0.0
+ },
+ {
+ "x": 390.31746901639497,
+ "y": -61.961662842362216,
+ "z": 0.0
+ },
+ {
+ "x": 390.3162663481978,
+ "y": -62.96390252072709,
+ "z": 0.0
+ },
+ {
+ "x": 390.3150636800007,
+ "y": -63.96614219909221,
+ "z": 0.0
+ },
+ {
+ "x": 390.31386101180357,
+ "y": -64.96838187745689,
+ "z": 0.0
+ },
+ {
+ "x": 390.3126583436064,
+ "y": -65.9706215558218,
+ "z": 0.0
+ },
+ {
+ "x": 390.31145567540926,
+ "y": -66.97286123418672,
+ "z": 0.0
+ },
+ {
+ "x": 390.31025300721217,
+ "y": -67.97510091255184,
+ "z": 0.0
+ },
+ {
+ "x": 390.309050339015,
+ "y": -68.97734059091651,
+ "z": 0.0
+ },
+ {
+ "x": 390.30784767081786,
+ "y": -69.97958026928141,
+ "z": 0.0
+ },
+ {
+ "x": 390.30664500262077,
+ "y": -70.98181994764653,
+ "z": 0.0
+ },
+ {
+ "x": 390.3054423344236,
+ "y": -71.98405962601122,
+ "z": 0.0
+ },
+ {
+ "x": 390.30423966622647,
+ "y": -72.9862993043761,
+ "z": 0.0
+ },
+ {
+ "x": 390.30303699802937,
+ "y": -73.98853898274126,
+ "z": 0.0
+ },
+ {
+ "x": 390.3018343298322,
+ "y": -74.99077866110594,
+ "z": 0.0
+ },
+ {
+ "x": 390.30063166163507,
+ "y": -75.99301833947084,
+ "z": 0.0
+ },
+ {
+ "x": 390.2994289934379,
+ "y": -76.99525801783574,
+ "z": 0.0
+ },
+ {
+ "x": 390.29822632524076,
+ "y": -77.99749769620063,
+ "z": 0.0
+ },
+ {
+ "x": 390.29702365704367,
+ "y": -78.99973737456575,
+ "z": 0.0
+ },
+ {
+ "x": 390.2958209888465,
+ "y": -80.00197705293043,
+ "z": 0.0
+ },
+ {
+ "x": 390.29461832064936,
+ "y": -81.00421673129533,
+ "z": 0.0
+ },
+ {
+ "x": 390.29341565245227,
+ "y": -82.00645640966046,
+ "z": 0.0
+ },
+ {
+ "x": 390.2922129842551,
+ "y": -83.00869608802516,
+ "z": 0.0
+ },
+ {
+ "x": 390.29101031605796,
+ "y": -84.01093576639005,
+ "z": 0.0
+ },
+ {
+ "x": 390.28980764786087,
+ "y": -85.01317544475518,
+ "z": 0.0
+ },
+ {
+ "x": 390.2886049796637,
+ "y": -86.01541512311985,
+ "z": 0.0
+ },
+ {
+ "x": 390.2876623789813,
+ "y": -87.01869741734455,
+ "z": 0.0
+ },
+ {
+ "x": 390.2876355630676,
+ "y": -88.0245953007731,
+ "z": 0.0
+ },
+ {
+ "x": 390.28784715222,
+ "y": -89.02777977775638,
+ "z": 0.0
+ },
+ {
+ "x": 390.28805865355594,
+ "y": -90.03002015539369,
+ "z": 0.0
+ },
+ {
+ "x": 390.28827015489185,
+ "y": -91.03226053303119,
+ "z": 0.0
+ },
+ {
+ "x": 390.28848165622776,
+ "y": -92.0345009106687,
+ "z": 0.0
+ },
+ {
+ "x": 390.2886931575636,
+ "y": -93.03674128830598,
+ "z": 0.0
+ },
+ {
+ "x": 390.2889046588996,
+ "y": -94.03898166594394,
+ "z": 0.0
+ },
+ {
+ "x": 390.2891161602355,
+ "y": -95.04122204358121,
+ "z": 0.0
+ },
+ {
+ "x": 390.2893276615714,
+ "y": -96.04346242121872,
+ "z": 0.0
+ },
+ {
+ "x": 390.28953916290726,
+ "y": -97.045702798856,
+ "z": 0.0
+ },
+ {
+ "x": 390.28975066424323,
+ "y": -98.04794317649396,
+ "z": 0.0
+ },
+ {
+ "x": 390.28996216557914,
+ "y": -99.05018355413127,
+ "z": 0.0
+ },
+ {
+ "x": 390.29017366691505,
+ "y": -100.05242393176877,
+ "z": 0.0
+ },
+ {
+ "x": 390.29038516825096,
+ "y": -101.05466430940628,
+ "z": 0.0
+ },
+ {
+ "x": 390.2905966695868,
+ "y": -102.05690468704356,
+ "z": 0.0
+ },
+ {
+ "x": 390.2908081709228,
+ "y": -103.05914506468152,
+ "z": 0.0
+ },
+ {
+ "x": 390.2910196722587,
+ "y": -104.06138544231878,
+ "z": 0.0
+ },
+ {
+ "x": 390.2912311735946,
+ "y": -105.06362581995629,
+ "z": 0.0
+ },
+ {
+ "x": 390.29144267493047,
+ "y": -106.06586619759359,
+ "z": 0.0
+ },
+ {
+ "x": 390.2916541762664,
+ "y": -107.06810657523133,
+ "z": 0.0
+ },
+ {
+ "x": 390.2918656776023,
+ "y": -108.07034695286883,
+ "z": 0.0
+ },
+ {
+ "x": 390.29207717893826,
+ "y": -109.07258733050656,
+ "z": 0.0
+ },
+ {
+ "x": 390.2922886802741,
+ "y": -110.07482770814362,
+ "z": 0.0
+ },
+ {
+ "x": 390.29250018161,
+ "y": -111.07706808578135,
+ "z": 0.0
+ },
+ {
+ "x": 390.29271168294594,
+ "y": -112.07930846341885,
+ "z": 0.0
+ },
+ {
+ "x": 390.2929231842819,
+ "y": -113.08154884105659,
+ "z": 0.0
+ },
+ {
+ "x": 390.2931346856178,
+ "y": -114.08378921869385,
+ "z": 0.0
+ },
+ {
+ "x": 390.29334618695367,
+ "y": -115.08602959633114,
+ "z": 0.0
+ },
+ {
+ "x": 390.2935576882896,
+ "y": -116.08826997396886,
+ "z": 0.0
+ },
+ {
+ "x": 390.2937691896255,
+ "y": -117.09051035160635,
+ "z": 0.0
+ },
+ {
+ "x": 390.29398069096146,
+ "y": -118.09275072924407,
+ "z": 0.0
+ },
+ {
+ "x": 390.2941921922973,
+ "y": -119.09499110688111,
+ "z": 0.0
+ },
+ {
+ "x": 390.2944036936332,
+ "y": -120.09723148451884,
+ "z": 0.0
+ },
+ {
+ "x": 390.29461519496914,
+ "y": -121.09947186215635,
+ "z": 0.0
+ },
+ {
+ "x": 390.29482669630505,
+ "y": -122.10171223979387,
+ "z": 0.0
+ },
+ {
+ "x": 390.295038197641,
+ "y": -123.1039526174316,
+ "z": 0.0
+ },
+ {
+ "x": 390.2952496989769,
+ "y": -124.10619299506864,
+ "z": 0.0
+ },
+ {
+ "x": 390.2954612003128,
+ "y": -125.10843337270637,
+ "z": 0.0
+ },
+ {
+ "x": 390.2956727016487,
+ "y": -126.11067375034386,
+ "z": 0.0
+ },
+ {
+ "x": 390.29588420298467,
+ "y": -127.11291412798158,
+ "z": 0.0
+ },
+ {
+ "x": 390.2960957043205,
+ "y": -128.11515450561862,
+ "z": 0.0
+ },
+ {
+ "x": 390.29630720565643,
+ "y": -129.11739488325634,
+ "z": 0.0
+ },
+ {
+ "x": 390.29651870699234,
+ "y": -130.11963526089386,
+ "z": 0.0
+ },
+ {
+ "x": 390.29673020832826,
+ "y": -131.12187563853138,
+ "z": 0.0
+ },
+ {
+ "x": 390.29694170966417,
+ "y": -132.1241160161689,
+ "z": 0.0
+ },
+ {
+ "x": 390.2971532110001,
+ "y": -133.1263563938064,
+ "z": 0.0
+ },
+ {
+ "x": 390.297364712336,
+ "y": -134.1285967714439,
+ "z": 0.0
+ },
+ {
+ "x": 390.2975762136719,
+ "y": -135.1308371490814,
+ "z": 0.0
+ },
+ {
+ "x": 390.29778771500787,
+ "y": -136.13307752671915,
+ "z": 0.0
+ },
+ {
+ "x": 390.2979992163437,
+ "y": -137.13531790435619,
+ "z": 0.0
+ },
+ {
+ "x": 390.29821071767964,
+ "y": -138.13755828199396,
+ "z": 0.0
+ },
+ {
+ "x": 390.29842221901555,
+ "y": -139.13979865963145,
+ "z": 0.0
+ },
+ {
+ "x": 390.29863372035146,
+ "y": -140.14203903726897,
+ "z": 0.0
+ },
+ {
+ "x": 390.2988452216874,
+ "y": -141.14427941490646,
+ "z": 0.0
+ },
+ {
+ "x": 390.2990567230233,
+ "y": -142.14651979254398,
+ "z": 0.0
+ },
+ {
+ "x": 390.2992682243592,
+ "y": -143.14876017018148,
+ "z": 0.0
+ },
+ {
+ "x": 390.2994797256951,
+ "y": -144.151000547819,
+ "z": 0.0
+ },
+ {
+ "x": 390.299691227031,
+ "y": -145.1532409254565,
+ "z": 0.0
+ },
+ {
+ "x": 390.29990272836693,
+ "y": -146.155481303094,
+ "z": 0.0
+ },
+ {
+ "x": 390.30011422970284,
+ "y": -147.15772168073153,
+ "z": 0.0
+ },
+ {
+ "x": 390.30032573103875,
+ "y": -148.15996205836905,
+ "z": 0.0
+ },
+ {
+ "x": 390.30053723237467,
+ "y": -149.16220243600654,
+ "z": 0.0
+ },
+ {
+ "x": 390.3007487337106,
+ "y": -150.16444281364403,
+ "z": 0.0
+ },
+ {
+ "x": 390.3009602350465,
+ "y": -151.16668319128155,
+ "z": 0.0
+ },
+ {
+ "x": 390.3011717363824,
+ "y": -152.16892356891904,
+ "z": 0.0
+ },
+ {
+ "x": 390.3013832377183,
+ "y": -153.17116394655656,
+ "z": 0.0
+ },
+ {
+ "x": 390.30159473905417,
+ "y": -154.17340432419385,
+ "z": 0.0
+ },
+ {
+ "x": 390.30180624039014,
+ "y": -155.17564470183183,
+ "z": 0.0
+ },
+ {
+ "x": 390.30201774172605,
+ "y": -156.1778850794691,
+ "z": 0.0
+ },
+ {
+ "x": 390.30222924306196,
+ "y": -157.1801254571066,
+ "z": 0.0
+ },
+ {
+ "x": 390.30244074439787,
+ "y": -158.1823658347441,
+ "z": 0.0
+ },
+ {
+ "x": 390.3026522457337,
+ "y": -159.1846062123814,
+ "z": 0.0
+ },
+ {
+ "x": 390.3028637470697,
+ "y": -160.18684659001934,
+ "z": 0.0
+ },
+ {
+ "x": 390.3030752484056,
+ "y": -161.18908696765664,
+ "z": 0.0
+ },
+ {
+ "x": 390.3032867497415,
+ "y": -162.19132734529413,
+ "z": 0.0
+ },
+ {
+ "x": 390.3034982510774,
+ "y": -163.19356772293145,
+ "z": 0.0
+ },
+ {
+ "x": 390.30370975241334,
+ "y": -164.1958081005694,
+ "z": 0.0
+ },
+ {
+ "x": 390.30392125374925,
+ "y": -165.1980484782067,
+ "z": 0.0
+ },
+ {
+ "x": 390.30413275508516,
+ "y": -166.20028885584418,
+ "z": 0.0
+ },
+ {
+ "x": 390.3043442564211,
+ "y": -167.2025292334817,
+ "z": 0.0
+ },
+ {
+ "x": 390.30455575775693,
+ "y": -168.20476961111896,
+ "z": 0.0
+ },
+ {
+ "x": 390.3047672590929,
+ "y": -169.20700998875694,
+ "z": 0.0
+ },
+ {
+ "x": 390.3049787604288,
+ "y": -170.20925036639423,
+ "z": 0.0
+ },
+ {
+ "x": 390.3051902617647,
+ "y": -171.21149074403175,
+ "z": 0.0
+ },
+ {
+ "x": 390.3054017631006,
+ "y": -172.213731121669,
+ "z": 0.0
+ },
+ {
+ "x": 390.30561326443654,
+ "y": -173.215971499307,
+ "z": 0.0
+ },
+ {
+ "x": 390.30582476577246,
+ "y": -174.21821187694425,
+ "z": 0.0
+ },
+ {
+ "x": 390.30603626710837,
+ "y": -175.22045225458177,
+ "z": 0.0
+ },
+ {
+ "x": 390.3062477684443,
+ "y": -176.22269263221926,
+ "z": 0.0
+ },
+ {
+ "x": 390.30645926978013,
+ "y": -177.22493300985656,
+ "z": 0.0
+ },
+ {
+ "x": 390.3066707711161,
+ "y": -178.2271733874945,
+ "z": 0.0
+ },
+ {
+ "x": 390.306882272452,
+ "y": -179.22941376513182,
+ "z": 0.0
+ },
+ {
+ "x": 390.3070937737879,
+ "y": -180.23165414276932,
+ "z": 0.0
+ },
+ {
+ "x": 390.3073052751238,
+ "y": -181.23389452040658,
+ "z": 0.0
+ },
+ {
+ "x": 390.3075167764597,
+ "y": -182.23613489804433,
+ "z": 0.0
+ },
+ {
+ "x": 390.30772827779566,
+ "y": -183.23837527568205,
+ "z": 0.0
+ },
+ {
+ "x": 390.3079397791316,
+ "y": -184.24061565331934,
+ "z": 0.0
+ },
+ {
+ "x": 390.3081512804674,
+ "y": -185.2428560309566,
+ "z": 0.0
+ },
+ {
+ "x": 390.30836278180334,
+ "y": -186.24509640859438,
+ "z": 0.0
+ },
+ {
+ "x": 390.3085742831393,
+ "y": -187.2473367862321,
+ "z": 0.0
+ },
+ {
+ "x": 390.3087857844752,
+ "y": -188.2495771638694,
+ "z": 0.0
+ },
+ {
+ "x": 390.30899728581113,
+ "y": -189.25181754150688,
+ "z": 0.0
+ },
+ {
+ "x": 390.309208787147,
+ "y": -190.25405791914417,
+ "z": 0.0
+ },
+ {
+ "x": 390.3094202884829,
+ "y": -191.2562982967819,
+ "z": 0.0
+ },
+ {
+ "x": 390.3096317898188,
+ "y": -192.25853867441938,
+ "z": 0.0
+ },
+ {
+ "x": 390.3098432911548,
+ "y": -193.2607790520571,
+ "z": 0.0
+ },
+ {
+ "x": 390.31005479249063,
+ "y": -194.26301942969414,
+ "z": 0.0
+ },
+ {
+ "x": 390.31026629382654,
+ "y": -195.26525980733186,
+ "z": 0.0
+ },
+ {
+ "x": 390.31047779516246,
+ "y": -196.26750018496938,
+ "z": 0.0
+ },
+ {
+ "x": 390.31068929649837,
+ "y": -197.26974056260687,
+ "z": 0.0
+ },
+ {
+ "x": 390.31090079783434,
+ "y": -198.2719809402446,
+ "z": 0.0
+ },
+ {
+ "x": 390.3111122991702,
+ "y": -199.27422131788163,
+ "z": 0.0
+ },
+ {
+ "x": 390.3113238005061,
+ "y": -200.27646169551934,
+ "z": 0.0
+ },
+ {
+ "x": 390.311535301842,
+ "y": -201.27870207315684,
+ "z": 0.0
+ },
+ {
+ "x": 390.311746803178,
+ "y": -202.28094245079456,
+ "z": 0.0
+ },
+ {
+ "x": 390.31195830451384,
+ "y": -203.2831828284316,
+ "z": 0.0
+ },
+ {
+ "x": 390.31216980584975,
+ "y": -204.28542320606934,
+ "z": 0.0
+ },
+ {
+ "x": 390.31238130718566,
+ "y": -205.28766358370683,
+ "z": 0.0
+ },
+ {
+ "x": 390.3125928085216,
+ "y": -206.28990396134432,
+ "z": 0.0
+ },
+ {
+ "x": 390.3128043098575,
+ "y": -207.2921443389818,
+ "z": 0.0
+ },
+ {
+ "x": 390.3130158111934,
+ "y": -208.2943847166193,
+ "z": 0.0
+ },
+ {
+ "x": 390.3132273125293,
+ "y": -209.2966250942568,
+ "z": 0.0
+ },
+ {
+ "x": 390.3134388138652,
+ "y": -210.2988654718943,
+ "z": 0.0
+ },
+ {
+ "x": 390.3136503152012,
+ "y": -211.301105849532,
+ "z": 0.0
+ },
+ {
+ "x": 390.31386181653704,
+ "y": -212.30334622716907,
+ "z": 0.0
+ },
+ {
+ "x": 390.31407331787295,
+ "y": -213.3055866048068,
+ "z": 0.0
+ },
+ {
+ "x": 390.31428481920886,
+ "y": -214.30782698244428,
+ "z": 0.0
+ },
+ {
+ "x": 390.3144963205448,
+ "y": -215.31006736008177,
+ "z": 0.0
+ },
+ {
+ "x": 390.3147078218807,
+ "y": -216.31230773771927,
+ "z": 0.0
+ },
+ {
+ "x": 390.3149193232166,
+ "y": -217.31454811535676,
+ "z": 0.0
+ },
+ {
+ "x": 390.3151308245525,
+ "y": -218.31678849299425,
+ "z": 0.0
+ },
+ {
+ "x": 390.3153423258884,
+ "y": -219.31902887063174,
+ "z": 0.0
+ },
+ {
+ "x": 390.31555382722433,
+ "y": -220.32126924826926,
+ "z": 0.0
+ },
+ {
+ "x": 390.31576532856025,
+ "y": -221.32350962590675,
+ "z": 0.0
+ },
+ {
+ "x": 390.31597682989616,
+ "y": -222.32575000354424,
+ "z": 0.0
+ },
+ {
+ "x": 390.31618833123207,
+ "y": -223.32799038118173,
+ "z": 0.0
+ },
+ {
+ "x": 390.316399832568,
+ "y": -224.33023075881923,
+ "z": 0.0
+ },
+ {
+ "x": 390.3166113339039,
+ "y": -225.33247113645672,
+ "z": 0.0
+ },
+ {
+ "x": 390.3168228352398,
+ "y": -226.3347115140942,
+ "z": 0.0
+ },
+ {
+ "x": 390.3170343365757,
+ "y": -227.3369518917317,
+ "z": 0.0
+ },
+ {
+ "x": 390.3172458379116,
+ "y": -228.33919226936922,
+ "z": 0.0
+ },
+ {
+ "x": 390.31745733924754,
+ "y": -229.3414326470067,
+ "z": 0.0
+ },
+ {
+ "x": 390.31766884058345,
+ "y": -230.3436730246442,
+ "z": 0.0
+ },
+ {
+ "x": 390.31788034191936,
+ "y": -231.3459134022817,
+ "z": 0.0
+ },
+ {
+ "x": 390.3180918432553,
+ "y": -232.3481537799192,
+ "z": 0.0
+ },
+ {
+ "x": 390.3183033445912,
+ "y": -233.35039415755668,
+ "z": 0.0
+ },
+ {
+ "x": 390.3185148459271,
+ "y": -234.35263453519417,
+ "z": 0.0
+ },
+ {
+ "x": 390.318726347263,
+ "y": -235.35487491283166,
+ "z": 0.0
+ },
+ {
+ "x": 390.3189378485989,
+ "y": -236.35711529046915,
+ "z": 0.0
+ },
+ {
+ "x": 390.31914934993483,
+ "y": -237.35935566810664,
+ "z": 0.0
+ },
+ {
+ "x": 390.31936085127074,
+ "y": -238.36159604574414,
+ "z": 0.0
+ },
+ {
+ "x": 390.31957235260666,
+ "y": -239.36383642338163,
+ "z": 0.0
+ },
+ {
+ "x": 390.31978385394257,
+ "y": -240.36607680101912,
+ "z": 0.0
+ },
+ {
+ "x": 390.3200109086524,
+ "y": -241.36837919461823,
+ "z": 0.0
+ },
+ {
+ "x": 390.32040065747765,
+ "y": -242.3712680984976,
+ "z": 0.0
+ },
+ {
+ "x": 390.3207902067958,
+ "y": -243.37350842274657,
+ "z": 0.0
+ },
+ {
+ "x": 390.3211797561139,
+ "y": -244.37574874699575,
+ "z": 0.0
+ },
+ {
+ "x": 390.3215693054321,
+ "y": -245.37798907124514,
+ "z": 0.0
+ },
+ {
+ "x": 390.3219588547503,
+ "y": -246.38022939549433,
+ "z": 0.0
+ },
+ {
+ "x": 390.3223484040684,
+ "y": -247.38246971974326,
+ "z": 0.0
+ },
+ {
+ "x": 390.3227379533866,
+ "y": -248.38471004399267,
+ "z": 0.0
+ },
+ {
+ "x": 390.3231275027047,
+ "y": -249.38695036824163,
+ "z": 0.0
+ },
+ {
+ "x": 390.32351705202285,
+ "y": -250.38919069249079,
+ "z": 0.0
+ },
+ {
+ "x": 390.32390660134104,
+ "y": -251.3914310167402,
+ "z": 0.0
+ },
+ {
+ "x": 390.3242961506592,
+ "y": -252.39367134098939,
+ "z": 0.0
+ },
+ {
+ "x": 390.32468569997735,
+ "y": -253.39591166523832,
+ "z": 0.0
+ },
+ {
+ "x": 390.32507524929554,
+ "y": -254.39815198948773,
+ "z": 0.0
+ },
+ {
+ "x": 390.32546479861367,
+ "y": -255.40039231373666,
+ "z": 0.0
+ },
+ {
+ "x": 390.3258543479318,
+ "y": -256.40263263798585,
+ "z": 0.0
+ },
+ {
+ "x": 390.32624389725,
+ "y": -257.4048729622353,
+ "z": 0.0
+ },
+ {
+ "x": 390.32663344656817,
+ "y": -258.40711328648445,
+ "z": 0.0
+ },
+ {
+ "x": 390.3270229958863,
+ "y": -259.4093536107334,
+ "z": 0.0
+ },
+ {
+ "x": 390.3274125452044,
+ "y": -260.41159393498253,
+ "z": 0.0
+ },
+ {
+ "x": 390.3278020945226,
+ "y": -261.413834259232,
+ "z": 0.0
+ },
+ {
+ "x": 390.3281916438408,
+ "y": -262.41607458348113,
+ "z": 0.0
+ },
+ {
+ "x": 390.3285811931589,
+ "y": -263.41831490773006,
+ "z": 0.0
+ },
+ {
+ "x": 390.3289707424771,
+ "y": -264.4205552319795,
+ "z": 0.0
+ },
+ {
+ "x": 390.3293602917953,
+ "y": -265.42279555622866,
+ "z": 0.0
+ },
+ {
+ "x": 390.3297498411134,
+ "y": -266.4250358804776,
+ "z": 0.0
+ },
+ {
+ "x": 390.33013939043155,
+ "y": -267.4272762047268,
+ "z": 0.0
+ },
+ {
+ "x": 390.33052893974974,
+ "y": -268.4295165289762,
+ "z": 0.0
+ },
+ {
+ "x": 390.33091848906787,
+ "y": -269.4317568532251,
+ "z": 0.0
+ },
+ {
+ "x": 390.33130803838606,
+ "y": -270.43399717747457,
+ "z": 0.0
+ },
+ {
+ "x": 390.3316975877042,
+ "y": -271.4362375017235,
+ "z": 0.0
+ },
+ {
+ "x": 390.3320871370223,
+ "y": -272.43847782597265,
+ "z": 0.0
+ },
+ {
+ "x": 390.3324766863405,
+ "y": -273.4407181502221,
+ "z": 0.0
+ },
+ {
+ "x": 390.3328662356587,
+ "y": -274.44295847447125,
+ "z": 0.0
+ },
+ {
+ "x": 390.3332557849768,
+ "y": -275.4451987987202,
+ "z": 0.0
+ },
+ {
+ "x": 390.333645334295,
+ "y": -276.4474391229696,
+ "z": 0.0
+ },
+ {
+ "x": 390.3340348836131,
+ "y": -277.44967944721856,
+ "z": 0.0
+ },
+ {
+ "x": 390.3344244329313,
+ "y": -278.45191977146794,
+ "z": 0.0
+ },
+ {
+ "x": 390.33481398224944,
+ "y": -279.4541600957169,
+ "z": 0.0
+ },
+ {
+ "x": 390.33520353156763,
+ "y": -280.4564004199663,
+ "z": 0.0
+ },
+ {
+ "x": 390.3355930808858,
+ "y": -281.4586407442155,
+ "z": 0.0
+ },
+ {
+ "x": 390.33598263020394,
+ "y": -282.46088106846446,
+ "z": 0.0
+ },
+ {
+ "x": 390.3363721795221,
+ "y": -283.4631213927136,
+ "z": 0.0
+ },
+ {
+ "x": 390.33676172884026,
+ "y": -284.465361716963,
+ "z": 0.0
+ },
+ {
+ "x": 390.3371512781584,
+ "y": -285.467602041212,
+ "z": 0.0
+ },
+ {
+ "x": 390.3375408274766,
+ "y": -286.4698423654614,
+ "z": 0.0
+ },
+ {
+ "x": 390.33793037679476,
+ "y": -287.47208268971053,
+ "z": 0.0
+ },
+ {
+ "x": 390.3383199261129,
+ "y": -288.4743230139595,
+ "z": 0.0
+ },
+ {
+ "x": 390.338709475431,
+ "y": -289.4765633382087,
+ "z": 0.0
+ },
+ {
+ "x": 390.3390990247492,
+ "y": -290.47880366245806,
+ "z": 0.0
+ },
+ {
+ "x": 390.33948857406733,
+ "y": -291.48104398670705,
+ "z": 0.0
+ },
+ {
+ "x": 390.3398781233855,
+ "y": -292.48328431095644,
+ "z": 0.0
+ },
+ {
+ "x": 390.34026767270365,
+ "y": -293.4855246352054,
+ "z": 0.0
+ },
+ {
+ "x": 390.34065722202183,
+ "y": -294.4877649594548,
+ "z": 0.0
+ },
+ {
+ "x": 390.34104677133996,
+ "y": -295.49000528370374,
+ "z": 0.0
+ },
+ {
+ "x": 390.34143632065815,
+ "y": -296.4922456079532,
+ "z": 0.0
+ },
+ {
+ "x": 390.34182586997633,
+ "y": -297.49448593220234,
+ "z": 0.0
+ },
+ {
+ "x": 390.34221541929446,
+ "y": -298.49672625645127,
+ "z": 0.0
+ },
+ {
+ "x": 390.3426049686126,
+ "y": -299.4989665807005,
+ "z": 0.0
+ },
+ {
+ "x": 390.3429945179308,
+ "y": -300.50120690494987,
+ "z": 0.0
+ },
+ {
+ "x": 390.3433840672489,
+ "y": -301.50344722919885,
+ "z": 0.0
+ },
+ {
+ "x": 390.3437736165671,
+ "y": -302.50568755344824,
+ "z": 0.0
+ },
+ {
+ "x": 390.3441631658853,
+ "y": -303.5079278776974,
+ "z": 0.0
+ },
+ {
+ "x": 390.3445527152034,
+ "y": -304.5101682019464,
+ "z": 0.0
+ },
+ {
+ "x": 390.34494226452153,
+ "y": -305.51240852619554,
+ "z": 0.0
+ },
+ {
+ "x": 390.3453318138397,
+ "y": -306.5146488504449,
+ "z": 0.0
+ },
+ {
+ "x": 390.34572136315785,
+ "y": -307.5168891746939,
+ "z": 0.0
+ },
+ {
+ "x": 390.34611091247604,
+ "y": -308.5191294989433,
+ "z": 0.0
+ },
+ {
+ "x": 390.3465004617942,
+ "y": -309.5213698231925,
+ "z": 0.0
+ },
+ {
+ "x": 390.34689001111235,
+ "y": -310.52361014744145,
+ "z": 0.0
+ },
+ {
+ "x": 390.3472795604305,
+ "y": -311.5258504716906,
+ "z": 0.0
+ },
+ {
+ "x": 390.34766910974867,
+ "y": -312.52809079594005,
+ "z": 0.0
+ },
+ {
+ "x": 390.34805865906685,
+ "y": -313.5303311201892,
+ "z": 0.0
+ },
+ {
+ "x": 390.348448208385,
+ "y": -314.5325714444382,
+ "z": 0.0
+ },
+ {
+ "x": 390.34883775770317,
+ "y": -315.5348117686876,
+ "z": 0.0
+ },
+ {
+ "x": 390.3492273070213,
+ "y": -316.5370520929365,
+ "z": 0.0
+ },
+ {
+ "x": 390.3496168563394,
+ "y": -317.5392924171857,
+ "z": 0.0
+ },
+ {
+ "x": 390.3500064056576,
+ "y": -318.5415327414351,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 41,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 398.35000580137364,
+ "y": -318.5384233132524,
+ "z": 0.0
+ },
+ {
+ "x": 398.34961625205545,
+ "y": -317.53618298900346,
+ "z": 0.0
+ },
+ {
+ "x": 398.3492267027373,
+ "y": -316.53394266475425,
+ "z": 0.0
+ },
+ {
+ "x": 398.3488371534192,
+ "y": -315.53170234050486,
+ "z": 0.0
+ },
+ {
+ "x": 398.348447604101,
+ "y": -314.52946201625593,
+ "z": 0.0
+ },
+ {
+ "x": 398.3480580547829,
+ "y": -313.5272216920065,
+ "z": 0.0
+ },
+ {
+ "x": 398.3476685054647,
+ "y": -312.52498136775733,
+ "z": 0.0
+ },
+ {
+ "x": 398.3472789561465,
+ "y": -311.52274104350835,
+ "z": 0.0
+ },
+ {
+ "x": 398.3468894068284,
+ "y": -310.5205007192592,
+ "z": 0.0
+ },
+ {
+ "x": 398.34649985751025,
+ "y": -309.5182603950098,
+ "z": 0.0
+ },
+ {
+ "x": 398.34611030819207,
+ "y": -308.5160200707606,
+ "z": 0.0
+ },
+ {
+ "x": 398.3457207588739,
+ "y": -307.51377974651166,
+ "z": 0.0
+ },
+ {
+ "x": 398.34533120955575,
+ "y": -306.5115394222622,
+ "z": 0.0
+ },
+ {
+ "x": 398.34494166023757,
+ "y": -305.5092990980133,
+ "z": 0.0
+ },
+ {
+ "x": 398.34455211091944,
+ "y": -304.50705877376413,
+ "z": 0.0
+ },
+ {
+ "x": 398.3441625616013,
+ "y": -303.5048184495147,
+ "z": 0.0
+ },
+ {
+ "x": 398.3437730122831,
+ "y": -302.50257812526553,
+ "z": 0.0
+ },
+ {
+ "x": 398.34338346296494,
+ "y": -301.5003378010166,
+ "z": 0.0
+ },
+ {
+ "x": 398.3429939136468,
+ "y": -300.49809747676716,
+ "z": 0.0
+ },
+ {
+ "x": 398.3426043643286,
+ "y": -299.4958571525182,
+ "z": 0.0
+ },
+ {
+ "x": 398.3422148150105,
+ "y": -298.493616828269,
+ "z": 0.0
+ },
+ {
+ "x": 398.34182526569236,
+ "y": -297.4913765040196,
+ "z": 0.0
+ },
+ {
+ "x": 398.3414357163742,
+ "y": -296.48913617977047,
+ "z": 0.0
+ },
+ {
+ "x": 398.341046167056,
+ "y": -295.4868958555215,
+ "z": 0.0
+ },
+ {
+ "x": 398.34065661773786,
+ "y": -294.4846555312721,
+ "z": 0.0
+ },
+ {
+ "x": 398.3402670684197,
+ "y": -293.48241520702317,
+ "z": 0.0
+ },
+ {
+ "x": 398.33987751910155,
+ "y": -292.4801748827737,
+ "z": 0.0
+ },
+ {
+ "x": 398.33948796978336,
+ "y": -291.4779345585248,
+ "z": 0.0
+ },
+ {
+ "x": 398.33909842046523,
+ "y": -290.47569423427535,
+ "z": 0.0
+ },
+ {
+ "x": 398.33870887114705,
+ "y": -289.4734539100264,
+ "z": 0.0
+ },
+ {
+ "x": 398.3383193218289,
+ "y": -288.47121358577726,
+ "z": 0.0
+ },
+ {
+ "x": 398.3379297725108,
+ "y": -287.4689732615278,
+ "z": 0.0
+ },
+ {
+ "x": 398.3375402231926,
+ "y": -286.46673293727866,
+ "z": 0.0
+ },
+ {
+ "x": 398.3371506738744,
+ "y": -285.46449261302973,
+ "z": 0.0
+ },
+ {
+ "x": 398.3367611245563,
+ "y": -284.4622522887803,
+ "z": 0.0
+ },
+ {
+ "x": 398.3363715752381,
+ "y": -283.46001196453136,
+ "z": 0.0
+ },
+ {
+ "x": 398.33598202592,
+ "y": -282.4577716402822,
+ "z": 0.0
+ },
+ {
+ "x": 398.33559247660185,
+ "y": -281.45553131603276,
+ "z": 0.0
+ },
+ {
+ "x": 398.33520292728366,
+ "y": -280.4532909917836,
+ "z": 0.0
+ },
+ {
+ "x": 398.3348133779655,
+ "y": -279.4510506675346,
+ "z": 0.0
+ },
+ {
+ "x": 398.33442382864735,
+ "y": -278.44881034328523,
+ "z": 0.0
+ },
+ {
+ "x": 398.33403427932916,
+ "y": -277.4465700190363,
+ "z": 0.0
+ },
+ {
+ "x": 398.33364473001103,
+ "y": -276.4443296947869,
+ "z": 0.0
+ },
+ {
+ "x": 398.33325518069284,
+ "y": -275.44208937053793,
+ "z": 0.0
+ },
+ {
+ "x": 398.3328656313747,
+ "y": -274.43984904628854,
+ "z": 0.0
+ },
+ {
+ "x": 398.33247608205653,
+ "y": -273.4376087220394,
+ "z": 0.0
+ },
+ {
+ "x": 398.33208653273834,
+ "y": -272.4353683977904,
+ "z": 0.0
+ },
+ {
+ "x": 398.3316969834202,
+ "y": -271.43312807354124,
+ "z": 0.0
+ },
+ {
+ "x": 398.3313074341021,
+ "y": -270.43088774929186,
+ "z": 0.0
+ },
+ {
+ "x": 398.3309178847839,
+ "y": -269.42864742504287,
+ "z": 0.0
+ },
+ {
+ "x": 398.3305283354658,
+ "y": -268.4264071007935,
+ "z": 0.0
+ },
+ {
+ "x": 398.3301387861476,
+ "y": -267.42416677654455,
+ "z": 0.0
+ },
+ {
+ "x": 398.32974923682946,
+ "y": -266.42192645229534,
+ "z": 0.0
+ },
+ {
+ "x": 398.3293596875113,
+ "y": -265.41968612804595,
+ "z": 0.0
+ },
+ {
+ "x": 398.32897013819314,
+ "y": -264.4174458037968,
+ "z": 0.0
+ },
+ {
+ "x": 398.32858058887496,
+ "y": -263.4152054795478,
+ "z": 0.0
+ },
+ {
+ "x": 398.3281910395568,
+ "y": -262.4129651552984,
+ "z": 0.0
+ },
+ {
+ "x": 398.32780149023864,
+ "y": -261.41072483104927,
+ "z": 0.0
+ },
+ {
+ "x": 398.32741194092046,
+ "y": -260.4084845068003,
+ "z": 0.0
+ },
+ {
+ "x": 398.3270223916023,
+ "y": -259.4062441825511,
+ "z": 0.0
+ },
+ {
+ "x": 398.3266328422842,
+ "y": -258.40400385830173,
+ "z": 0.0
+ },
+ {
+ "x": 398.326243292966,
+ "y": -257.4017635340526,
+ "z": 0.0
+ },
+ {
+ "x": 398.3258537436478,
+ "y": -256.3995232098036,
+ "z": 0.0
+ },
+ {
+ "x": 398.3254641943297,
+ "y": -255.3972828855544,
+ "z": 0.0
+ },
+ {
+ "x": 398.32507464501157,
+ "y": -254.39504256130502,
+ "z": 0.0
+ },
+ {
+ "x": 398.3246850956934,
+ "y": -253.39280223705606,
+ "z": 0.0
+ },
+ {
+ "x": 398.32429554637525,
+ "y": -252.39056191280667,
+ "z": 0.0
+ },
+ {
+ "x": 398.32390599705707,
+ "y": -251.3883215885575,
+ "z": 0.0
+ },
+ {
+ "x": 398.3235164477389,
+ "y": -250.38608126430853,
+ "z": 0.0
+ },
+ {
+ "x": 398.32312689842075,
+ "y": -249.38384094005937,
+ "z": 0.0
+ },
+ {
+ "x": 398.3227373491026,
+ "y": -248.38160061580996,
+ "z": 0.0
+ },
+ {
+ "x": 398.32234779978444,
+ "y": -247.379360291561,
+ "z": 0.0
+ },
+ {
+ "x": 398.3219582504663,
+ "y": -246.37711996731161,
+ "z": 0.0
+ },
+ {
+ "x": 398.3215687011481,
+ "y": -245.37487964306243,
+ "z": 0.0
+ },
+ {
+ "x": 398.32117915182994,
+ "y": -244.3726393188135,
+ "z": 0.0
+ },
+ {
+ "x": 398.3207896025118,
+ "y": -243.3703989945643,
+ "z": 0.0
+ },
+ {
+ "x": 398.3204000531937,
+ "y": -242.3681586703149,
+ "z": 0.0
+ },
+ {
+ "x": 398.32001070338254,
+ "y": -241.3665669256959,
+ "z": 0.0
+ },
+ {
+ "x": 398.3197836758104,
+ "y": -240.36438857263863,
+ "z": 0.0
+ },
+ {
+ "x": 398.3195721744745,
+ "y": -239.36214819500114,
+ "z": 0.0
+ },
+ {
+ "x": 398.3193606731386,
+ "y": -238.35990781736365,
+ "z": 0.0
+ },
+ {
+ "x": 398.3191491718027,
+ "y": -237.35766743972616,
+ "z": 0.0
+ },
+ {
+ "x": 398.31893767046677,
+ "y": -236.35542706208867,
+ "z": 0.0
+ },
+ {
+ "x": 398.31872616913085,
+ "y": -235.35318668445117,
+ "z": 0.0
+ },
+ {
+ "x": 398.31851466779494,
+ "y": -234.35094630681368,
+ "z": 0.0
+ },
+ {
+ "x": 398.31830316645903,
+ "y": -233.3487059291762,
+ "z": 0.0
+ },
+ {
+ "x": 398.3180916651231,
+ "y": -232.3464655515387,
+ "z": 0.0
+ },
+ {
+ "x": 398.3178801637872,
+ "y": -231.3442251739012,
+ "z": 0.0
+ },
+ {
+ "x": 398.3176686624513,
+ "y": -230.34198479626372,
+ "z": 0.0
+ },
+ {
+ "x": 398.3174571611154,
+ "y": -229.33974441862622,
+ "z": 0.0
+ },
+ {
+ "x": 398.3172456597795,
+ "y": -228.33750404098873,
+ "z": 0.0
+ },
+ {
+ "x": 398.31703415844356,
+ "y": -227.3352636633512,
+ "z": 0.0
+ },
+ {
+ "x": 398.31682265710765,
+ "y": -226.33302328571372,
+ "z": 0.0
+ },
+ {
+ "x": 398.31661115577174,
+ "y": -225.33078290807623,
+ "z": 0.0
+ },
+ {
+ "x": 398.3163996544358,
+ "y": -224.32854253043874,
+ "z": 0.0
+ },
+ {
+ "x": 398.3161881530999,
+ "y": -223.32630215280125,
+ "z": 0.0
+ },
+ {
+ "x": 398.315976651764,
+ "y": -222.32406177516376,
+ "z": 0.0
+ },
+ {
+ "x": 398.3157651504281,
+ "y": -221.32182139752626,
+ "z": 0.0
+ },
+ {
+ "x": 398.3155536490922,
+ "y": -220.31958101988877,
+ "z": 0.0
+ },
+ {
+ "x": 398.31534214775627,
+ "y": -219.31734064225125,
+ "z": 0.0
+ },
+ {
+ "x": 398.31513064642036,
+ "y": -218.31510026461376,
+ "z": 0.0
+ },
+ {
+ "x": 398.31491914508445,
+ "y": -217.31285988697627,
+ "z": 0.0
+ },
+ {
+ "x": 398.31470764374853,
+ "y": -216.31061950933878,
+ "z": 0.0
+ },
+ {
+ "x": 398.3144961424126,
+ "y": -215.3083791317013,
+ "z": 0.0
+ },
+ {
+ "x": 398.3142846410767,
+ "y": -214.3061387540638,
+ "z": 0.0
+ },
+ {
+ "x": 398.3140731397408,
+ "y": -213.3038983764263,
+ "z": 0.0
+ },
+ {
+ "x": 398.3138616384049,
+ "y": -212.30165799878904,
+ "z": 0.0
+ },
+ {
+ "x": 398.31365013706903,
+ "y": -211.29941762115106,
+ "z": 0.0
+ },
+ {
+ "x": 398.31343863573306,
+ "y": -210.2971772435138,
+ "z": 0.0
+ },
+ {
+ "x": 398.31322713439715,
+ "y": -209.2949368658763,
+ "z": 0.0
+ },
+ {
+ "x": 398.31301563306124,
+ "y": -208.29269648823882,
+ "z": 0.0
+ },
+ {
+ "x": 398.31280413172533,
+ "y": -207.29045611060133,
+ "z": 0.0
+ },
+ {
+ "x": 398.3125926303894,
+ "y": -206.28821573296383,
+ "z": 0.0
+ },
+ {
+ "x": 398.3123811290535,
+ "y": -205.28597535532634,
+ "z": 0.0
+ },
+ {
+ "x": 398.3121696277176,
+ "y": -204.28373497768885,
+ "z": 0.0
+ },
+ {
+ "x": 398.3119581263817,
+ "y": -203.28149460005156,
+ "z": 0.0
+ },
+ {
+ "x": 398.3117466250458,
+ "y": -202.2792542224136,
+ "z": 0.0
+ },
+ {
+ "x": 398.31153512370986,
+ "y": -201.27701384477635,
+ "z": 0.0
+ },
+ {
+ "x": 398.31132362237395,
+ "y": -200.27477346713886,
+ "z": 0.0
+ },
+ {
+ "x": 398.31111212103804,
+ "y": -199.2725330895016,
+ "z": 0.0
+ },
+ {
+ "x": 398.3109006197022,
+ "y": -198.27029271186365,
+ "z": 0.0
+ },
+ {
+ "x": 398.3106891183662,
+ "y": -197.26805233422638,
+ "z": 0.0
+ },
+ {
+ "x": 398.3104776170303,
+ "y": -196.2658119565889,
+ "z": 0.0
+ },
+ {
+ "x": 398.3102661156944,
+ "y": -195.26357157895137,
+ "z": 0.0
+ },
+ {
+ "x": 398.3100546143585,
+ "y": -194.2613312013141,
+ "z": 0.0
+ },
+ {
+ "x": 398.3098431130226,
+ "y": -193.25909082367616,
+ "z": 0.0
+ },
+ {
+ "x": 398.30963161168665,
+ "y": -192.2568504460389,
+ "z": 0.0
+ },
+ {
+ "x": 398.30942011035074,
+ "y": -191.2546100684014,
+ "z": 0.0
+ },
+ {
+ "x": 398.30920860901483,
+ "y": -190.25236969076414,
+ "z": 0.0
+ },
+ {
+ "x": 398.308997107679,
+ "y": -189.2501293131264,
+ "z": 0.0
+ },
+ {
+ "x": 398.30878560634306,
+ "y": -188.2478889354889,
+ "z": 0.0
+ },
+ {
+ "x": 398.30857410500715,
+ "y": -187.24564855785115,
+ "z": 0.0
+ },
+ {
+ "x": 398.3083626036712,
+ "y": -186.2434081802139,
+ "z": 0.0
+ },
+ {
+ "x": 398.3081511023353,
+ "y": -185.24116780257657,
+ "z": 0.0
+ },
+ {
+ "x": 398.3079396009994,
+ "y": -184.23892742493885,
+ "z": 0.0
+ },
+ {
+ "x": 398.3077280996635,
+ "y": -183.2366870473011,
+ "z": 0.0
+ },
+ {
+ "x": 398.30751659832754,
+ "y": -182.23444666966384,
+ "z": 0.0
+ },
+ {
+ "x": 398.3073050969916,
+ "y": -181.23220629202655,
+ "z": 0.0
+ },
+ {
+ "x": 398.3070935956558,
+ "y": -180.22996591438883,
+ "z": 0.0
+ },
+ {
+ "x": 398.30688209431986,
+ "y": -179.22772553675134,
+ "z": 0.0
+ },
+ {
+ "x": 398.30667059298395,
+ "y": -178.22548515911356,
+ "z": 0.0
+ },
+ {
+ "x": 398.306459091648,
+ "y": -177.22324478147652,
+ "z": 0.0
+ },
+ {
+ "x": 398.3062475903121,
+ "y": -176.22100440383878,
+ "z": 0.0
+ },
+ {
+ "x": 398.3060360889762,
+ "y": -175.21876402620128,
+ "z": 0.0
+ },
+ {
+ "x": 398.3058245876403,
+ "y": -174.21652364856376,
+ "z": 0.0
+ },
+ {
+ "x": 398.3056130863044,
+ "y": -173.21428327092605,
+ "z": 0.0
+ },
+ {
+ "x": 398.3054015849684,
+ "y": -172.21204289328898,
+ "z": 0.0
+ },
+ {
+ "x": 398.30519008363257,
+ "y": -171.20980251565126,
+ "z": 0.0
+ },
+ {
+ "x": 398.30497858229666,
+ "y": -170.20756213801374,
+ "z": 0.0
+ },
+ {
+ "x": 398.30476708096074,
+ "y": -169.205321760376,
+ "z": 0.0
+ },
+ {
+ "x": 398.3045555796248,
+ "y": -168.20308138273893,
+ "z": 0.0
+ },
+ {
+ "x": 398.3043440782889,
+ "y": -167.2008410051012,
+ "z": 0.0
+ },
+ {
+ "x": 398.304132576953,
+ "y": -166.1986006274637,
+ "z": 0.0
+ },
+ {
+ "x": 398.3039210756171,
+ "y": -165.1963602498262,
+ "z": 0.0
+ },
+ {
+ "x": 398.3037095742812,
+ "y": -164.19411987218845,
+ "z": 0.0
+ },
+ {
+ "x": 398.3034980729452,
+ "y": -163.19187949455142,
+ "z": 0.0
+ },
+ {
+ "x": 398.30328657160936,
+ "y": -162.18963911691364,
+ "z": 0.0
+ },
+ {
+ "x": 398.30307507027345,
+ "y": -161.18739873927615,
+ "z": 0.0
+ },
+ {
+ "x": 398.30286356893754,
+ "y": -160.1851583616384,
+ "z": 0.0
+ },
+ {
+ "x": 398.30265206760157,
+ "y": -159.18291798400136,
+ "z": 0.0
+ },
+ {
+ "x": 398.3024405662657,
+ "y": -158.18067760636362,
+ "z": 0.0
+ },
+ {
+ "x": 398.3022290649298,
+ "y": -157.17843722872612,
+ "z": 0.0
+ },
+ {
+ "x": 398.3020175635939,
+ "y": -156.1761968510886,
+ "z": 0.0
+ },
+ {
+ "x": 398.301806062258,
+ "y": -155.1739564734509,
+ "z": 0.0
+ },
+ {
+ "x": 398.301594560922,
+ "y": -154.17171609581382,
+ "z": 0.0
+ },
+ {
+ "x": 398.30138305958616,
+ "y": -153.16947571817607,
+ "z": 0.0
+ },
+ {
+ "x": 398.30117155825025,
+ "y": -152.16723534053855,
+ "z": 0.0
+ },
+ {
+ "x": 398.30096005691433,
+ "y": -151.16499496290106,
+ "z": 0.0
+ },
+ {
+ "x": 398.3007485555784,
+ "y": -150.16275458526354,
+ "z": 0.0
+ },
+ {
+ "x": 398.3005370542425,
+ "y": -149.16051420762605,
+ "z": 0.0
+ },
+ {
+ "x": 398.3003255529066,
+ "y": -148.15827382998856,
+ "z": 0.0
+ },
+ {
+ "x": 398.3001140515707,
+ "y": -147.15603345235104,
+ "z": 0.0
+ },
+ {
+ "x": 398.2999025502348,
+ "y": -146.15379307471352,
+ "z": 0.0
+ },
+ {
+ "x": 398.29969104889886,
+ "y": -145.151552697076,
+ "z": 0.0
+ },
+ {
+ "x": 398.29947954756295,
+ "y": -144.1493123194385,
+ "z": 0.0
+ },
+ {
+ "x": 398.29926804622704,
+ "y": -143.147071941801,
+ "z": 0.0
+ },
+ {
+ "x": 398.29905654489113,
+ "y": -142.1448315641635,
+ "z": 0.0
+ },
+ {
+ "x": 398.2988450435552,
+ "y": -141.14259118652598,
+ "z": 0.0
+ },
+ {
+ "x": 398.2986335422193,
+ "y": -140.14035080888848,
+ "z": 0.0
+ },
+ {
+ "x": 398.2984220408834,
+ "y": -139.13811043125096,
+ "z": 0.0
+ },
+ {
+ "x": 398.2982105395475,
+ "y": -138.13587005361347,
+ "z": 0.0
+ },
+ {
+ "x": 398.2979990382116,
+ "y": -137.13362967597615,
+ "z": 0.0
+ },
+ {
+ "x": 398.2977875368757,
+ "y": -136.1313892983382,
+ "z": 0.0
+ },
+ {
+ "x": 398.29757603553975,
+ "y": -135.1291489207009,
+ "z": 0.0
+ },
+ {
+ "x": 398.29736453420384,
+ "y": -134.12690854306342,
+ "z": 0.0
+ },
+ {
+ "x": 398.2971530328679,
+ "y": -133.1246681654259,
+ "z": 0.0
+ },
+ {
+ "x": 398.296941531532,
+ "y": -132.1224277877884,
+ "z": 0.0
+ },
+ {
+ "x": 398.2967300301961,
+ "y": -131.1201874101509,
+ "z": 0.0
+ },
+ {
+ "x": 398.2965185288602,
+ "y": -130.11794703251337,
+ "z": 0.0
+ },
+ {
+ "x": 398.2963070275243,
+ "y": -129.11570665487585,
+ "z": 0.0
+ },
+ {
+ "x": 398.29609552618837,
+ "y": -128.1134662772386,
+ "z": 0.0
+ },
+ {
+ "x": 398.2958840248525,
+ "y": -127.11122589960061,
+ "z": 0.0
+ },
+ {
+ "x": 398.29567252351654,
+ "y": -126.10898552196335,
+ "z": 0.0
+ },
+ {
+ "x": 398.29546102218063,
+ "y": -125.10674514432586,
+ "z": 0.0
+ },
+ {
+ "x": 398.2952495208447,
+ "y": -124.10450476668858,
+ "z": 0.0
+ },
+ {
+ "x": 398.29503801950887,
+ "y": -123.10226438905063,
+ "z": 0.0
+ },
+ {
+ "x": 398.2948265181729,
+ "y": -122.10002401141335,
+ "z": 0.0
+ },
+ {
+ "x": 398.294615016837,
+ "y": -121.09778363377583,
+ "z": 0.0
+ },
+ {
+ "x": 398.2944035155011,
+ "y": -120.09554325613833,
+ "z": 0.0
+ },
+ {
+ "x": 398.29419201416516,
+ "y": -119.09330287850105,
+ "z": 0.0
+ },
+ {
+ "x": 398.2939805128293,
+ "y": -118.0910625008631,
+ "z": 0.0
+ },
+ {
+ "x": 398.29376901149334,
+ "y": -117.08882212322584,
+ "z": 0.0
+ },
+ {
+ "x": 398.2935575101574,
+ "y": -116.08658174558835,
+ "z": 0.0
+ },
+ {
+ "x": 398.2933460088215,
+ "y": -115.08434136795108,
+ "z": 0.0
+ },
+ {
+ "x": 398.29313450748566,
+ "y": -114.08210099031334,
+ "z": 0.0
+ },
+ {
+ "x": 398.29292300614975,
+ "y": -113.07986061267562,
+ "z": 0.0
+ },
+ {
+ "x": 398.2927115048138,
+ "y": -112.07762023503834,
+ "z": 0.0
+ },
+ {
+ "x": 398.29250000347787,
+ "y": -111.07537985740083,
+ "z": 0.0
+ },
+ {
+ "x": 398.29228850214196,
+ "y": -110.07313947976355,
+ "z": 0.0
+ },
+ {
+ "x": 398.2920770008061,
+ "y": -109.0708991021256,
+ "z": 0.0
+ },
+ {
+ "x": 398.29186549947013,
+ "y": -108.06865872448832,
+ "z": 0.0
+ },
+ {
+ "x": 398.2916539981342,
+ "y": -107.06641834685081,
+ "z": 0.0
+ },
+ {
+ "x": 398.2914424967983,
+ "y": -106.06417796921353,
+ "z": 0.0
+ },
+ {
+ "x": 398.29123099546246,
+ "y": -105.06193759157577,
+ "z": 0.0
+ },
+ {
+ "x": 398.29101949412654,
+ "y": -104.05969721393826,
+ "z": 0.0
+ },
+ {
+ "x": 398.29080799279063,
+ "y": -103.05745683630055,
+ "z": 0.0
+ },
+ {
+ "x": 398.29059649145466,
+ "y": -102.0552164586635,
+ "z": 0.0
+ },
+ {
+ "x": 398.2903849901188,
+ "y": -101.05297608102576,
+ "z": 0.0
+ },
+ {
+ "x": 398.2901734887829,
+ "y": -100.05073570338826,
+ "z": 0.0
+ },
+ {
+ "x": 398.289961987447,
+ "y": -99.04849532575075,
+ "z": 0.0
+ },
+ {
+ "x": 398.2897504861111,
+ "y": -98.04625494811299,
+ "z": 0.0
+ },
+ {
+ "x": 398.2895389847751,
+ "y": -97.04401457047594,
+ "z": 0.0
+ },
+ {
+ "x": 398.28932748343925,
+ "y": -96.0417741928382,
+ "z": 0.0
+ },
+ {
+ "x": 398.28911598210334,
+ "y": -95.0395338152007,
+ "z": 0.0
+ },
+ {
+ "x": 398.2889044807674,
+ "y": -94.03729343756297,
+ "z": 0.0
+ },
+ {
+ "x": 398.28869297943146,
+ "y": -93.03505305992591,
+ "z": 0.0
+ },
+ {
+ "x": 398.2884814780956,
+ "y": -92.03281268228818,
+ "z": 0.0
+ },
+ {
+ "x": 398.2882699767597,
+ "y": -91.03057230465068,
+ "z": 0.0
+ },
+ {
+ "x": 398.2880584754238,
+ "y": -90.02833192701317,
+ "z": 0.0
+ },
+ {
+ "x": 398.28784697408787,
+ "y": -89.02609154937541,
+ "z": 0.0
+ },
+ {
+ "x": 398.28763556056833,
+ "y": -88.02479527108368,
+ "z": 0.0
+ },
+ {
+ "x": 398.2876588492329,
+ "y": -87.02621246628772,
+ "z": 0.0
+ },
+ {
+ "x": 398.28859921985594,
+ "y": -86.02501496122022,
+ "z": 0.0
+ },
+ {
+ "x": 398.2898018880531,
+ "y": -85.0227752828551,
+ "z": 0.0
+ },
+ {
+ "x": 398.2910045562502,
+ "y": -84.02053560449042,
+ "z": 0.0
+ },
+ {
+ "x": 398.29220722444734,
+ "y": -83.01829592612553,
+ "z": 0.0
+ },
+ {
+ "x": 398.2934098926445,
+ "y": -82.01605624776037,
+ "z": 0.0
+ },
+ {
+ "x": 398.2946125608416,
+ "y": -81.0138165693957,
+ "z": 0.0
+ },
+ {
+ "x": 398.29581522903874,
+ "y": -80.0115768910308,
+ "z": 0.0
+ },
+ {
+ "x": 398.2970178972359,
+ "y": -79.00933721266567,
+ "z": 0.0
+ },
+ {
+ "x": 398.298220565433,
+ "y": -78.007097534301,
+ "z": 0.0
+ },
+ {
+ "x": 398.29942323363014,
+ "y": -77.00485785593611,
+ "z": 0.0
+ },
+ {
+ "x": 398.3006259018273,
+ "y": -76.00261817757121,
+ "z": 0.0
+ },
+ {
+ "x": 398.30182857002444,
+ "y": -75.0003784992063,
+ "z": 0.0
+ },
+ {
+ "x": 398.3030312382216,
+ "y": -73.99813882084118,
+ "z": 0.0
+ },
+ {
+ "x": 398.3042339064187,
+ "y": -72.99589914247647,
+ "z": 0.0
+ },
+ {
+ "x": 398.30543657461584,
+ "y": -71.99365946411159,
+ "z": 0.0
+ },
+ {
+ "x": 398.306639242813,
+ "y": -70.99141978574644,
+ "z": 0.0
+ },
+ {
+ "x": 398.3078419110101,
+ "y": -69.98918010738178,
+ "z": 0.0
+ },
+ {
+ "x": 398.30904457920724,
+ "y": -68.98694042901688,
+ "z": 0.0
+ },
+ {
+ "x": 398.3102472474044,
+ "y": -67.98470075065175,
+ "z": 0.0
+ },
+ {
+ "x": 398.3114499156015,
+ "y": -66.9824610722871,
+ "z": 0.0
+ },
+ {
+ "x": 398.31265258379864,
+ "y": -65.98022139392216,
+ "z": 0.0
+ },
+ {
+ "x": 398.3138552519958,
+ "y": -64.97798171555726,
+ "z": 0.0
+ },
+ {
+ "x": 398.31505792019294,
+ "y": -63.97574203719214,
+ "z": 0.0
+ },
+ {
+ "x": 398.31626058839004,
+ "y": -62.973502358827474,
+ "z": 0.0
+ },
+ {
+ "x": 398.3174632565872,
+ "y": -61.9712626804626,
+ "z": 0.0
+ },
+ {
+ "x": 398.31866592478434,
+ "y": -60.9690230020975,
+ "z": 0.0
+ },
+ {
+ "x": 398.31986859298144,
+ "y": -59.96678332373281,
+ "z": 0.0
+ },
+ {
+ "x": 398.3210712611786,
+ "y": -58.964543645367925,
+ "z": 0.0
+ },
+ {
+ "x": 398.32227392937574,
+ "y": -57.96230396700278,
+ "z": 0.0
+ },
+ {
+ "x": 398.32347659757284,
+ "y": -56.96006428863836,
+ "z": 0.0
+ },
+ {
+ "x": 398.32467926577004,
+ "y": -55.957824610273036,
+ "z": 0.0
+ },
+ {
+ "x": 398.32588193396714,
+ "y": -54.95558493190812,
+ "z": 0.0
+ },
+ {
+ "x": 398.32708460216423,
+ "y": -53.95334525354369,
+ "z": 0.0
+ },
+ {
+ "x": 398.32828727036144,
+ "y": -52.95110557517826,
+ "z": 0.0
+ },
+ {
+ "x": 398.32948993855854,
+ "y": -51.9488658968136,
+ "z": 0.0
+ },
+ {
+ "x": 398.3306926067557,
+ "y": -50.94662621844869,
+ "z": 0.0
+ },
+ {
+ "x": 398.33189527495284,
+ "y": -49.944386540083585,
+ "z": 0.0
+ },
+ {
+ "x": 398.33309794314994,
+ "y": -48.94214686171893,
+ "z": 0.0
+ },
+ {
+ "x": 398.3343006113471,
+ "y": -47.93990718335402,
+ "z": 0.0
+ },
+ {
+ "x": 398.33550327954424,
+ "y": -46.93766750498914,
+ "z": 0.0
+ },
+ {
+ "x": 398.3367059477414,
+ "y": -45.93542782662401,
+ "z": 0.0
+ },
+ {
+ "x": 398.3379086159385,
+ "y": -44.93318814825934,
+ "z": 0.0
+ },
+ {
+ "x": 398.33911128413564,
+ "y": -43.93094846989443,
+ "z": 0.0
+ },
+ {
+ "x": 398.3403139523328,
+ "y": -42.928708791529324,
+ "z": 0.0
+ },
+ {
+ "x": 398.3415166205299,
+ "y": -41.92646911316468,
+ "z": 0.0
+ },
+ {
+ "x": 398.34271928872704,
+ "y": -40.924229434799805,
+ "z": 0.0
+ },
+ {
+ "x": 398.3439219569242,
+ "y": -39.921989756434705,
+ "z": 0.0
+ },
+ {
+ "x": 398.3451246251213,
+ "y": -38.91975007807005,
+ "z": 0.0
+ },
+ {
+ "x": 398.34632729331844,
+ "y": -37.91751039970513,
+ "z": 0.0
+ },
+ {
+ "x": 398.3475299615156,
+ "y": -36.91527072134,
+ "z": 0.0
+ },
+ {
+ "x": 398.3487326297127,
+ "y": -35.913031042975334,
+ "z": 0.0
+ },
+ {
+ "x": 398.34993529790984,
+ "y": -34.91079136461043,
+ "z": 0.0
+ },
+ {
+ "x": 398.351137966107,
+ "y": -33.90855168624554,
+ "z": 0.0
+ },
+ {
+ "x": 398.35234063430414,
+ "y": -32.906312007880665,
+ "z": 0.0
+ },
+ {
+ "x": 398.3535433025013,
+ "y": -31.904072329515564,
+ "z": 0.0
+ },
+ {
+ "x": 398.3547459706984,
+ "y": -30.90183265115092,
+ "z": 0.0
+ },
+ {
+ "x": 398.35594863889554,
+ "y": -29.899592972786046,
+ "z": 0.0
+ },
+ {
+ "x": 398.3571513070927,
+ "y": -28.89735329442095,
+ "z": 0.0
+ },
+ {
+ "x": 398.3583539752898,
+ "y": -27.895113616056285,
+ "z": 0.0
+ },
+ {
+ "x": 398.35955664348694,
+ "y": -26.89287393769138,
+ "z": 0.0
+ },
+ {
+ "x": 398.3607593116841,
+ "y": -25.890634259326283,
+ "z": 0.0
+ },
+ {
+ "x": 398.3619619798812,
+ "y": -24.888394580961638,
+ "z": 0.0
+ },
+ {
+ "x": 398.36316464807834,
+ "y": -23.88615490259675,
+ "z": 0.0
+ },
+ {
+ "x": 398.3643673162755,
+ "y": -22.883915224231615,
+ "z": 0.0
+ },
+ {
+ "x": 398.3655699844726,
+ "y": -21.881675545866944,
+ "z": 0.0
+ },
+ {
+ "x": 398.36677265266974,
+ "y": -20.879435867501968,
+ "z": 0.0
+ },
+ {
+ "x": 398.3679753208669,
+ "y": -19.87719618913705,
+ "z": 0.0
+ },
+ {
+ "x": 398.36917798906404,
+ "y": -18.87495651077191,
+ "z": 0.0
+ },
+ {
+ "x": 398.37038065726114,
+ "y": -17.872716832407257,
+ "z": 0.0
+ },
+ {
+ "x": 398.3715833254583,
+ "y": -16.870477154042373,
+ "z": 0.0
+ },
+ {
+ "x": 398.37278599365544,
+ "y": -15.868237475677223,
+ "z": 0.0
+ },
+ {
+ "x": 398.37398866185254,
+ "y": -14.865997797312762,
+ "z": 0.0
+ },
+ {
+ "x": 398.37519133004974,
+ "y": -13.863758118947425,
+ "z": 0.0
+ },
+ {
+ "x": 398.37639399824684,
+ "y": -12.861518440582504,
+ "z": 0.0
+ },
+ {
+ "x": 398.37759666644394,
+ "y": -11.85927876221804,
+ "z": 0.0
+ },
+ {
+ "x": 398.37879933464114,
+ "y": -10.857039083852692,
+ "z": 0.0
+ },
+ {
+ "x": 398.38000200283824,
+ "y": -9.854799405487771,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 42,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 394.3500061035156,
+ "y": -318.53997802734375,
+ "z": 0.0
+ },
+ {
+ "x": 394.34961655419744,
+ "y": -317.5377377030946,
+ "z": 0.0
+ },
+ {
+ "x": 394.3492270048793,
+ "y": -316.5354973788454,
+ "z": 0.0
+ },
+ {
+ "x": 394.3488374555612,
+ "y": -315.5332570545962,
+ "z": 0.0
+ },
+ {
+ "x": 394.348447906243,
+ "y": -314.53101673034706,
+ "z": 0.0
+ },
+ {
+ "x": 394.34805835692487,
+ "y": -313.52877640609785,
+ "z": 0.0
+ },
+ {
+ "x": 394.3476688076067,
+ "y": -312.5265360818487,
+ "z": 0.0
+ },
+ {
+ "x": 394.3472792582885,
+ "y": -311.5242957575995,
+ "z": 0.0
+ },
+ {
+ "x": 394.34688970897037,
+ "y": -310.5220554333503,
+ "z": 0.0
+ },
+ {
+ "x": 394.34650015965224,
+ "y": -309.51981510910116,
+ "z": 0.0
+ },
+ {
+ "x": 394.34611061033405,
+ "y": -308.51757478485194,
+ "z": 0.0
+ },
+ {
+ "x": 394.34572106101587,
+ "y": -307.5153344606028,
+ "z": 0.0
+ },
+ {
+ "x": 394.34533151169774,
+ "y": -306.5130941363536,
+ "z": 0.0
+ },
+ {
+ "x": 394.34494196237955,
+ "y": -305.5108538121044,
+ "z": 0.0
+ },
+ {
+ "x": 394.3445524130614,
+ "y": -304.50861348785526,
+ "z": 0.0
+ },
+ {
+ "x": 394.3441628637433,
+ "y": -303.50637316360604,
+ "z": 0.0
+ },
+ {
+ "x": 394.3437733144251,
+ "y": -302.5041328393569,
+ "z": 0.0
+ },
+ {
+ "x": 394.3433837651069,
+ "y": -301.5018925151077,
+ "z": 0.0
+ },
+ {
+ "x": 394.3429942157888,
+ "y": -300.4996521908585,
+ "z": 0.0
+ },
+ {
+ "x": 394.3426046664706,
+ "y": -299.49741186660935,
+ "z": 0.0
+ },
+ {
+ "x": 394.3422151171525,
+ "y": -298.49517154236014,
+ "z": 0.0
+ },
+ {
+ "x": 394.34182556783435,
+ "y": -297.492931218111,
+ "z": 0.0
+ },
+ {
+ "x": 394.34143601851616,
+ "y": -296.4906908938618,
+ "z": 0.0
+ },
+ {
+ "x": 394.341046469198,
+ "y": -295.4884505696126,
+ "z": 0.0
+ },
+ {
+ "x": 394.34065691987985,
+ "y": -294.48621024536345,
+ "z": 0.0
+ },
+ {
+ "x": 394.34026737056166,
+ "y": -293.4839699211143,
+ "z": 0.0
+ },
+ {
+ "x": 394.33987782124353,
+ "y": -292.4817295968651,
+ "z": 0.0
+ },
+ {
+ "x": 394.33948827192535,
+ "y": -291.4794892726159,
+ "z": 0.0
+ },
+ {
+ "x": 394.3390987226072,
+ "y": -290.4772489483667,
+ "z": 0.0
+ },
+ {
+ "x": 394.33870917328903,
+ "y": -289.47500862411755,
+ "z": 0.0
+ },
+ {
+ "x": 394.3383196239709,
+ "y": -288.4727682998684,
+ "z": 0.0
+ },
+ {
+ "x": 394.3379300746528,
+ "y": -287.4705279756192,
+ "z": 0.0
+ },
+ {
+ "x": 394.3375405253346,
+ "y": -286.46828765137,
+ "z": 0.0
+ },
+ {
+ "x": 394.3371509760164,
+ "y": -285.46604732712086,
+ "z": 0.0
+ },
+ {
+ "x": 394.3367614266983,
+ "y": -284.46380700287165,
+ "z": 0.0
+ },
+ {
+ "x": 394.3363718773801,
+ "y": -283.4615666786225,
+ "z": 0.0
+ },
+ {
+ "x": 394.33598232806196,
+ "y": -282.45932635437333,
+ "z": 0.0
+ },
+ {
+ "x": 394.33559277874383,
+ "y": -281.4570860301241,
+ "z": 0.0
+ },
+ {
+ "x": 394.33520322942564,
+ "y": -280.45484570587496,
+ "z": 0.0
+ },
+ {
+ "x": 394.33481368010746,
+ "y": -279.45260538162574,
+ "z": 0.0
+ },
+ {
+ "x": 394.33442413078933,
+ "y": -278.4503650573766,
+ "z": 0.0
+ },
+ {
+ "x": 394.33403458147114,
+ "y": -277.44812473312743,
+ "z": 0.0
+ },
+ {
+ "x": 394.333645032153,
+ "y": -276.44588440887827,
+ "z": 0.0
+ },
+ {
+ "x": 394.33325548283483,
+ "y": -275.44364408462906,
+ "z": 0.0
+ },
+ {
+ "x": 394.3328659335167,
+ "y": -274.4414037603799,
+ "z": 0.0
+ },
+ {
+ "x": 394.3324763841985,
+ "y": -273.43916343613074,
+ "z": 0.0
+ },
+ {
+ "x": 394.33208683488033,
+ "y": -272.4369231118815,
+ "z": 0.0
+ },
+ {
+ "x": 394.3316972855622,
+ "y": -271.43468278763237,
+ "z": 0.0
+ },
+ {
+ "x": 394.33130773624407,
+ "y": -270.4324424633832,
+ "z": 0.0
+ },
+ {
+ "x": 394.3309181869259,
+ "y": -269.430202139134,
+ "z": 0.0
+ },
+ {
+ "x": 394.33052863760776,
+ "y": -268.42796181488484,
+ "z": 0.0
+ },
+ {
+ "x": 394.33013908828957,
+ "y": -267.4257214906357,
+ "z": 0.0
+ },
+ {
+ "x": 394.32974953897144,
+ "y": -266.42348116638647,
+ "z": 0.0
+ },
+ {
+ "x": 394.3293599896533,
+ "y": -265.4212408421373,
+ "z": 0.0
+ },
+ {
+ "x": 394.3289704403351,
+ "y": -264.41900051788815,
+ "z": 0.0
+ },
+ {
+ "x": 394.32858089101694,
+ "y": -263.41676019363894,
+ "z": 0.0
+ },
+ {
+ "x": 394.3281913416988,
+ "y": -262.4145198693898,
+ "z": 0.0
+ },
+ {
+ "x": 394.3278017923806,
+ "y": -261.4122795451406,
+ "z": 0.0
+ },
+ {
+ "x": 394.32741224306244,
+ "y": -260.4100392208914,
+ "z": 0.0
+ },
+ {
+ "x": 394.3270226937443,
+ "y": -259.40779889664225,
+ "z": 0.0
+ },
+ {
+ "x": 394.3266331444262,
+ "y": -258.4055585723931,
+ "z": 0.0
+ },
+ {
+ "x": 394.326243595108,
+ "y": -257.40331824814393,
+ "z": 0.0
+ },
+ {
+ "x": 394.3258540457898,
+ "y": -256.4010779238947,
+ "z": 0.0
+ },
+ {
+ "x": 394.3254644964717,
+ "y": -255.39883759964553,
+ "z": 0.0
+ },
+ {
+ "x": 394.32507494715355,
+ "y": -254.39659727539637,
+ "z": 0.0
+ },
+ {
+ "x": 394.32468539783537,
+ "y": -253.3943569511472,
+ "z": 0.0
+ },
+ {
+ "x": 394.32429584851724,
+ "y": -252.39211662689803,
+ "z": 0.0
+ },
+ {
+ "x": 394.32390629919905,
+ "y": -251.38987630264884,
+ "z": 0.0
+ },
+ {
+ "x": 394.32351674988087,
+ "y": -250.38763597839966,
+ "z": 0.0
+ },
+ {
+ "x": 394.32312720056274,
+ "y": -249.3853956541505,
+ "z": 0.0
+ },
+ {
+ "x": 394.3227376512446,
+ "y": -248.3831553299013,
+ "z": 0.0
+ },
+ {
+ "x": 394.3223481019264,
+ "y": -247.38091500565213,
+ "z": 0.0
+ },
+ {
+ "x": 394.3219585526083,
+ "y": -246.37867468140297,
+ "z": 0.0
+ },
+ {
+ "x": 394.3215690032901,
+ "y": -245.37643435715378,
+ "z": 0.0
+ },
+ {
+ "x": 394.3211794539719,
+ "y": -244.37419403290463,
+ "z": 0.0
+ },
+ {
+ "x": 394.3207899046538,
+ "y": -243.37195370865544,
+ "z": 0.0
+ },
+ {
+ "x": 394.32040035533566,
+ "y": -242.36971338440625,
+ "z": 0.0
+ },
+ {
+ "x": 394.3200108060175,
+ "y": -241.36747306015707,
+ "z": 0.0
+ },
+ {
+ "x": 394.3197837648765,
+ "y": -240.36523268682888,
+ "z": 0.0
+ },
+ {
+ "x": 394.3195722635406,
+ "y": -239.36299230919138,
+ "z": 0.0
+ },
+ {
+ "x": 394.31936076220467,
+ "y": -238.3607519315539,
+ "z": 0.0
+ },
+ {
+ "x": 394.31914926086876,
+ "y": -237.3585115539164,
+ "z": 0.0
+ },
+ {
+ "x": 394.31893775953284,
+ "y": -236.3562711762789,
+ "z": 0.0
+ },
+ {
+ "x": 394.31872625819693,
+ "y": -235.35403079864142,
+ "z": 0.0
+ },
+ {
+ "x": 394.318514756861,
+ "y": -234.35179042100393,
+ "z": 0.0
+ },
+ {
+ "x": 394.3183032555251,
+ "y": -233.34955004336643,
+ "z": 0.0
+ },
+ {
+ "x": 394.3180917541892,
+ "y": -232.34730966572894,
+ "z": 0.0
+ },
+ {
+ "x": 394.3178802528533,
+ "y": -231.34506928809145,
+ "z": 0.0
+ },
+ {
+ "x": 394.3176687515174,
+ "y": -230.34282891045396,
+ "z": 0.0
+ },
+ {
+ "x": 394.31745725018146,
+ "y": -229.34058853281647,
+ "z": 0.0
+ },
+ {
+ "x": 394.31724574884555,
+ "y": -228.33834815517898,
+ "z": 0.0
+ },
+ {
+ "x": 394.31703424750964,
+ "y": -227.33610777754146,
+ "z": 0.0
+ },
+ {
+ "x": 394.3168227461737,
+ "y": -226.33386739990397,
+ "z": 0.0
+ },
+ {
+ "x": 394.3166112448378,
+ "y": -225.33162702226647,
+ "z": 0.0
+ },
+ {
+ "x": 394.3163997435019,
+ "y": -224.32938664462898,
+ "z": 0.0
+ },
+ {
+ "x": 394.316188242166,
+ "y": -223.3271462669915,
+ "z": 0.0
+ },
+ {
+ "x": 394.3159767408301,
+ "y": -222.324905889354,
+ "z": 0.0
+ },
+ {
+ "x": 394.31576523949417,
+ "y": -221.3226655117165,
+ "z": 0.0
+ },
+ {
+ "x": 394.31555373815826,
+ "y": -220.32042513407902,
+ "z": 0.0
+ },
+ {
+ "x": 394.31534223682235,
+ "y": -219.3181847564415,
+ "z": 0.0
+ },
+ {
+ "x": 394.31513073548643,
+ "y": -218.315944378804,
+ "z": 0.0
+ },
+ {
+ "x": 394.3149192341505,
+ "y": -217.3137040011665,
+ "z": 0.0
+ },
+ {
+ "x": 394.3147077328146,
+ "y": -216.31146362352902,
+ "z": 0.0
+ },
+ {
+ "x": 394.3144962314787,
+ "y": -215.30922324589153,
+ "z": 0.0
+ },
+ {
+ "x": 394.3142847301428,
+ "y": -214.30698286825404,
+ "z": 0.0
+ },
+ {
+ "x": 394.3140732288069,
+ "y": -213.30474249061655,
+ "z": 0.0
+ },
+ {
+ "x": 394.31386172747096,
+ "y": -212.30250211297906,
+ "z": 0.0
+ },
+ {
+ "x": 394.3136502261351,
+ "y": -211.30026173534154,
+ "z": 0.0
+ },
+ {
+ "x": 394.31343872479914,
+ "y": -210.29802135770404,
+ "z": 0.0
+ },
+ {
+ "x": 394.31322722346323,
+ "y": -209.29578098006655,
+ "z": 0.0
+ },
+ {
+ "x": 394.3130157221273,
+ "y": -208.29354060242906,
+ "z": 0.0
+ },
+ {
+ "x": 394.3128042207914,
+ "y": -207.29130022479157,
+ "z": 0.0
+ },
+ {
+ "x": 394.3125927194555,
+ "y": -206.28905984715408,
+ "z": 0.0
+ },
+ {
+ "x": 394.3123812181196,
+ "y": -205.2868194695166,
+ "z": 0.0
+ },
+ {
+ "x": 394.31216971678367,
+ "y": -204.2845790918791,
+ "z": 0.0
+ },
+ {
+ "x": 394.31195821544776,
+ "y": -203.28233871424158,
+ "z": 0.0
+ },
+ {
+ "x": 394.3117467141119,
+ "y": -202.28009833660408,
+ "z": 0.0
+ },
+ {
+ "x": 394.31153521277594,
+ "y": -201.2778579589666,
+ "z": 0.0
+ },
+ {
+ "x": 394.31132371144,
+ "y": -200.2756175813291,
+ "z": 0.0
+ },
+ {
+ "x": 394.3111122101041,
+ "y": -199.2733772036916,
+ "z": 0.0
+ },
+ {
+ "x": 394.31090070876826,
+ "y": -198.27113682605412,
+ "z": 0.0
+ },
+ {
+ "x": 394.3106892074323,
+ "y": -197.26889644841663,
+ "z": 0.0
+ },
+ {
+ "x": 394.3104777060964,
+ "y": -196.26665607077913,
+ "z": 0.0
+ },
+ {
+ "x": 394.31026620476047,
+ "y": -195.26441569314161,
+ "z": 0.0
+ },
+ {
+ "x": 394.31005470342456,
+ "y": -194.26217531550412,
+ "z": 0.0
+ },
+ {
+ "x": 394.3098432020887,
+ "y": -193.25993493786663,
+ "z": 0.0
+ },
+ {
+ "x": 394.30963170075273,
+ "y": -192.25769456022914,
+ "z": 0.0
+ },
+ {
+ "x": 394.3094201994168,
+ "y": -191.25545418259165,
+ "z": 0.0
+ },
+ {
+ "x": 394.3092086980809,
+ "y": -190.25321380495416,
+ "z": 0.0
+ },
+ {
+ "x": 394.30899719674505,
+ "y": -189.25097342731664,
+ "z": 0.0
+ },
+ {
+ "x": 394.30878569540914,
+ "y": -188.24873304967915,
+ "z": 0.0
+ },
+ {
+ "x": 394.30857419407323,
+ "y": -187.24649267204163,
+ "z": 0.0
+ },
+ {
+ "x": 394.30836269273726,
+ "y": -186.24425229440413,
+ "z": 0.0
+ },
+ {
+ "x": 394.30815119140135,
+ "y": -185.2420119167666,
+ "z": 0.0
+ },
+ {
+ "x": 394.3079396900655,
+ "y": -184.2397715391291,
+ "z": 0.0
+ },
+ {
+ "x": 394.3077281887296,
+ "y": -183.23753116149157,
+ "z": 0.0
+ },
+ {
+ "x": 394.3075166873936,
+ "y": -182.23529078385408,
+ "z": 0.0
+ },
+ {
+ "x": 394.3073051860577,
+ "y": -181.23305040621656,
+ "z": 0.0
+ },
+ {
+ "x": 394.30709368472185,
+ "y": -180.23081002857907,
+ "z": 0.0
+ },
+ {
+ "x": 394.30688218338594,
+ "y": -179.22856965094158,
+ "z": 0.0
+ },
+ {
+ "x": 394.30667068205,
+ "y": -178.22632927330403,
+ "z": 0.0
+ },
+ {
+ "x": 394.30645918071406,
+ "y": -177.22408889566654,
+ "z": 0.0
+ },
+ {
+ "x": 394.3062476793782,
+ "y": -176.22184851802902,
+ "z": 0.0
+ },
+ {
+ "x": 394.3060361780423,
+ "y": -175.21960814039153,
+ "z": 0.0
+ },
+ {
+ "x": 394.3058246767064,
+ "y": -174.217367762754,
+ "z": 0.0
+ },
+ {
+ "x": 394.30561317537047,
+ "y": -173.21512738511652,
+ "z": 0.0
+ },
+ {
+ "x": 394.3054016740345,
+ "y": -172.212887007479,
+ "z": 0.0
+ },
+ {
+ "x": 394.30519017269864,
+ "y": -171.2106466298415,
+ "z": 0.0
+ },
+ {
+ "x": 394.30497867136273,
+ "y": -170.20840625220399,
+ "z": 0.0
+ },
+ {
+ "x": 394.3047671700268,
+ "y": -169.20616587456647,
+ "z": 0.0
+ },
+ {
+ "x": 394.30455566869085,
+ "y": -168.20392549692895,
+ "z": 0.0
+ },
+ {
+ "x": 394.304344167355,
+ "y": -167.20168511929145,
+ "z": 0.0
+ },
+ {
+ "x": 394.3041326660191,
+ "y": -166.19944474165393,
+ "z": 0.0
+ },
+ {
+ "x": 394.3039211646832,
+ "y": -165.19720436401644,
+ "z": 0.0
+ },
+ {
+ "x": 394.30370966334726,
+ "y": -164.19496398637892,
+ "z": 0.0
+ },
+ {
+ "x": 394.3034981620113,
+ "y": -163.19272360874143,
+ "z": 0.0
+ },
+ {
+ "x": 394.30328666067544,
+ "y": -162.19048323110388,
+ "z": 0.0
+ },
+ {
+ "x": 394.3030751593395,
+ "y": -161.1882428534664,
+ "z": 0.0
+ },
+ {
+ "x": 394.3028636580036,
+ "y": -160.18600247582887,
+ "z": 0.0
+ },
+ {
+ "x": 394.30265215666765,
+ "y": -159.18376209819138,
+ "z": 0.0
+ },
+ {
+ "x": 394.3024406553318,
+ "y": -158.18152172055386,
+ "z": 0.0
+ },
+ {
+ "x": 394.3022291539959,
+ "y": -157.17928134291637,
+ "z": 0.0
+ },
+ {
+ "x": 394.30201765265997,
+ "y": -156.17704096527885,
+ "z": 0.0
+ },
+ {
+ "x": 394.30180615132406,
+ "y": -155.17480058764136,
+ "z": 0.0
+ },
+ {
+ "x": 394.3015946499881,
+ "y": -154.17256021000384,
+ "z": 0.0
+ },
+ {
+ "x": 394.30138314865223,
+ "y": -153.17031983236632,
+ "z": 0.0
+ },
+ {
+ "x": 394.3011716473163,
+ "y": -152.1680794547288,
+ "z": 0.0
+ },
+ {
+ "x": 394.3009601459804,
+ "y": -151.1658390770913,
+ "z": 0.0
+ },
+ {
+ "x": 394.3007486446445,
+ "y": -150.1635986994538,
+ "z": 0.0
+ },
+ {
+ "x": 394.3005371433086,
+ "y": -149.1613583218163,
+ "z": 0.0
+ },
+ {
+ "x": 394.3003256419727,
+ "y": -148.1591179441788,
+ "z": 0.0
+ },
+ {
+ "x": 394.30011414063677,
+ "y": -147.15687756654128,
+ "z": 0.0
+ },
+ {
+ "x": 394.29990263930085,
+ "y": -146.15463718890376,
+ "z": 0.0
+ },
+ {
+ "x": 394.29969113796494,
+ "y": -145.15239681126624,
+ "z": 0.0
+ },
+ {
+ "x": 394.29947963662903,
+ "y": -144.15015643362875,
+ "z": 0.0
+ },
+ {
+ "x": 394.2992681352931,
+ "y": -143.14791605599123,
+ "z": 0.0
+ },
+ {
+ "x": 394.2990566339572,
+ "y": -142.14567567835374,
+ "z": 0.0
+ },
+ {
+ "x": 394.2988451326213,
+ "y": -141.14343530071622,
+ "z": 0.0
+ },
+ {
+ "x": 394.2986336312854,
+ "y": -140.14119492307873,
+ "z": 0.0
+ },
+ {
+ "x": 394.2984221299495,
+ "y": -139.1389545454412,
+ "z": 0.0
+ },
+ {
+ "x": 394.29821062861356,
+ "y": -138.13671416780372,
+ "z": 0.0
+ },
+ {
+ "x": 394.29799912727765,
+ "y": -137.13447379016617,
+ "z": 0.0
+ },
+ {
+ "x": 394.2977876259418,
+ "y": -136.13223341252868,
+ "z": 0.0
+ },
+ {
+ "x": 394.2975761246058,
+ "y": -135.12999303489116,
+ "z": 0.0
+ },
+ {
+ "x": 394.2973646232699,
+ "y": -134.12775265725367,
+ "z": 0.0
+ },
+ {
+ "x": 394.297153121934,
+ "y": -133.12551227961615,
+ "z": 0.0
+ },
+ {
+ "x": 394.2969416205981,
+ "y": -132.12327190197865,
+ "z": 0.0
+ },
+ {
+ "x": 394.2967301192622,
+ "y": -131.12103152434113,
+ "z": 0.0
+ },
+ {
+ "x": 394.29651861792627,
+ "y": -130.11879114670361,
+ "z": 0.0
+ },
+ {
+ "x": 394.29630711659036,
+ "y": -129.1165507690661,
+ "z": 0.0
+ },
+ {
+ "x": 394.29609561525444,
+ "y": -128.1143103914286,
+ "z": 0.0
+ },
+ {
+ "x": 394.2958841139186,
+ "y": -127.1120700137911,
+ "z": 0.0
+ },
+ {
+ "x": 394.2956726125826,
+ "y": -126.1098296361536,
+ "z": 0.0
+ },
+ {
+ "x": 394.2954611112467,
+ "y": -125.10758925851611,
+ "z": 0.0
+ },
+ {
+ "x": 394.2952496099108,
+ "y": -124.10534888087861,
+ "z": 0.0
+ },
+ {
+ "x": 394.29503810857494,
+ "y": -123.10310850324112,
+ "z": 0.0
+ },
+ {
+ "x": 394.294826607239,
+ "y": -122.10086812560361,
+ "z": 0.0
+ },
+ {
+ "x": 394.29461510590306,
+ "y": -121.09862774796609,
+ "z": 0.0
+ },
+ {
+ "x": 394.29440360456715,
+ "y": -120.09638737032859,
+ "z": 0.0
+ },
+ {
+ "x": 394.29419210323124,
+ "y": -119.09414699269108,
+ "z": 0.0
+ },
+ {
+ "x": 394.2939806018954,
+ "y": -118.09190661505359,
+ "z": 0.0
+ },
+ {
+ "x": 394.2937691005594,
+ "y": -117.0896662374161,
+ "z": 0.0
+ },
+ {
+ "x": 394.2935575992235,
+ "y": -116.0874258597786,
+ "z": 0.0
+ },
+ {
+ "x": 394.2933460978876,
+ "y": -115.08518548214111,
+ "z": 0.0
+ },
+ {
+ "x": 394.29313459655174,
+ "y": -114.0829451045036,
+ "z": 0.0
+ },
+ {
+ "x": 394.2929230952158,
+ "y": -113.0807047268661,
+ "z": 0.0
+ },
+ {
+ "x": 394.29271159387986,
+ "y": -112.0784643492286,
+ "z": 0.0
+ },
+ {
+ "x": 394.29250009254395,
+ "y": -111.07622397159109,
+ "z": 0.0
+ },
+ {
+ "x": 394.29228859120803,
+ "y": -110.07398359395359,
+ "z": 0.0
+ },
+ {
+ "x": 394.2920770898722,
+ "y": -109.07174321631608,
+ "z": 0.0
+ },
+ {
+ "x": 394.2918655885362,
+ "y": -108.06950283867857,
+ "z": 0.0
+ },
+ {
+ "x": 394.2916540872003,
+ "y": -107.06726246104107,
+ "z": 0.0
+ },
+ {
+ "x": 394.2914425858644,
+ "y": -106.06502208340356,
+ "z": 0.0
+ },
+ {
+ "x": 394.29123108452853,
+ "y": -105.06278170576603,
+ "z": 0.0
+ },
+ {
+ "x": 394.2910195831926,
+ "y": -104.06054132812852,
+ "z": 0.0
+ },
+ {
+ "x": 394.2908080818567,
+ "y": -103.05830095049103,
+ "z": 0.0
+ },
+ {
+ "x": 394.29059658052074,
+ "y": -102.05606057285353,
+ "z": 0.0
+ },
+ {
+ "x": 394.2903850791849,
+ "y": -101.05382019521602,
+ "z": 0.0
+ },
+ {
+ "x": 394.290173577849,
+ "y": -100.05157981757851,
+ "z": 0.0
+ },
+ {
+ "x": 394.28996207651306,
+ "y": -99.04933943994101,
+ "z": 0.0
+ },
+ {
+ "x": 394.28975057517715,
+ "y": -98.04709906230347,
+ "z": 0.0
+ },
+ {
+ "x": 394.2895390738412,
+ "y": -97.04485868466597,
+ "z": 0.0
+ },
+ {
+ "x": 394.28932757250533,
+ "y": -96.04261830702846,
+ "z": 0.0
+ },
+ {
+ "x": 394.2891160711694,
+ "y": -95.04037792939096,
+ "z": 0.0
+ },
+ {
+ "x": 394.2889045698335,
+ "y": -94.03813755175345,
+ "z": 0.0
+ },
+ {
+ "x": 394.28869306849754,
+ "y": -93.03589717411595,
+ "z": 0.0
+ },
+ {
+ "x": 394.2884815671617,
+ "y": -92.03365679647844,
+ "z": 0.0
+ },
+ {
+ "x": 394.28827006582577,
+ "y": -91.03141641884093,
+ "z": 0.0
+ },
+ {
+ "x": 394.28805856448986,
+ "y": -90.02917604120343,
+ "z": 0.0
+ },
+ {
+ "x": 394.28784706315395,
+ "y": -89.0269356635659,
+ "z": 0.0
+ },
+ {
+ "x": 394.287635561818,
+ "y": -88.02469528592839,
+ "z": 0.0
+ },
+ {
+ "x": 394.2876606141071,
+ "y": -87.02245494181614,
+ "z": 0.0
+ },
+ {
+ "x": 394.2886020997598,
+ "y": -86.02021504217004,
+ "z": 0.0
+ },
+ {
+ "x": 394.289804767957,
+ "y": -85.01797536380514,
+ "z": 0.0
+ },
+ {
+ "x": 394.2910074361541,
+ "y": -84.01573568544023,
+ "z": 0.0
+ },
+ {
+ "x": 394.2922101043512,
+ "y": -83.01349600707535,
+ "z": 0.0
+ },
+ {
+ "x": 394.2934127725484,
+ "y": -82.01125632871042,
+ "z": 0.0
+ },
+ {
+ "x": 394.2946154407455,
+ "y": -81.00901665034552,
+ "z": 0.0
+ },
+ {
+ "x": 394.2958181089426,
+ "y": -80.00677697198061,
+ "z": 0.0
+ },
+ {
+ "x": 394.2970207771398,
+ "y": -79.00453729361571,
+ "z": 0.0
+ },
+ {
+ "x": 394.2982234453369,
+ "y": -78.00229761525081,
+ "z": 0.0
+ },
+ {
+ "x": 394.299426113534,
+ "y": -77.00005793688592,
+ "z": 0.0
+ },
+ {
+ "x": 394.3006287817312,
+ "y": -75.99781825852102,
+ "z": 0.0
+ },
+ {
+ "x": 394.30183144992833,
+ "y": -74.99557858015612,
+ "z": 0.0
+ },
+ {
+ "x": 394.3030341181255,
+ "y": -73.99333890179122,
+ "z": 0.0
+ },
+ {
+ "x": 394.3042367863226,
+ "y": -72.99109922342629,
+ "z": 0.0
+ },
+ {
+ "x": 394.3054394545197,
+ "y": -71.9888595450614,
+ "z": 0.0
+ },
+ {
+ "x": 394.3066421227169,
+ "y": -70.98661986669649,
+ "z": 0.0
+ },
+ {
+ "x": 394.307844790914,
+ "y": -69.9843801883316,
+ "z": 0.0
+ },
+ {
+ "x": 394.3090474591111,
+ "y": -68.9821405099667,
+ "z": 0.0
+ },
+ {
+ "x": 394.3102501273083,
+ "y": -67.9799008316018,
+ "z": 0.0
+ },
+ {
+ "x": 394.3114527955054,
+ "y": -66.97766115323691,
+ "z": 0.0
+ },
+ {
+ "x": 394.3126554637025,
+ "y": -65.97542147487198,
+ "z": 0.0
+ },
+ {
+ "x": 394.3138581318997,
+ "y": -64.97318179650708,
+ "z": 0.0
+ },
+ {
+ "x": 394.31506080009683,
+ "y": -63.970942118142176,
+ "z": 0.0
+ },
+ {
+ "x": 394.3162634682939,
+ "y": -62.96870243977728,
+ "z": 0.0
+ },
+ {
+ "x": 394.3174661364911,
+ "y": -61.96646276141241,
+ "z": 0.0
+ },
+ {
+ "x": 394.31866880468823,
+ "y": -60.964223083047536,
+ "z": 0.0
+ },
+ {
+ "x": 394.3198714728853,
+ "y": -59.96198340468262,
+ "z": 0.0
+ },
+ {
+ "x": 394.3210741410825,
+ "y": -58.95974372631774,
+ "z": 0.0
+ },
+ {
+ "x": 394.32227680927963,
+ "y": -57.95750404795282,
+ "z": 0.0
+ },
+ {
+ "x": 394.3234794774767,
+ "y": -56.955264369587944,
+ "z": 0.0
+ },
+ {
+ "x": 394.32468214567393,
+ "y": -55.95302469122307,
+ "z": 0.0
+ },
+ {
+ "x": 394.325884813871,
+ "y": -54.950785012858155,
+ "z": 0.0
+ },
+ {
+ "x": 394.3270874820681,
+ "y": -53.948545334493275,
+ "z": 0.0
+ },
+ {
+ "x": 394.32829015026533,
+ "y": -52.946305656128295,
+ "z": 0.0
+ },
+ {
+ "x": 394.3294928184624,
+ "y": -51.944065977763415,
+ "z": 0.0
+ },
+ {
+ "x": 394.3306954866596,
+ "y": -50.9418262993985,
+ "z": 0.0
+ },
+ {
+ "x": 394.33189815485673,
+ "y": -49.93958662103362,
+ "z": 0.0
+ },
+ {
+ "x": 394.3331008230538,
+ "y": -48.937346942668746,
+ "z": 0.0
+ },
+ {
+ "x": 394.334303491251,
+ "y": -47.93510726430383,
+ "z": 0.0
+ },
+ {
+ "x": 394.33550615944813,
+ "y": -46.93286758593895,
+ "z": 0.0
+ },
+ {
+ "x": 394.3367088276453,
+ "y": -45.93062790757404,
+ "z": 0.0
+ },
+ {
+ "x": 394.3379114958424,
+ "y": -44.92838822920915,
+ "z": 0.0
+ },
+ {
+ "x": 394.33911416403953,
+ "y": -43.92614855084424,
+ "z": 0.0
+ },
+ {
+ "x": 394.3403168322367,
+ "y": -42.92390887247936,
+ "z": 0.0
+ },
+ {
+ "x": 394.3415195004338,
+ "y": -41.921669194114486,
+ "z": 0.0
+ },
+ {
+ "x": 394.3427221686309,
+ "y": -40.91942951574961,
+ "z": 0.0
+ },
+ {
+ "x": 394.3439248368281,
+ "y": -39.91718983738474,
+ "z": 0.0
+ },
+ {
+ "x": 394.3451275050252,
+ "y": -38.91495015901987,
+ "z": 0.0
+ },
+ {
+ "x": 394.3463301732223,
+ "y": -37.91271048065494,
+ "z": 0.0
+ },
+ {
+ "x": 394.3475328414195,
+ "y": -36.910470802290035,
+ "z": 0.0
+ },
+ {
+ "x": 394.3487355096166,
+ "y": -35.90823112392514,
+ "z": 0.0
+ },
+ {
+ "x": 394.3499381778137,
+ "y": -34.90599144556024,
+ "z": 0.0
+ },
+ {
+ "x": 394.3511408460109,
+ "y": -33.903751767195345,
+ "z": 0.0
+ },
+ {
+ "x": 394.35234351420803,
+ "y": -32.90151208883047,
+ "z": 0.0
+ },
+ {
+ "x": 394.3535461824052,
+ "y": -31.899272410465603,
+ "z": 0.0
+ },
+ {
+ "x": 394.3547488506023,
+ "y": -30.89703273210073,
+ "z": 0.0
+ },
+ {
+ "x": 394.35595151879943,
+ "y": -29.894793053735857,
+ "z": 0.0
+ },
+ {
+ "x": 394.3571541869966,
+ "y": -28.892553375370987,
+ "z": 0.0
+ },
+ {
+ "x": 394.3583568551937,
+ "y": -27.890313697006096,
+ "z": 0.0
+ },
+ {
+ "x": 394.3595595233908,
+ "y": -26.88807401864119,
+ "z": 0.0
+ },
+ {
+ "x": 394.360762191588,
+ "y": -25.885834340276322,
+ "z": 0.0
+ },
+ {
+ "x": 394.3619648597851,
+ "y": -24.88359466191145,
+ "z": 0.0
+ },
+ {
+ "x": 394.3631675279822,
+ "y": -23.88135498354656,
+ "z": 0.0
+ },
+ {
+ "x": 394.3643701961794,
+ "y": -22.879115305181653,
+ "z": 0.0
+ },
+ {
+ "x": 394.3655728643765,
+ "y": -21.876875626816755,
+ "z": 0.0
+ },
+ {
+ "x": 394.3667755325736,
+ "y": -20.87463594845178,
+ "z": 0.0
+ },
+ {
+ "x": 394.3679782007708,
+ "y": -19.87239627008686,
+ "z": 0.0
+ },
+ {
+ "x": 394.36918086896793,
+ "y": -18.870156591721948,
+ "z": 0.0
+ },
+ {
+ "x": 394.370383537165,
+ "y": -17.867916913357067,
+ "z": 0.0
+ },
+ {
+ "x": 394.3715862053622,
+ "y": -16.865677234992184,
+ "z": 0.0
+ },
+ {
+ "x": 394.37278887355933,
+ "y": -15.863437556627261,
+ "z": 0.0
+ },
+ {
+ "x": 394.3739915417564,
+ "y": -14.861197878262345,
+ "z": 0.0
+ },
+ {
+ "x": 394.37519420995363,
+ "y": -13.858958199897463,
+ "z": 0.0
+ },
+ {
+ "x": 394.37639687815073,
+ "y": -12.856718521532542,
+ "z": 0.0
+ },
+ {
+ "x": 394.3775995463478,
+ "y": -11.854478843167623,
+ "z": 0.0
+ },
+ {
+ "x": 394.37880221454503,
+ "y": -10.85223916480273,
+ "z": 0.0
+ },
+ {
+ "x": 394.3800048827421,
+ "y": -9.84999948643781,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 43,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 392.38000632269404,
+ "y": -9.847599526912829,
+ "z": 0.0
+ },
+ {
+ "x": 392.378803654497,
+ "y": -10.84983920527775,
+ "z": 0.0
+ },
+ {
+ "x": 392.37760098629974,
+ "y": -11.852078883642415,
+ "z": 0.0
+ },
+ {
+ "x": 392.3763983181027,
+ "y": -12.854318562007562,
+ "z": 0.0
+ },
+ {
+ "x": 392.37519564990555,
+ "y": -13.856558240372483,
+ "z": 0.0
+ },
+ {
+ "x": 392.3739929817084,
+ "y": -14.858797918737137,
+ "z": 0.0
+ },
+ {
+ "x": 392.37279031351125,
+ "y": -15.86103759710228,
+ "z": 0.0
+ },
+ {
+ "x": 392.3715876453141,
+ "y": -16.86327727546709,
+ "z": 0.0
+ },
+ {
+ "x": 392.37038497711694,
+ "y": -17.86551695383197,
+ "z": 0.0
+ },
+ {
+ "x": 392.3691823089199,
+ "y": -18.867756632196965,
+ "z": 0.0
+ },
+ {
+ "x": 392.36797964072275,
+ "y": -19.869996310561767,
+ "z": 0.0
+ },
+ {
+ "x": 392.3667769725256,
+ "y": -20.872235988926683,
+ "z": 0.0
+ },
+ {
+ "x": 392.36557430432845,
+ "y": -21.874475667291662,
+ "z": 0.0
+ },
+ {
+ "x": 392.3643716361313,
+ "y": -22.87671534565667,
+ "z": 0.0
+ },
+ {
+ "x": 392.36316896793414,
+ "y": -23.878955024021465,
+ "z": 0.0
+ },
+ {
+ "x": 392.361966299737,
+ "y": -24.881194702386352,
+ "z": 0.0
+ },
+ {
+ "x": 392.36076363153995,
+ "y": -25.88343438075134,
+ "z": 0.0
+ },
+ {
+ "x": 392.3595609633428,
+ "y": -26.8856740591161,
+ "z": 0.0
+ },
+ {
+ "x": 392.35835829514565,
+ "y": -27.887913737481,
+ "z": 0.0
+ },
+ {
+ "x": 392.3571556269485,
+ "y": -28.890153415846008,
+ "z": 0.0
+ },
+ {
+ "x": 392.35595295875135,
+ "y": -29.89239309421076,
+ "z": 0.0
+ },
+ {
+ "x": 392.3547502905542,
+ "y": -30.894632772575633,
+ "z": 0.0
+ },
+ {
+ "x": 392.35354762235715,
+ "y": -31.89687245094062,
+ "z": 0.0
+ },
+ {
+ "x": 392.35234495416,
+ "y": -32.89911212930538,
+ "z": 0.0
+ },
+ {
+ "x": 392.35114228596285,
+ "y": -33.90135180767025,
+ "z": 0.0
+ },
+ {
+ "x": 392.3499396177657,
+ "y": -34.90359148603514,
+ "z": 0.0
+ },
+ {
+ "x": 392.34873694956855,
+ "y": -35.90583116440004,
+ "z": 0.0
+ },
+ {
+ "x": 392.3475342813714,
+ "y": -36.908070842765056,
+ "z": 0.0
+ },
+ {
+ "x": 392.34633161317424,
+ "y": -37.910310521129844,
+ "z": 0.0
+ },
+ {
+ "x": 392.3451289449771,
+ "y": -38.912550199494774,
+ "z": 0.0
+ },
+ {
+ "x": 392.34392627678005,
+ "y": -39.91478987785976,
+ "z": 0.0
+ },
+ {
+ "x": 392.3427236085829,
+ "y": -40.91702955622452,
+ "z": 0.0
+ },
+ {
+ "x": 392.34152094038575,
+ "y": -41.91926923458939,
+ "z": 0.0
+ },
+ {
+ "x": 392.3403182721886,
+ "y": -42.92150891295438,
+ "z": 0.0
+ },
+ {
+ "x": 392.33911560399144,
+ "y": -43.92374859131914,
+ "z": 0.0
+ },
+ {
+ "x": 392.3379129357943,
+ "y": -44.925988269684055,
+ "z": 0.0
+ },
+ {
+ "x": 392.33671026759725,
+ "y": -45.928227948049056,
+ "z": 0.0
+ },
+ {
+ "x": 392.3355075994001,
+ "y": -46.93046762641386,
+ "z": 0.0
+ },
+ {
+ "x": 392.33430493120295,
+ "y": -47.93270730477873,
+ "z": 0.0
+ },
+ {
+ "x": 392.3331022630058,
+ "y": -48.934946983143654,
+ "z": 0.0
+ },
+ {
+ "x": 392.33189959480865,
+ "y": -49.93718666150863,
+ "z": 0.0
+ },
+ {
+ "x": 392.3306969266115,
+ "y": -50.93942633987341,
+ "z": 0.0
+ },
+ {
+ "x": 392.32949425841434,
+ "y": -51.94166601823832,
+ "z": 0.0
+ },
+ {
+ "x": 392.3282915902173,
+ "y": -52.94390569660331,
+ "z": 0.0
+ },
+ {
+ "x": 392.32708892202004,
+ "y": -53.94614537496807,
+ "z": 0.0
+ },
+ {
+ "x": 392.325886253823,
+ "y": -54.94838505333317,
+ "z": 0.0
+ },
+ {
+ "x": 392.32468358562585,
+ "y": -55.950624731698085,
+ "z": 0.0
+ },
+ {
+ "x": 392.3234809174287,
+ "y": -56.95286441006274,
+ "z": 0.0
+ },
+ {
+ "x": 392.32227824923154,
+ "y": -57.95510408842783,
+ "z": 0.0
+ },
+ {
+ "x": 392.3210755810344,
+ "y": -58.95734376679265,
+ "z": 0.0
+ },
+ {
+ "x": 392.31987291283724,
+ "y": -59.95958344515752,
+ "z": 0.0
+ },
+ {
+ "x": 392.3186702446402,
+ "y": -60.96182312352255,
+ "z": 0.0
+ },
+ {
+ "x": 392.31746757644305,
+ "y": -61.96406280188731,
+ "z": 0.0
+ },
+ {
+ "x": 392.3162649082459,
+ "y": -62.96630248025218,
+ "z": 0.0
+ },
+ {
+ "x": 392.31506224004875,
+ "y": -63.9685421586172,
+ "z": 0.0
+ },
+ {
+ "x": 392.3138595718516,
+ "y": -64.97078183698198,
+ "z": 0.0
+ },
+ {
+ "x": 392.31265690365444,
+ "y": -65.97302151534689,
+ "z": 0.0
+ },
+ {
+ "x": 392.3114542354573,
+ "y": -66.97526119371182,
+ "z": 0.0
+ },
+ {
+ "x": 392.31025156726025,
+ "y": -67.97750087207682,
+ "z": 0.0
+ },
+ {
+ "x": 392.3090488990631,
+ "y": -68.9797405504416,
+ "z": 0.0
+ },
+ {
+ "x": 392.30784623086595,
+ "y": -69.9819802288065,
+ "z": 0.0
+ },
+ {
+ "x": 392.3066435626688,
+ "y": -70.98421990717151,
+ "z": 0.0
+ },
+ {
+ "x": 392.30544089447164,
+ "y": -71.98645958553631,
+ "z": 0.0
+ },
+ {
+ "x": 392.3042382262745,
+ "y": -72.9886992639012,
+ "z": 0.0
+ },
+ {
+ "x": 392.30303555807745,
+ "y": -73.99093894226624,
+ "z": 0.0
+ },
+ {
+ "x": 392.3018328898803,
+ "y": -74.99317862063103,
+ "z": 0.0
+ },
+ {
+ "x": 392.30063022168315,
+ "y": -75.99541829899593,
+ "z": 0.0
+ },
+ {
+ "x": 392.299427553486,
+ "y": -76.99765797736083,
+ "z": 0.0
+ },
+ {
+ "x": 392.29822488528885,
+ "y": -77.99989765572572,
+ "z": 0.0
+ },
+ {
+ "x": 392.2970222170917,
+ "y": -79.00213733409073,
+ "z": 0.0
+ },
+ {
+ "x": 392.29581954889454,
+ "y": -80.00437701245552,
+ "z": 0.0
+ },
+ {
+ "x": 392.2946168806974,
+ "y": -81.00661669082042,
+ "z": 0.0
+ },
+ {
+ "x": 392.29341421250035,
+ "y": -82.00885636918544,
+ "z": 0.0
+ },
+ {
+ "x": 392.2922115443032,
+ "y": -83.01109604755025,
+ "z": 0.0
+ },
+ {
+ "x": 392.29100887610605,
+ "y": -84.01333572591514,
+ "z": 0.0
+ },
+ {
+ "x": 392.2898062079089,
+ "y": -85.01557540428016,
+ "z": 0.0
+ },
+ {
+ "x": 392.28860353971174,
+ "y": -86.01781508264494,
+ "z": 0.0
+ },
+ {
+ "x": 392.28766149654416,
+ "y": -87.02057617958035,
+ "z": 0.0
+ },
+ {
+ "x": 392.2876355624428,
+ "y": -88.02464529335074,
+ "z": 0.0
+ },
+ {
+ "x": 392.28784710768696,
+ "y": -89.02735772066114,
+ "z": 0.0
+ },
+ {
+ "x": 392.28805860902287,
+ "y": -90.02959809829855,
+ "z": 0.0
+ },
+ {
+ "x": 392.2882701103588,
+ "y": -91.03183847593607,
+ "z": 0.0
+ },
+ {
+ "x": 392.2884816116947,
+ "y": -92.03407885357356,
+ "z": 0.0
+ },
+ {
+ "x": 392.2886931130306,
+ "y": -93.03631923121097,
+ "z": 0.0
+ },
+ {
+ "x": 392.2889046143665,
+ "y": -94.03855960884869,
+ "z": 0.0
+ },
+ {
+ "x": 392.2891161157024,
+ "y": -95.04079998648609,
+ "z": 0.0
+ },
+ {
+ "x": 392.28932761703834,
+ "y": -96.04304036412358,
+ "z": 0.0
+ },
+ {
+ "x": 392.28953911837425,
+ "y": -97.04528074176099,
+ "z": 0.0
+ },
+ {
+ "x": 392.28975061971016,
+ "y": -98.04752111939871,
+ "z": 0.0
+ },
+ {
+ "x": 392.2899621210461,
+ "y": -99.04976149703614,
+ "z": 0.0
+ },
+ {
+ "x": 392.290173622382,
+ "y": -100.05200187467364,
+ "z": 0.0
+ },
+ {
+ "x": 392.2903851237179,
+ "y": -101.05424225231116,
+ "z": 0.0
+ },
+ {
+ "x": 392.2905966250538,
+ "y": -102.05648262994853,
+ "z": 0.0
+ },
+ {
+ "x": 392.2908081263897,
+ "y": -103.05872300758628,
+ "z": 0.0
+ },
+ {
+ "x": 392.29101962772563,
+ "y": -104.06096338522366,
+ "z": 0.0
+ },
+ {
+ "x": 392.29123112906154,
+ "y": -105.06320376286115,
+ "z": 0.0
+ },
+ {
+ "x": 392.29144263039746,
+ "y": -106.06544414049858,
+ "z": 0.0
+ },
+ {
+ "x": 392.29165413173337,
+ "y": -107.06768451813619,
+ "z": 0.0
+ },
+ {
+ "x": 392.2918656330693,
+ "y": -108.06992489577371,
+ "z": 0.0
+ },
+ {
+ "x": 392.2920771344052,
+ "y": -109.07216527341131,
+ "z": 0.0
+ },
+ {
+ "x": 392.2922886357411,
+ "y": -110.07440565104861,
+ "z": 0.0
+ },
+ {
+ "x": 392.292500137077,
+ "y": -111.07664602868621,
+ "z": 0.0
+ },
+ {
+ "x": 392.2927116384129,
+ "y": -112.07888640632373,
+ "z": 0.0
+ },
+ {
+ "x": 392.29292313974884,
+ "y": -113.08112678396134,
+ "z": 0.0
+ },
+ {
+ "x": 392.29313464108475,
+ "y": -114.08336716159872,
+ "z": 0.0
+ },
+ {
+ "x": 392.29334614242066,
+ "y": -115.08560753923612,
+ "z": 0.0
+ },
+ {
+ "x": 392.29355764375657,
+ "y": -116.08784791687373,
+ "z": 0.0
+ },
+ {
+ "x": 392.2937691450925,
+ "y": -117.09008829451122,
+ "z": 0.0
+ },
+ {
+ "x": 392.2939806464284,
+ "y": -118.09232867214882,
+ "z": 0.0
+ },
+ {
+ "x": 392.2941921477643,
+ "y": -119.09456904978609,
+ "z": 0.0
+ },
+ {
+ "x": 392.2944036491002,
+ "y": -120.09680942742372,
+ "z": 0.0
+ },
+ {
+ "x": 392.29461515043613,
+ "y": -121.09904980506121,
+ "z": 0.0
+ },
+ {
+ "x": 392.29482665177204,
+ "y": -122.10129018269873,
+ "z": 0.0
+ },
+ {
+ "x": 392.29503815310795,
+ "y": -123.10353056033637,
+ "z": 0.0
+ },
+ {
+ "x": 392.29524965444386,
+ "y": -124.10577093797363,
+ "z": 0.0
+ },
+ {
+ "x": 392.2954611557798,
+ "y": -125.10801131561124,
+ "z": 0.0
+ },
+ {
+ "x": 392.2956726571157,
+ "y": -126.11025169324873,
+ "z": 0.0
+ },
+ {
+ "x": 392.2958841584516,
+ "y": -127.11249207088633,
+ "z": 0.0
+ },
+ {
+ "x": 392.2960956597875,
+ "y": -128.11473244852363,
+ "z": 0.0
+ },
+ {
+ "x": 392.2963071611234,
+ "y": -129.1169728261612,
+ "z": 0.0
+ },
+ {
+ "x": 392.29651866245933,
+ "y": -130.11921320379872,
+ "z": 0.0
+ },
+ {
+ "x": 392.29673016379525,
+ "y": -131.12145358143624,
+ "z": 0.0
+ },
+ {
+ "x": 392.29694166513116,
+ "y": -132.12369395907376,
+ "z": 0.0
+ },
+ {
+ "x": 392.29715316646707,
+ "y": -133.12593433671128,
+ "z": 0.0
+ },
+ {
+ "x": 392.297364667803,
+ "y": -134.1281747143488,
+ "z": 0.0
+ },
+ {
+ "x": 392.2975761691389,
+ "y": -135.13041509198626,
+ "z": 0.0
+ },
+ {
+ "x": 392.2977876704748,
+ "y": -136.1326554696239,
+ "z": 0.0
+ },
+ {
+ "x": 392.2979991718107,
+ "y": -137.1348958472612,
+ "z": 0.0
+ },
+ {
+ "x": 392.2982106731466,
+ "y": -138.13713622489882,
+ "z": 0.0
+ },
+ {
+ "x": 392.29842217448254,
+ "y": -139.13937660253634,
+ "z": 0.0
+ },
+ {
+ "x": 392.29863367581845,
+ "y": -140.14161698017386,
+ "z": 0.0
+ },
+ {
+ "x": 392.29884517715436,
+ "y": -141.14385735781133,
+ "z": 0.0
+ },
+ {
+ "x": 392.2990566784903,
+ "y": -142.14609773544885,
+ "z": 0.0
+ },
+ {
+ "x": 392.2992681798262,
+ "y": -143.14833811308637,
+ "z": 0.0
+ },
+ {
+ "x": 392.2994796811621,
+ "y": -144.1505784907239,
+ "z": 0.0
+ },
+ {
+ "x": 392.299691182498,
+ "y": -145.15281886836135,
+ "z": 0.0
+ },
+ {
+ "x": 392.2999026838339,
+ "y": -146.15505924599887,
+ "z": 0.0
+ },
+ {
+ "x": 392.30011418516983,
+ "y": -147.1572996236364,
+ "z": 0.0
+ },
+ {
+ "x": 392.30032568650574,
+ "y": -148.1595400012739,
+ "z": 0.0
+ },
+ {
+ "x": 392.30053718784166,
+ "y": -149.16178037891143,
+ "z": 0.0
+ },
+ {
+ "x": 392.30074868917757,
+ "y": -150.1640207565489,
+ "z": 0.0
+ },
+ {
+ "x": 392.3009601905135,
+ "y": -151.1662611341864,
+ "z": 0.0
+ },
+ {
+ "x": 392.3011716918494,
+ "y": -152.16850151182393,
+ "z": 0.0
+ },
+ {
+ "x": 392.3013831931853,
+ "y": -153.17074188946145,
+ "z": 0.0
+ },
+ {
+ "x": 392.3015946945211,
+ "y": -154.17298226709886,
+ "z": 0.0
+ },
+ {
+ "x": 392.3018061958571,
+ "y": -155.1752226447366,
+ "z": 0.0
+ },
+ {
+ "x": 392.30201769719304,
+ "y": -156.17746302237396,
+ "z": 0.0
+ },
+ {
+ "x": 392.30222919852895,
+ "y": -157.17970340001148,
+ "z": 0.0
+ },
+ {
+ "x": 392.30244069986486,
+ "y": -158.181943777649,
+ "z": 0.0
+ },
+ {
+ "x": 392.30265220120066,
+ "y": -159.1841841552864,
+ "z": 0.0
+ },
+ {
+ "x": 392.3028637025367,
+ "y": -160.1864245329241,
+ "z": 0.0
+ },
+ {
+ "x": 392.3030752038726,
+ "y": -161.1886649105615,
+ "z": 0.0
+ },
+ {
+ "x": 392.3032867052085,
+ "y": -162.19090528819902,
+ "z": 0.0
+ },
+ {
+ "x": 392.3034982065443,
+ "y": -163.19314566583643,
+ "z": 0.0
+ },
+ {
+ "x": 392.30370970788033,
+ "y": -164.19538604347417,
+ "z": 0.0
+ },
+ {
+ "x": 392.30392120921624,
+ "y": -165.19762642111158,
+ "z": 0.0
+ },
+ {
+ "x": 392.30413271055215,
+ "y": -166.19986679874904,
+ "z": 0.0
+ },
+ {
+ "x": 392.30434421188806,
+ "y": -167.20210717638656,
+ "z": 0.0
+ },
+ {
+ "x": 392.30455571322386,
+ "y": -168.20434755402397,
+ "z": 0.0
+ },
+ {
+ "x": 392.3047672145599,
+ "y": -169.20658793166172,
+ "z": 0.0
+ },
+ {
+ "x": 392.3049787158958,
+ "y": -170.20882830929912,
+ "z": 0.0
+ },
+ {
+ "x": 392.3051902172317,
+ "y": -171.21106868693664,
+ "z": 0.0
+ },
+ {
+ "x": 392.3054017185675,
+ "y": -172.213309064574,
+ "z": 0.0
+ },
+ {
+ "x": 392.30561321990353,
+ "y": -173.21554944221174,
+ "z": 0.0
+ },
+ {
+ "x": 392.30582472123945,
+ "y": -174.21778981984914,
+ "z": 0.0
+ },
+ {
+ "x": 392.30603622257536,
+ "y": -175.22003019748666,
+ "z": 0.0
+ },
+ {
+ "x": 392.30624772391127,
+ "y": -176.22227057512413,
+ "z": 0.0
+ },
+ {
+ "x": 392.30645922524707,
+ "y": -177.22451095276153,
+ "z": 0.0
+ },
+ {
+ "x": 392.3066707265831,
+ "y": -178.22675133039928,
+ "z": 0.0
+ },
+ {
+ "x": 392.306882227919,
+ "y": -179.2289917080367,
+ "z": 0.0
+ },
+ {
+ "x": 392.3070937292549,
+ "y": -180.2312320856742,
+ "z": 0.0
+ },
+ {
+ "x": 392.3073052305907,
+ "y": -181.23347246331156,
+ "z": 0.0
+ },
+ {
+ "x": 392.3075167319266,
+ "y": -182.2357128409492,
+ "z": 0.0
+ },
+ {
+ "x": 392.30772823326265,
+ "y": -183.23795321858682,
+ "z": 0.0
+ },
+ {
+ "x": 392.30793973459856,
+ "y": -184.24019359622423,
+ "z": 0.0
+ },
+ {
+ "x": 392.30815123593436,
+ "y": -185.24243397386158,
+ "z": 0.0
+ },
+ {
+ "x": 392.3083627372703,
+ "y": -186.24467435149927,
+ "z": 0.0
+ },
+ {
+ "x": 392.3085742386063,
+ "y": -187.24691472913685,
+ "z": 0.0
+ },
+ {
+ "x": 392.3087857399422,
+ "y": -188.24915510677425,
+ "z": 0.0
+ },
+ {
+ "x": 392.3089972412781,
+ "y": -189.25139548441177,
+ "z": 0.0
+ },
+ {
+ "x": 392.3092087426139,
+ "y": -190.25363586204918,
+ "z": 0.0
+ },
+ {
+ "x": 392.30942024394983,
+ "y": -191.25587623968676,
+ "z": 0.0
+ },
+ {
+ "x": 392.30963174528574,
+ "y": -192.25811661732428,
+ "z": 0.0
+ },
+ {
+ "x": 392.30984324662177,
+ "y": -193.26035699496185,
+ "z": 0.0
+ },
+ {
+ "x": 392.31005474795757,
+ "y": -194.26259737259915,
+ "z": 0.0
+ },
+ {
+ "x": 392.3102662492935,
+ "y": -195.26483775023672,
+ "z": 0.0
+ },
+ {
+ "x": 392.3104777506294,
+ "y": -196.26707812787424,
+ "z": 0.0
+ },
+ {
+ "x": 392.3106892519653,
+ "y": -197.26931850551176,
+ "z": 0.0
+ },
+ {
+ "x": 392.3109007533013,
+ "y": -198.27155888314934,
+ "z": 0.0
+ },
+ {
+ "x": 392.3111122546371,
+ "y": -199.27379926078663,
+ "z": 0.0
+ },
+ {
+ "x": 392.31132375597304,
+ "y": -200.2760396384242,
+ "z": 0.0
+ },
+ {
+ "x": 392.31153525730895,
+ "y": -201.27828001606173,
+ "z": 0.0
+ },
+ {
+ "x": 392.311746758645,
+ "y": -202.2805203936993,
+ "z": 0.0
+ },
+ {
+ "x": 392.31195825998077,
+ "y": -203.2827607713366,
+ "z": 0.0
+ },
+ {
+ "x": 392.3121697613167,
+ "y": -204.28500114897423,
+ "z": 0.0
+ },
+ {
+ "x": 392.3123812626526,
+ "y": -205.2872415266117,
+ "z": 0.0
+ },
+ {
+ "x": 392.3125927639885,
+ "y": -206.28948190424921,
+ "z": 0.0
+ },
+ {
+ "x": 392.3128042653244,
+ "y": -207.29172228188668,
+ "z": 0.0
+ },
+ {
+ "x": 392.3130157666603,
+ "y": -208.2939626595242,
+ "z": 0.0
+ },
+ {
+ "x": 392.31322726799624,
+ "y": -209.29620303716166,
+ "z": 0.0
+ },
+ {
+ "x": 392.31343876933215,
+ "y": -210.29844341479918,
+ "z": 0.0
+ },
+ {
+ "x": 392.3136502706682,
+ "y": -211.30068379243676,
+ "z": 0.0
+ },
+ {
+ "x": 392.313861772004,
+ "y": -212.30292417007405,
+ "z": 0.0
+ },
+ {
+ "x": 392.3140732733399,
+ "y": -213.30516454771168,
+ "z": 0.0
+ },
+ {
+ "x": 392.3142847746758,
+ "y": -214.30740492534915,
+ "z": 0.0
+ },
+ {
+ "x": 392.3144962760117,
+ "y": -215.30964530298667,
+ "z": 0.0
+ },
+ {
+ "x": 392.3147077773476,
+ "y": -216.31188568062413,
+ "z": 0.0
+ },
+ {
+ "x": 392.31491927868353,
+ "y": -217.31412605826165,
+ "z": 0.0
+ },
+ {
+ "x": 392.31513078001944,
+ "y": -218.3163664358991,
+ "z": 0.0
+ },
+ {
+ "x": 392.31534228135536,
+ "y": -219.31860681353663,
+ "z": 0.0
+ },
+ {
+ "x": 392.31555378269127,
+ "y": -220.32084719117415,
+ "z": 0.0
+ },
+ {
+ "x": 392.3157652840272,
+ "y": -221.32308756881162,
+ "z": 0.0
+ },
+ {
+ "x": 392.3159767853631,
+ "y": -222.32532794644914,
+ "z": 0.0
+ },
+ {
+ "x": 392.316188286699,
+ "y": -223.3275683240866,
+ "z": 0.0
+ },
+ {
+ "x": 392.3163997880349,
+ "y": -224.32980870172412,
+ "z": 0.0
+ },
+ {
+ "x": 392.3166112893708,
+ "y": -225.33204907936158,
+ "z": 0.0
+ },
+ {
+ "x": 392.31682279070674,
+ "y": -226.3342894569991,
+ "z": 0.0
+ },
+ {
+ "x": 392.31703429204265,
+ "y": -227.33652983463656,
+ "z": 0.0
+ },
+ {
+ "x": 392.31724579337856,
+ "y": -228.33877021227408,
+ "z": 0.0
+ },
+ {
+ "x": 392.3174572947145,
+ "y": -229.3410105899116,
+ "z": 0.0
+ },
+ {
+ "x": 392.3176687960504,
+ "y": -230.34325096754907,
+ "z": 0.0
+ },
+ {
+ "x": 392.3178802973863,
+ "y": -231.3454913451866,
+ "z": 0.0
+ },
+ {
+ "x": 392.3180917987222,
+ "y": -232.34773172282405,
+ "z": 0.0
+ },
+ {
+ "x": 392.3183033000581,
+ "y": -233.34997210046157,
+ "z": 0.0
+ },
+ {
+ "x": 392.31851480139403,
+ "y": -234.35221247809903,
+ "z": 0.0
+ },
+ {
+ "x": 392.31872630272994,
+ "y": -235.35445285573655,
+ "z": 0.0
+ },
+ {
+ "x": 392.31893780406585,
+ "y": -236.35669323337402,
+ "z": 0.0
+ },
+ {
+ "x": 392.31914930540177,
+ "y": -237.35893361101154,
+ "z": 0.0
+ },
+ {
+ "x": 392.3193608067377,
+ "y": -238.361173988649,
+ "z": 0.0
+ },
+ {
+ "x": 392.3195723080736,
+ "y": -239.36341436628652,
+ "z": 0.0
+ },
+ {
+ "x": 392.3197838094095,
+ "y": -240.36565474392398,
+ "z": 0.0
+ },
+ {
+ "x": 392.320010857335,
+ "y": -241.36792612738765,
+ "z": 0.0
+ },
+ {
+ "x": 392.32040050640666,
+ "y": -242.37049074145193,
+ "z": 0.0
+ },
+ {
+ "x": 392.3207900557248,
+ "y": -243.372731065701,
+ "z": 0.0
+ },
+ {
+ "x": 392.3211796050429,
+ "y": -244.3749713899502,
+ "z": 0.0
+ },
+ {
+ "x": 392.3215691543611,
+ "y": -245.37721171419946,
+ "z": 0.0
+ },
+ {
+ "x": 392.3219587036793,
+ "y": -246.37945203844865,
+ "z": 0.0
+ },
+ {
+ "x": 392.3223482529974,
+ "y": -247.3816923626977,
+ "z": 0.0
+ },
+ {
+ "x": 392.3227378023156,
+ "y": -248.383932686947,
+ "z": 0.0
+ },
+ {
+ "x": 392.32312735163373,
+ "y": -249.38617301119606,
+ "z": 0.0
+ },
+ {
+ "x": 392.32351690095186,
+ "y": -250.38841333544522,
+ "z": 0.0
+ },
+ {
+ "x": 392.32390645027004,
+ "y": -251.39065365969452,
+ "z": 0.0
+ },
+ {
+ "x": 392.32429599958823,
+ "y": -252.3928939839437,
+ "z": 0.0
+ },
+ {
+ "x": 392.32468554890636,
+ "y": -253.39513430819275,
+ "z": 0.0
+ },
+ {
+ "x": 392.32507509822454,
+ "y": -254.39737463244205,
+ "z": 0.0
+ },
+ {
+ "x": 392.3254646475427,
+ "y": -255.3996149566911,
+ "z": 0.0
+ },
+ {
+ "x": 392.3258541968608,
+ "y": -256.40185528094025,
+ "z": 0.0
+ },
+ {
+ "x": 392.326243746179,
+ "y": -257.4040956051896,
+ "z": 0.0
+ },
+ {
+ "x": 392.3266332954972,
+ "y": -258.4063359294388,
+ "z": 0.0
+ },
+ {
+ "x": 392.3270228448153,
+ "y": -259.4085762536878,
+ "z": 0.0
+ },
+ {
+ "x": 392.32741239413343,
+ "y": -260.410816577937,
+ "z": 0.0
+ },
+ {
+ "x": 392.3278019434516,
+ "y": -261.4130569021863,
+ "z": 0.0
+ },
+ {
+ "x": 392.3281914927698,
+ "y": -262.4152972264354,
+ "z": 0.0
+ },
+ {
+ "x": 392.32858104208793,
+ "y": -263.41753755068453,
+ "z": 0.0
+ },
+ {
+ "x": 392.3289705914061,
+ "y": -264.41977787493386,
+ "z": 0.0
+ },
+ {
+ "x": 392.3293601407243,
+ "y": -265.42201819918296,
+ "z": 0.0
+ },
+ {
+ "x": 392.32974969004243,
+ "y": -266.42425852343206,
+ "z": 0.0
+ },
+ {
+ "x": 392.33013923936056,
+ "y": -267.4264988476813,
+ "z": 0.0
+ },
+ {
+ "x": 392.33052878867875,
+ "y": -268.4287391719305,
+ "z": 0.0
+ },
+ {
+ "x": 392.3309183379969,
+ "y": -269.4309794961796,
+ "z": 0.0
+ },
+ {
+ "x": 392.33130788731506,
+ "y": -270.4332198204289,
+ "z": 0.0
+ },
+ {
+ "x": 392.3316974366332,
+ "y": -271.4354601446779,
+ "z": 0.0
+ },
+ {
+ "x": 392.3320869859513,
+ "y": -272.4377004689271,
+ "z": 0.0
+ },
+ {
+ "x": 392.3324765352695,
+ "y": -273.43994079317645,
+ "z": 0.0
+ },
+ {
+ "x": 392.3328660845877,
+ "y": -274.44218111742555,
+ "z": 0.0
+ },
+ {
+ "x": 392.3332556339058,
+ "y": -275.44442144167465,
+ "z": 0.0
+ },
+ {
+ "x": 392.333645183224,
+ "y": -276.446661765924,
+ "z": 0.0
+ },
+ {
+ "x": 392.33403473254214,
+ "y": -277.44890209017296,
+ "z": 0.0
+ },
+ {
+ "x": 392.3344242818603,
+ "y": -278.4511424144223,
+ "z": 0.0
+ },
+ {
+ "x": 392.33481383117845,
+ "y": -279.4533827386713,
+ "z": 0.0
+ },
+ {
+ "x": 392.33520338049664,
+ "y": -280.4556230629206,
+ "z": 0.0
+ },
+ {
+ "x": 392.3355929298148,
+ "y": -281.4578633871698,
+ "z": 0.0
+ },
+ {
+ "x": 392.33598247913295,
+ "y": -282.4601037114189,
+ "z": 0.0
+ },
+ {
+ "x": 392.3363720284511,
+ "y": -283.462344035668,
+ "z": 0.0
+ },
+ {
+ "x": 392.33676157776927,
+ "y": -284.46458435991735,
+ "z": 0.0
+ },
+ {
+ "x": 392.3371511270874,
+ "y": -285.46682468416645,
+ "z": 0.0
+ },
+ {
+ "x": 392.3375406764056,
+ "y": -286.46906500841567,
+ "z": 0.0
+ },
+ {
+ "x": 392.33793022572377,
+ "y": -287.4713053326649,
+ "z": 0.0
+ },
+ {
+ "x": 392.3383197750419,
+ "y": -288.473545656914,
+ "z": 0.0
+ },
+ {
+ "x": 392.33870932436,
+ "y": -289.4757859811631,
+ "z": 0.0
+ },
+ {
+ "x": 392.3390988736782,
+ "y": -290.4780263054124,
+ "z": 0.0
+ },
+ {
+ "x": 392.33948842299634,
+ "y": -291.4802666296615,
+ "z": 0.0
+ },
+ {
+ "x": 392.3398779723145,
+ "y": -292.48250695391073,
+ "z": 0.0
+ },
+ {
+ "x": 392.34026752163265,
+ "y": -293.48474727815983,
+ "z": 0.0
+ },
+ {
+ "x": 392.34065707095084,
+ "y": -294.48698760240916,
+ "z": 0.0
+ },
+ {
+ "x": 392.34104662026897,
+ "y": -295.48922792665815,
+ "z": 0.0
+ },
+ {
+ "x": 392.34143616958715,
+ "y": -296.4914682509075,
+ "z": 0.0
+ },
+ {
+ "x": 392.34182571890534,
+ "y": -297.4937085751567,
+ "z": 0.0
+ },
+ {
+ "x": 392.34221526822347,
+ "y": -298.4959488994057,
+ "z": 0.0
+ },
+ {
+ "x": 392.3426048175416,
+ "y": -299.4981892236549,
+ "z": 0.0
+ },
+ {
+ "x": 392.3429943668598,
+ "y": -300.5004295479042,
+ "z": 0.0
+ },
+ {
+ "x": 392.3433839161779,
+ "y": -301.5026698721533,
+ "z": 0.0
+ },
+ {
+ "x": 392.3437734654961,
+ "y": -302.50491019640253,
+ "z": 0.0
+ },
+ {
+ "x": 392.3441630148143,
+ "y": -303.50715052065175,
+ "z": 0.0
+ },
+ {
+ "x": 392.3445525641324,
+ "y": -304.50939084490085,
+ "z": 0.0
+ },
+ {
+ "x": 392.34494211345054,
+ "y": -305.51163116914995,
+ "z": 0.0
+ },
+ {
+ "x": 392.34533166276873,
+ "y": -306.5138714933993,
+ "z": 0.0
+ },
+ {
+ "x": 392.34572121208686,
+ "y": -307.5161118176484,
+ "z": 0.0
+ },
+ {
+ "x": 392.34611076140504,
+ "y": -308.5183521418976,
+ "z": 0.0
+ },
+ {
+ "x": 392.34650031072323,
+ "y": -309.5205924661468,
+ "z": 0.0
+ },
+ {
+ "x": 392.34688986004136,
+ "y": -310.5228327903959,
+ "z": 0.0
+ },
+ {
+ "x": 392.3472794093595,
+ "y": -311.525073114645,
+ "z": 0.0
+ },
+ {
+ "x": 392.3476689586777,
+ "y": -312.52731343889434,
+ "z": 0.0
+ },
+ {
+ "x": 392.34805850799586,
+ "y": -313.52955376314355,
+ "z": 0.0
+ },
+ {
+ "x": 392.348448057314,
+ "y": -314.53179408739265,
+ "z": 0.0
+ },
+ {
+ "x": 392.3488376066322,
+ "y": -315.53403441164187,
+ "z": 0.0
+ },
+ {
+ "x": 392.3492271559503,
+ "y": -316.53627473589097,
+ "z": 0.0
+ },
+ {
+ "x": 392.34961670526843,
+ "y": -317.5385150601402,
+ "z": 0.0
+ },
+ {
+ "x": 392.3500062545866,
+ "y": -318.5407553843894,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 44,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 396.35000595244463,
+ "y": -318.5392006702981,
+ "z": 0.0
+ },
+ {
+ "x": 396.34961640312645,
+ "y": -317.536960346049,
+ "z": 0.0
+ },
+ {
+ "x": 396.3492268538083,
+ "y": -316.5347200217998,
+ "z": 0.0
+ },
+ {
+ "x": 396.3488373044902,
+ "y": -315.53247969755057,
+ "z": 0.0
+ },
+ {
+ "x": 396.348447755172,
+ "y": -314.53023937330147,
+ "z": 0.0
+ },
+ {
+ "x": 396.3480582058539,
+ "y": -313.52799904905214,
+ "z": 0.0
+ },
+ {
+ "x": 396.3476686565357,
+ "y": -312.52575872480304,
+ "z": 0.0
+ },
+ {
+ "x": 396.3472791072175,
+ "y": -311.52351840055394,
+ "z": 0.0
+ },
+ {
+ "x": 396.3468895578994,
+ "y": -310.5212780763047,
+ "z": 0.0
+ },
+ {
+ "x": 396.34650000858124,
+ "y": -309.5190377520555,
+ "z": 0.0
+ },
+ {
+ "x": 396.34611045926306,
+ "y": -308.5167974278063,
+ "z": 0.0
+ },
+ {
+ "x": 396.3457209099449,
+ "y": -307.5145571035572,
+ "z": 0.0
+ },
+ {
+ "x": 396.34533136062674,
+ "y": -306.51231677930787,
+ "z": 0.0
+ },
+ {
+ "x": 396.34494181130856,
+ "y": -305.5100764550589,
+ "z": 0.0
+ },
+ {
+ "x": 396.34455226199043,
+ "y": -304.50783613080966,
+ "z": 0.0
+ },
+ {
+ "x": 396.3441627126723,
+ "y": -303.50559580656034,
+ "z": 0.0
+ },
+ {
+ "x": 396.3437731633541,
+ "y": -302.50335548231124,
+ "z": 0.0
+ },
+ {
+ "x": 396.34338361403593,
+ "y": -301.50111515806213,
+ "z": 0.0
+ },
+ {
+ "x": 396.3429940647178,
+ "y": -300.4988748338128,
+ "z": 0.0
+ },
+ {
+ "x": 396.3426045153996,
+ "y": -299.4966345095638,
+ "z": 0.0
+ },
+ {
+ "x": 396.3422149660815,
+ "y": -298.4943941853146,
+ "z": 0.0
+ },
+ {
+ "x": 396.34182541676336,
+ "y": -297.4921538610653,
+ "z": 0.0
+ },
+ {
+ "x": 396.34143586744517,
+ "y": -296.4899135368162,
+ "z": 0.0
+ },
+ {
+ "x": 396.341046318127,
+ "y": -295.4876732125671,
+ "z": 0.0
+ },
+ {
+ "x": 396.34065676880886,
+ "y": -294.48543288831775,
+ "z": 0.0
+ },
+ {
+ "x": 396.34026721949067,
+ "y": -293.48319256406876,
+ "z": 0.0
+ },
+ {
+ "x": 396.33987767017254,
+ "y": -292.48095223981943,
+ "z": 0.0
+ },
+ {
+ "x": 396.33948812085436,
+ "y": -291.47871191557033,
+ "z": 0.0
+ },
+ {
+ "x": 396.3390985715362,
+ "y": -290.476471591321,
+ "z": 0.0
+ },
+ {
+ "x": 396.33870902221804,
+ "y": -289.474231267072,
+ "z": 0.0
+ },
+ {
+ "x": 396.3383194728999,
+ "y": -288.4719909428228,
+ "z": 0.0
+ },
+ {
+ "x": 396.3379299235818,
+ "y": -287.46975061857347,
+ "z": 0.0
+ },
+ {
+ "x": 396.3375403742636,
+ "y": -286.46751029432437,
+ "z": 0.0
+ },
+ {
+ "x": 396.3371508249454,
+ "y": -285.46526997007527,
+ "z": 0.0
+ },
+ {
+ "x": 396.3367612756273,
+ "y": -284.46302964582594,
+ "z": 0.0
+ },
+ {
+ "x": 396.3363717263091,
+ "y": -283.46078932157695,
+ "z": 0.0
+ },
+ {
+ "x": 396.33598217699097,
+ "y": -282.45854899732774,
+ "z": 0.0
+ },
+ {
+ "x": 396.33559262767284,
+ "y": -281.4563086730784,
+ "z": 0.0
+ },
+ {
+ "x": 396.33520307835465,
+ "y": -280.4540683488293,
+ "z": 0.0
+ },
+ {
+ "x": 396.33481352903647,
+ "y": -279.4518280245802,
+ "z": 0.0
+ },
+ {
+ "x": 396.33442397971834,
+ "y": -278.4495877003309,
+ "z": 0.0
+ },
+ {
+ "x": 396.33403443040015,
+ "y": -277.4473473760819,
+ "z": 0.0
+ },
+ {
+ "x": 396.333644881082,
+ "y": -276.44510705183257,
+ "z": 0.0
+ },
+ {
+ "x": 396.33325533176384,
+ "y": -275.44286672758346,
+ "z": 0.0
+ },
+ {
+ "x": 396.3328657824457,
+ "y": -274.44062640333425,
+ "z": 0.0
+ },
+ {
+ "x": 396.3324762331275,
+ "y": -273.43838607908503,
+ "z": 0.0
+ },
+ {
+ "x": 396.33208668380934,
+ "y": -272.43614575483593,
+ "z": 0.0
+ },
+ {
+ "x": 396.3316971344912,
+ "y": -271.43390543058683,
+ "z": 0.0
+ },
+ {
+ "x": 396.3313075851731,
+ "y": -270.4316651063375,
+ "z": 0.0
+ },
+ {
+ "x": 396.3309180358549,
+ "y": -269.4294247820884,
+ "z": 0.0
+ },
+ {
+ "x": 396.33052848653676,
+ "y": -268.4271844578392,
+ "z": 0.0
+ },
+ {
+ "x": 396.3301389372186,
+ "y": -267.4249441335901,
+ "z": 0.0
+ },
+ {
+ "x": 396.32974938790045,
+ "y": -266.4227038093409,
+ "z": 0.0
+ },
+ {
+ "x": 396.3293598385823,
+ "y": -265.42046348509166,
+ "z": 0.0
+ },
+ {
+ "x": 396.32897028926413,
+ "y": -264.41822316084244,
+ "z": 0.0
+ },
+ {
+ "x": 396.32858073994595,
+ "y": -263.41598283659334,
+ "z": 0.0
+ },
+ {
+ "x": 396.3281911906278,
+ "y": -262.41374251234413,
+ "z": 0.0
+ },
+ {
+ "x": 396.32780164130963,
+ "y": -261.4115021880949,
+ "z": 0.0
+ },
+ {
+ "x": 396.32741209199145,
+ "y": -260.4092618638458,
+ "z": 0.0
+ },
+ {
+ "x": 396.3270225426733,
+ "y": -259.4070215395967,
+ "z": 0.0
+ },
+ {
+ "x": 396.3266329933552,
+ "y": -258.4047812153474,
+ "z": 0.0
+ },
+ {
+ "x": 396.326243444037,
+ "y": -257.4025408910983,
+ "z": 0.0
+ },
+ {
+ "x": 396.3258538947188,
+ "y": -256.4003005668492,
+ "z": 0.0
+ },
+ {
+ "x": 396.3254643454007,
+ "y": -255.39806024259997,
+ "z": 0.0
+ },
+ {
+ "x": 396.32507479608256,
+ "y": -254.3958199183507,
+ "z": 0.0
+ },
+ {
+ "x": 396.3246852467644,
+ "y": -253.39357959410162,
+ "z": 0.0
+ },
+ {
+ "x": 396.32429569744625,
+ "y": -252.39133926985235,
+ "z": 0.0
+ },
+ {
+ "x": 396.32390614812806,
+ "y": -251.38909894560317,
+ "z": 0.0
+ },
+ {
+ "x": 396.3235165988099,
+ "y": -250.3868586213541,
+ "z": 0.0
+ },
+ {
+ "x": 396.32312704949175,
+ "y": -249.38461829710494,
+ "z": 0.0
+ },
+ {
+ "x": 396.3227375001736,
+ "y": -248.38237797285564,
+ "z": 0.0
+ },
+ {
+ "x": 396.32234795085543,
+ "y": -247.38013764860656,
+ "z": 0.0
+ },
+ {
+ "x": 396.3219584015373,
+ "y": -246.3778973243573,
+ "z": 0.0
+ },
+ {
+ "x": 396.3215688522191,
+ "y": -245.3756570001081,
+ "z": 0.0
+ },
+ {
+ "x": 396.32117930290093,
+ "y": -244.37341667585906,
+ "z": 0.0
+ },
+ {
+ "x": 396.3207897535828,
+ "y": -243.37117635160988,
+ "z": 0.0
+ },
+ {
+ "x": 396.3204002042647,
+ "y": -242.36893602736058,
+ "z": 0.0
+ },
+ {
+ "x": 396.3200107547,
+ "y": -241.3670199929265,
+ "z": 0.0
+ },
+ {
+ "x": 396.3197837203435,
+ "y": -240.36481062973377,
+ "z": 0.0
+ },
+ {
+ "x": 396.31957221900757,
+ "y": -239.36257025209625,
+ "z": 0.0
+ },
+ {
+ "x": 396.31936071767166,
+ "y": -238.36032987445878,
+ "z": 0.0
+ },
+ {
+ "x": 396.31914921633575,
+ "y": -237.35808949682126,
+ "z": 0.0
+ },
+ {
+ "x": 396.31893771499983,
+ "y": -236.3558491191838,
+ "z": 0.0
+ },
+ {
+ "x": 396.3187262136639,
+ "y": -235.35360874154628,
+ "z": 0.0
+ },
+ {
+ "x": 396.318514712328,
+ "y": -234.35136836390882,
+ "z": 0.0
+ },
+ {
+ "x": 396.3183032109921,
+ "y": -233.3491279862713,
+ "z": 0.0
+ },
+ {
+ "x": 396.3180917096562,
+ "y": -232.34688760863384,
+ "z": 0.0
+ },
+ {
+ "x": 396.3178802083203,
+ "y": -231.34464723099632,
+ "z": 0.0
+ },
+ {
+ "x": 396.31766870698436,
+ "y": -230.34240685335885,
+ "z": 0.0
+ },
+ {
+ "x": 396.31745720564845,
+ "y": -229.34016647572133,
+ "z": 0.0
+ },
+ {
+ "x": 396.31724570431254,
+ "y": -228.33792609808387,
+ "z": 0.0
+ },
+ {
+ "x": 396.31703420297663,
+ "y": -227.33568572044635,
+ "z": 0.0
+ },
+ {
+ "x": 396.3168227016407,
+ "y": -226.33344534280883,
+ "z": 0.0
+ },
+ {
+ "x": 396.3166112003048,
+ "y": -225.33120496517137,
+ "z": 0.0
+ },
+ {
+ "x": 396.3163996989689,
+ "y": -224.32896458753385,
+ "z": 0.0
+ },
+ {
+ "x": 396.316188197633,
+ "y": -223.32672420989638,
+ "z": 0.0
+ },
+ {
+ "x": 396.31597669629707,
+ "y": -222.32448383225886,
+ "z": 0.0
+ },
+ {
+ "x": 396.31576519496116,
+ "y": -221.3222434546214,
+ "z": 0.0
+ },
+ {
+ "x": 396.31555369362525,
+ "y": -220.32000307698388,
+ "z": 0.0
+ },
+ {
+ "x": 396.31534219228934,
+ "y": -219.31776269934636,
+ "z": 0.0
+ },
+ {
+ "x": 396.3151306909534,
+ "y": -218.3155223217089,
+ "z": 0.0
+ },
+ {
+ "x": 396.3149191896175,
+ "y": -217.31328194407138,
+ "z": 0.0
+ },
+ {
+ "x": 396.3147076882816,
+ "y": -216.31104156643391,
+ "z": 0.0
+ },
+ {
+ "x": 396.3144961869457,
+ "y": -215.3088011887964,
+ "z": 0.0
+ },
+ {
+ "x": 396.3142846856098,
+ "y": -214.30656081115893,
+ "z": 0.0
+ },
+ {
+ "x": 396.31407318427387,
+ "y": -213.3043204335214,
+ "z": 0.0
+ },
+ {
+ "x": 396.31386168293795,
+ "y": -212.30208005588406,
+ "z": 0.0
+ },
+ {
+ "x": 396.31365018160204,
+ "y": -211.29983967824631,
+ "z": 0.0
+ },
+ {
+ "x": 396.31343868026613,
+ "y": -210.2975993006089,
+ "z": 0.0
+ },
+ {
+ "x": 396.3132271789302,
+ "y": -209.29535892297145,
+ "z": 0.0
+ },
+ {
+ "x": 396.3130156775943,
+ "y": -208.29311854533393,
+ "z": 0.0
+ },
+ {
+ "x": 396.3128041762584,
+ "y": -207.29087816769646,
+ "z": 0.0
+ },
+ {
+ "x": 396.3125926749225,
+ "y": -206.28863779005894,
+ "z": 0.0
+ },
+ {
+ "x": 396.3123811735866,
+ "y": -205.28639741242148,
+ "z": 0.0
+ },
+ {
+ "x": 396.31216967225066,
+ "y": -204.28415703478396,
+ "z": 0.0
+ },
+ {
+ "x": 396.31195817091475,
+ "y": -203.28191665714655,
+ "z": 0.0
+ },
+ {
+ "x": 396.31174666957884,
+ "y": -202.27967627950886,
+ "z": 0.0
+ },
+ {
+ "x": 396.3115351682429,
+ "y": -201.27743590187146,
+ "z": 0.0
+ },
+ {
+ "x": 396.311323666907,
+ "y": -200.275195524234,
+ "z": 0.0
+ },
+ {
+ "x": 396.3111121655711,
+ "y": -199.2729551465966,
+ "z": 0.0
+ },
+ {
+ "x": 396.3109006642352,
+ "y": -198.2707147689589,
+ "z": 0.0
+ },
+ {
+ "x": 396.3106891628993,
+ "y": -197.2684743913215,
+ "z": 0.0
+ },
+ {
+ "x": 396.31047766156337,
+ "y": -196.26623401368403,
+ "z": 0.0
+ },
+ {
+ "x": 396.31026616022746,
+ "y": -195.2639936360465,
+ "z": 0.0
+ },
+ {
+ "x": 396.31005465889154,
+ "y": -194.2617532584091,
+ "z": 0.0
+ },
+ {
+ "x": 396.30984315755563,
+ "y": -193.2595128807714,
+ "z": 0.0
+ },
+ {
+ "x": 396.3096316562197,
+ "y": -192.257272503134,
+ "z": 0.0
+ },
+ {
+ "x": 396.3094201548838,
+ "y": -191.25503212549654,
+ "z": 0.0
+ },
+ {
+ "x": 396.3092086535479,
+ "y": -190.25279174785913,
+ "z": 0.0
+ },
+ {
+ "x": 396.308997152212,
+ "y": -189.2505513702215,
+ "z": 0.0
+ },
+ {
+ "x": 396.3087856508761,
+ "y": -188.24831099258404,
+ "z": 0.0
+ },
+ {
+ "x": 396.30857414954016,
+ "y": -187.2460706149464,
+ "z": 0.0
+ },
+ {
+ "x": 396.30836264820425,
+ "y": -186.243830237309,
+ "z": 0.0
+ },
+ {
+ "x": 396.30815114686834,
+ "y": -185.2415898596716,
+ "z": 0.0
+ },
+ {
+ "x": 396.30793964553243,
+ "y": -184.23934948203396,
+ "z": 0.0
+ },
+ {
+ "x": 396.3077281441965,
+ "y": -183.23710910439632,
+ "z": 0.0
+ },
+ {
+ "x": 396.3075166428606,
+ "y": -182.23486872675898,
+ "z": 0.0
+ },
+ {
+ "x": 396.3073051415247,
+ "y": -181.23262834912157,
+ "z": 0.0
+ },
+ {
+ "x": 396.3070936401888,
+ "y": -180.23038797148394,
+ "z": 0.0
+ },
+ {
+ "x": 396.30688213885287,
+ "y": -179.22814759384647,
+ "z": 0.0
+ },
+ {
+ "x": 396.30667063751696,
+ "y": -178.22590721620878,
+ "z": 0.0
+ },
+ {
+ "x": 396.30645913618105,
+ "y": -177.22366683857155,
+ "z": 0.0
+ },
+ {
+ "x": 396.30624763484514,
+ "y": -176.2214264609339,
+ "z": 0.0
+ },
+ {
+ "x": 396.3060361335092,
+ "y": -175.2191860832964,
+ "z": 0.0
+ },
+ {
+ "x": 396.3058246321733,
+ "y": -174.21694570565887,
+ "z": 0.0
+ },
+ {
+ "x": 396.3056131308374,
+ "y": -173.2147053280213,
+ "z": 0.0
+ },
+ {
+ "x": 396.3054016295015,
+ "y": -172.212464950384,
+ "z": 0.0
+ },
+ {
+ "x": 396.3051901281656,
+ "y": -171.21022457274637,
+ "z": 0.0
+ },
+ {
+ "x": 396.30497862682967,
+ "y": -170.20798419510885,
+ "z": 0.0
+ },
+ {
+ "x": 396.30476712549375,
+ "y": -169.20574381747122,
+ "z": 0.0
+ },
+ {
+ "x": 396.30455562415784,
+ "y": -168.20350343983392,
+ "z": 0.0
+ },
+ {
+ "x": 396.30434412282193,
+ "y": -167.20126306219635,
+ "z": 0.0
+ },
+ {
+ "x": 396.304132621486,
+ "y": -166.19902268455883,
+ "z": 0.0
+ },
+ {
+ "x": 396.3039211201501,
+ "y": -165.1967823069213,
+ "z": 0.0
+ },
+ {
+ "x": 396.3037096188142,
+ "y": -164.19454192928367,
+ "z": 0.0
+ },
+ {
+ "x": 396.3034981174783,
+ "y": -163.19230155164644,
+ "z": 0.0
+ },
+ {
+ "x": 396.3032866161424,
+ "y": -162.19006117400875,
+ "z": 0.0
+ },
+ {
+ "x": 396.30307511480646,
+ "y": -161.18782079637128,
+ "z": 0.0
+ },
+ {
+ "x": 396.30286361347055,
+ "y": -160.18558041873365,
+ "z": 0.0
+ },
+ {
+ "x": 396.30265211213464,
+ "y": -159.18334004109636,
+ "z": 0.0
+ },
+ {
+ "x": 396.3024406107987,
+ "y": -158.18109966345872,
+ "z": 0.0
+ },
+ {
+ "x": 396.3022291094628,
+ "y": -157.17885928582126,
+ "z": 0.0
+ },
+ {
+ "x": 396.3020176081269,
+ "y": -156.17661890818374,
+ "z": 0.0
+ },
+ {
+ "x": 396.301806106791,
+ "y": -155.1743785305461,
+ "z": 0.0
+ },
+ {
+ "x": 396.3015946054551,
+ "y": -154.17213815290881,
+ "z": 0.0
+ },
+ {
+ "x": 396.30138310411917,
+ "y": -153.16989777527118,
+ "z": 0.0
+ },
+ {
+ "x": 396.30117160278326,
+ "y": -152.16765739763366,
+ "z": 0.0
+ },
+ {
+ "x": 396.30096010144734,
+ "y": -151.1654170199962,
+ "z": 0.0
+ },
+ {
+ "x": 396.30074860011143,
+ "y": -150.16317664235868,
+ "z": 0.0
+ },
+ {
+ "x": 396.3005370987755,
+ "y": -149.16093626472116,
+ "z": 0.0
+ },
+ {
+ "x": 396.3003255974396,
+ "y": -148.1586958870837,
+ "z": 0.0
+ },
+ {
+ "x": 396.3001140961037,
+ "y": -147.15645550944618,
+ "z": 0.0
+ },
+ {
+ "x": 396.2999025947678,
+ "y": -146.15421513180866,
+ "z": 0.0
+ },
+ {
+ "x": 396.2996910934319,
+ "y": -145.15197475417114,
+ "z": 0.0
+ },
+ {
+ "x": 396.29947959209596,
+ "y": -144.14973437653362,
+ "z": 0.0
+ },
+ {
+ "x": 396.29926809076005,
+ "y": -143.1474939988961,
+ "z": 0.0
+ },
+ {
+ "x": 396.29905658942414,
+ "y": -142.14525362125863,
+ "z": 0.0
+ },
+ {
+ "x": 396.2988450880882,
+ "y": -141.1430132436211,
+ "z": 0.0
+ },
+ {
+ "x": 396.2986335867523,
+ "y": -140.1407728659836,
+ "z": 0.0
+ },
+ {
+ "x": 396.2984220854164,
+ "y": -139.13853248834607,
+ "z": 0.0
+ },
+ {
+ "x": 396.2982105840805,
+ "y": -138.1362921107086,
+ "z": 0.0
+ },
+ {
+ "x": 396.2979990827446,
+ "y": -137.13405173307115,
+ "z": 0.0
+ },
+ {
+ "x": 396.2977875814088,
+ "y": -136.13181135543346,
+ "z": 0.0
+ },
+ {
+ "x": 396.29757608007276,
+ "y": -135.12957097779605,
+ "z": 0.0
+ },
+ {
+ "x": 396.29736457873685,
+ "y": -134.12733060015853,
+ "z": 0.0
+ },
+ {
+ "x": 396.29715307740094,
+ "y": -133.125090222521,
+ "z": 0.0
+ },
+ {
+ "x": 396.296941576065,
+ "y": -132.12284984488355,
+ "z": 0.0
+ },
+ {
+ "x": 396.2967300747291,
+ "y": -131.12060946724603,
+ "z": 0.0
+ },
+ {
+ "x": 396.2965185733932,
+ "y": -130.1183690896085,
+ "z": 0.0
+ },
+ {
+ "x": 396.2963070720573,
+ "y": -129.116128711971,
+ "z": 0.0
+ },
+ {
+ "x": 396.2960955707214,
+ "y": -128.11388833433358,
+ "z": 0.0
+ },
+ {
+ "x": 396.2958840693856,
+ "y": -127.11164795669586,
+ "z": 0.0
+ },
+ {
+ "x": 396.29567256804955,
+ "y": -126.10940757905848,
+ "z": 0.0
+ },
+ {
+ "x": 396.29546106671364,
+ "y": -125.10716720142099,
+ "z": 0.0
+ },
+ {
+ "x": 396.29524956537773,
+ "y": -124.10492682378359,
+ "z": 0.0
+ },
+ {
+ "x": 396.29503806404193,
+ "y": -123.10268644614587,
+ "z": 0.0
+ },
+ {
+ "x": 396.2948265627059,
+ "y": -122.10044606850849,
+ "z": 0.0
+ },
+ {
+ "x": 396.29461506137,
+ "y": -121.09820569087097,
+ "z": 0.0
+ },
+ {
+ "x": 396.2944035600341,
+ "y": -120.09596531323345,
+ "z": 0.0
+ },
+ {
+ "x": 396.2941920586982,
+ "y": -119.09372493559607,
+ "z": 0.0
+ },
+ {
+ "x": 396.2939805573624,
+ "y": -118.09148455795835,
+ "z": 0.0
+ },
+ {
+ "x": 396.29376905602635,
+ "y": -117.08924418032097,
+ "z": 0.0
+ },
+ {
+ "x": 396.29355755469044,
+ "y": -116.08700380268348,
+ "z": 0.0
+ },
+ {
+ "x": 396.2933460533545,
+ "y": -115.0847634250461,
+ "z": 0.0
+ },
+ {
+ "x": 396.2931345520187,
+ "y": -114.08252304740847,
+ "z": 0.0
+ },
+ {
+ "x": 396.2929230506828,
+ "y": -113.08028266977087,
+ "z": 0.0
+ },
+ {
+ "x": 396.2927115493468,
+ "y": -112.07804229213346,
+ "z": 0.0
+ },
+ {
+ "x": 396.2925000480109,
+ "y": -111.07580191449597,
+ "z": 0.0
+ },
+ {
+ "x": 396.29228854667497,
+ "y": -110.07356153685856,
+ "z": 0.0
+ },
+ {
+ "x": 396.29207704533917,
+ "y": -109.07132115922084,
+ "z": 0.0
+ },
+ {
+ "x": 396.29186554400314,
+ "y": -108.06908078158344,
+ "z": 0.0
+ },
+ {
+ "x": 396.29165404266723,
+ "y": -107.06684040394595,
+ "z": 0.0
+ },
+ {
+ "x": 396.2914425413313,
+ "y": -106.06460002630854,
+ "z": 0.0
+ },
+ {
+ "x": 396.2912310399955,
+ "y": -105.0623596486709,
+ "z": 0.0
+ },
+ {
+ "x": 396.2910195386596,
+ "y": -104.06011927103339,
+ "z": 0.0
+ },
+ {
+ "x": 396.2908080373237,
+ "y": -103.05787889339578,
+ "z": 0.0
+ },
+ {
+ "x": 396.2905965359877,
+ "y": -102.05563851575852,
+ "z": 0.0
+ },
+ {
+ "x": 396.2903850346519,
+ "y": -101.05339813812088,
+ "z": 0.0
+ },
+ {
+ "x": 396.29017353331596,
+ "y": -100.05115776048339,
+ "z": 0.0
+ },
+ {
+ "x": 396.28996203198005,
+ "y": -99.04891738284587,
+ "z": 0.0
+ },
+ {
+ "x": 396.28975053064414,
+ "y": -98.04667700520824,
+ "z": 0.0
+ },
+ {
+ "x": 396.2895390293081,
+ "y": -97.04443662757095,
+ "z": 0.0
+ },
+ {
+ "x": 396.2893275279723,
+ "y": -96.04219624993334,
+ "z": 0.0
+ },
+ {
+ "x": 396.2891160266364,
+ "y": -95.03995587229582,
+ "z": 0.0
+ },
+ {
+ "x": 396.2889045253005,
+ "y": -94.03771549465822,
+ "z": 0.0
+ },
+ {
+ "x": 396.28869302396447,
+ "y": -93.03547511702092,
+ "z": 0.0
+ },
+ {
+ "x": 396.2884815226287,
+ "y": -92.03323473938332,
+ "z": 0.0
+ },
+ {
+ "x": 396.28827002129276,
+ "y": -91.0309943617458,
+ "z": 0.0
+ },
+ {
+ "x": 396.28805851995685,
+ "y": -90.0287539841083,
+ "z": 0.0
+ },
+ {
+ "x": 396.28784701862094,
+ "y": -89.02651360647064,
+ "z": 0.0
+ },
+ {
+ "x": 396.28763556119316,
+ "y": -88.02474527850603,
+ "z": 0.0
+ },
+ {
+ "x": 396.28765973167003,
+ "y": -87.02433370405193,
+ "z": 0.0
+ },
+ {
+ "x": 396.2886006598079,
+ "y": -86.02261500169513,
+ "z": 0.0
+ },
+ {
+ "x": 396.28980332800506,
+ "y": -85.02037532333011,
+ "z": 0.0
+ },
+ {
+ "x": 396.2910059962021,
+ "y": -84.01813564496533,
+ "z": 0.0
+ },
+ {
+ "x": 396.29220866439925,
+ "y": -83.01589596660044,
+ "z": 0.0
+ },
+ {
+ "x": 396.2934113325964,
+ "y": -82.0136562882354,
+ "z": 0.0
+ },
+ {
+ "x": 396.29461400079356,
+ "y": -81.01141660987061,
+ "z": 0.0
+ },
+ {
+ "x": 396.2958166689907,
+ "y": -80.0091769315057,
+ "z": 0.0
+ },
+ {
+ "x": 396.29701933718786,
+ "y": -79.00693725314069,
+ "z": 0.0
+ },
+ {
+ "x": 396.2982220053849,
+ "y": -78.0046975747759,
+ "z": 0.0
+ },
+ {
+ "x": 396.29942467358205,
+ "y": -77.00245789641102,
+ "z": 0.0
+ },
+ {
+ "x": 396.3006273417792,
+ "y": -76.00021821804611,
+ "z": 0.0
+ },
+ {
+ "x": 396.30183000997636,
+ "y": -74.99797853968121,
+ "z": 0.0
+ },
+ {
+ "x": 396.3030326781735,
+ "y": -73.9957388613162,
+ "z": 0.0
+ },
+ {
+ "x": 396.30423534637066,
+ "y": -72.99349918295138,
+ "z": 0.0
+ },
+ {
+ "x": 396.3054380145678,
+ "y": -71.9912595045865,
+ "z": 0.0
+ },
+ {
+ "x": 396.30664068276496,
+ "y": -70.98901982622147,
+ "z": 0.0
+ },
+ {
+ "x": 396.307843350962,
+ "y": -69.98678014785669,
+ "z": 0.0
+ },
+ {
+ "x": 396.30904601915915,
+ "y": -68.98454046949179,
+ "z": 0.0
+ },
+ {
+ "x": 396.3102486873563,
+ "y": -67.98230079112678,
+ "z": 0.0
+ },
+ {
+ "x": 396.31145135555346,
+ "y": -66.980061112762,
+ "z": 0.0
+ },
+ {
+ "x": 396.3126540237506,
+ "y": -65.97782143439707,
+ "z": 0.0
+ },
+ {
+ "x": 396.31385669194776,
+ "y": -64.97558175603217,
+ "z": 0.0
+ },
+ {
+ "x": 396.3150593601449,
+ "y": -63.973342077667155,
+ "z": 0.0
+ },
+ {
+ "x": 396.31626202834195,
+ "y": -62.97110239930238,
+ "z": 0.0
+ },
+ {
+ "x": 396.3174646965391,
+ "y": -61.96886272093751,
+ "z": 0.0
+ },
+ {
+ "x": 396.31866736473626,
+ "y": -60.96662304257252,
+ "z": 0.0
+ },
+ {
+ "x": 396.3198700329334,
+ "y": -59.96438336420772,
+ "z": 0.0
+ },
+ {
+ "x": 396.32107270113056,
+ "y": -58.96214368584283,
+ "z": 0.0
+ },
+ {
+ "x": 396.3222753693277,
+ "y": -57.9599040074778,
+ "z": 0.0
+ },
+ {
+ "x": 396.32347803752475,
+ "y": -56.95766432911315,
+ "z": 0.0
+ },
+ {
+ "x": 396.324680705722,
+ "y": -55.95542465074806,
+ "z": 0.0
+ },
+ {
+ "x": 396.32588337391905,
+ "y": -54.95318497238314,
+ "z": 0.0
+ },
+ {
+ "x": 396.3270860421162,
+ "y": -53.95094529401848,
+ "z": 0.0
+ },
+ {
+ "x": 396.32828871031336,
+ "y": -52.94870561565328,
+ "z": 0.0
+ },
+ {
+ "x": 396.3294913785105,
+ "y": -51.94646593728851,
+ "z": 0.0
+ },
+ {
+ "x": 396.33069404670766,
+ "y": -50.94422625892359,
+ "z": 0.0
+ },
+ {
+ "x": 396.3318967149048,
+ "y": -49.941986580558606,
+ "z": 0.0
+ },
+ {
+ "x": 396.33309938310185,
+ "y": -48.93974690219384,
+ "z": 0.0
+ },
+ {
+ "x": 396.334302051299,
+ "y": -47.93750722382893,
+ "z": 0.0
+ },
+ {
+ "x": 396.33550471949616,
+ "y": -46.93526754546404,
+ "z": 0.0
+ },
+ {
+ "x": 396.3367073876933,
+ "y": -45.93302786709903,
+ "z": 0.0
+ },
+ {
+ "x": 396.33791005589046,
+ "y": -44.93078818873424,
+ "z": 0.0
+ },
+ {
+ "x": 396.3391127240876,
+ "y": -43.92854851036934,
+ "z": 0.0
+ },
+ {
+ "x": 396.34031539228477,
+ "y": -42.92630883200434,
+ "z": 0.0
+ },
+ {
+ "x": 396.3415180604818,
+ "y": -41.92406915363958,
+ "z": 0.0
+ },
+ {
+ "x": 396.34272072867896,
+ "y": -40.921829475274706,
+ "z": 0.0
+ },
+ {
+ "x": 396.3439233968761,
+ "y": -39.91958979690972,
+ "z": 0.0
+ },
+ {
+ "x": 396.34512606507326,
+ "y": -38.91735011854496,
+ "z": 0.0
+ },
+ {
+ "x": 396.3463287332704,
+ "y": -37.91511044018003,
+ "z": 0.0
+ },
+ {
+ "x": 396.34753140146756,
+ "y": -36.912870761815014,
+ "z": 0.0
+ },
+ {
+ "x": 396.3487340696646,
+ "y": -35.91063108345024,
+ "z": 0.0
+ },
+ {
+ "x": 396.34993673786175,
+ "y": -34.90839140508534,
+ "z": 0.0
+ },
+ {
+ "x": 396.3511394060589,
+ "y": -33.90615172672044,
+ "z": 0.0
+ },
+ {
+ "x": 396.35234207425606,
+ "y": -32.903912048355565,
+ "z": 0.0
+ },
+ {
+ "x": 396.3535447424532,
+ "y": -31.901672369990585,
+ "z": 0.0
+ },
+ {
+ "x": 396.35474741065036,
+ "y": -30.899432691625826,
+ "z": 0.0
+ },
+ {
+ "x": 396.3559500788475,
+ "y": -29.897193013260953,
+ "z": 0.0
+ },
+ {
+ "x": 396.35715274704467,
+ "y": -28.894953334895966,
+ "z": 0.0
+ },
+ {
+ "x": 396.3583554152417,
+ "y": -27.892713656531193,
+ "z": 0.0
+ },
+ {
+ "x": 396.35955808343886,
+ "y": -26.890473978166284,
+ "z": 0.0
+ },
+ {
+ "x": 396.360760751636,
+ "y": -25.888234299801304,
+ "z": 0.0
+ },
+ {
+ "x": 396.36196341983316,
+ "y": -24.885994621436545,
+ "z": 0.0
+ },
+ {
+ "x": 396.3631660880303,
+ "y": -23.883754943071658,
+ "z": 0.0
+ },
+ {
+ "x": 396.36436875622746,
+ "y": -22.881515264706636,
+ "z": 0.0
+ },
+ {
+ "x": 396.3655714244245,
+ "y": -21.879275586341848,
+ "z": 0.0
+ },
+ {
+ "x": 396.36677409262165,
+ "y": -20.877035907976875,
+ "z": 0.0
+ },
+ {
+ "x": 396.3679767608188,
+ "y": -19.874796229611952,
+ "z": 0.0
+ },
+ {
+ "x": 396.36917942901596,
+ "y": -18.87255655124693,
+ "z": 0.0
+ },
+ {
+ "x": 396.3703820972131,
+ "y": -17.870316872882164,
+ "z": 0.0
+ },
+ {
+ "x": 396.37158476541026,
+ "y": -16.868077194517276,
+ "z": 0.0
+ },
+ {
+ "x": 396.3727874336074,
+ "y": -15.865837516152242,
+ "z": 0.0
+ },
+ {
+ "x": 396.37399010180445,
+ "y": -14.863597837787554,
+ "z": 0.0
+ },
+ {
+ "x": 396.3751927700017,
+ "y": -13.861358159422444,
+ "z": 0.0
+ },
+ {
+ "x": 396.37639543819876,
+ "y": -12.859118481057523,
+ "z": 0.0
+ },
+ {
+ "x": 396.3775981063959,
+ "y": -11.856878802692831,
+ "z": 0.0
+ },
+ {
+ "x": 396.37880077459306,
+ "y": -10.854639124327711,
+ "z": 0.0
+ },
+ {
+ "x": 396.3800034427902,
+ "y": -9.85239944596279,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 45,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 144.9895082163707,
+ "y": -53.49334930469749,
+ "z": 0.0
+ },
+ {
+ "x": 143.97555473552626,
+ "y": -53.49347285775378,
+ "z": 0.0
+ },
+ {
+ "x": 142.96160125468174,
+ "y": -53.493596410810085,
+ "z": 0.0
+ },
+ {
+ "x": 141.94764777383736,
+ "y": -53.493719963866376,
+ "z": 0.0
+ },
+ {
+ "x": 140.93369429299287,
+ "y": -53.493843516922674,
+ "z": 0.0
+ },
+ {
+ "x": 139.9197408121484,
+ "y": -53.49396706997897,
+ "z": 0.0
+ },
+ {
+ "x": 138.90578733130397,
+ "y": -53.49409062303527,
+ "z": 0.0
+ },
+ {
+ "x": 137.89183385045953,
+ "y": -53.49421417609156,
+ "z": 0.0
+ },
+ {
+ "x": 136.87788036961507,
+ "y": -53.49433772914786,
+ "z": 0.0
+ },
+ {
+ "x": 135.8639268887706,
+ "y": -53.494461282204156,
+ "z": 0.0
+ },
+ {
+ "x": 134.8499734079262,
+ "y": -53.49458483526045,
+ "z": 0.0
+ },
+ {
+ "x": 133.83601992708168,
+ "y": -53.49470838831675,
+ "z": 0.0
+ },
+ {
+ "x": 132.8220664462373,
+ "y": -53.49483194137304,
+ "z": 0.0
+ },
+ {
+ "x": 131.8081129653928,
+ "y": -53.49495549442934,
+ "z": 0.0
+ },
+ {
+ "x": 130.79415948454835,
+ "y": -53.49507904748564,
+ "z": 0.0
+ },
+ {
+ "x": 129.7802060037039,
+ "y": -53.49520260054194,
+ "z": 0.0
+ },
+ {
+ "x": 128.76625252285947,
+ "y": -53.49532615359823,
+ "z": 0.0
+ },
+ {
+ "x": 127.752299042015,
+ "y": -53.495449706654526,
+ "z": 0.0
+ },
+ {
+ "x": 126.73834556117055,
+ "y": -53.495573259710824,
+ "z": 0.0
+ },
+ {
+ "x": 125.72439208032611,
+ "y": -53.495696812767115,
+ "z": 0.0
+ },
+ {
+ "x": 124.71043859948163,
+ "y": -53.49582036582341,
+ "z": 0.0
+ },
+ {
+ "x": 123.69648511863718,
+ "y": -53.49594391887971,
+ "z": 0.0
+ },
+ {
+ "x": 122.68253163779274,
+ "y": -53.49606747193601,
+ "z": 0.0
+ },
+ {
+ "x": 121.66857815694829,
+ "y": -53.49619102499231,
+ "z": 0.0
+ },
+ {
+ "x": 120.65462467610384,
+ "y": -53.496314578048604,
+ "z": 0.0
+ },
+ {
+ "x": 119.64067119525942,
+ "y": -53.496438131104895,
+ "z": 0.0
+ },
+ {
+ "x": 118.62671771441494,
+ "y": -53.49656168416119,
+ "z": 0.0
+ },
+ {
+ "x": 117.61276423357049,
+ "y": -53.49668523721749,
+ "z": 0.0
+ },
+ {
+ "x": 116.59881075272605,
+ "y": -53.49680879027378,
+ "z": 0.0
+ },
+ {
+ "x": 115.58485727188157,
+ "y": -53.49693234333008,
+ "z": 0.0
+ },
+ {
+ "x": 114.57090379103713,
+ "y": -53.49705589638638,
+ "z": 0.0
+ },
+ {
+ "x": 113.55695031019268,
+ "y": -53.497179449442676,
+ "z": 0.0
+ },
+ {
+ "x": 112.54299682934824,
+ "y": -53.49730300249897,
+ "z": 0.0
+ },
+ {
+ "x": 111.52904334850375,
+ "y": -53.49742655555527,
+ "z": 0.0
+ },
+ {
+ "x": 110.51508986765934,
+ "y": -53.49755010861156,
+ "z": 0.0
+ },
+ {
+ "x": 109.50113638681486,
+ "y": -53.49767366166786,
+ "z": 0.0
+ },
+ {
+ "x": 108.48718290597041,
+ "y": -53.49779721472416,
+ "z": 0.0
+ },
+ {
+ "x": 107.47322942512598,
+ "y": -53.49792076778045,
+ "z": 0.0
+ },
+ {
+ "x": 106.4592759442815,
+ "y": -53.49804432083675,
+ "z": 0.0
+ },
+ {
+ "x": 105.44532246343705,
+ "y": -53.498167873893046,
+ "z": 0.0
+ },
+ {
+ "x": 104.4313689825926,
+ "y": -53.49829142694934,
+ "z": 0.0
+ },
+ {
+ "x": 103.41741550174817,
+ "y": -53.498414980005634,
+ "z": 0.0
+ },
+ {
+ "x": 102.40346202090367,
+ "y": -53.49853853306194,
+ "z": 0.0
+ },
+ {
+ "x": 101.38950854005927,
+ "y": -53.49866208611823,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 46,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 101.39048336233827,
+ "y": -61.498662026725825,
+ "z": 0.0
+ },
+ {
+ "x": 102.40443684318276,
+ "y": -61.498538473669534,
+ "z": 0.0
+ },
+ {
+ "x": 103.41839032402717,
+ "y": -61.49841492061323,
+ "z": 0.0
+ },
+ {
+ "x": 104.43234380487166,
+ "y": -61.49829136755694,
+ "z": 0.0
+ },
+ {
+ "x": 105.44629728571611,
+ "y": -61.49816781450064,
+ "z": 0.0
+ },
+ {
+ "x": 106.46025076656056,
+ "y": -61.49804426144434,
+ "z": 0.0
+ },
+ {
+ "x": 107.47420424740498,
+ "y": -61.497920708388044,
+ "z": 0.0
+ },
+ {
+ "x": 108.48815772824948,
+ "y": -61.49779715533175,
+ "z": 0.0
+ },
+ {
+ "x": 109.50211120909393,
+ "y": -61.497673602275455,
+ "z": 0.0
+ },
+ {
+ "x": 110.51606468993835,
+ "y": -61.49755004921916,
+ "z": 0.0
+ },
+ {
+ "x": 111.53001817078284,
+ "y": -61.497426496162866,
+ "z": 0.0
+ },
+ {
+ "x": 112.54397165162725,
+ "y": -61.49730294310656,
+ "z": 0.0
+ },
+ {
+ "x": 113.55792513247174,
+ "y": -61.49717939005027,
+ "z": 0.0
+ },
+ {
+ "x": 114.57187861331619,
+ "y": -61.49705583699397,
+ "z": 0.0
+ },
+ {
+ "x": 115.58583209416064,
+ "y": -61.496932283937674,
+ "z": 0.0
+ },
+ {
+ "x": 116.59978557500506,
+ "y": -61.49680873088138,
+ "z": 0.0
+ },
+ {
+ "x": 117.61373905584955,
+ "y": -61.496685177825086,
+ "z": 0.0
+ },
+ {
+ "x": 118.627692536694,
+ "y": -61.49656162476879,
+ "z": 0.0
+ },
+ {
+ "x": 119.64164601753842,
+ "y": -61.49643807171249,
+ "z": 0.0
+ },
+ {
+ "x": 120.6555994983829,
+ "y": -61.4963145186562,
+ "z": 0.0
+ },
+ {
+ "x": 121.66955297922735,
+ "y": -61.4961909655999,
+ "z": 0.0
+ },
+ {
+ "x": 122.6835064600718,
+ "y": -61.4960674125436,
+ "z": 0.0
+ },
+ {
+ "x": 123.69745994091625,
+ "y": -61.495943859487305,
+ "z": 0.0
+ },
+ {
+ "x": 124.7114134217607,
+ "y": -61.49582030643101,
+ "z": 0.0
+ },
+ {
+ "x": 125.72536690260512,
+ "y": -61.49569675337471,
+ "z": 0.0
+ },
+ {
+ "x": 126.73932038344961,
+ "y": -61.49557320031842,
+ "z": 0.0
+ },
+ {
+ "x": 127.75327386429406,
+ "y": -61.49544964726212,
+ "z": 0.0
+ },
+ {
+ "x": 128.76722734513845,
+ "y": -61.49532609420582,
+ "z": 0.0
+ },
+ {
+ "x": 129.78118082598294,
+ "y": -61.49520254114953,
+ "z": 0.0
+ },
+ {
+ "x": 130.79513430682738,
+ "y": -61.49507898809323,
+ "z": 0.0
+ },
+ {
+ "x": 131.80908778767184,
+ "y": -61.494955435036935,
+ "z": 0.0
+ },
+ {
+ "x": 132.82304126851628,
+ "y": -61.49483188198064,
+ "z": 0.0
+ },
+ {
+ "x": 133.83699474936077,
+ "y": -61.49470832892435,
+ "z": 0.0
+ },
+ {
+ "x": 134.85094823020518,
+ "y": -61.49458477586804,
+ "z": 0.0
+ },
+ {
+ "x": 135.86490171104964,
+ "y": -61.49446122281175,
+ "z": 0.0
+ },
+ {
+ "x": 136.8788551918941,
+ "y": -61.49433766975545,
+ "z": 0.0
+ },
+ {
+ "x": 137.8928086727385,
+ "y": -61.494214116699155,
+ "z": 0.0
+ },
+ {
+ "x": 138.906762153583,
+ "y": -61.494090563642864,
+ "z": 0.0
+ },
+ {
+ "x": 139.92071563442744,
+ "y": -61.493967010586566,
+ "z": 0.0
+ },
+ {
+ "x": 140.9346691152719,
+ "y": -61.49384345753027,
+ "z": 0.0
+ },
+ {
+ "x": 141.94862259611634,
+ "y": -61.49371990447397,
+ "z": 0.0
+ },
+ {
+ "x": 142.96257607696083,
+ "y": -61.49359635141768,
+ "z": 0.0
+ },
+ {
+ "x": 143.97652955780524,
+ "y": -61.493472798361374,
+ "z": 0.0
+ },
+ {
+ "x": 144.99048303864967,
+ "y": -61.49334924530508,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 47,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 101.38999595119877,
+ "y": -57.49866205642203,
+ "z": 0.0
+ },
+ {
+ "x": 102.40394943204322,
+ "y": -57.49853850336574,
+ "z": 0.0
+ },
+ {
+ "x": 103.41790291288767,
+ "y": -57.49841495030943,
+ "z": 0.0
+ },
+ {
+ "x": 104.43185639373213,
+ "y": -57.49829139725314,
+ "z": 0.0
+ },
+ {
+ "x": 105.44580987457658,
+ "y": -57.49816784419684,
+ "z": 0.0
+ },
+ {
+ "x": 106.45976335542103,
+ "y": -57.498044291140545,
+ "z": 0.0
+ },
+ {
+ "x": 107.47371683626548,
+ "y": -57.49792073808425,
+ "z": 0.0
+ },
+ {
+ "x": 108.48767031710995,
+ "y": -57.497797185027956,
+ "z": 0.0
+ },
+ {
+ "x": 109.5016237979544,
+ "y": -57.49767363197166,
+ "z": 0.0
+ },
+ {
+ "x": 110.51557727879884,
+ "y": -57.49755007891536,
+ "z": 0.0
+ },
+ {
+ "x": 111.5295307596433,
+ "y": -57.49742652585907,
+ "z": 0.0
+ },
+ {
+ "x": 112.54348424048774,
+ "y": -57.497302972802764,
+ "z": 0.0
+ },
+ {
+ "x": 113.5574377213322,
+ "y": -57.49717941974647,
+ "z": 0.0
+ },
+ {
+ "x": 114.57139120217666,
+ "y": -57.497055866690175,
+ "z": 0.0
+ },
+ {
+ "x": 115.5853446830211,
+ "y": -57.49693231363388,
+ "z": 0.0
+ },
+ {
+ "x": 116.59929816386556,
+ "y": -57.49680876057758,
+ "z": 0.0
+ },
+ {
+ "x": 117.61325164471002,
+ "y": -57.49668520752129,
+ "z": 0.0
+ },
+ {
+ "x": 118.62720512555447,
+ "y": -57.49656165446499,
+ "z": 0.0
+ },
+ {
+ "x": 119.64115860639892,
+ "y": -57.49643810140869,
+ "z": 0.0
+ },
+ {
+ "x": 120.65511208724337,
+ "y": -57.4963145483524,
+ "z": 0.0
+ },
+ {
+ "x": 121.66906556808782,
+ "y": -57.496190995296104,
+ "z": 0.0
+ },
+ {
+ "x": 122.68301904893227,
+ "y": -57.496067442239806,
+ "z": 0.0
+ },
+ {
+ "x": 123.69697252977672,
+ "y": -57.49594388918351,
+ "z": 0.0
+ },
+ {
+ "x": 124.71092601062117,
+ "y": -57.49582033612721,
+ "z": 0.0
+ },
+ {
+ "x": 125.72487949146561,
+ "y": -57.49569678307091,
+ "z": 0.0
+ },
+ {
+ "x": 126.73883297231008,
+ "y": -57.49557323001462,
+ "z": 0.0
+ },
+ {
+ "x": 127.75278645315453,
+ "y": -57.49544967695832,
+ "z": 0.0
+ },
+ {
+ "x": 128.76673993399896,
+ "y": -57.495326123902025,
+ "z": 0.0
+ },
+ {
+ "x": 129.78069341484343,
+ "y": -57.495202570845734,
+ "z": 0.0
+ },
+ {
+ "x": 130.79464689568786,
+ "y": -57.495079017789436,
+ "z": 0.0
+ },
+ {
+ "x": 131.80860037653233,
+ "y": -57.49495546473314,
+ "z": 0.0
+ },
+ {
+ "x": 132.8225538573768,
+ "y": -57.49483191167684,
+ "z": 0.0
+ },
+ {
+ "x": 133.83650733822122,
+ "y": -57.49470835862055,
+ "z": 0.0
+ },
+ {
+ "x": 134.8504608190657,
+ "y": -57.494584805564244,
+ "z": 0.0
+ },
+ {
+ "x": 135.86441429991012,
+ "y": -57.49446125250795,
+ "z": 0.0
+ },
+ {
+ "x": 136.8783677807546,
+ "y": -57.494337699451656,
+ "z": 0.0
+ },
+ {
+ "x": 137.89232126159902,
+ "y": -57.49421414639536,
+ "z": 0.0
+ },
+ {
+ "x": 138.9062747424435,
+ "y": -57.49409059333907,
+ "z": 0.0
+ },
+ {
+ "x": 139.92022822328792,
+ "y": -57.49396704028277,
+ "z": 0.0
+ },
+ {
+ "x": 140.93418170413238,
+ "y": -57.49384348722647,
+ "z": 0.0
+ },
+ {
+ "x": 141.94813518497685,
+ "y": -57.49371993417017,
+ "z": 0.0
+ },
+ {
+ "x": 142.96208866582128,
+ "y": -57.49359638111388,
+ "z": 0.0
+ },
+ {
+ "x": 143.97604214666575,
+ "y": -57.49347282805758,
+ "z": 0.0
+ },
+ {
+ "x": 144.98999562751018,
+ "y": -57.493349275001286,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 48,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 144.98975192194044,
+ "y": -55.49334928984939,
+ "z": 0.0
+ },
+ {
+ "x": 143.975798441096,
+ "y": -55.493472842905675,
+ "z": 0.0
+ },
+ {
+ "x": 142.9618449602515,
+ "y": -55.49359639596199,
+ "z": 0.0
+ },
+ {
+ "x": 141.9478914794071,
+ "y": -55.49371994901827,
+ "z": 0.0
+ },
+ {
+ "x": 140.9339379985626,
+ "y": -55.49384350207457,
+ "z": 0.0
+ },
+ {
+ "x": 139.91998451771815,
+ "y": -55.49396705513087,
+ "z": 0.0
+ },
+ {
+ "x": 138.90603103687374,
+ "y": -55.494090608187165,
+ "z": 0.0
+ },
+ {
+ "x": 137.89207755602928,
+ "y": -55.49421416124346,
+ "z": 0.0
+ },
+ {
+ "x": 136.87812407518481,
+ "y": -55.49433771429976,
+ "z": 0.0
+ },
+ {
+ "x": 135.86417059434035,
+ "y": -55.49446126735606,
+ "z": 0.0
+ },
+ {
+ "x": 134.85021711349594,
+ "y": -55.49458482041234,
+ "z": 0.0
+ },
+ {
+ "x": 133.83626363265145,
+ "y": -55.494708373468654,
+ "z": 0.0
+ },
+ {
+ "x": 132.82231015180705,
+ "y": -55.49483192652494,
+ "z": 0.0
+ },
+ {
+ "x": 131.80835667096255,
+ "y": -55.494955479581236,
+ "z": 0.0
+ },
+ {
+ "x": 130.7944031901181,
+ "y": -55.495079032637534,
+ "z": 0.0
+ },
+ {
+ "x": 129.78044970927368,
+ "y": -55.49520258569383,
+ "z": 0.0
+ },
+ {
+ "x": 128.76649622842922,
+ "y": -55.49532613875013,
+ "z": 0.0
+ },
+ {
+ "x": 127.75254274758476,
+ "y": -55.49544969180643,
+ "z": 0.0
+ },
+ {
+ "x": 126.73858926674032,
+ "y": -55.495573244862726,
+ "z": 0.0
+ },
+ {
+ "x": 125.72463578589586,
+ "y": -55.49569679791901,
+ "z": 0.0
+ },
+ {
+ "x": 124.71068230505139,
+ "y": -55.49582035097531,
+ "z": 0.0
+ },
+ {
+ "x": 123.69672882420696,
+ "y": -55.495943904031606,
+ "z": 0.0
+ },
+ {
+ "x": 122.6827753433625,
+ "y": -55.496067457087904,
+ "z": 0.0
+ },
+ {
+ "x": 121.66882186251806,
+ "y": -55.4961910101442,
+ "z": 0.0
+ },
+ {
+ "x": 120.6548683816736,
+ "y": -55.4963145632005,
+ "z": 0.0
+ },
+ {
+ "x": 119.64091490082916,
+ "y": -55.4964381162568,
+ "z": 0.0
+ },
+ {
+ "x": 118.6269614199847,
+ "y": -55.496561669313095,
+ "z": 0.0
+ },
+ {
+ "x": 117.61300793914026,
+ "y": -55.49668522236939,
+ "z": 0.0
+ },
+ {
+ "x": 116.5990544582958,
+ "y": -55.49680877542568,
+ "z": 0.0
+ },
+ {
+ "x": 115.58510097745133,
+ "y": -55.496932328481975,
+ "z": 0.0
+ },
+ {
+ "x": 114.5711474966069,
+ "y": -55.49705588153827,
+ "z": 0.0
+ },
+ {
+ "x": 113.55719401576243,
+ "y": -55.49717943459457,
+ "z": 0.0
+ },
+ {
+ "x": 112.543240534918,
+ "y": -55.49730298765087,
+ "z": 0.0
+ },
+ {
+ "x": 111.52928705407352,
+ "y": -55.49742654070717,
+ "z": 0.0
+ },
+ {
+ "x": 110.5153335732291,
+ "y": -55.497550093763465,
+ "z": 0.0
+ },
+ {
+ "x": 109.50138009238464,
+ "y": -55.49767364681976,
+ "z": 0.0
+ },
+ {
+ "x": 108.48742661154017,
+ "y": -55.49779719987606,
+ "z": 0.0
+ },
+ {
+ "x": 107.47347313069574,
+ "y": -55.497920752932345,
+ "z": 0.0
+ },
+ {
+ "x": 106.45951964985127,
+ "y": -55.49804430598864,
+ "z": 0.0
+ },
+ {
+ "x": 105.44556616900681,
+ "y": -55.49816785904494,
+ "z": 0.0
+ },
+ {
+ "x": 104.43161268816237,
+ "y": -55.49829141210124,
+ "z": 0.0
+ },
+ {
+ "x": 103.41765920731791,
+ "y": -55.49841496515754,
+ "z": 0.0
+ },
+ {
+ "x": 102.40370572647345,
+ "y": -55.498538518213834,
+ "z": 0.0
+ },
+ {
+ "x": 101.38975224562901,
+ "y": -55.49866207127013,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 49,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 101.39023965676853,
+ "y": -59.49866204157392,
+ "z": 0.0
+ },
+ {
+ "x": 102.40419313761299,
+ "y": -59.49853848851764,
+ "z": 0.0
+ },
+ {
+ "x": 103.41814661845743,
+ "y": -59.49841493546133,
+ "z": 0.0
+ },
+ {
+ "x": 104.43210009930189,
+ "y": -59.49829138240504,
+ "z": 0.0
+ },
+ {
+ "x": 105.44605358014635,
+ "y": -59.498167829348745,
+ "z": 0.0
+ },
+ {
+ "x": 106.46000706099079,
+ "y": -59.49804427629245,
+ "z": 0.0
+ },
+ {
+ "x": 107.47396054183523,
+ "y": -59.49792072323615,
+ "z": 0.0
+ },
+ {
+ "x": 108.48791402267972,
+ "y": -59.49779717017985,
+ "z": 0.0
+ },
+ {
+ "x": 109.50186750352415,
+ "y": -59.49767361712355,
+ "z": 0.0
+ },
+ {
+ "x": 110.51582098436859,
+ "y": -59.497550064067255,
+ "z": 0.0
+ },
+ {
+ "x": 111.52977446521307,
+ "y": -59.49742651101097,
+ "z": 0.0
+ },
+ {
+ "x": 112.54372794605749,
+ "y": -59.49730295795466,
+ "z": 0.0
+ },
+ {
+ "x": 113.55768142690198,
+ "y": -59.497179404898375,
+ "z": 0.0
+ },
+ {
+ "x": 114.57163490774641,
+ "y": -59.49705585184208,
+ "z": 0.0
+ },
+ {
+ "x": 115.58558838859088,
+ "y": -59.49693229878578,
+ "z": 0.0
+ },
+ {
+ "x": 116.59954186943531,
+ "y": -59.49680874572948,
+ "z": 0.0
+ },
+ {
+ "x": 117.61349535027978,
+ "y": -59.49668519267318,
+ "z": 0.0
+ },
+ {
+ "x": 118.62744883112424,
+ "y": -59.496561639616885,
+ "z": 0.0
+ },
+ {
+ "x": 119.64140231196868,
+ "y": -59.49643808656059,
+ "z": 0.0
+ },
+ {
+ "x": 120.65535579281314,
+ "y": -59.496314533504304,
+ "z": 0.0
+ },
+ {
+ "x": 121.66930927365757,
+ "y": -59.496190980448006,
+ "z": 0.0
+ },
+ {
+ "x": 122.68326275450204,
+ "y": -59.49606742739171,
+ "z": 0.0
+ },
+ {
+ "x": 123.69721623534647,
+ "y": -59.49594387433541,
+ "z": 0.0
+ },
+ {
+ "x": 124.71116971619094,
+ "y": -59.49582032127911,
+ "z": 0.0
+ },
+ {
+ "x": 125.72512319703537,
+ "y": -59.495696768222814,
+ "z": 0.0
+ },
+ {
+ "x": 126.73907667787984,
+ "y": -59.495573215166516,
+ "z": 0.0
+ },
+ {
+ "x": 127.7530301587243,
+ "y": -59.49544966211022,
+ "z": 0.0
+ },
+ {
+ "x": 128.7669836395687,
+ "y": -59.49532610905392,
+ "z": 0.0
+ },
+ {
+ "x": 129.78093712041317,
+ "y": -59.495202555997636,
+ "z": 0.0
+ },
+ {
+ "x": 130.79489060125763,
+ "y": -59.49507900294134,
+ "z": 0.0
+ },
+ {
+ "x": 131.8088440821021,
+ "y": -59.49495544988504,
+ "z": 0.0
+ },
+ {
+ "x": 132.82279756294653,
+ "y": -59.49483189682874,
+ "z": 0.0
+ },
+ {
+ "x": 133.836751043791,
+ "y": -59.494708343772444,
+ "z": 0.0
+ },
+ {
+ "x": 134.85070452463543,
+ "y": -59.49458479071615,
+ "z": 0.0
+ },
+ {
+ "x": 135.8646580054799,
+ "y": -59.49446123765985,
+ "z": 0.0
+ },
+ {
+ "x": 136.87861148632436,
+ "y": -59.49433768460355,
+ "z": 0.0
+ },
+ {
+ "x": 137.89256496716877,
+ "y": -59.49421413154725,
+ "z": 0.0
+ },
+ {
+ "x": 138.90651844801323,
+ "y": -59.49409057849097,
+ "z": 0.0
+ },
+ {
+ "x": 139.9204719288577,
+ "y": -59.49396702543467,
+ "z": 0.0
+ },
+ {
+ "x": 140.93442540970216,
+ "y": -59.49384347237837,
+ "z": 0.0
+ },
+ {
+ "x": 141.9483788905466,
+ "y": -59.493719919322075,
+ "z": 0.0
+ },
+ {
+ "x": 142.96233237139106,
+ "y": -59.49359636626578,
+ "z": 0.0
+ },
+ {
+ "x": 143.9762858522355,
+ "y": -59.49347281320948,
+ "z": 0.0
+ },
+ {
+ "x": 144.99023933307993,
+ "y": -59.49334926015318,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 50,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 325.15950687877944,
+ "y": -53.47139508844576,
+ "z": 0.0
+ },
+ {
+ "x": 324.15320115376625,
+ "y": -53.471517709601706,
+ "z": 0.0
+ },
+ {
+ "x": 323.1468954287531,
+ "y": -53.471640330757644,
+ "z": 0.0
+ },
+ {
+ "x": 322.14058970373986,
+ "y": -53.47176295191359,
+ "z": 0.0
+ },
+ {
+ "x": 321.13428397872667,
+ "y": -53.471885573069535,
+ "z": 0.0
+ },
+ {
+ "x": 320.1279782537135,
+ "y": -53.472008194225474,
+ "z": 0.0
+ },
+ {
+ "x": 319.12167252870023,
+ "y": -53.47213081538142,
+ "z": 0.0
+ },
+ {
+ "x": 318.11536680368704,
+ "y": -53.472253436537365,
+ "z": 0.0
+ },
+ {
+ "x": 317.10906107867385,
+ "y": -53.47237605769331,
+ "z": 0.0
+ },
+ {
+ "x": 316.10275535366065,
+ "y": -53.472498678849256,
+ "z": 0.0
+ },
+ {
+ "x": 315.09644962864746,
+ "y": -53.472621300005194,
+ "z": 0.0
+ },
+ {
+ "x": 314.0901439036342,
+ "y": -53.47274392116114,
+ "z": 0.0
+ },
+ {
+ "x": 313.083838178621,
+ "y": -53.472866542317085,
+ "z": 0.0
+ },
+ {
+ "x": 312.0775324536079,
+ "y": -53.472989163473024,
+ "z": 0.0
+ },
+ {
+ "x": 311.07122672859464,
+ "y": -53.47311178462897,
+ "z": 0.0
+ },
+ {
+ "x": 310.0649210035814,
+ "y": -53.473234405784915,
+ "z": 0.0
+ },
+ {
+ "x": 309.05861527856825,
+ "y": -53.47335702694085,
+ "z": 0.0
+ },
+ {
+ "x": 308.052309553555,
+ "y": -53.4734796480968,
+ "z": 0.0
+ },
+ {
+ "x": 307.0460038285418,
+ "y": -53.473602269252744,
+ "z": 0.0
+ },
+ {
+ "x": 306.0396981035287,
+ "y": -53.47372489040868,
+ "z": 0.0
+ },
+ {
+ "x": 305.03339237851543,
+ "y": -53.47384751156463,
+ "z": 0.0
+ },
+ {
+ "x": 304.0270866535022,
+ "y": -53.473970132720574,
+ "z": 0.0
+ },
+ {
+ "x": 303.02078092848905,
+ "y": -53.47409275387651,
+ "z": 0.0
+ },
+ {
+ "x": 302.0144752034758,
+ "y": -53.47421537503246,
+ "z": 0.0
+ },
+ {
+ "x": 301.0081694784626,
+ "y": -53.4743379961884,
+ "z": 0.0
+ },
+ {
+ "x": 300.00186375344947,
+ "y": -53.47446061734434,
+ "z": 0.0
+ },
+ {
+ "x": 298.99555802843616,
+ "y": -53.47458323850029,
+ "z": 0.0
+ },
+ {
+ "x": 297.989252303423,
+ "y": -53.47470585965623,
+ "z": 0.0
+ },
+ {
+ "x": 296.98294657840984,
+ "y": -53.47482848081217,
+ "z": 0.0
+ },
+ {
+ "x": 295.9766408533966,
+ "y": -53.47495110196812,
+ "z": 0.0
+ },
+ {
+ "x": 294.9703351283834,
+ "y": -53.475073723124055,
+ "z": 0.0
+ },
+ {
+ "x": 293.96402940337015,
+ "y": -53.47519634428,
+ "z": 0.0
+ },
+ {
+ "x": 292.95772367835696,
+ "y": -53.475318965435946,
+ "z": 0.0
+ },
+ {
+ "x": 291.95141795334376,
+ "y": -53.475441586591884,
+ "z": 0.0
+ },
+ {
+ "x": 290.9451122283305,
+ "y": -53.47556420774783,
+ "z": 0.0
+ },
+ {
+ "x": 289.93880650331727,
+ "y": -53.47568682890378,
+ "z": 0.0
+ },
+ {
+ "x": 288.93250077830413,
+ "y": -53.47580945005972,
+ "z": 0.0
+ },
+ {
+ "x": 287.9261950532908,
+ "y": -53.47593207121567,
+ "z": 0.0
+ },
+ {
+ "x": 286.91988932827763,
+ "y": -53.47605469237161,
+ "z": 0.0
+ },
+ {
+ "x": 285.91358360326444,
+ "y": -53.47617731352755,
+ "z": 0.0
+ },
+ {
+ "x": 284.9072778782512,
+ "y": -53.476299934683496,
+ "z": 0.0
+ },
+ {
+ "x": 283.900972153238,
+ "y": -53.47642255583944,
+ "z": 0.0
+ },
+ {
+ "x": 282.8946664282248,
+ "y": -53.47654517699538,
+ "z": 0.0
+ },
+ {
+ "x": 281.88836070321156,
+ "y": -53.476667798151325,
+ "z": 0.0
+ },
+ {
+ "x": 280.8820549781983,
+ "y": -53.47679041930727,
+ "z": 0.0
+ },
+ {
+ "x": 279.8757492531852,
+ "y": -53.47691304046321,
+ "z": 0.0
+ },
+ {
+ "x": 278.86944352817187,
+ "y": -53.477035661619155,
+ "z": 0.0
+ },
+ {
+ "x": 277.8631378031587,
+ "y": -53.4771582827751,
+ "z": 0.0
+ },
+ {
+ "x": 276.8568320781455,
+ "y": -53.47728090393104,
+ "z": 0.0
+ },
+ {
+ "x": 275.85052635313224,
+ "y": -53.477403525086984,
+ "z": 0.0
+ },
+ {
+ "x": 274.8442206281191,
+ "y": -53.47752614624292,
+ "z": 0.0
+ },
+ {
+ "x": 273.8379149031058,
+ "y": -53.47764876739887,
+ "z": 0.0
+ },
+ {
+ "x": 272.8316091780926,
+ "y": -53.477771388554814,
+ "z": 0.0
+ },
+ {
+ "x": 271.8253034530794,
+ "y": -53.47789400971075,
+ "z": 0.0
+ },
+ {
+ "x": 270.81899772806617,
+ "y": -53.4780166308667,
+ "z": 0.0
+ },
+ {
+ "x": 269.8126920030529,
+ "y": -53.47813925202264,
+ "z": 0.0
+ },
+ {
+ "x": 268.8063862780398,
+ "y": -53.47826187317858,
+ "z": 0.0
+ },
+ {
+ "x": 267.8000805530265,
+ "y": -53.47838449433453,
+ "z": 0.0
+ },
+ {
+ "x": 266.7937748280133,
+ "y": -53.47850711549047,
+ "z": 0.0
+ },
+ {
+ "x": 265.78746910300015,
+ "y": -53.47862973664641,
+ "z": 0.0
+ },
+ {
+ "x": 264.78116337798684,
+ "y": -53.47875235780236,
+ "z": 0.0
+ },
+ {
+ "x": 263.77485765297365,
+ "y": -53.4788749789583,
+ "z": 0.0
+ },
+ {
+ "x": 262.7685519279604,
+ "y": -53.47899760011425,
+ "z": 0.0
+ },
+ {
+ "x": 261.7622462029472,
+ "y": -53.47912022127019,
+ "z": 0.0
+ },
+ {
+ "x": 260.755940477934,
+ "y": -53.47924284242614,
+ "z": 0.0
+ },
+ {
+ "x": 259.7496347529208,
+ "y": -53.47936546358208,
+ "z": 0.0
+ },
+ {
+ "x": 258.7433290279076,
+ "y": -53.47948808473802,
+ "z": 0.0
+ },
+ {
+ "x": 257.73702330289433,
+ "y": -53.47961070589397,
+ "z": 0.0
+ },
+ {
+ "x": 256.7307175778812,
+ "y": -53.47973332704991,
+ "z": 0.0
+ },
+ {
+ "x": 255.72441185286795,
+ "y": -53.47985594820585,
+ "z": 0.0
+ },
+ {
+ "x": 254.71810612785475,
+ "y": -53.47997856936179,
+ "z": 0.0
+ },
+ {
+ "x": 253.7118004028415,
+ "y": -53.480101190517736,
+ "z": 0.0
+ },
+ {
+ "x": 252.70549467782828,
+ "y": -53.48022381167368,
+ "z": 0.0
+ },
+ {
+ "x": 251.6991889528151,
+ "y": -53.48034643282962,
+ "z": 0.0
+ },
+ {
+ "x": 250.69288322780184,
+ "y": -53.480469053985566,
+ "z": 0.0
+ },
+ {
+ "x": 249.68657750278862,
+ "y": -53.48059167514151,
+ "z": 0.0
+ },
+ {
+ "x": 248.68027177777543,
+ "y": -53.48071429629745,
+ "z": 0.0
+ },
+ {
+ "x": 247.67396605276218,
+ "y": -53.480836917453395,
+ "z": 0.0
+ },
+ {
+ "x": 246.667660327749,
+ "y": -53.48095953860934,
+ "z": 0.0
+ },
+ {
+ "x": 245.6613546027358,
+ "y": -53.48108215976528,
+ "z": 0.0
+ },
+ {
+ "x": 244.65504887772255,
+ "y": -53.481204780921225,
+ "z": 0.0
+ },
+ {
+ "x": 243.64874315270933,
+ "y": -53.48132740207717,
+ "z": 0.0
+ },
+ {
+ "x": 242.64243742769614,
+ "y": -53.48145002323311,
+ "z": 0.0
+ },
+ {
+ "x": 241.6361317026829,
+ "y": -53.481572644389054,
+ "z": 0.0
+ },
+ {
+ "x": 240.62982597766967,
+ "y": -53.481695265545,
+ "z": 0.0
+ },
+ {
+ "x": 239.62352025265648,
+ "y": -53.48181788670094,
+ "z": 0.0
+ },
+ {
+ "x": 238.61721452764323,
+ "y": -53.48194050785688,
+ "z": 0.0
+ },
+ {
+ "x": 237.61090880263004,
+ "y": -53.48206312901283,
+ "z": 0.0
+ },
+ {
+ "x": 236.60460307761684,
+ "y": -53.48218575016877,
+ "z": 0.0
+ },
+ {
+ "x": 235.5982973526036,
+ "y": -53.48230837132471,
+ "z": 0.0
+ },
+ {
+ "x": 234.59199162759037,
+ "y": -53.48243099248066,
+ "z": 0.0
+ },
+ {
+ "x": 233.58568590257715,
+ "y": -53.482553613636604,
+ "z": 0.0
+ },
+ {
+ "x": 232.57938017756393,
+ "y": -53.48267623479255,
+ "z": 0.0
+ },
+ {
+ "x": 231.57307445255074,
+ "y": -53.48279885594849,
+ "z": 0.0
+ },
+ {
+ "x": 230.56676872753752,
+ "y": -53.48292147710443,
+ "z": 0.0
+ },
+ {
+ "x": 229.5604630025243,
+ "y": -53.48304409826038,
+ "z": 0.0
+ },
+ {
+ "x": 228.5541572775111,
+ "y": -53.48316671941632,
+ "z": 0.0
+ },
+ {
+ "x": 227.5478515524979,
+ "y": -53.48328934057226,
+ "z": 0.0
+ },
+ {
+ "x": 226.54154582748467,
+ "y": -53.48341196172821,
+ "z": 0.0
+ },
+ {
+ "x": 225.5352401024715,
+ "y": -53.48353458288415,
+ "z": 0.0
+ },
+ {
+ "x": 224.52893437745826,
+ "y": -53.48365720404009,
+ "z": 0.0
+ },
+ {
+ "x": 223.52262865244504,
+ "y": -53.48377982519604,
+ "z": 0.0
+ },
+ {
+ "x": 222.51632292743187,
+ "y": -53.483902446351976,
+ "z": 0.0
+ },
+ {
+ "x": 221.51001720241862,
+ "y": -53.48402506750792,
+ "z": 0.0
+ },
+ {
+ "x": 220.5037114774054,
+ "y": -53.48414768866387,
+ "z": 0.0
+ },
+ {
+ "x": 219.49740575239224,
+ "y": -53.484270309819806,
+ "z": 0.0
+ },
+ {
+ "x": 218.491100027379,
+ "y": -53.48439293097575,
+ "z": 0.0
+ },
+ {
+ "x": 217.4847943023658,
+ "y": -53.4845155521317,
+ "z": 0.0
+ },
+ {
+ "x": 216.4784885773526,
+ "y": -53.484638173287635,
+ "z": 0.0
+ },
+ {
+ "x": 215.47218285233936,
+ "y": -53.48476079444358,
+ "z": 0.0
+ },
+ {
+ "x": 214.4658771273262,
+ "y": -53.48488341559952,
+ "z": 0.0
+ },
+ {
+ "x": 213.45957140231295,
+ "y": -53.485006036755465,
+ "z": 0.0
+ },
+ {
+ "x": 212.45326567729973,
+ "y": -53.48512865791141,
+ "z": 0.0
+ },
+ {
+ "x": 211.44695995228656,
+ "y": -53.48525127906735,
+ "z": 0.0
+ },
+ {
+ "x": 210.4406542272733,
+ "y": -53.485373900223294,
+ "z": 0.0
+ },
+ {
+ "x": 209.43434850226012,
+ "y": -53.48549652137924,
+ "z": 0.0
+ },
+ {
+ "x": 208.4280427772469,
+ "y": -53.485619142535185,
+ "z": 0.0
+ },
+ {
+ "x": 207.42173705223368,
+ "y": -53.48574176369113,
+ "z": 0.0
+ },
+ {
+ "x": 206.4154313272205,
+ "y": -53.485864384847076,
+ "z": 0.0
+ },
+ {
+ "x": 205.4091256022073,
+ "y": -53.485987006003015,
+ "z": 0.0
+ },
+ {
+ "x": 204.40281987719405,
+ "y": -53.48610962715896,
+ "z": 0.0
+ },
+ {
+ "x": 203.39651415218086,
+ "y": -53.486232248314906,
+ "z": 0.0
+ },
+ {
+ "x": 202.39020842716766,
+ "y": -53.486354869470844,
+ "z": 0.0
+ },
+ {
+ "x": 201.38390270215444,
+ "y": -53.48647749062679,
+ "z": 0.0
+ },
+ {
+ "x": 200.37759697714122,
+ "y": -53.486600111782735,
+ "z": 0.0
+ },
+ {
+ "x": 199.37129125212803,
+ "y": -53.486722732938674,
+ "z": 0.0
+ },
+ {
+ "x": 198.3649855271148,
+ "y": -53.48684535409462,
+ "z": 0.0
+ },
+ {
+ "x": 197.3586798021016,
+ "y": -53.486967975250565,
+ "z": 0.0
+ },
+ {
+ "x": 196.3523740770884,
+ "y": -53.4870905964065,
+ "z": 0.0
+ },
+ {
+ "x": 195.34606835207515,
+ "y": -53.48721321756245,
+ "z": 0.0
+ },
+ {
+ "x": 194.33976262706196,
+ "y": -53.48733583871839,
+ "z": 0.0
+ },
+ {
+ "x": 193.33345690204874,
+ "y": -53.48745845987433,
+ "z": 0.0
+ },
+ {
+ "x": 192.32715117703552,
+ "y": -53.48758108103028,
+ "z": 0.0
+ },
+ {
+ "x": 191.32084545202233,
+ "y": -53.48770370218622,
+ "z": 0.0
+ },
+ {
+ "x": 190.3145397270091,
+ "y": -53.48782632334216,
+ "z": 0.0
+ },
+ {
+ "x": 189.30823400199588,
+ "y": -53.48794894449811,
+ "z": 0.0
+ },
+ {
+ "x": 188.3019282769827,
+ "y": -53.488071565654046,
+ "z": 0.0
+ },
+ {
+ "x": 187.29562255196944,
+ "y": -53.48819418680999,
+ "z": 0.0
+ },
+ {
+ "x": 186.28931682695622,
+ "y": -53.48831680796594,
+ "z": 0.0
+ },
+ {
+ "x": 185.28301110194306,
+ "y": -53.488439429121875,
+ "z": 0.0
+ },
+ {
+ "x": 184.2767053769298,
+ "y": -53.48856205027782,
+ "z": 0.0
+ },
+ {
+ "x": 183.2703996519166,
+ "y": -53.48868467143377,
+ "z": 0.0
+ },
+ {
+ "x": 182.26409392690343,
+ "y": -53.488807292589705,
+ "z": 0.0
+ },
+ {
+ "x": 181.25778820189018,
+ "y": -53.48892991374565,
+ "z": 0.0
+ },
+ {
+ "x": 180.25148247687693,
+ "y": -53.4890525349016,
+ "z": 0.0
+ },
+ {
+ "x": 179.24517675186377,
+ "y": -53.48917515605754,
+ "z": 0.0
+ },
+ {
+ "x": 178.23887102685055,
+ "y": -53.48929777721349,
+ "z": 0.0
+ },
+ {
+ "x": 177.23256530183733,
+ "y": -53.48942039836943,
+ "z": 0.0
+ },
+ {
+ "x": 176.22625957682413,
+ "y": -53.48954301952537,
+ "z": 0.0
+ },
+ {
+ "x": 175.2199538518109,
+ "y": -53.48966564068132,
+ "z": 0.0
+ },
+ {
+ "x": 174.21364812679772,
+ "y": -53.489788261837255,
+ "z": 0.0
+ },
+ {
+ "x": 173.20734240178447,
+ "y": -53.4899108829932,
+ "z": 0.0
+ },
+ {
+ "x": 172.20103667677128,
+ "y": -53.490033504149146,
+ "z": 0.0
+ },
+ {
+ "x": 171.1947309517581,
+ "y": -53.490156125305084,
+ "z": 0.0
+ },
+ {
+ "x": 170.18842522674484,
+ "y": -53.49027874646103,
+ "z": 0.0
+ },
+ {
+ "x": 169.18211950173162,
+ "y": -53.490401367616975,
+ "z": 0.0
+ },
+ {
+ "x": 168.17581377671846,
+ "y": -53.490523988772914,
+ "z": 0.0
+ },
+ {
+ "x": 167.1695080517052,
+ "y": -53.49064660992886,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 51,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 167.17048287398424,
+ "y": -61.490646550536454,
+ "z": 0.0
+ },
+ {
+ "x": 168.17678859899743,
+ "y": -61.49052392938051,
+ "z": 0.0
+ },
+ {
+ "x": 169.18309432401065,
+ "y": -61.49040130822457,
+ "z": 0.0
+ },
+ {
+ "x": 170.18940004902387,
+ "y": -61.490278687068624,
+ "z": 0.0
+ },
+ {
+ "x": 171.19570577403707,
+ "y": -61.49015606591268,
+ "z": 0.0
+ },
+ {
+ "x": 172.20201149905031,
+ "y": -61.49003344475674,
+ "z": 0.0
+ },
+ {
+ "x": 173.2083172240635,
+ "y": -61.489910823600795,
+ "z": 0.0
+ },
+ {
+ "x": 174.2146229490767,
+ "y": -61.48978820244485,
+ "z": 0.0
+ },
+ {
+ "x": 175.22092867408995,
+ "y": -61.48966558128891,
+ "z": 0.0
+ },
+ {
+ "x": 176.2272343991031,
+ "y": -61.489542960132965,
+ "z": 0.0
+ },
+ {
+ "x": 177.23354012411636,
+ "y": -61.48942033897703,
+ "z": 0.0
+ },
+ {
+ "x": 178.23984584912958,
+ "y": -61.48929771782108,
+ "z": 0.0
+ },
+ {
+ "x": 179.24615157414274,
+ "y": -61.489175096665136,
+ "z": 0.0
+ },
+ {
+ "x": 180.25245729915602,
+ "y": -61.4890524755092,
+ "z": 0.0
+ },
+ {
+ "x": 181.2587630241692,
+ "y": -61.488929854353245,
+ "z": 0.0
+ },
+ {
+ "x": 182.2650687491824,
+ "y": -61.4888072331973,
+ "z": 0.0
+ },
+ {
+ "x": 183.27137447419562,
+ "y": -61.48868461204136,
+ "z": 0.0
+ },
+ {
+ "x": 184.27768019920885,
+ "y": -61.488561990885415,
+ "z": 0.0
+ },
+ {
+ "x": 185.28398592422204,
+ "y": -61.48843936972947,
+ "z": 0.0
+ },
+ {
+ "x": 186.29029164923526,
+ "y": -61.48831674857353,
+ "z": 0.0
+ },
+ {
+ "x": 187.29659737424848,
+ "y": -61.488194127417586,
+ "z": 0.0
+ },
+ {
+ "x": 188.30290309926167,
+ "y": -61.48807150626164,
+ "z": 0.0
+ },
+ {
+ "x": 189.30920882427492,
+ "y": -61.4879488851057,
+ "z": 0.0
+ },
+ {
+ "x": 190.31551454928814,
+ "y": -61.487826263949756,
+ "z": 0.0
+ },
+ {
+ "x": 191.3218202743013,
+ "y": -61.48770364279381,
+ "z": 0.0
+ },
+ {
+ "x": 192.32812599931455,
+ "y": -61.48758102163787,
+ "z": 0.0
+ },
+ {
+ "x": 193.33443172432777,
+ "y": -61.48745840048193,
+ "z": 0.0
+ },
+ {
+ "x": 194.34073744934093,
+ "y": -61.48733577932598,
+ "z": 0.0
+ },
+ {
+ "x": 195.34704317435418,
+ "y": -61.48721315817004,
+ "z": 0.0
+ },
+ {
+ "x": 196.35334889936738,
+ "y": -61.4870905370141,
+ "z": 0.0
+ },
+ {
+ "x": 197.35965462438062,
+ "y": -61.48696791585816,
+ "z": 0.0
+ },
+ {
+ "x": 198.36596034939384,
+ "y": -61.48684529470221,
+ "z": 0.0
+ },
+ {
+ "x": 199.372266074407,
+ "y": -61.48672267354627,
+ "z": 0.0
+ },
+ {
+ "x": 200.37857179942026,
+ "y": -61.48660005239033,
+ "z": 0.0
+ },
+ {
+ "x": 201.38487752443348,
+ "y": -61.486477431234384,
+ "z": 0.0
+ },
+ {
+ "x": 202.39118324944664,
+ "y": -61.48635481007844,
+ "z": 0.0
+ },
+ {
+ "x": 203.3974889744599,
+ "y": -61.4862321889225,
+ "z": 0.0
+ },
+ {
+ "x": 204.40379469947308,
+ "y": -61.486109567766555,
+ "z": 0.0
+ },
+ {
+ "x": 205.41010042448627,
+ "y": -61.48598694661061,
+ "z": 0.0
+ },
+ {
+ "x": 206.41640614949952,
+ "y": -61.48586432545467,
+ "z": 0.0
+ },
+ {
+ "x": 207.42271187451271,
+ "y": -61.485741704298725,
+ "z": 0.0
+ },
+ {
+ "x": 208.42901759952593,
+ "y": -61.48561908314278,
+ "z": 0.0
+ },
+ {
+ "x": 209.43532332453916,
+ "y": -61.485496461986834,
+ "z": 0.0
+ },
+ {
+ "x": 210.44162904955235,
+ "y": -61.48537384083089,
+ "z": 0.0
+ },
+ {
+ "x": 211.44793477456554,
+ "y": -61.48525121967494,
+ "z": 0.0
+ },
+ {
+ "x": 212.45424049957876,
+ "y": -61.485128598519005,
+ "z": 0.0
+ },
+ {
+ "x": 213.46054622459198,
+ "y": -61.48500597736306,
+ "z": 0.0
+ },
+ {
+ "x": 214.46685194960517,
+ "y": -61.48488335620711,
+ "z": 0.0
+ },
+ {
+ "x": 215.4731576746184,
+ "y": -61.484760735051175,
+ "z": 0.0
+ },
+ {
+ "x": 216.47946339963158,
+ "y": -61.48463811389523,
+ "z": 0.0
+ },
+ {
+ "x": 217.48576912464483,
+ "y": -61.48451549273929,
+ "z": 0.0
+ },
+ {
+ "x": 218.49207484965802,
+ "y": -61.484392871583346,
+ "z": 0.0
+ },
+ {
+ "x": 219.49838057467122,
+ "y": -61.4842702504274,
+ "z": 0.0
+ },
+ {
+ "x": 220.50468629968444,
+ "y": -61.48414762927146,
+ "z": 0.0
+ },
+ {
+ "x": 221.51099202469766,
+ "y": -61.484025008115516,
+ "z": 0.0
+ },
+ {
+ "x": 222.51729774971085,
+ "y": -61.48390238695957,
+ "z": 0.0
+ },
+ {
+ "x": 223.52360347472407,
+ "y": -61.48377976580363,
+ "z": 0.0
+ },
+ {
+ "x": 224.5299091997373,
+ "y": -61.48365714464769,
+ "z": 0.0
+ },
+ {
+ "x": 225.53621492475048,
+ "y": -61.48353452349174,
+ "z": 0.0
+ },
+ {
+ "x": 226.5425206497637,
+ "y": -61.4834119023358,
+ "z": 0.0
+ },
+ {
+ "x": 227.54882637477692,
+ "y": -61.48328928117986,
+ "z": 0.0
+ },
+ {
+ "x": 228.5551320997901,
+ "y": -61.48316666002391,
+ "z": 0.0
+ },
+ {
+ "x": 229.56143782480333,
+ "y": -61.48304403886797,
+ "z": 0.0
+ },
+ {
+ "x": 230.56774354981656,
+ "y": -61.48292141771203,
+ "z": 0.0
+ },
+ {
+ "x": 231.57404927482972,
+ "y": -61.48279879655608,
+ "z": 0.0
+ },
+ {
+ "x": 232.58035499984297,
+ "y": -61.482676175400144,
+ "z": 0.0
+ },
+ {
+ "x": 233.5866607248562,
+ "y": -61.4825535542442,
+ "z": 0.0
+ },
+ {
+ "x": 234.5929664498694,
+ "y": -61.48243093308825,
+ "z": 0.0
+ },
+ {
+ "x": 235.59927217488263,
+ "y": -61.48230831193231,
+ "z": 0.0
+ },
+ {
+ "x": 236.60557789989582,
+ "y": -61.48218569077636,
+ "z": 0.0
+ },
+ {
+ "x": 237.61188362490907,
+ "y": -61.48206306962042,
+ "z": 0.0
+ },
+ {
+ "x": 238.61818934992226,
+ "y": -61.48194044846448,
+ "z": 0.0
+ },
+ {
+ "x": 239.62449507493545,
+ "y": -61.48181782730853,
+ "z": 0.0
+ },
+ {
+ "x": 240.6308007999487,
+ "y": -61.481695206152594,
+ "z": 0.0
+ },
+ {
+ "x": 241.63710652496192,
+ "y": -61.48157258499665,
+ "z": 0.0
+ },
+ {
+ "x": 242.6434122499751,
+ "y": -61.4814499638407,
+ "z": 0.0
+ },
+ {
+ "x": 243.64971797498836,
+ "y": -61.481327342684764,
+ "z": 0.0
+ },
+ {
+ "x": 244.65602370000158,
+ "y": -61.48120472152882,
+ "z": 0.0
+ },
+ {
+ "x": 245.66232942501478,
+ "y": -61.48108210037287,
+ "z": 0.0
+ },
+ {
+ "x": 246.66863515002802,
+ "y": -61.480959479216935,
+ "z": 0.0
+ },
+ {
+ "x": 247.67494087504122,
+ "y": -61.48083685806099,
+ "z": 0.0
+ },
+ {
+ "x": 248.6812466000544,
+ "y": -61.480714236905044,
+ "z": 0.0
+ },
+ {
+ "x": 249.68755232506766,
+ "y": -61.480591615749105,
+ "z": 0.0
+ },
+ {
+ "x": 250.69385805008088,
+ "y": -61.48046899459316,
+ "z": 0.0
+ },
+ {
+ "x": 251.70016377509407,
+ "y": -61.480346373437214,
+ "z": 0.0
+ },
+ {
+ "x": 252.70646950010732,
+ "y": -61.480223752281276,
+ "z": 0.0
+ },
+ {
+ "x": 253.71277522512054,
+ "y": -61.48010113112533,
+ "z": 0.0
+ },
+ {
+ "x": 254.71908095013373,
+ "y": -61.479978509969385,
+ "z": 0.0
+ },
+ {
+ "x": 255.72538667514698,
+ "y": -61.47985588881345,
+ "z": 0.0
+ },
+ {
+ "x": 256.73169240016017,
+ "y": -61.4797332676575,
+ "z": 0.0
+ },
+ {
+ "x": 257.7379981251734,
+ "y": -61.47961064650156,
+ "z": 0.0
+ },
+ {
+ "x": 258.74430385018667,
+ "y": -61.47948802534562,
+ "z": 0.0
+ },
+ {
+ "x": 259.7506095751998,
+ "y": -61.47936540418967,
+ "z": 0.0
+ },
+ {
+ "x": 260.7569153002131,
+ "y": -61.47924278303373,
+ "z": 0.0
+ },
+ {
+ "x": 261.7632210252263,
+ "y": -61.47912016187779,
+ "z": 0.0
+ },
+ {
+ "x": 262.7695267502395,
+ "y": -61.47899754072184,
+ "z": 0.0
+ },
+ {
+ "x": 263.77583247525274,
+ "y": -61.4788749195659,
+ "z": 0.0
+ },
+ {
+ "x": 264.78213820026593,
+ "y": -61.47875229840995,
+ "z": 0.0
+ },
+ {
+ "x": 265.7884439252791,
+ "y": -61.478629677254006,
+ "z": 0.0
+ },
+ {
+ "x": 266.7947496502924,
+ "y": -61.47850705609807,
+ "z": 0.0
+ },
+ {
+ "x": 267.80105537530557,
+ "y": -61.47838443494212,
+ "z": 0.0
+ },
+ {
+ "x": 268.80736110031876,
+ "y": -61.478261813786176,
+ "z": 0.0
+ },
+ {
+ "x": 269.813666825332,
+ "y": -61.47813919263024,
+ "z": 0.0
+ },
+ {
+ "x": 270.81997255034526,
+ "y": -61.47801657147429,
+ "z": 0.0
+ },
+ {
+ "x": 271.8262782753584,
+ "y": -61.47789395031835,
+ "z": 0.0
+ },
+ {
+ "x": 272.8325840003717,
+ "y": -61.47777132916241,
+ "z": 0.0
+ },
+ {
+ "x": 273.8388897253849,
+ "y": -61.47764870800646,
+ "z": 0.0
+ },
+ {
+ "x": 274.8451954503981,
+ "y": -61.47752608685052,
+ "z": 0.0
+ },
+ {
+ "x": 275.85150117541133,
+ "y": -61.47740346569458,
+ "z": 0.0
+ },
+ {
+ "x": 276.85780690042446,
+ "y": -61.47728084453863,
+ "z": 0.0
+ },
+ {
+ "x": 277.86411262543777,
+ "y": -61.477158223382695,
+ "z": 0.0
+ },
+ {
+ "x": 278.87041835045096,
+ "y": -61.47703560222675,
+ "z": 0.0
+ },
+ {
+ "x": 279.87672407546415,
+ "y": -61.476912981070804,
+ "z": 0.0
+ },
+ {
+ "x": 280.8830298004774,
+ "y": -61.476790359914865,
+ "z": 0.0
+ },
+ {
+ "x": 281.88933552549065,
+ "y": -61.47666773875892,
+ "z": 0.0
+ },
+ {
+ "x": 282.8956412505038,
+ "y": -61.476545117602974,
+ "z": 0.0
+ },
+ {
+ "x": 283.9019469755171,
+ "y": -61.476422496447036,
+ "z": 0.0
+ },
+ {
+ "x": 284.9082527005303,
+ "y": -61.47629987529109,
+ "z": 0.0
+ },
+ {
+ "x": 285.9145584255434,
+ "y": -61.476177254135145,
+ "z": 0.0
+ },
+ {
+ "x": 286.9208641505567,
+ "y": -61.476054632979206,
+ "z": 0.0
+ },
+ {
+ "x": 287.9271698755699,
+ "y": -61.47593201182326,
+ "z": 0.0
+ },
+ {
+ "x": 288.9334756005831,
+ "y": -61.475809390667315,
+ "z": 0.0
+ },
+ {
+ "x": 289.93978132559636,
+ "y": -61.47568676951138,
+ "z": 0.0
+ },
+ {
+ "x": 290.9460870506096,
+ "y": -61.475564148355424,
+ "z": 0.0
+ },
+ {
+ "x": 291.95239277562274,
+ "y": -61.47544152719948,
+ "z": 0.0
+ },
+ {
+ "x": 292.95869850063605,
+ "y": -61.47531890604354,
+ "z": 0.0
+ },
+ {
+ "x": 293.96500422564924,
+ "y": -61.475196284887595,
+ "z": 0.0
+ },
+ {
+ "x": 294.9713099506624,
+ "y": -61.47507366373165,
+ "z": 0.0
+ },
+ {
+ "x": 295.9776156756757,
+ "y": -61.47495104257571,
+ "z": 0.0
+ },
+ {
+ "x": 296.9839214006888,
+ "y": -61.474828421419765,
+ "z": 0.0
+ },
+ {
+ "x": 297.99022712570206,
+ "y": -61.47470580026383,
+ "z": 0.0
+ },
+ {
+ "x": 298.99653285071525,
+ "y": -61.47458317910788,
+ "z": 0.0
+ },
+ {
+ "x": 300.00283857572845,
+ "y": -61.474460557951936,
+ "z": 0.0
+ },
+ {
+ "x": 301.0091443007417,
+ "y": -61.474337936796,
+ "z": 0.0
+ },
+ {
+ "x": 302.0154500257549,
+ "y": -61.47421531564005,
+ "z": 0.0
+ },
+ {
+ "x": 303.021755750768,
+ "y": -61.474092694484106,
+ "z": 0.0
+ },
+ {
+ "x": 304.02806147578127,
+ "y": -61.47397007332817,
+ "z": 0.0
+ },
+ {
+ "x": 305.0343672007945,
+ "y": -61.47384745217222,
+ "z": 0.0
+ },
+ {
+ "x": 306.04067292580766,
+ "y": -61.47372483101628,
+ "z": 0.0
+ },
+ {
+ "x": 307.0469786508209,
+ "y": -61.47360220986034,
+ "z": 0.0
+ },
+ {
+ "x": 308.0532843758341,
+ "y": -61.47347958870439,
+ "z": 0.0
+ },
+ {
+ "x": 309.05959010084723,
+ "y": -61.47335696754845,
+ "z": 0.0
+ },
+ {
+ "x": 310.0658958258605,
+ "y": -61.47323434639251,
+ "z": 0.0
+ },
+ {
+ "x": 311.07220155087373,
+ "y": -61.47311172523656,
+ "z": 0.0
+ },
+ {
+ "x": 312.07850727588686,
+ "y": -61.47298910408062,
+ "z": 0.0
+ },
+ {
+ "x": 313.0848130009001,
+ "y": -61.47286648292468,
+ "z": 0.0
+ },
+ {
+ "x": 314.0911187259133,
+ "y": -61.472743861768734,
+ "z": 0.0
+ },
+ {
+ "x": 315.09742445092644,
+ "y": -61.47262124061279,
+ "z": 0.0
+ },
+ {
+ "x": 316.10373017593975,
+ "y": -61.47249861945685,
+ "z": 0.0
+ },
+ {
+ "x": 317.11003590095294,
+ "y": -61.472375998300905,
+ "z": 0.0
+ },
+ {
+ "x": 318.11634162596613,
+ "y": -61.47225337714496,
+ "z": 0.0
+ },
+ {
+ "x": 319.1226473509793,
+ "y": -61.47213075598901,
+ "z": 0.0
+ },
+ {
+ "x": 320.12895307599246,
+ "y": -61.47200813483307,
+ "z": 0.0
+ },
+ {
+ "x": 321.13525880100576,
+ "y": -61.47188551367713,
+ "z": 0.0
+ },
+ {
+ "x": 322.14156452601895,
+ "y": -61.471762892521184,
+ "z": 0.0
+ },
+ {
+ "x": 323.1478702510321,
+ "y": -61.47164027136524,
+ "z": 0.0
+ },
+ {
+ "x": 324.15417597604534,
+ "y": -61.4715176502093,
+ "z": 0.0
+ },
+ {
+ "x": 325.16048170105853,
+ "y": -61.471395029053355,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 52,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 167.16999546284472,
+ "y": -57.49064658023266,
+ "z": 0.0
+ },
+ {
+ "x": 168.17630118785794,
+ "y": -57.49052395907671,
+ "z": 0.0
+ },
+ {
+ "x": 169.18260691287114,
+ "y": -57.49040133792077,
+ "z": 0.0
+ },
+ {
+ "x": 170.18891263788436,
+ "y": -57.49027871676483,
+ "z": 0.0
+ },
+ {
+ "x": 171.19521836289758,
+ "y": -57.49015609560888,
+ "z": 0.0
+ },
+ {
+ "x": 172.2015240879108,
+ "y": -57.49003347445294,
+ "z": 0.0
+ },
+ {
+ "x": 173.207829812924,
+ "y": -57.489910853297,
+ "z": 0.0
+ },
+ {
+ "x": 174.2141355379372,
+ "y": -57.48978823214105,
+ "z": 0.0
+ },
+ {
+ "x": 175.22044126295043,
+ "y": -57.489665610985114,
+ "z": 0.0
+ },
+ {
+ "x": 176.22674698796362,
+ "y": -57.48954298982917,
+ "z": 0.0
+ },
+ {
+ "x": 177.23305271297684,
+ "y": -57.48942036867323,
+ "z": 0.0
+ },
+ {
+ "x": 178.23935843799006,
+ "y": -57.489297747517284,
+ "z": 0.0
+ },
+ {
+ "x": 179.24566416300325,
+ "y": -57.48917512636134,
+ "z": 0.0
+ },
+ {
+ "x": 180.25196988801648,
+ "y": -57.4890525052054,
+ "z": 0.0
+ },
+ {
+ "x": 181.2582756130297,
+ "y": -57.48892988404945,
+ "z": 0.0
+ },
+ {
+ "x": 182.26458133804292,
+ "y": -57.4888072628935,
+ "z": 0.0
+ },
+ {
+ "x": 183.2708870630561,
+ "y": -57.488684641737564,
+ "z": 0.0
+ },
+ {
+ "x": 184.27719278806933,
+ "y": -57.48856202058162,
+ "z": 0.0
+ },
+ {
+ "x": 185.28349851308255,
+ "y": -57.48843939942567,
+ "z": 0.0
+ },
+ {
+ "x": 186.28980423809574,
+ "y": -57.488316778269734,
+ "z": 0.0
+ },
+ {
+ "x": 187.29610996310896,
+ "y": -57.48819415711379,
+ "z": 0.0
+ },
+ {
+ "x": 188.30241568812218,
+ "y": -57.48807153595784,
+ "z": 0.0
+ },
+ {
+ "x": 189.3087214131354,
+ "y": -57.487948914801905,
+ "z": 0.0
+ },
+ {
+ "x": 190.31502713814862,
+ "y": -57.48782629364596,
+ "z": 0.0
+ },
+ {
+ "x": 191.3213328631618,
+ "y": -57.487703672490014,
+ "z": 0.0
+ },
+ {
+ "x": 192.32763858817503,
+ "y": -57.487581051334075,
+ "z": 0.0
+ },
+ {
+ "x": 193.33394431318825,
+ "y": -57.48745843017813,
+ "z": 0.0
+ },
+ {
+ "x": 194.34025003820145,
+ "y": -57.487335809022184,
+ "z": 0.0
+ },
+ {
+ "x": 195.34655576321467,
+ "y": -57.487213187866246,
+ "z": 0.0
+ },
+ {
+ "x": 196.3528614882279,
+ "y": -57.4870905667103,
+ "z": 0.0
+ },
+ {
+ "x": 197.3591672132411,
+ "y": -57.48696794555436,
+ "z": 0.0
+ },
+ {
+ "x": 198.36547293825433,
+ "y": -57.486845324398416,
+ "z": 0.0
+ },
+ {
+ "x": 199.37177866326752,
+ "y": -57.48672270324247,
+ "z": 0.0
+ },
+ {
+ "x": 200.37808438828074,
+ "y": -57.48660008208653,
+ "z": 0.0
+ },
+ {
+ "x": 201.38439011329396,
+ "y": -57.48647746093059,
+ "z": 0.0
+ },
+ {
+ "x": 202.39069583830715,
+ "y": -57.48635483977464,
+ "z": 0.0
+ },
+ {
+ "x": 203.39700156332037,
+ "y": -57.4862322186187,
+ "z": 0.0
+ },
+ {
+ "x": 204.40330728833356,
+ "y": -57.48610959746276,
+ "z": 0.0
+ },
+ {
+ "x": 205.40961301334679,
+ "y": -57.48598697630681,
+ "z": 0.0
+ },
+ {
+ "x": 206.41591873836,
+ "y": -57.48586435515087,
+ "z": 0.0
+ },
+ {
+ "x": 207.4222244633732,
+ "y": -57.48574173399493,
+ "z": 0.0
+ },
+ {
+ "x": 208.42853018838642,
+ "y": -57.48561911283898,
+ "z": 0.0
+ },
+ {
+ "x": 209.43483591339964,
+ "y": -57.48549649168304,
+ "z": 0.0
+ },
+ {
+ "x": 210.44114163841283,
+ "y": -57.48537387052709,
+ "z": 0.0
+ },
+ {
+ "x": 211.44744736342605,
+ "y": -57.485251249371146,
+ "z": 0.0
+ },
+ {
+ "x": 212.45375308843924,
+ "y": -57.48512862821521,
+ "z": 0.0
+ },
+ {
+ "x": 213.46005881345246,
+ "y": -57.48500600705926,
+ "z": 0.0
+ },
+ {
+ "x": 214.46636453846568,
+ "y": -57.484883385903316,
+ "z": 0.0
+ },
+ {
+ "x": 215.47267026347888,
+ "y": -57.48476076474738,
+ "z": 0.0
+ },
+ {
+ "x": 216.4789759884921,
+ "y": -57.48463814359143,
+ "z": 0.0
+ },
+ {
+ "x": 217.48528171350532,
+ "y": -57.484515522435494,
+ "z": 0.0
+ },
+ {
+ "x": 218.4915874385185,
+ "y": -57.48439290127955,
+ "z": 0.0
+ },
+ {
+ "x": 219.49789316353173,
+ "y": -57.4842702801236,
+ "z": 0.0
+ },
+ {
+ "x": 220.50419888854492,
+ "y": -57.484147658967665,
+ "z": 0.0
+ },
+ {
+ "x": 221.51050461355814,
+ "y": -57.48402503781172,
+ "z": 0.0
+ },
+ {
+ "x": 222.51681033857136,
+ "y": -57.48390241665577,
+ "z": 0.0
+ },
+ {
+ "x": 223.52311606358455,
+ "y": -57.483779795499835,
+ "z": 0.0
+ },
+ {
+ "x": 224.52942178859777,
+ "y": -57.48365717434389,
+ "z": 0.0
+ },
+ {
+ "x": 225.535727513611,
+ "y": -57.483534553187944,
+ "z": 0.0
+ },
+ {
+ "x": 226.54203323862419,
+ "y": -57.483411932032006,
+ "z": 0.0
+ },
+ {
+ "x": 227.5483389636374,
+ "y": -57.48328931087606,
+ "z": 0.0
+ },
+ {
+ "x": 228.5546446886506,
+ "y": -57.483166689720115,
+ "z": 0.0
+ },
+ {
+ "x": 229.56095041366382,
+ "y": -57.483044068564176,
+ "z": 0.0
+ },
+ {
+ "x": 230.56725613867704,
+ "y": -57.48292144740823,
+ "z": 0.0
+ },
+ {
+ "x": 231.57356186369023,
+ "y": -57.482798826252285,
+ "z": 0.0
+ },
+ {
+ "x": 232.57986758870345,
+ "y": -57.48267620509635,
+ "z": 0.0
+ },
+ {
+ "x": 233.58617331371667,
+ "y": -57.4825535839404,
+ "z": 0.0
+ },
+ {
+ "x": 234.5924790387299,
+ "y": -57.482430962784456,
+ "z": 0.0
+ },
+ {
+ "x": 235.5987847637431,
+ "y": -57.48230834162851,
+ "z": 0.0
+ },
+ {
+ "x": 236.60509048875633,
+ "y": -57.482185720472565,
+ "z": 0.0
+ },
+ {
+ "x": 237.61139621376955,
+ "y": -57.482063099316626,
+ "z": 0.0
+ },
+ {
+ "x": 238.61770193878274,
+ "y": -57.48194047816068,
+ "z": 0.0
+ },
+ {
+ "x": 239.62400766379596,
+ "y": -57.481817857004735,
+ "z": 0.0
+ },
+ {
+ "x": 240.63031338880918,
+ "y": -57.4816952358488,
+ "z": 0.0
+ },
+ {
+ "x": 241.6366191138224,
+ "y": -57.48157261469285,
+ "z": 0.0
+ },
+ {
+ "x": 242.64292483883563,
+ "y": -57.481449993536906,
+ "z": 0.0
+ },
+ {
+ "x": 243.64923056384885,
+ "y": -57.48132737238097,
+ "z": 0.0
+ },
+ {
+ "x": 244.65553628886207,
+ "y": -57.48120475122502,
+ "z": 0.0
+ },
+ {
+ "x": 245.6618420138753,
+ "y": -57.481082130069076,
+ "z": 0.0
+ },
+ {
+ "x": 246.6681477388885,
+ "y": -57.48095950891314,
+ "z": 0.0
+ },
+ {
+ "x": 247.6744534639017,
+ "y": -57.48083688775719,
+ "z": 0.0
+ },
+ {
+ "x": 248.68075918891492,
+ "y": -57.48071426660125,
+ "z": 0.0
+ },
+ {
+ "x": 249.68706491392814,
+ "y": -57.48059164544531,
+ "z": 0.0
+ },
+ {
+ "x": 250.69337063894136,
+ "y": -57.48046902428936,
+ "z": 0.0
+ },
+ {
+ "x": 251.69967636395458,
+ "y": -57.48034640313342,
+ "z": 0.0
+ },
+ {
+ "x": 252.7059820889678,
+ "y": -57.48022378197748,
+ "z": 0.0
+ },
+ {
+ "x": 253.71228781398102,
+ "y": -57.48010116082153,
+ "z": 0.0
+ },
+ {
+ "x": 254.71859353899424,
+ "y": -57.47997853966559,
+ "z": 0.0
+ },
+ {
+ "x": 255.72489926400746,
+ "y": -57.47985591850965,
+ "z": 0.0
+ },
+ {
+ "x": 256.7312049890207,
+ "y": -57.479733297353704,
+ "z": 0.0
+ },
+ {
+ "x": 257.7375107140339,
+ "y": -57.479610676197765,
+ "z": 0.0
+ },
+ {
+ "x": 258.7438164390471,
+ "y": -57.47948805504182,
+ "z": 0.0
+ },
+ {
+ "x": 259.7501221640603,
+ "y": -57.479365433885874,
+ "z": 0.0
+ },
+ {
+ "x": 260.75642788907356,
+ "y": -57.479242812729936,
+ "z": 0.0
+ },
+ {
+ "x": 261.76273361408676,
+ "y": -57.47912019157399,
+ "z": 0.0
+ },
+ {
+ "x": 262.76903933909995,
+ "y": -57.478997570418045,
+ "z": 0.0
+ },
+ {
+ "x": 263.7753450641132,
+ "y": -57.4788749492621,
+ "z": 0.0
+ },
+ {
+ "x": 264.7816507891264,
+ "y": -57.478752328106154,
+ "z": 0.0
+ },
+ {
+ "x": 265.78795651413964,
+ "y": -57.47862970695021,
+ "z": 0.0
+ },
+ {
+ "x": 266.79426223915283,
+ "y": -57.47850708579427,
+ "z": 0.0
+ },
+ {
+ "x": 267.800567964166,
+ "y": -57.478384464638324,
+ "z": 0.0
+ },
+ {
+ "x": 268.80687368917927,
+ "y": -57.47826184348238,
+ "z": 0.0
+ },
+ {
+ "x": 269.81317941419246,
+ "y": -57.47813922232644,
+ "z": 0.0
+ },
+ {
+ "x": 270.8194851392057,
+ "y": -57.478016601170495,
+ "z": 0.0
+ },
+ {
+ "x": 271.8257908642189,
+ "y": -57.47789398001455,
+ "z": 0.0
+ },
+ {
+ "x": 272.83209658923215,
+ "y": -57.47777135885861,
+ "z": 0.0
+ },
+ {
+ "x": 273.83840231424534,
+ "y": -57.477648737702665,
+ "z": 0.0
+ },
+ {
+ "x": 274.8447080392586,
+ "y": -57.47752611654672,
+ "z": 0.0
+ },
+ {
+ "x": 275.8510137642718,
+ "y": -57.47740349539078,
+ "z": 0.0
+ },
+ {
+ "x": 276.857319489285,
+ "y": -57.477280874234836,
+ "z": 0.0
+ },
+ {
+ "x": 277.8636252142982,
+ "y": -57.4771582530789,
+ "z": 0.0
+ },
+ {
+ "x": 278.8699309393114,
+ "y": -57.47703563192295,
+ "z": 0.0
+ },
+ {
+ "x": 279.87623666432467,
+ "y": -57.47691301076701,
+ "z": 0.0
+ },
+ {
+ "x": 280.88254238933786,
+ "y": -57.47679038961107,
+ "z": 0.0
+ },
+ {
+ "x": 281.8888481143511,
+ "y": -57.47666776845512,
+ "z": 0.0
+ },
+ {
+ "x": 282.8951538393643,
+ "y": -57.47654514729918,
+ "z": 0.0
+ },
+ {
+ "x": 283.90145956437755,
+ "y": -57.47642252614324,
+ "z": 0.0
+ },
+ {
+ "x": 284.90776528939074,
+ "y": -57.47629990498729,
+ "z": 0.0
+ },
+ {
+ "x": 285.91407101440393,
+ "y": -57.47617728383135,
+ "z": 0.0
+ },
+ {
+ "x": 286.9203767394172,
+ "y": -57.47605466267541,
+ "z": 0.0
+ },
+ {
+ "x": 287.92668246443037,
+ "y": -57.475932041519464,
+ "z": 0.0
+ },
+ {
+ "x": 288.9329881894436,
+ "y": -57.47580942036352,
+ "z": 0.0
+ },
+ {
+ "x": 289.9392939144568,
+ "y": -57.47568679920758,
+ "z": 0.0
+ },
+ {
+ "x": 290.94559963947006,
+ "y": -57.47556417805163,
+ "z": 0.0
+ },
+ {
+ "x": 291.95190536448325,
+ "y": -57.47544155689568,
+ "z": 0.0
+ },
+ {
+ "x": 292.9582110894965,
+ "y": -57.47531893573974,
+ "z": 0.0
+ },
+ {
+ "x": 293.9645168145097,
+ "y": -57.4751963145838,
+ "z": 0.0
+ },
+ {
+ "x": 294.9708225395229,
+ "y": -57.47507369342785,
+ "z": 0.0
+ },
+ {
+ "x": 295.97712826453613,
+ "y": -57.474951072271914,
+ "z": 0.0
+ },
+ {
+ "x": 296.9834339895493,
+ "y": -57.47482845111597,
+ "z": 0.0
+ },
+ {
+ "x": 297.9897397145625,
+ "y": -57.47470582996003,
+ "z": 0.0
+ },
+ {
+ "x": 298.9960454395757,
+ "y": -57.474583208804084,
+ "z": 0.0
+ },
+ {
+ "x": 300.00235116458896,
+ "y": -57.47446058764814,
+ "z": 0.0
+ },
+ {
+ "x": 301.00865688960215,
+ "y": -57.4743379664922,
+ "z": 0.0
+ },
+ {
+ "x": 302.01496261461534,
+ "y": -57.474215345336255,
+ "z": 0.0
+ },
+ {
+ "x": 303.02126833962853,
+ "y": -57.47409272418031,
+ "z": 0.0
+ },
+ {
+ "x": 304.0275740646417,
+ "y": -57.47397010302437,
+ "z": 0.0
+ },
+ {
+ "x": 305.033879789655,
+ "y": -57.473847481868425,
+ "z": 0.0
+ },
+ {
+ "x": 306.04018551466817,
+ "y": -57.47372486071248,
+ "z": 0.0
+ },
+ {
+ "x": 307.04649123968136,
+ "y": -57.47360223955654,
+ "z": 0.0
+ },
+ {
+ "x": 308.05279696469455,
+ "y": -57.473479618400596,
+ "z": 0.0
+ },
+ {
+ "x": 309.05910268970774,
+ "y": -57.47335699724465,
+ "z": 0.0
+ },
+ {
+ "x": 310.06540841472093,
+ "y": -57.47323437608871,
+ "z": 0.0
+ },
+ {
+ "x": 311.0717141397342,
+ "y": -57.473111754932766,
+ "z": 0.0
+ },
+ {
+ "x": 312.0780198647474,
+ "y": -57.47298913377682,
+ "z": 0.0
+ },
+ {
+ "x": 313.08432558976057,
+ "y": -57.47286651262088,
+ "z": 0.0
+ },
+ {
+ "x": 314.09063131477376,
+ "y": -57.47274389146494,
+ "z": 0.0
+ },
+ {
+ "x": 315.09693703978695,
+ "y": -57.47262127030899,
+ "z": 0.0
+ },
+ {
+ "x": 316.1032427648002,
+ "y": -57.47249864915305,
+ "z": 0.0
+ },
+ {
+ "x": 317.1095484898134,
+ "y": -57.47237602799711,
+ "z": 0.0
+ },
+ {
+ "x": 318.1158542148266,
+ "y": -57.47225340684116,
+ "z": 0.0
+ },
+ {
+ "x": 319.1221599398398,
+ "y": -57.472130785685216,
+ "z": 0.0
+ },
+ {
+ "x": 320.12846566485297,
+ "y": -57.47200816452927,
+ "z": 0.0
+ },
+ {
+ "x": 321.1347713898662,
+ "y": -57.47188554337333,
+ "z": 0.0
+ },
+ {
+ "x": 322.1410771148794,
+ "y": -57.47176292221739,
+ "z": 0.0
+ },
+ {
+ "x": 323.1473828398926,
+ "y": -57.47164030106144,
+ "z": 0.0
+ },
+ {
+ "x": 324.1536885649058,
+ "y": -57.4715176799055,
+ "z": 0.0
+ },
+ {
+ "x": 325.159994289919,
+ "y": -57.47139505874956,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 53,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 325.15975058434924,
+ "y": -55.47139507359766,
+ "z": 0.0
+ },
+ {
+ "x": 324.153444859336,
+ "y": -55.4715176947536,
+ "z": 0.0
+ },
+ {
+ "x": 323.14713913432286,
+ "y": -55.47164031590954,
+ "z": 0.0
+ },
+ {
+ "x": 322.1408334093096,
+ "y": -55.47176293706549,
+ "z": 0.0
+ },
+ {
+ "x": 321.1345276842965,
+ "y": -55.47188555822143,
+ "z": 0.0
+ },
+ {
+ "x": 320.1282219592832,
+ "y": -55.47200817937737,
+ "z": 0.0
+ },
+ {
+ "x": 319.12191623427,
+ "y": -55.47213080053332,
+ "z": 0.0
+ },
+ {
+ "x": 318.11561050925684,
+ "y": -55.47225342168926,
+ "z": 0.0
+ },
+ {
+ "x": 317.1093047842436,
+ "y": -55.47237604284521,
+ "z": 0.0
+ },
+ {
+ "x": 316.10299905923046,
+ "y": -55.47249866400115,
+ "z": 0.0
+ },
+ {
+ "x": 315.0966933342172,
+ "y": -55.47262128515709,
+ "z": 0.0
+ },
+ {
+ "x": 314.09038760920396,
+ "y": -55.47274390631304,
+ "z": 0.0
+ },
+ {
+ "x": 313.0840818841908,
+ "y": -55.47286652746898,
+ "z": 0.0
+ },
+ {
+ "x": 312.07777615917763,
+ "y": -55.47298914862492,
+ "z": 0.0
+ },
+ {
+ "x": 311.07147043416444,
+ "y": -55.47311176978087,
+ "z": 0.0
+ },
+ {
+ "x": 310.0651647091512,
+ "y": -55.47323439093681,
+ "z": 0.0
+ },
+ {
+ "x": 309.058858984138,
+ "y": -55.47335701209275,
+ "z": 0.0
+ },
+ {
+ "x": 308.0525532591248,
+ "y": -55.4734796332487,
+ "z": 0.0
+ },
+ {
+ "x": 307.04624753411156,
+ "y": -55.47360225440464,
+ "z": 0.0
+ },
+ {
+ "x": 306.0399418090984,
+ "y": -55.47372487556058,
+ "z": 0.0
+ },
+ {
+ "x": 305.0336360840852,
+ "y": -55.47384749671653,
+ "z": 0.0
+ },
+ {
+ "x": 304.0273303590719,
+ "y": -55.47397011787247,
+ "z": 0.0
+ },
+ {
+ "x": 303.0210246340588,
+ "y": -55.47409273902841,
+ "z": 0.0
+ },
+ {
+ "x": 302.01471890904554,
+ "y": -55.47421536018436,
+ "z": 0.0
+ },
+ {
+ "x": 301.0084131840324,
+ "y": -55.4743379813403,
+ "z": 0.0
+ },
+ {
+ "x": 300.0021074590192,
+ "y": -55.47446060249624,
+ "z": 0.0
+ },
+ {
+ "x": 298.9958017340059,
+ "y": -55.47458322365219,
+ "z": 0.0
+ },
+ {
+ "x": 297.9894960089928,
+ "y": -55.47470584480813,
+ "z": 0.0
+ },
+ {
+ "x": 296.9831902839796,
+ "y": -55.474828465964066,
+ "z": 0.0
+ },
+ {
+ "x": 295.9768845589664,
+ "y": -55.47495108712002,
+ "z": 0.0
+ },
+ {
+ "x": 294.97057883395314,
+ "y": -55.47507370827596,
+ "z": 0.0
+ },
+ {
+ "x": 293.9642731089399,
+ "y": -55.475196329431895,
+ "z": 0.0
+ },
+ {
+ "x": 292.95796738392676,
+ "y": -55.47531895058785,
+ "z": 0.0
+ },
+ {
+ "x": 291.9516616589135,
+ "y": -55.47544157174379,
+ "z": 0.0
+ },
+ {
+ "x": 290.94535593390026,
+ "y": -55.475564192899725,
+ "z": 0.0
+ },
+ {
+ "x": 289.939050208887,
+ "y": -55.47568681405568,
+ "z": 0.0
+ },
+ {
+ "x": 288.9327444838739,
+ "y": -55.475809435211616,
+ "z": 0.0
+ },
+ {
+ "x": 287.9264387588606,
+ "y": -55.47593205636757,
+ "z": 0.0
+ },
+ {
+ "x": 286.9201330338474,
+ "y": -55.47605467752351,
+ "z": 0.0
+ },
+ {
+ "x": 285.9138273088342,
+ "y": -55.476177298679445,
+ "z": 0.0
+ },
+ {
+ "x": 284.907521583821,
+ "y": -55.4762999198354,
+ "z": 0.0
+ },
+ {
+ "x": 283.90121585880775,
+ "y": -55.47642254099134,
+ "z": 0.0
+ },
+ {
+ "x": 282.89491013379455,
+ "y": -55.476545162147275,
+ "z": 0.0
+ },
+ {
+ "x": 281.88860440878136,
+ "y": -55.47666778330323,
+ "z": 0.0
+ },
+ {
+ "x": 280.8822986837681,
+ "y": -55.476790404459166,
+ "z": 0.0
+ },
+ {
+ "x": 279.8759929587549,
+ "y": -55.476913025615104,
+ "z": 0.0
+ },
+ {
+ "x": 278.8696872337416,
+ "y": -55.47703564677106,
+ "z": 0.0
+ },
+ {
+ "x": 277.8633815087285,
+ "y": -55.477158267926995,
+ "z": 0.0
+ },
+ {
+ "x": 276.85707578371523,
+ "y": -55.477280889082934,
+ "z": 0.0
+ },
+ {
+ "x": 275.850770058702,
+ "y": -55.47740351023889,
+ "z": 0.0
+ },
+ {
+ "x": 274.84446433368885,
+ "y": -55.477526131394825,
+ "z": 0.0
+ },
+ {
+ "x": 273.8381586086756,
+ "y": -55.47764875255076,
+ "z": 0.0
+ },
+ {
+ "x": 272.83185288366235,
+ "y": -55.477771373706716,
+ "z": 0.0
+ },
+ {
+ "x": 271.82554715864916,
+ "y": -55.477893994862654,
+ "z": 0.0
+ },
+ {
+ "x": 270.81924143363597,
+ "y": -55.47801661601859,
+ "z": 0.0
+ },
+ {
+ "x": 269.8129357086227,
+ "y": -55.478139237174545,
+ "z": 0.0
+ },
+ {
+ "x": 268.8066299836095,
+ "y": -55.478261858330484,
+ "z": 0.0
+ },
+ {
+ "x": 267.8003242585962,
+ "y": -55.47838447948642,
+ "z": 0.0
+ },
+ {
+ "x": 266.7940185335831,
+ "y": -55.478507100642375,
+ "z": 0.0
+ },
+ {
+ "x": 265.7877128085699,
+ "y": -55.47862972179831,
+ "z": 0.0
+ },
+ {
+ "x": 264.7814070835566,
+ "y": -55.47875234295425,
+ "z": 0.0
+ },
+ {
+ "x": 263.77510135854345,
+ "y": -55.478874964110204,
+ "z": 0.0
+ },
+ {
+ "x": 262.7687956335302,
+ "y": -55.47899758526614,
+ "z": 0.0
+ },
+ {
+ "x": 261.76248990851695,
+ "y": -55.479120206422095,
+ "z": 0.0
+ },
+ {
+ "x": 260.7561841835038,
+ "y": -55.479242827578034,
+ "z": 0.0
+ },
+ {
+ "x": 259.74987845849057,
+ "y": -55.47936544873397,
+ "z": 0.0
+ },
+ {
+ "x": 258.7435727334773,
+ "y": -55.479488069889925,
+ "z": 0.0
+ },
+ {
+ "x": 257.7372670084641,
+ "y": -55.47961069104586,
+ "z": 0.0
+ },
+ {
+ "x": 256.73096128345094,
+ "y": -55.4797333122018,
+ "z": 0.0
+ },
+ {
+ "x": 255.7246555584377,
+ "y": -55.479855933357754,
+ "z": 0.0
+ },
+ {
+ "x": 254.7183498334245,
+ "y": -55.47997855451369,
+ "z": 0.0
+ },
+ {
+ "x": 253.71204410841125,
+ "y": -55.48010117566963,
+ "z": 0.0
+ },
+ {
+ "x": 252.70573838339806,
+ "y": -55.480223796825584,
+ "z": 0.0
+ },
+ {
+ "x": 251.69943265838484,
+ "y": -55.48034641798152,
+ "z": 0.0
+ },
+ {
+ "x": 250.69312693337162,
+ "y": -55.48046903913746,
+ "z": 0.0
+ },
+ {
+ "x": 249.68682120835837,
+ "y": -55.48059166029341,
+ "z": 0.0
+ },
+ {
+ "x": 248.68051548334518,
+ "y": -55.48071428144935,
+ "z": 0.0
+ },
+ {
+ "x": 247.67420975833193,
+ "y": -55.48083690260529,
+ "z": 0.0
+ },
+ {
+ "x": 246.66790403331873,
+ "y": -55.48095952376124,
+ "z": 0.0
+ },
+ {
+ "x": 245.66159830830554,
+ "y": -55.48108214491718,
+ "z": 0.0
+ },
+ {
+ "x": 244.6552925832923,
+ "y": -55.48120476607312,
+ "z": 0.0
+ },
+ {
+ "x": 243.6489868582791,
+ "y": -55.48132738722907,
+ "z": 0.0
+ },
+ {
+ "x": 242.64268113326588,
+ "y": -55.48145000838501,
+ "z": 0.0
+ },
+ {
+ "x": 241.63637540825266,
+ "y": -55.48157262954095,
+ "z": 0.0
+ },
+ {
+ "x": 240.6300696832394,
+ "y": -55.4816952506969,
+ "z": 0.0
+ },
+ {
+ "x": 239.62376395822622,
+ "y": -55.48181787185284,
+ "z": 0.0
+ },
+ {
+ "x": 238.61745823321297,
+ "y": -55.48194049300878,
+ "z": 0.0
+ },
+ {
+ "x": 237.61115250819978,
+ "y": -55.48206311416473,
+ "z": 0.0
+ },
+ {
+ "x": 236.6048467831866,
+ "y": -55.48218573532067,
+ "z": 0.0
+ },
+ {
+ "x": 235.59854105817334,
+ "y": -55.48230835647661,
+ "z": 0.0
+ },
+ {
+ "x": 234.59223533316015,
+ "y": -55.48243097763256,
+ "z": 0.0
+ },
+ {
+ "x": 233.5859296081469,
+ "y": -55.4825535987885,
+ "z": 0.0
+ },
+ {
+ "x": 232.5796238831337,
+ "y": -55.48267621994445,
+ "z": 0.0
+ },
+ {
+ "x": 231.5733181581205,
+ "y": -55.48279884110039,
+ "z": 0.0
+ },
+ {
+ "x": 230.56701243310727,
+ "y": -55.48292146225633,
+ "z": 0.0
+ },
+ {
+ "x": 229.56070670809407,
+ "y": -55.48304408341228,
+ "z": 0.0
+ },
+ {
+ "x": 228.55440098308085,
+ "y": -55.48316670456822,
+ "z": 0.0
+ },
+ {
+ "x": 227.54809525806763,
+ "y": -55.48328932572416,
+ "z": 0.0
+ },
+ {
+ "x": 226.54178953305444,
+ "y": -55.48341194688011,
+ "z": 0.0
+ },
+ {
+ "x": 225.53548380804125,
+ "y": -55.48353456803605,
+ "z": 0.0
+ },
+ {
+ "x": 224.529178083028,
+ "y": -55.48365718919199,
+ "z": 0.0
+ },
+ {
+ "x": 223.5228723580148,
+ "y": -55.48377981034794,
+ "z": 0.0
+ },
+ {
+ "x": 222.51656663300162,
+ "y": -55.48390243150388,
+ "z": 0.0
+ },
+ {
+ "x": 221.51026090798837,
+ "y": -55.48402505265982,
+ "z": 0.0
+ },
+ {
+ "x": 220.50395518297518,
+ "y": -55.48414767381577,
+ "z": 0.0
+ },
+ {
+ "x": 219.49764945796198,
+ "y": -55.48427029497171,
+ "z": 0.0
+ },
+ {
+ "x": 218.49134373294874,
+ "y": -55.484392916127646,
+ "z": 0.0
+ },
+ {
+ "x": 217.48503800793554,
+ "y": -55.4845155372836,
+ "z": 0.0
+ },
+ {
+ "x": 216.47873228292235,
+ "y": -55.48463815843954,
+ "z": 0.0
+ },
+ {
+ "x": 215.4724265579091,
+ "y": -55.484760779595476,
+ "z": 0.0
+ },
+ {
+ "x": 214.46612083289594,
+ "y": -55.484883400751414,
+ "z": 0.0
+ },
+ {
+ "x": 213.45981510788272,
+ "y": -55.48500602190737,
+ "z": 0.0
+ },
+ {
+ "x": 212.45350938286947,
+ "y": -55.485128643063305,
+ "z": 0.0
+ },
+ {
+ "x": 211.4472036578563,
+ "y": -55.485251264219244,
+ "z": 0.0
+ },
+ {
+ "x": 210.4408979328431,
+ "y": -55.485373885375196,
+ "z": 0.0
+ },
+ {
+ "x": 209.4345922078299,
+ "y": -55.485496506531135,
+ "z": 0.0
+ },
+ {
+ "x": 208.42828648281665,
+ "y": -55.48561912768709,
+ "z": 0.0
+ },
+ {
+ "x": 207.42198075780345,
+ "y": -55.485741748843026,
+ "z": 0.0
+ },
+ {
+ "x": 206.41567503279026,
+ "y": -55.48586436999898,
+ "z": 0.0
+ },
+ {
+ "x": 205.40936930777704,
+ "y": -55.48598699115492,
+ "z": 0.0
+ },
+ {
+ "x": 204.40306358276382,
+ "y": -55.486109612310855,
+ "z": 0.0
+ },
+ {
+ "x": 203.39675785775063,
+ "y": -55.48623223346681,
+ "z": 0.0
+ },
+ {
+ "x": 202.3904521327374,
+ "y": -55.486354854622746,
+ "z": 0.0
+ },
+ {
+ "x": 201.3841464077242,
+ "y": -55.486477475778685,
+ "z": 0.0
+ },
+ {
+ "x": 200.377840682711,
+ "y": -55.48660009693464,
+ "z": 0.0
+ },
+ {
+ "x": 199.37153495769778,
+ "y": -55.486722718090576,
+ "z": 0.0
+ },
+ {
+ "x": 198.36522923268456,
+ "y": -55.486845339246514,
+ "z": 0.0
+ },
+ {
+ "x": 197.35892350767136,
+ "y": -55.48696796040247,
+ "z": 0.0
+ },
+ {
+ "x": 196.35261778265814,
+ "y": -55.487090581558405,
+ "z": 0.0
+ },
+ {
+ "x": 195.34631205764492,
+ "y": -55.487213202714344,
+ "z": 0.0
+ },
+ {
+ "x": 194.3400063326317,
+ "y": -55.48733582387028,
+ "z": 0.0
+ },
+ {
+ "x": 193.33370060761848,
+ "y": -55.487458445026235,
+ "z": 0.0
+ },
+ {
+ "x": 192.3273948826053,
+ "y": -55.48758106618217,
+ "z": 0.0
+ },
+ {
+ "x": 191.32108915759207,
+ "y": -55.48770368733811,
+ "z": 0.0
+ },
+ {
+ "x": 190.31478343257885,
+ "y": -55.487826308494064,
+ "z": 0.0
+ },
+ {
+ "x": 189.30847770756566,
+ "y": -55.48794892965,
+ "z": 0.0
+ },
+ {
+ "x": 188.30217198255244,
+ "y": -55.48807155080594,
+ "z": 0.0
+ },
+ {
+ "x": 187.29586625753922,
+ "y": -55.488194171961894,
+ "z": 0.0
+ },
+ {
+ "x": 186.28956053252597,
+ "y": -55.48831679311783,
+ "z": 0.0
+ },
+ {
+ "x": 185.2832548075128,
+ "y": -55.48843941427377,
+ "z": 0.0
+ },
+ {
+ "x": 184.27694908249958,
+ "y": -55.48856203542972,
+ "z": 0.0
+ },
+ {
+ "x": 183.27064335748634,
+ "y": -55.48868465658566,
+ "z": 0.0
+ },
+ {
+ "x": 182.26433763247317,
+ "y": -55.4888072777416,
+ "z": 0.0
+ },
+ {
+ "x": 181.25803190745995,
+ "y": -55.48892989889755,
+ "z": 0.0
+ },
+ {
+ "x": 180.2517261824467,
+ "y": -55.489052520053505,
+ "z": 0.0
+ },
+ {
+ "x": 179.2454204574335,
+ "y": -55.489175141209444,
+ "z": 0.0
+ },
+ {
+ "x": 178.23911473242032,
+ "y": -55.48929776236538,
+ "z": 0.0
+ },
+ {
+ "x": 177.23280900740707,
+ "y": -55.489420383521335,
+ "z": 0.0
+ },
+ {
+ "x": 176.22650328239388,
+ "y": -55.48954300467727,
+ "z": 0.0
+ },
+ {
+ "x": 175.2201975573807,
+ "y": -55.48966562583321,
+ "z": 0.0
+ },
+ {
+ "x": 174.21389183236747,
+ "y": -55.48978824698915,
+ "z": 0.0
+ },
+ {
+ "x": 173.20758610735425,
+ "y": -55.4899108681451,
+ "z": 0.0
+ },
+ {
+ "x": 172.20128038234105,
+ "y": -55.49003348930104,
+ "z": 0.0
+ },
+ {
+ "x": 171.19497465732783,
+ "y": -55.49015611045698,
+ "z": 0.0
+ },
+ {
+ "x": 170.1886689323146,
+ "y": -55.49027873161293,
+ "z": 0.0
+ },
+ {
+ "x": 169.18236320730136,
+ "y": -55.49040135276887,
+ "z": 0.0
+ },
+ {
+ "x": 168.1760574822882,
+ "y": -55.49052397392481,
+ "z": 0.0
+ },
+ {
+ "x": 167.16975175727498,
+ "y": -55.49064659508076,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 54,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 167.17023916841447,
+ "y": -59.49064656538455,
+ "z": 0.0
+ },
+ {
+ "x": 168.1765448934277,
+ "y": -59.49052394422861,
+ "z": 0.0
+ },
+ {
+ "x": 169.1828506184409,
+ "y": -59.490401323072675,
+ "z": 0.0
+ },
+ {
+ "x": 170.1891563434541,
+ "y": -59.49027870191672,
+ "z": 0.0
+ },
+ {
+ "x": 171.19546206846732,
+ "y": -59.490156080760784,
+ "z": 0.0
+ },
+ {
+ "x": 172.20176779348054,
+ "y": -59.490033459604845,
+ "z": 0.0
+ },
+ {
+ "x": 173.20807351849373,
+ "y": -59.48991083844889,
+ "z": 0.0
+ },
+ {
+ "x": 174.21437924350695,
+ "y": -59.489788217292954,
+ "z": 0.0
+ },
+ {
+ "x": 175.22068496852017,
+ "y": -59.489665596137016,
+ "z": 0.0
+ },
+ {
+ "x": 176.22699069353337,
+ "y": -59.48954297498106,
+ "z": 0.0
+ },
+ {
+ "x": 177.23329641854662,
+ "y": -59.489420353825125,
+ "z": 0.0
+ },
+ {
+ "x": 178.2396021435598,
+ "y": -59.489297732669186,
+ "z": 0.0
+ },
+ {
+ "x": 179.245907868573,
+ "y": -59.489175111513234,
+ "z": 0.0
+ },
+ {
+ "x": 180.25221359358625,
+ "y": -59.489052490357295,
+ "z": 0.0
+ },
+ {
+ "x": 181.25851931859944,
+ "y": -59.48892986920134,
+ "z": 0.0
+ },
+ {
+ "x": 182.26482504361266,
+ "y": -59.488807248045404,
+ "z": 0.0
+ },
+ {
+ "x": 183.27113076862588,
+ "y": -59.488684626889466,
+ "z": 0.0
+ },
+ {
+ "x": 184.27743649363907,
+ "y": -59.48856200573351,
+ "z": 0.0
+ },
+ {
+ "x": 185.2837422186523,
+ "y": -59.488439384577575,
+ "z": 0.0
+ },
+ {
+ "x": 186.2900479436655,
+ "y": -59.488316763421636,
+ "z": 0.0
+ },
+ {
+ "x": 187.2963536686787,
+ "y": -59.488194142265684,
+ "z": 0.0
+ },
+ {
+ "x": 188.30265939369193,
+ "y": -59.488071521109745,
+ "z": 0.0
+ },
+ {
+ "x": 189.30896511870515,
+ "y": -59.48794889995381,
+ "z": 0.0
+ },
+ {
+ "x": 190.3152708437184,
+ "y": -59.487826278797854,
+ "z": 0.0
+ },
+ {
+ "x": 191.32157656873156,
+ "y": -59.487703657641916,
+ "z": 0.0
+ },
+ {
+ "x": 192.32788229374478,
+ "y": -59.48758103648598,
+ "z": 0.0
+ },
+ {
+ "x": 193.33418801875803,
+ "y": -59.487458415330025,
+ "z": 0.0
+ },
+ {
+ "x": 194.3404937437712,
+ "y": -59.487335794174086,
+ "z": 0.0
+ },
+ {
+ "x": 195.3467994687844,
+ "y": -59.48721317301815,
+ "z": 0.0
+ },
+ {
+ "x": 196.35310519379763,
+ "y": -59.487090551862195,
+ "z": 0.0
+ },
+ {
+ "x": 197.35941091881085,
+ "y": -59.48696793070626,
+ "z": 0.0
+ },
+ {
+ "x": 198.3657166438241,
+ "y": -59.48684530955032,
+ "z": 0.0
+ },
+ {
+ "x": 199.37202236883726,
+ "y": -59.486722688394366,
+ "z": 0.0
+ },
+ {
+ "x": 200.37832809385048,
+ "y": -59.48660006723843,
+ "z": 0.0
+ },
+ {
+ "x": 201.38463381886373,
+ "y": -59.48647744608249,
+ "z": 0.0
+ },
+ {
+ "x": 202.3909395438769,
+ "y": -59.486354824926536,
+ "z": 0.0
+ },
+ {
+ "x": 203.39724526889012,
+ "y": -59.4862322037706,
+ "z": 0.0
+ },
+ {
+ "x": 204.4035509939033,
+ "y": -59.48610958261466,
+ "z": 0.0
+ },
+ {
+ "x": 205.40985671891653,
+ "y": -59.48598696145871,
+ "z": 0.0
+ },
+ {
+ "x": 206.41616244392975,
+ "y": -59.48586434030277,
+ "z": 0.0
+ },
+ {
+ "x": 207.42246816894294,
+ "y": -59.48574171914683,
+ "z": 0.0
+ },
+ {
+ "x": 208.4287738939562,
+ "y": -59.48561909799088,
+ "z": 0.0
+ },
+ {
+ "x": 209.43507961896938,
+ "y": -59.48549647683494,
+ "z": 0.0
+ },
+ {
+ "x": 210.44138534398257,
+ "y": -59.485373855678986,
+ "z": 0.0
+ },
+ {
+ "x": 211.4476910689958,
+ "y": -59.48525123452305,
+ "z": 0.0
+ },
+ {
+ "x": 212.45399679400902,
+ "y": -59.48512861336711,
+ "z": 0.0
+ },
+ {
+ "x": 213.4603025190222,
+ "y": -59.48500599221116,
+ "z": 0.0
+ },
+ {
+ "x": 214.46660824403543,
+ "y": -59.48488337105522,
+ "z": 0.0
+ },
+ {
+ "x": 215.47291396904865,
+ "y": -59.48476074989928,
+ "z": 0.0
+ },
+ {
+ "x": 216.47921969406184,
+ "y": -59.48463812874333,
+ "z": 0.0
+ },
+ {
+ "x": 217.4855254190751,
+ "y": -59.48451550758739,
+ "z": 0.0
+ },
+ {
+ "x": 218.49183114408828,
+ "y": -59.48439288643145,
+ "z": 0.0
+ },
+ {
+ "x": 219.49813686910147,
+ "y": -59.4842702652755,
+ "z": 0.0
+ },
+ {
+ "x": 220.50444259411466,
+ "y": -59.48414764411956,
+ "z": 0.0
+ },
+ {
+ "x": 221.5107483191279,
+ "y": -59.48402502296362,
+ "z": 0.0
+ },
+ {
+ "x": 222.5170540441411,
+ "y": -59.48390240180767,
+ "z": 0.0
+ },
+ {
+ "x": 223.5233597691543,
+ "y": -59.48377978065173,
+ "z": 0.0
+ },
+ {
+ "x": 224.52966549416755,
+ "y": -59.48365715949579,
+ "z": 0.0
+ },
+ {
+ "x": 225.53597121918074,
+ "y": -59.48353453833984,
+ "z": 0.0
+ },
+ {
+ "x": 226.54227694419393,
+ "y": -59.4834119171839,
+ "z": 0.0
+ },
+ {
+ "x": 227.54858266920718,
+ "y": -59.48328929602796,
+ "z": 0.0
+ },
+ {
+ "x": 228.55488839422034,
+ "y": -59.48316667487201,
+ "z": 0.0
+ },
+ {
+ "x": 229.56119411923356,
+ "y": -59.48304405371607,
+ "z": 0.0
+ },
+ {
+ "x": 230.5674998442468,
+ "y": -59.48292143256013,
+ "z": 0.0
+ },
+ {
+ "x": 231.57380556925997,
+ "y": -59.48279881140418,
+ "z": 0.0
+ },
+ {
+ "x": 232.5801112942732,
+ "y": -59.48267619024824,
+ "z": 0.0
+ },
+ {
+ "x": 233.58641701928644,
+ "y": -59.4825535690923,
+ "z": 0.0
+ },
+ {
+ "x": 234.59272274429964,
+ "y": -59.48243094793635,
+ "z": 0.0
+ },
+ {
+ "x": 235.59902846931288,
+ "y": -59.48230832678041,
+ "z": 0.0
+ },
+ {
+ "x": 236.60533419432608,
+ "y": -59.48218570562446,
+ "z": 0.0
+ },
+ {
+ "x": 237.61163991933932,
+ "y": -59.48206308446852,
+ "z": 0.0
+ },
+ {
+ "x": 238.61794564435252,
+ "y": -59.48194046331258,
+ "z": 0.0
+ },
+ {
+ "x": 239.6242513693657,
+ "y": -59.48181784215663,
+ "z": 0.0
+ },
+ {
+ "x": 240.63055709437896,
+ "y": -59.48169522100069,
+ "z": 0.0
+ },
+ {
+ "x": 241.63686281939215,
+ "y": -59.48157259984475,
+ "z": 0.0
+ },
+ {
+ "x": 242.64316854440537,
+ "y": -59.4814499786888,
+ "z": 0.0
+ },
+ {
+ "x": 243.6494742694186,
+ "y": -59.48132735753286,
+ "z": 0.0
+ },
+ {
+ "x": 244.65577999443184,
+ "y": -59.481204736376924,
+ "z": 0.0
+ },
+ {
+ "x": 245.66208571944503,
+ "y": -59.48108211522097,
+ "z": 0.0
+ },
+ {
+ "x": 246.66839144445828,
+ "y": -59.48095949406503,
+ "z": 0.0
+ },
+ {
+ "x": 247.67469716947147,
+ "y": -59.480836872909094,
+ "z": 0.0
+ },
+ {
+ "x": 248.68100289448466,
+ "y": -59.48071425175314,
+ "z": 0.0
+ },
+ {
+ "x": 249.6873086194979,
+ "y": -59.4805916305972,
+ "z": 0.0
+ },
+ {
+ "x": 250.6936143445111,
+ "y": -59.480469009441265,
+ "z": 0.0
+ },
+ {
+ "x": 251.69992006952432,
+ "y": -59.48034638828531,
+ "z": 0.0
+ },
+ {
+ "x": 252.70622579453754,
+ "y": -59.480223767129374,
+ "z": 0.0
+ },
+ {
+ "x": 253.7125315195508,
+ "y": -59.480101145973435,
+ "z": 0.0
+ },
+ {
+ "x": 254.71883724456399,
+ "y": -59.47997852481748,
+ "z": 0.0
+ },
+ {
+ "x": 255.72514296957723,
+ "y": -59.479855903661544,
+ "z": 0.0
+ },
+ {
+ "x": 256.7314486945904,
+ "y": -59.479733282505606,
+ "z": 0.0
+ },
+ {
+ "x": 257.7377544196037,
+ "y": -59.47961066134967,
+ "z": 0.0
+ },
+ {
+ "x": 258.7440601446169,
+ "y": -59.479488040193715,
+ "z": 0.0
+ },
+ {
+ "x": 259.75036586963006,
+ "y": -59.47936541903778,
+ "z": 0.0
+ },
+ {
+ "x": 260.7566715946433,
+ "y": -59.47924279788184,
+ "z": 0.0
+ },
+ {
+ "x": 261.76297731965656,
+ "y": -59.479120176725885,
+ "z": 0.0
+ },
+ {
+ "x": 262.7692830446697,
+ "y": -59.47899755556995,
+ "z": 0.0
+ },
+ {
+ "x": 263.77558876968294,
+ "y": -59.478874934413994,
+ "z": 0.0
+ },
+ {
+ "x": 264.7818944946962,
+ "y": -59.478752313258056,
+ "z": 0.0
+ },
+ {
+ "x": 265.7882002197094,
+ "y": -59.4786296921021,
+ "z": 0.0
+ },
+ {
+ "x": 266.7945059447226,
+ "y": -59.478507070946165,
+ "z": 0.0
+ },
+ {
+ "x": 267.8008116697358,
+ "y": -59.47838444979023,
+ "z": 0.0
+ },
+ {
+ "x": 268.807117394749,
+ "y": -59.478261828634274,
+ "z": 0.0
+ },
+ {
+ "x": 269.8134231197622,
+ "y": -59.478139207478335,
+ "z": 0.0
+ },
+ {
+ "x": 270.81972884477545,
+ "y": -59.4780165863224,
+ "z": 0.0
+ },
+ {
+ "x": 271.82603456978865,
+ "y": -59.477893965166444,
+ "z": 0.0
+ },
+ {
+ "x": 272.83234029480195,
+ "y": -59.477771344010506,
+ "z": 0.0
+ },
+ {
+ "x": 273.8386460198151,
+ "y": -59.47764872285457,
+ "z": 0.0
+ },
+ {
+ "x": 274.84495174482834,
+ "y": -59.477526101698615,
+ "z": 0.0
+ },
+ {
+ "x": 275.8512574698416,
+ "y": -59.47740348054268,
+ "z": 0.0
+ },
+ {
+ "x": 276.8575631948547,
+ "y": -59.47728085938674,
+ "z": 0.0
+ },
+ {
+ "x": 277.86386891986797,
+ "y": -59.4771582382308,
+ "z": 0.0
+ },
+ {
+ "x": 278.8701746448812,
+ "y": -59.47703561707485,
+ "z": 0.0
+ },
+ {
+ "x": 279.8764803698944,
+ "y": -59.47691299591891,
+ "z": 0.0
+ },
+ {
+ "x": 280.8827860949076,
+ "y": -59.47679037476297,
+ "z": 0.0
+ },
+ {
+ "x": 281.88909181992085,
+ "y": -59.47666775360702,
+ "z": 0.0
+ },
+ {
+ "x": 282.89539754493404,
+ "y": -59.47654513245108,
+ "z": 0.0
+ },
+ {
+ "x": 283.90170326994735,
+ "y": -59.47642251129514,
+ "z": 0.0
+ },
+ {
+ "x": 284.9080089949605,
+ "y": -59.47629989013919,
+ "z": 0.0
+ },
+ {
+ "x": 285.9143147199737,
+ "y": -59.47617726898325,
+ "z": 0.0
+ },
+ {
+ "x": 286.920620444987,
+ "y": -59.47605464782731,
+ "z": 0.0
+ },
+ {
+ "x": 287.9269261700001,
+ "y": -59.47593202667136,
+ "z": 0.0
+ },
+ {
+ "x": 288.93323189501336,
+ "y": -59.47580940551542,
+ "z": 0.0
+ },
+ {
+ "x": 289.9395376200266,
+ "y": -59.47568678435948,
+ "z": 0.0
+ },
+ {
+ "x": 290.94584334503986,
+ "y": -59.47556416320353,
+ "z": 0.0
+ },
+ {
+ "x": 291.952149070053,
+ "y": -59.47544154204758,
+ "z": 0.0
+ },
+ {
+ "x": 292.95845479506625,
+ "y": -59.47531892089164,
+ "z": 0.0
+ },
+ {
+ "x": 293.9647605200795,
+ "y": -59.4751962997357,
+ "z": 0.0
+ },
+ {
+ "x": 294.97106624509263,
+ "y": -59.47507367857975,
+ "z": 0.0
+ },
+ {
+ "x": 295.9773719701059,
+ "y": -59.47495105742381,
+ "z": 0.0
+ },
+ {
+ "x": 296.98367769511907,
+ "y": -59.47482843626787,
+ "z": 0.0
+ },
+ {
+ "x": 297.98998342013226,
+ "y": -59.47470581511193,
+ "z": 0.0
+ },
+ {
+ "x": 298.9962891451455,
+ "y": -59.47458319395598,
+ "z": 0.0
+ },
+ {
+ "x": 300.0025948701587,
+ "y": -59.47446057280004,
+ "z": 0.0
+ },
+ {
+ "x": 301.0089005951719,
+ "y": -59.4743379516441,
+ "z": 0.0
+ },
+ {
+ "x": 302.01520632018514,
+ "y": -59.47421533048815,
+ "z": 0.0
+ },
+ {
+ "x": 303.0215120451983,
+ "y": -59.47409270933221,
+ "z": 0.0
+ },
+ {
+ "x": 304.0278177702115,
+ "y": -59.47397008817627,
+ "z": 0.0
+ },
+ {
+ "x": 305.0341234952248,
+ "y": -59.47384746702032,
+ "z": 0.0
+ },
+ {
+ "x": 306.0404292202379,
+ "y": -59.47372484586438,
+ "z": 0.0
+ },
+ {
+ "x": 307.04673494525116,
+ "y": -59.47360222470844,
+ "z": 0.0
+ },
+ {
+ "x": 308.0530406702643,
+ "y": -59.47347960355249,
+ "z": 0.0
+ },
+ {
+ "x": 309.0593463952775,
+ "y": -59.47335698239655,
+ "z": 0.0
+ },
+ {
+ "x": 310.0656521202907,
+ "y": -59.473234361240614,
+ "z": 0.0
+ },
+ {
+ "x": 311.0719578453039,
+ "y": -59.47311174008466,
+ "z": 0.0
+ },
+ {
+ "x": 312.0782635703171,
+ "y": -59.47298911892872,
+ "z": 0.0
+ },
+ {
+ "x": 313.0845692953303,
+ "y": -59.472866497772785,
+ "z": 0.0
+ },
+ {
+ "x": 314.09087502034356,
+ "y": -59.47274387661683,
+ "z": 0.0
+ },
+ {
+ "x": 315.0971807453567,
+ "y": -59.47262125546089,
+ "z": 0.0
+ },
+ {
+ "x": 316.10348647036994,
+ "y": -59.472498634304955,
+ "z": 0.0
+ },
+ {
+ "x": 317.1097921953832,
+ "y": -59.472376013149,
+ "z": 0.0
+ },
+ {
+ "x": 318.1160979203963,
+ "y": -59.472253391993064,
+ "z": 0.0
+ },
+ {
+ "x": 319.1224036454096,
+ "y": -59.47213077083711,
+ "z": 0.0
+ },
+ {
+ "x": 320.1287093704227,
+ "y": -59.47200814968117,
+ "z": 0.0
+ },
+ {
+ "x": 321.13501509543596,
+ "y": -59.471885528525235,
+ "z": 0.0
+ },
+ {
+ "x": 322.1413208204492,
+ "y": -59.47176290736928,
+ "z": 0.0
+ },
+ {
+ "x": 323.14762654546234,
+ "y": -59.47164028621334,
+ "z": 0.0
+ },
+ {
+ "x": 324.1539322704756,
+ "y": -59.471517665057405,
+ "z": 0.0
+ },
+ {
+ "x": 325.1602379954887,
+ "y": -59.47139504390145,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 55,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 398.37974812672553,
+ "y": -9.804292031687147,
+ "z": 0.0
+ },
+ {
+ "x": 398.36780240926834,
+ "y": -8.75089642316067,
+ "z": 0.0
+ },
+ {
+ "x": 398.2768958325799,
+ "y": -7.442858360963409,
+ "z": 0.0
+ },
+ {
+ "x": 397.9900120694231,
+ "y": -5.900146342483256,
+ "z": 0.0
+ },
+ {
+ "x": 397.5637979654414,
+ "y": -4.495994891100093,
+ "z": 0.0
+ },
+ {
+ "x": 396.99328823353665,
+ "y": -3.1428683346251147,
+ "z": 0.0
+ },
+ {
+ "x": 396.2283922371167,
+ "y": -1.799105281797945,
+ "z": 0.0
+ },
+ {
+ "x": 395.2664453280994,
+ "y": -0.5316745673262111,
+ "z": 0.0
+ },
+ {
+ "x": 394.24725845204534,
+ "y": 0.534257017414824,
+ "z": 0.0
+ },
+ {
+ "x": 393.11216551907125,
+ "y": 1.4903391899191767,
+ "z": 0.0
+ },
+ {
+ "x": 391.8245853286279,
+ "y": 2.3367176074276426,
+ "z": 0.0
+ },
+ {
+ "x": 390.3361931478448,
+ "y": 3.0382856252769592,
+ "z": 0.0
+ },
+ {
+ "x": 388.92224985890766,
+ "y": 3.5068677477098023,
+ "z": 0.0
+ },
+ {
+ "x": 387.4654183079017,
+ "y": 3.817648145243075,
+ "z": 0.0
+ },
+ {
+ "x": 385.96655987486594,
+ "y": 3.964678690223338,
+ "z": 0.0
+ },
+ {
+ "x": 384.598648710693,
+ "y": 3.9799906424916998,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 56,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 384.58134396508825,
+ "y": -4.01999064159763,
+ "z": 0.0
+ },
+ {
+ "x": 385.3210700215233,
+ "y": -4.009237715736265,
+ "z": 0.0
+ },
+ {
+ "x": 385.92311669882133,
+ "y": -4.032275787294617,
+ "z": 0.0
+ },
+ {
+ "x": 386.5289887266621,
+ "y": -4.1267618708191725,
+ "z": 0.0
+ },
+ {
+ "x": 387.12013661858225,
+ "y": -4.286806892950213,
+ "z": 0.0
+ },
+ {
+ "x": 387.55998559978843,
+ "y": -4.4318264865989745,
+ "z": 0.0
+ },
+ {
+ "x": 388.0557284532175,
+ "y": -4.709051441349425,
+ "z": 0.0
+ },
+ {
+ "x": 388.5501652261215,
+ "y": -5.082069965154249,
+ "z": 0.0
+ },
+ {
+ "x": 389.0062153063385,
+ "y": -5.5125901533047585,
+ "z": 0.0
+ },
+ {
+ "x": 389.3549299813356,
+ "y": -5.892455574449731,
+ "z": 0.0
+ },
+ {
+ "x": 389.66851789550583,
+ "y": -6.359658581921938,
+ "z": 0.0
+ },
+ {
+ "x": 389.9439489261116,
+ "y": -6.932775680958885,
+ "z": 0.0
+ },
+ {
+ "x": 390.1578642512467,
+ "y": -7.530318282566346,
+ "z": 0.0
+ },
+ {
+ "x": 390.2998091030685,
+ "y": -8.047909854519496,
+ "z": 0.0
+ },
+ {
+ "x": 390.36831676025355,
+ "y": -8.841612194702273,
+ "z": 0.0
+ },
+ {
+ "x": 390.38026247771074,
+ "y": -9.89500780322875,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 57,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 384.5899963378906,
+ "y": -0.019999999552965164,
+ "z": 0.0
+ },
+ {
+ "x": 385.64381494819463,
+ "y": -0.022279512756463074,
+ "z": 0.0
+ },
+ {
+ "x": 386.6942675033615,
+ "y": -0.10731382102577092,
+ "z": 0.0
+ },
+ {
+ "x": 387.72561929278487,
+ "y": -0.3099470615546849,
+ "z": 0.0
+ },
+ {
+ "x": 388.72816488321354,
+ "y": -0.624260633836627,
+ "z": 0.0
+ },
+ {
+ "x": 389.69228546420817,
+ "y": -1.0475544395856662,
+ "z": 0.0
+ },
+ {
+ "x": 390.5839469861444,
+ "y": -1.6093561257151243,
+ "z": 0.0
+ },
+ {
+ "x": 391.39871183908343,
+ "y": -2.2739064738697126,
+ "z": 0.0
+ },
+ {
+ "x": 392.13633031721895,
+ "y": -3.022132360315485,
+ "z": 0.0
+ },
+ {
+ "x": 392.79166110922614,
+ "y": -3.845780428123838,
+ "z": 0.0
+ },
+ {
+ "x": 393.33090306452124,
+ "y": -4.7512634582735265,
+ "z": 0.0
+ },
+ {
+ "x": 393.7538734457765,
+ "y": -5.714385286029489,
+ "z": 0.0
+ },
+ {
+ "x": 394.0739381603349,
+ "y": -6.715232312524801,
+ "z": 0.0
+ },
+ {
+ "x": 394.2883524678242,
+ "y": -7.745384107741452,
+ "z": 0.0
+ },
+ {
+ "x": 394.36805958476094,
+ "y": -8.796254308931472,
+ "z": 0.0
+ },
+ {
+ "x": 394.38000530221814,
+ "y": -9.849649917457949,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 58,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 396.37987671447183,
+ "y": -9.826970974572548,
+ "z": 0.0
+ },
+ {
+ "x": 396.36793099701464,
+ "y": -8.773575366046071,
+ "z": 0.0
+ },
+ {
+ "x": 396.2826241502021,
+ "y": -7.59412123435243,
+ "z": 0.0
+ },
+ {
+ "x": 396.03197511487895,
+ "y": -6.307689327504029,
+ "z": 0.0
+ },
+ {
+ "x": 395.6588357056089,
+ "y": -5.105190088564791,
+ "z": 0.0
+ },
+ {
+ "x": 395.16209564902897,
+ "y": -3.9470658964493204,
+ "z": 0.0
+ },
+ {
+ "x": 394.5100266731714,
+ "y": -2.8224428549608915,
+ "z": 0.0
+ },
+ {
+ "x": 393.70138782265917,
+ "y": -1.776903463820848,
+ "z": 0.0
+ },
+ {
+ "x": 392.8229851455644,
+ "y": -0.8698247282274443,
+ "z": 0.0
+ },
+ {
+ "x": 391.8480562526078,
+ "y": -0.059508467897973816,
+ "z": 0.0
+ },
+ {
+ "x": 390.758435396418,
+ "y": 0.6445815839209882,
+ "z": 0.0
+ },
+ {
+ "x": 389.5321790155292,
+ "y": 1.207012495720166,
+ "z": 0.0
+ },
+ {
+ "x": 388.32393457584624,
+ "y": 1.5984603430775586,
+ "z": 0.0
+ },
+ {
+ "x": 387.0798429056316,
+ "y": 1.855167162108652,
+ "z": 0.0
+ },
+ {
+ "x": 385.80518741153026,
+ "y": 1.9711995887334375,
+ "z": 0.0
+ },
+ {
+ "x": 384.5943225242918,
+ "y": 1.9799953214693673,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 59,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 384.58567015148947,
+ "y": -2.0199953205752976,
+ "z": 0.0
+ },
+ {
+ "x": 385.482442484859,
+ "y": -2.015758614246364,
+ "z": 0.0
+ },
+ {
+ "x": 386.3086921010914,
+ "y": -2.0697948041601943,
+ "z": 0.0
+ },
+ {
+ "x": 387.1273040097235,
+ "y": -2.2183544661869288,
+ "z": 0.0
+ },
+ {
+ "x": 387.92415075089787,
+ "y": -2.45553376339342,
+ "z": 0.0
+ },
+ {
+ "x": 388.62613553199833,
+ "y": -2.7396904630923204,
+ "z": 0.0
+ },
+ {
+ "x": 389.31983771968095,
+ "y": -3.159203783532275,
+ "z": 0.0
+ },
+ {
+ "x": 389.97443853260245,
+ "y": -3.6779882195119806,
+ "z": 0.0
+ },
+ {
+ "x": 390.5712728117787,
+ "y": -4.267361256810122,
+ "z": 0.0
+ },
+ {
+ "x": 391.07329554528087,
+ "y": -4.869118001286784,
+ "z": 0.0
+ },
+ {
+ "x": 391.4997104800135,
+ "y": -5.555461020097733,
+ "z": 0.0
+ },
+ {
+ "x": 391.8489111859441,
+ "y": -6.323580483494187,
+ "z": 0.0
+ },
+ {
+ "x": 392.1159012057908,
+ "y": -7.122775297545573,
+ "z": 0.0
+ },
+ {
+ "x": 392.29408078544634,
+ "y": -7.896646981130473,
+ "z": 0.0
+ },
+ {
+ "x": 392.36818817250725,
+ "y": -8.818933251816873,
+ "z": 0.0
+ },
+ {
+ "x": 392.38013388996444,
+ "y": -9.87232886034335,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 60,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 325.6703254820158,
+ "y": -193.1591116276879,
+ "z": 0.0
+ },
+ {
+ "x": 324.66472010416993,
+ "y": -193.15902991273836,
+ "z": 0.0
+ },
+ {
+ "x": 323.6591147263242,
+ "y": -193.1589481977888,
+ "z": 0.0
+ },
+ {
+ "x": 322.65350934847834,
+ "y": -193.15886648283922,
+ "z": 0.0
+ },
+ {
+ "x": 321.64790397063246,
+ "y": -193.15878476788964,
+ "z": 0.0
+ },
+ {
+ "x": 320.6422985927866,
+ "y": -193.15870305294007,
+ "z": 0.0
+ },
+ {
+ "x": 319.6366932149407,
+ "y": -193.1586213379905,
+ "z": 0.0
+ },
+ {
+ "x": 318.63108783709475,
+ "y": -193.15853962304095,
+ "z": 0.0
+ },
+ {
+ "x": 317.62548245924904,
+ "y": -193.15845790809138,
+ "z": 0.0
+ },
+ {
+ "x": 316.61987708140316,
+ "y": -193.1583761931418,
+ "z": 0.0
+ },
+ {
+ "x": 315.6142717035573,
+ "y": -193.15829447819223,
+ "z": 0.0
+ },
+ {
+ "x": 314.6086663257114,
+ "y": -193.15821276324266,
+ "z": 0.0
+ },
+ {
+ "x": 313.6030609478655,
+ "y": -193.1581310482931,
+ "z": 0.0
+ },
+ {
+ "x": 312.5974555700196,
+ "y": -193.15804933334354,
+ "z": 0.0
+ },
+ {
+ "x": 311.5918501921738,
+ "y": -193.15796761839397,
+ "z": 0.0
+ },
+ {
+ "x": 310.586244814328,
+ "y": -193.1578859034444,
+ "z": 0.0
+ },
+ {
+ "x": 309.5806394364821,
+ "y": -193.15780418849482,
+ "z": 0.0
+ },
+ {
+ "x": 308.5750340586362,
+ "y": -193.15772247354525,
+ "z": 0.0
+ },
+ {
+ "x": 307.5694286807902,
+ "y": -193.1576407585957,
+ "z": 0.0
+ },
+ {
+ "x": 306.5638233029445,
+ "y": -193.15755904364613,
+ "z": 0.0
+ },
+ {
+ "x": 305.55821792509863,
+ "y": -193.15747732869656,
+ "z": 0.0
+ },
+ {
+ "x": 304.5526125472528,
+ "y": -193.15739561374698,
+ "z": 0.0
+ },
+ {
+ "x": 303.5470071694069,
+ "y": -193.1573138987974,
+ "z": 0.0
+ },
+ {
+ "x": 302.54140179156104,
+ "y": -193.15723218384784,
+ "z": 0.0
+ },
+ {
+ "x": 301.53579641371505,
+ "y": -193.1571504688983,
+ "z": 0.0
+ },
+ {
+ "x": 300.53019103586934,
+ "y": -193.15706875394872,
+ "z": 0.0
+ },
+ {
+ "x": 299.52458565802345,
+ "y": -193.15698703899915,
+ "z": 0.0
+ },
+ {
+ "x": 298.51898028017763,
+ "y": -193.15690532404957,
+ "z": 0.0
+ },
+ {
+ "x": 297.51337490233175,
+ "y": -193.1568236091,
+ "z": 0.0
+ },
+ {
+ "x": 296.50776952448575,
+ "y": -193.15674189415046,
+ "z": 0.0
+ },
+ {
+ "x": 295.50216414664,
+ "y": -193.15666017920088,
+ "z": 0.0
+ },
+ {
+ "x": 294.49655876879416,
+ "y": -193.1565784642513,
+ "z": 0.0
+ },
+ {
+ "x": 293.4909533909483,
+ "y": -193.15649674930174,
+ "z": 0.0
+ },
+ {
+ "x": 292.48534801310245,
+ "y": -193.15641503435216,
+ "z": 0.0
+ },
+ {
+ "x": 291.47974263525657,
+ "y": -193.1563333194026,
+ "z": 0.0
+ },
+ {
+ "x": 290.4741372574106,
+ "y": -193.15625160445305,
+ "z": 0.0
+ },
+ {
+ "x": 289.4685318795648,
+ "y": -193.15616988950347,
+ "z": 0.0
+ },
+ {
+ "x": 288.4629265017189,
+ "y": -193.1560881745539,
+ "z": 0.0
+ },
+ {
+ "x": 287.4573211238731,
+ "y": -193.15600645960433,
+ "z": 0.0
+ },
+ {
+ "x": 286.4517157460273,
+ "y": -193.15592474465475,
+ "z": 0.0
+ },
+ {
+ "x": 285.4461103681814,
+ "y": -193.15584302970518,
+ "z": 0.0
+ },
+ {
+ "x": 284.4405049903354,
+ "y": -193.15576131475564,
+ "z": 0.0
+ },
+ {
+ "x": 283.43489961248963,
+ "y": -193.15567959980606,
+ "z": 0.0
+ },
+ {
+ "x": 282.42929423464375,
+ "y": -193.1555978848565,
+ "z": 0.0
+ },
+ {
+ "x": 281.4236888567979,
+ "y": -193.15551616990692,
+ "z": 0.0
+ },
+ {
+ "x": 280.4180834789521,
+ "y": -193.15543445495734,
+ "z": 0.0
+ },
+ {
+ "x": 279.4124781011061,
+ "y": -193.1553527400078,
+ "z": 0.0
+ },
+ {
+ "x": 278.40687272326034,
+ "y": -193.15527102505823,
+ "z": 0.0
+ },
+ {
+ "x": 277.40126734541445,
+ "y": -193.15518931010865,
+ "z": 0.0
+ },
+ {
+ "x": 276.39566196756857,
+ "y": -193.15510759515908,
+ "z": 0.0
+ },
+ {
+ "x": 275.39005658972275,
+ "y": -193.1550258802095,
+ "z": 0.0
+ },
+ {
+ "x": 274.38445121187686,
+ "y": -193.15494416525993,
+ "z": 0.0
+ },
+ {
+ "x": 273.3788458340309,
+ "y": -193.1548624503104,
+ "z": 0.0
+ },
+ {
+ "x": 272.37324045618516,
+ "y": -193.15478073536082,
+ "z": 0.0
+ },
+ {
+ "x": 271.3676350783393,
+ "y": -193.15469902041124,
+ "z": 0.0
+ },
+ {
+ "x": 270.3620297004934,
+ "y": -193.15461730546167,
+ "z": 0.0
+ },
+ {
+ "x": 269.35642432264757,
+ "y": -193.1545355905121,
+ "z": 0.0
+ },
+ {
+ "x": 268.3508189448017,
+ "y": -193.15445387556252,
+ "z": 0.0
+ },
+ {
+ "x": 267.34521356695575,
+ "y": -193.15437216061298,
+ "z": 0.0
+ },
+ {
+ "x": 266.33960818911,
+ "y": -193.1542904456634,
+ "z": 0.0
+ },
+ {
+ "x": 265.3340028112641,
+ "y": -193.15420873071383,
+ "z": 0.0
+ },
+ {
+ "x": 264.3283974334182,
+ "y": -193.15412701576426,
+ "z": 0.0
+ },
+ {
+ "x": 263.3227920555724,
+ "y": -193.1540453008147,
+ "z": 0.0
+ },
+ {
+ "x": 262.3171866777264,
+ "y": -193.15396358586514,
+ "z": 0.0
+ },
+ {
+ "x": 261.3115812998807,
+ "y": -193.15388187091557,
+ "z": 0.0
+ },
+ {
+ "x": 260.3059759220348,
+ "y": -193.153800155966,
+ "z": 0.0
+ },
+ {
+ "x": 259.3003705441889,
+ "y": -193.15371844101642,
+ "z": 0.0
+ },
+ {
+ "x": 258.29476516634304,
+ "y": -193.15363672606685,
+ "z": 0.0
+ },
+ {
+ "x": 257.28915978849716,
+ "y": -193.15355501111728,
+ "z": 0.0
+ },
+ {
+ "x": 256.2835544106512,
+ "y": -193.15347329616773,
+ "z": 0.0
+ },
+ {
+ "x": 255.27794903280545,
+ "y": -193.15339158121816,
+ "z": 0.0
+ },
+ {
+ "x": 254.27234365495957,
+ "y": -193.1533098662686,
+ "z": 0.0
+ },
+ {
+ "x": 253.26673827711372,
+ "y": -193.153228151319,
+ "z": 0.0
+ },
+ {
+ "x": 252.26113289926786,
+ "y": -193.15314643636944,
+ "z": 0.0
+ },
+ {
+ "x": 251.25552752142187,
+ "y": -193.1530647214199,
+ "z": 0.0
+ },
+ {
+ "x": 250.24992214357613,
+ "y": -193.15298300647032,
+ "z": 0.0
+ },
+ {
+ "x": 249.24431676573028,
+ "y": -193.15290129152075,
+ "z": 0.0
+ },
+ {
+ "x": 248.2387113878844,
+ "y": -193.15281957657118,
+ "z": 0.0
+ },
+ {
+ "x": 247.23310601003854,
+ "y": -193.1527378616216,
+ "z": 0.0
+ },
+ {
+ "x": 246.2275006321927,
+ "y": -193.15265614667203,
+ "z": 0.0
+ },
+ {
+ "x": 245.2218952543467,
+ "y": -193.15257443172248,
+ "z": 0.0
+ },
+ {
+ "x": 244.21628987650095,
+ "y": -193.1524927167729,
+ "z": 0.0
+ },
+ {
+ "x": 243.2106844986551,
+ "y": -193.15241100182334,
+ "z": 0.0
+ },
+ {
+ "x": 242.20507912080922,
+ "y": -193.15232928687377,
+ "z": 0.0
+ },
+ {
+ "x": 241.19947374296336,
+ "y": -193.1522475719242,
+ "z": 0.0
+ },
+ {
+ "x": 240.1938683651175,
+ "y": -193.15216585697462,
+ "z": 0.0
+ },
+ {
+ "x": 239.18826298727151,
+ "y": -193.15208414202507,
+ "z": 0.0
+ },
+ {
+ "x": 238.18265760942577,
+ "y": -193.1520024270755,
+ "z": 0.0
+ },
+ {
+ "x": 237.1770522315799,
+ "y": -193.15192071212593,
+ "z": 0.0
+ },
+ {
+ "x": 236.17144685373404,
+ "y": -193.15183899717636,
+ "z": 0.0
+ },
+ {
+ "x": 235.1658414758882,
+ "y": -193.15175728222678,
+ "z": 0.0
+ },
+ {
+ "x": 234.1602360980422,
+ "y": -193.15167556727724,
+ "z": 0.0
+ },
+ {
+ "x": 233.15463072019645,
+ "y": -193.15159385232766,
+ "z": 0.0
+ },
+ {
+ "x": 232.1490253423506,
+ "y": -193.1515121373781,
+ "z": 0.0
+ },
+ {
+ "x": 231.14341996450472,
+ "y": -193.15143042242852,
+ "z": 0.0
+ },
+ {
+ "x": 230.13781458665886,
+ "y": -193.15134870747895,
+ "z": 0.0
+ },
+ {
+ "x": 229.132209208813,
+ "y": -193.15126699252937,
+ "z": 0.0
+ },
+ {
+ "x": 228.126603830967,
+ "y": -193.15118527757983,
+ "z": 0.0
+ },
+ {
+ "x": 227.12099845312127,
+ "y": -193.15110356263025,
+ "z": 0.0
+ },
+ {
+ "x": 226.11539307527542,
+ "y": -193.15102184768068,
+ "z": 0.0
+ },
+ {
+ "x": 225.10978769742954,
+ "y": -193.1509401327311,
+ "z": 0.0
+ },
+ {
+ "x": 224.10418231958369,
+ "y": -193.15085841778154,
+ "z": 0.0
+ },
+ {
+ "x": 223.09857694173783,
+ "y": -193.15077670283196,
+ "z": 0.0
+ },
+ {
+ "x": 222.09297156389184,
+ "y": -193.15069498788242,
+ "z": 0.0
+ },
+ {
+ "x": 221.0873661860461,
+ "y": -193.15061327293284,
+ "z": 0.0
+ },
+ {
+ "x": 220.08176080820024,
+ "y": -193.15053155798327,
+ "z": 0.0
+ },
+ {
+ "x": 219.07615543035436,
+ "y": -193.1504498430337,
+ "z": 0.0
+ },
+ {
+ "x": 218.0705500525085,
+ "y": -193.15036812808412,
+ "z": 0.0
+ },
+ {
+ "x": 217.06494467466254,
+ "y": -193.15028641313458,
+ "z": 0.0
+ },
+ {
+ "x": 216.05933929681677,
+ "y": -193.150204698185,
+ "z": 0.0
+ },
+ {
+ "x": 215.0537339189709,
+ "y": -193.15012298323543,
+ "z": 0.0
+ },
+ {
+ "x": 214.04812854112507,
+ "y": -193.15004126828586,
+ "z": 0.0
+ },
+ {
+ "x": 213.04252316327918,
+ "y": -193.1499595533363,
+ "z": 0.0
+ },
+ {
+ "x": 212.0369177854333,
+ "y": -193.14987783838671,
+ "z": 0.0
+ },
+ {
+ "x": 211.03131240758736,
+ "y": -193.14979612343717,
+ "z": 0.0
+ },
+ {
+ "x": 210.0257070297416,
+ "y": -193.1497144084876,
+ "z": 0.0
+ },
+ {
+ "x": 209.02010165189571,
+ "y": -193.14963269353802,
+ "z": 0.0
+ },
+ {
+ "x": 208.0144962740499,
+ "y": -193.14955097858845,
+ "z": 0.0
+ },
+ {
+ "x": 207.008890896204,
+ "y": -193.14946926363888,
+ "z": 0.0
+ },
+ {
+ "x": 206.003285518358,
+ "y": -193.14938754868933,
+ "z": 0.0
+ },
+ {
+ "x": 204.99768014051227,
+ "y": -193.14930583373976,
+ "z": 0.0
+ },
+ {
+ "x": 203.99207476266642,
+ "y": -193.1492241187902,
+ "z": 0.0
+ },
+ {
+ "x": 202.98646938482054,
+ "y": -193.1491424038406,
+ "z": 0.0
+ },
+ {
+ "x": 201.98086400697468,
+ "y": -193.14906068889104,
+ "z": 0.0
+ },
+ {
+ "x": 200.97525862912883,
+ "y": -193.14897897394147,
+ "z": 0.0
+ },
+ {
+ "x": 199.96965325128284,
+ "y": -193.14889725899192,
+ "z": 0.0
+ },
+ {
+ "x": 198.9640478734371,
+ "y": -193.14881554404235,
+ "z": 0.0
+ },
+ {
+ "x": 197.95844249559124,
+ "y": -193.14873382909278,
+ "z": 0.0
+ },
+ {
+ "x": 196.95283711774536,
+ "y": -193.1486521141432,
+ "z": 0.0
+ },
+ {
+ "x": 195.9472317398995,
+ "y": -193.14857039919363,
+ "z": 0.0
+ },
+ {
+ "x": 194.94162636205365,
+ "y": -193.14848868424406,
+ "z": 0.0
+ },
+ {
+ "x": 193.93602098420766,
+ "y": -193.1484069692945,
+ "z": 0.0
+ },
+ {
+ "x": 192.93041560636192,
+ "y": -193.14832525434494,
+ "z": 0.0
+ },
+ {
+ "x": 191.92481022851607,
+ "y": -193.14824353939537,
+ "z": 0.0
+ },
+ {
+ "x": 190.91920485067018,
+ "y": -193.1481618244458,
+ "z": 0.0
+ },
+ {
+ "x": 189.91359947282433,
+ "y": -193.14808010949622,
+ "z": 0.0
+ },
+ {
+ "x": 188.90799409497836,
+ "y": -193.14799839454668,
+ "z": 0.0
+ },
+ {
+ "x": 187.9023887171326,
+ "y": -193.1479166795971,
+ "z": 0.0
+ },
+ {
+ "x": 186.89678333928674,
+ "y": -193.14783496464753,
+ "z": 0.0
+ },
+ {
+ "x": 185.8911779614409,
+ "y": -193.14775324969796,
+ "z": 0.0
+ },
+ {
+ "x": 184.885572583595,
+ "y": -193.14767153474838,
+ "z": 0.0
+ },
+ {
+ "x": 183.87996720574915,
+ "y": -193.1475898197988,
+ "z": 0.0
+ },
+ {
+ "x": 182.8743618279032,
+ "y": -193.14750810484927,
+ "z": 0.0
+ },
+ {
+ "x": 181.86875645005742,
+ "y": -193.1474263898997,
+ "z": 0.0
+ },
+ {
+ "x": 180.86315107221156,
+ "y": -193.14734467495012,
+ "z": 0.0
+ },
+ {
+ "x": 179.8575456943657,
+ "y": -193.14726296000055,
+ "z": 0.0
+ },
+ {
+ "x": 178.85194031651983,
+ "y": -193.14718124505097,
+ "z": 0.0
+ },
+ {
+ "x": 177.84633493867395,
+ "y": -193.1470995301014,
+ "z": 0.0
+ },
+ {
+ "x": 176.840729560828,
+ "y": -193.14701781515186,
+ "z": 0.0
+ },
+ {
+ "x": 175.83512418298224,
+ "y": -193.14693610020228,
+ "z": 0.0
+ },
+ {
+ "x": 174.82951880513636,
+ "y": -193.1468543852527,
+ "z": 0.0
+ },
+ {
+ "x": 173.82391342729053,
+ "y": -193.14677267030314,
+ "z": 0.0
+ },
+ {
+ "x": 172.81830804944465,
+ "y": -193.14669095535356,
+ "z": 0.0
+ },
+ {
+ "x": 171.81270267159866,
+ "y": -193.14660924040402,
+ "z": 0.0
+ },
+ {
+ "x": 170.80709729375295,
+ "y": -193.14652752545445,
+ "z": 0.0
+ },
+ {
+ "x": 169.80149191590706,
+ "y": -193.14644581050487,
+ "z": 0.0
+ },
+ {
+ "x": 168.79588653806118,
+ "y": -193.1463640955553,
+ "z": 0.0
+ },
+ {
+ "x": 167.79028116021533,
+ "y": -193.14628238060573,
+ "z": 0.0
+ },
+ {
+ "x": 166.78467578236948,
+ "y": -193.14620066565615,
+ "z": 0.0
+ },
+ {
+ "x": 165.77907040452348,
+ "y": -193.1461189507066,
+ "z": 0.0
+ },
+ {
+ "x": 164.77346502667777,
+ "y": -193.14603723575703,
+ "z": 0.0
+ },
+ {
+ "x": 163.7678596488319,
+ "y": -193.14595552080746,
+ "z": 0.0
+ },
+ {
+ "x": 162.76225427098603,
+ "y": -193.1458738058579,
+ "z": 0.0
+ },
+ {
+ "x": 161.75664889314015,
+ "y": -193.14579209090832,
+ "z": 0.0
+ },
+ {
+ "x": 160.75104351529419,
+ "y": -193.14571037595877,
+ "z": 0.0
+ },
+ {
+ "x": 159.74543813744845,
+ "y": -193.1456286610092,
+ "z": 0.0
+ },
+ {
+ "x": 158.73983275960256,
+ "y": -193.14554694605962,
+ "z": 0.0
+ },
+ {
+ "x": 157.7342273817567,
+ "y": -193.14546523111005,
+ "z": 0.0
+ },
+ {
+ "x": 156.72862200391083,
+ "y": -193.14538351616048,
+ "z": 0.0
+ },
+ {
+ "x": 155.72301662606498,
+ "y": -193.1453018012109,
+ "z": 0.0
+ },
+ {
+ "x": 154.717411248219,
+ "y": -193.14522008626136,
+ "z": 0.0
+ },
+ {
+ "x": 153.71180587037324,
+ "y": -193.1451383713118,
+ "z": 0.0
+ },
+ {
+ "x": 152.7062004925274,
+ "y": -193.14505665636221,
+ "z": 0.0
+ },
+ {
+ "x": 151.70059511468153,
+ "y": -193.14497494141264,
+ "z": 0.0
+ },
+ {
+ "x": 150.69498973683565,
+ "y": -193.14489322646307,
+ "z": 0.0
+ },
+ {
+ "x": 149.6893843589898,
+ "y": -193.1448115115135,
+ "z": 0.0
+ },
+ {
+ "x": 148.68377898114383,
+ "y": -193.14472979656395,
+ "z": 0.0
+ },
+ {
+ "x": 147.67817360329806,
+ "y": -193.14464808161438,
+ "z": 0.0
+ },
+ {
+ "x": 146.6725682254522,
+ "y": -193.1445663666648,
+ "z": 0.0
+ },
+ {
+ "x": 145.66696284760636,
+ "y": -193.14448465171523,
+ "z": 0.0
+ },
+ {
+ "x": 144.66135746976047,
+ "y": -193.14440293676566,
+ "z": 0.0
+ },
+ {
+ "x": 143.6557520919145,
+ "y": -193.1443212218161,
+ "z": 0.0
+ },
+ {
+ "x": 142.65014671406877,
+ "y": -193.14423950686654,
+ "z": 0.0
+ },
+ {
+ "x": 141.6445413362229,
+ "y": -193.14415779191697,
+ "z": 0.0
+ },
+ {
+ "x": 140.63893595837703,
+ "y": -193.1440760769674,
+ "z": 0.0
+ },
+ {
+ "x": 139.63333058053118,
+ "y": -193.14399436201782,
+ "z": 0.0
+ },
+ {
+ "x": 138.6277252026853,
+ "y": -193.14391264706825,
+ "z": 0.0
+ },
+ {
+ "x": 137.62211982483933,
+ "y": -193.1438309321187,
+ "z": 0.0
+ },
+ {
+ "x": 136.6165144469936,
+ "y": -193.14374921716913,
+ "z": 0.0
+ },
+ {
+ "x": 135.6109090691477,
+ "y": -193.14366750221956,
+ "z": 0.0
+ },
+ {
+ "x": 134.60530369130186,
+ "y": -193.14358578726998,
+ "z": 0.0
+ },
+ {
+ "x": 133.599698313456,
+ "y": -193.1435040723204,
+ "z": 0.0
+ },
+ {
+ "x": 132.59409293561012,
+ "y": -193.14342235737084,
+ "z": 0.0
+ },
+ {
+ "x": 131.58848755776415,
+ "y": -193.1433406424213,
+ "z": 0.0
+ },
+ {
+ "x": 130.5828821799184,
+ "y": -193.14325892747172,
+ "z": 0.0
+ },
+ {
+ "x": 129.57727680207256,
+ "y": -193.14317721252215,
+ "z": 0.0
+ },
+ {
+ "x": 128.57167142422668,
+ "y": -193.14309549757257,
+ "z": 0.0
+ },
+ {
+ "x": 127.56606604638083,
+ "y": -193.143013782623,
+ "z": 0.0
+ },
+ {
+ "x": 126.56046066853487,
+ "y": -193.14293206767346,
+ "z": 0.0
+ },
+ {
+ "x": 125.55485529068912,
+ "y": -193.14285035272388,
+ "z": 0.0
+ },
+ {
+ "x": 124.54924991284325,
+ "y": -193.1427686377743,
+ "z": 0.0
+ },
+ {
+ "x": 123.54364453499738,
+ "y": -193.14268692282474,
+ "z": 0.0
+ },
+ {
+ "x": 122.53803915715153,
+ "y": -193.14260520787516,
+ "z": 0.0
+ },
+ {
+ "x": 121.53243377930568,
+ "y": -193.1425234929256,
+ "z": 0.0
+ },
+ {
+ "x": 120.52682840145971,
+ "y": -193.14244177797605,
+ "z": 0.0
+ },
+ {
+ "x": 119.52122302361396,
+ "y": -193.14236006302647,
+ "z": 0.0
+ },
+ {
+ "x": 118.51561764576809,
+ "y": -193.1422783480769,
+ "z": 0.0
+ },
+ {
+ "x": 117.51001226792224,
+ "y": -193.14219663312733,
+ "z": 0.0
+ },
+ {
+ "x": 116.50440689007637,
+ "y": -193.14211491817775,
+ "z": 0.0
+ },
+ {
+ "x": 115.49880151223041,
+ "y": -193.1420332032282,
+ "z": 0.0
+ },
+ {
+ "x": 114.49319613438465,
+ "y": -193.14195148827864,
+ "z": 0.0
+ },
+ {
+ "x": 113.4875907565388,
+ "y": -193.14186977332906,
+ "z": 0.0
+ },
+ {
+ "x": 112.48198537869294,
+ "y": -193.1417880583795,
+ "z": 0.0
+ },
+ {
+ "x": 111.47638000084707,
+ "y": -193.14170634342992,
+ "z": 0.0
+ },
+ {
+ "x": 110.47077462300122,
+ "y": -193.14162462848034,
+ "z": 0.0
+ },
+ {
+ "x": 109.46516924515525,
+ "y": -193.1415429135308,
+ "z": 0.0
+ },
+ {
+ "x": 108.4595638673095,
+ "y": -193.14146119858123,
+ "z": 0.0
+ },
+ {
+ "x": 107.45395848946363,
+ "y": -193.14137948363165,
+ "z": 0.0
+ },
+ {
+ "x": 106.44835311161778,
+ "y": -193.14129776868208,
+ "z": 0.0
+ },
+ {
+ "x": 105.44274773377191,
+ "y": -193.1412160537325,
+ "z": 0.0
+ },
+ {
+ "x": 104.43714235592606,
+ "y": -193.14113433878293,
+ "z": 0.0
+ },
+ {
+ "x": 103.43153697808009,
+ "y": -193.1410526238334,
+ "z": 0.0
+ },
+ {
+ "x": 102.42593160023434,
+ "y": -193.14097090888382,
+ "z": 0.0
+ },
+ {
+ "x": 101.42032622238847,
+ "y": -193.14088919393424,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 61,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 101.41967614671384,
+ "y": -201.14088916752183,
+ "z": 0.0
+ },
+ {
+ "x": 102.42528152455971,
+ "y": -201.1409708824714,
+ "z": 0.0
+ },
+ {
+ "x": 103.43088690240566,
+ "y": -201.14105259742098,
+ "z": 0.0
+ },
+ {
+ "x": 104.43649228025143,
+ "y": -201.14113431237053,
+ "z": 0.0
+ },
+ {
+ "x": 105.44209765809728,
+ "y": -201.1412160273201,
+ "z": 0.0
+ },
+ {
+ "x": 106.44770303594315,
+ "y": -201.14129774226967,
+ "z": 0.0
+ },
+ {
+ "x": 107.453308413789,
+ "y": -201.14137945721924,
+ "z": 0.0
+ },
+ {
+ "x": 108.45891379163487,
+ "y": -201.14146117216882,
+ "z": 0.0
+ },
+ {
+ "x": 109.46451916948082,
+ "y": -201.1415428871184,
+ "z": 0.0
+ },
+ {
+ "x": 110.47012454732659,
+ "y": -201.14162460206794,
+ "z": 0.0
+ },
+ {
+ "x": 111.47572992517244,
+ "y": -201.1417063170175,
+ "z": 0.0
+ },
+ {
+ "x": 112.48133530301831,
+ "y": -201.14178803196708,
+ "z": 0.0
+ },
+ {
+ "x": 113.48694068086417,
+ "y": -201.14186974691665,
+ "z": 0.0
+ },
+ {
+ "x": 114.49254605871002,
+ "y": -201.14195146186623,
+ "z": 0.0
+ },
+ {
+ "x": 115.49815143655599,
+ "y": -201.1420331768158,
+ "z": 0.0
+ },
+ {
+ "x": 116.50375681440174,
+ "y": -201.14211489176535,
+ "z": 0.0
+ },
+ {
+ "x": 117.50936219224761,
+ "y": -201.14219660671492,
+ "z": 0.0
+ },
+ {
+ "x": 118.51496757009346,
+ "y": -201.1422783216645,
+ "z": 0.0
+ },
+ {
+ "x": 119.52057294793933,
+ "y": -201.14236003661406,
+ "z": 0.0
+ },
+ {
+ "x": 120.52617832578528,
+ "y": -201.14244175156364,
+ "z": 0.0
+ },
+ {
+ "x": 121.53178370363105,
+ "y": -201.14252346651318,
+ "z": 0.0
+ },
+ {
+ "x": 122.5373890814769,
+ "y": -201.14260518146276,
+ "z": 0.0
+ },
+ {
+ "x": 123.54299445932276,
+ "y": -201.14268689641233,
+ "z": 0.0
+ },
+ {
+ "x": 124.54859983716862,
+ "y": -201.1427686113619,
+ "z": 0.0
+ },
+ {
+ "x": 125.55420521501449,
+ "y": -201.14285032631147,
+ "z": 0.0
+ },
+ {
+ "x": 126.55981059286044,
+ "y": -201.14293204126105,
+ "z": 0.0
+ },
+ {
+ "x": 127.5654159707062,
+ "y": -201.1430137562106,
+ "z": 0.0
+ },
+ {
+ "x": 128.57102134855205,
+ "y": -201.14309547116017,
+ "z": 0.0
+ },
+ {
+ "x": 129.57662672639793,
+ "y": -201.14317718610974,
+ "z": 0.0
+ },
+ {
+ "x": 130.5822321042438,
+ "y": -201.1432589010593,
+ "z": 0.0
+ },
+ {
+ "x": 131.58783748208975,
+ "y": -201.14334061600889,
+ "z": 0.0
+ },
+ {
+ "x": 132.5934428599355,
+ "y": -201.14342233095843,
+ "z": 0.0
+ },
+ {
+ "x": 133.59904823778137,
+ "y": -201.143504045908,
+ "z": 0.0
+ },
+ {
+ "x": 134.60465361562723,
+ "y": -201.14358576085758,
+ "z": 0.0
+ },
+ {
+ "x": 135.61025899347308,
+ "y": -201.14366747580715,
+ "z": 0.0
+ },
+ {
+ "x": 136.61586437131896,
+ "y": -201.14374919075672,
+ "z": 0.0
+ },
+ {
+ "x": 137.62146974916493,
+ "y": -201.1438309057063,
+ "z": 0.0
+ },
+ {
+ "x": 138.62707512701067,
+ "y": -201.14391262065584,
+ "z": 0.0
+ },
+ {
+ "x": 139.63268050485655,
+ "y": -201.1439943356054,
+ "z": 0.0
+ },
+ {
+ "x": 140.6382858827024,
+ "y": -201.144076050555,
+ "z": 0.0
+ },
+ {
+ "x": 141.64389126054826,
+ "y": -201.14415776550456,
+ "z": 0.0
+ },
+ {
+ "x": 142.64949663839414,
+ "y": -201.14423948045413,
+ "z": 0.0
+ },
+ {
+ "x": 143.6551020162401,
+ "y": -201.1443211954037,
+ "z": 0.0
+ },
+ {
+ "x": 144.66070739408585,
+ "y": -201.14440291035325,
+ "z": 0.0
+ },
+ {
+ "x": 145.66631277193173,
+ "y": -201.14448462530282,
+ "z": 0.0
+ },
+ {
+ "x": 146.67191814977758,
+ "y": -201.1445663402524,
+ "z": 0.0
+ },
+ {
+ "x": 147.67752352762344,
+ "y": -201.14464805520197,
+ "z": 0.0
+ },
+ {
+ "x": 148.68312890546943,
+ "y": -201.14472977015154,
+ "z": 0.0
+ },
+ {
+ "x": 149.68873428331517,
+ "y": -201.1448114851011,
+ "z": 0.0
+ },
+ {
+ "x": 150.69433966116102,
+ "y": -201.14489320005066,
+ "z": 0.0
+ },
+ {
+ "x": 151.6999450390069,
+ "y": -201.14497491500023,
+ "z": 0.0
+ },
+ {
+ "x": 152.70555041685276,
+ "y": -201.1450566299498,
+ "z": 0.0
+ },
+ {
+ "x": 153.7111557946986,
+ "y": -201.14513834489938,
+ "z": 0.0
+ },
+ {
+ "x": 154.7167611725446,
+ "y": -201.14522005984895,
+ "z": 0.0
+ },
+ {
+ "x": 155.72236655039035,
+ "y": -201.1453017747985,
+ "z": 0.0
+ },
+ {
+ "x": 156.7279719282362,
+ "y": -201.14538348974807,
+ "z": 0.0
+ },
+ {
+ "x": 157.73357730608208,
+ "y": -201.14546520469764,
+ "z": 0.0
+ },
+ {
+ "x": 158.73918268392794,
+ "y": -201.14554691964722,
+ "z": 0.0
+ },
+ {
+ "x": 159.74478806177382,
+ "y": -201.1456286345968,
+ "z": 0.0
+ },
+ {
+ "x": 160.75039343961978,
+ "y": -201.14571034954636,
+ "z": 0.0
+ },
+ {
+ "x": 161.75599881746552,
+ "y": -201.1457920644959,
+ "z": 0.0
+ },
+ {
+ "x": 162.7616041953114,
+ "y": -201.14587377944548,
+ "z": 0.0
+ },
+ {
+ "x": 163.76720957315726,
+ "y": -201.14595549439505,
+ "z": 0.0
+ },
+ {
+ "x": 164.77281495100314,
+ "y": -201.14603720934463,
+ "z": 0.0
+ },
+ {
+ "x": 165.77842032884908,
+ "y": -201.1461189242942,
+ "z": 0.0
+ },
+ {
+ "x": 166.78402570669485,
+ "y": -201.14620063924374,
+ "z": 0.0
+ },
+ {
+ "x": 167.7896310845407,
+ "y": -201.14628235419332,
+ "z": 0.0
+ },
+ {
+ "x": 168.79523646238655,
+ "y": -201.1463640691429,
+ "z": 0.0
+ },
+ {
+ "x": 169.80084184023244,
+ "y": -201.14644578409246,
+ "z": 0.0
+ },
+ {
+ "x": 170.80644721807832,
+ "y": -201.14652749904204,
+ "z": 0.0
+ },
+ {
+ "x": 171.81205259592426,
+ "y": -201.1466092139916,
+ "z": 0.0
+ },
+ {
+ "x": 172.81765797377003,
+ "y": -201.14669092894115,
+ "z": 0.0
+ },
+ {
+ "x": 173.8232633516159,
+ "y": -201.14677264389073,
+ "z": 0.0
+ },
+ {
+ "x": 174.82886872946173,
+ "y": -201.1468543588403,
+ "z": 0.0
+ },
+ {
+ "x": 175.8344741073076,
+ "y": -201.14693607378987,
+ "z": 0.0
+ },
+ {
+ "x": 176.8400794851536,
+ "y": -201.14701778873945,
+ "z": 0.0
+ },
+ {
+ "x": 177.84568486299932,
+ "y": -201.147099503689,
+ "z": 0.0
+ },
+ {
+ "x": 178.8512902408452,
+ "y": -201.14718121863856,
+ "z": 0.0
+ },
+ {
+ "x": 179.85689561869108,
+ "y": -201.14726293358814,
+ "z": 0.0
+ },
+ {
+ "x": 180.86250099653694,
+ "y": -201.1473446485377,
+ "z": 0.0
+ },
+ {
+ "x": 181.8681063743828,
+ "y": -201.14742636348728,
+ "z": 0.0
+ },
+ {
+ "x": 182.8737117522288,
+ "y": -201.14750807843686,
+ "z": 0.0
+ },
+ {
+ "x": 183.87931713007453,
+ "y": -201.1475897933864,
+ "z": 0.0
+ },
+ {
+ "x": 184.88492250792038,
+ "y": -201.14767150833597,
+ "z": 0.0
+ },
+ {
+ "x": 185.89052788576626,
+ "y": -201.14775322328555,
+ "z": 0.0
+ },
+ {
+ "x": 186.8961332636121,
+ "y": -201.14783493823512,
+ "z": 0.0
+ },
+ {
+ "x": 187.90173864145797,
+ "y": -201.1479166531847,
+ "z": 0.0
+ },
+ {
+ "x": 188.90734401930396,
+ "y": -201.14799836813427,
+ "z": 0.0
+ },
+ {
+ "x": 189.9129493971497,
+ "y": -201.1480800830838,
+ "z": 0.0
+ },
+ {
+ "x": 190.91855477499556,
+ "y": -201.14816179803339,
+ "z": 0.0
+ },
+ {
+ "x": 191.92416015284144,
+ "y": -201.14824351298296,
+ "z": 0.0
+ },
+ {
+ "x": 192.9297655306873,
+ "y": -201.14832522793253,
+ "z": 0.0
+ },
+ {
+ "x": 193.93537090853326,
+ "y": -201.1484069428821,
+ "z": 0.0
+ },
+ {
+ "x": 194.94097628637903,
+ "y": -201.14848865783165,
+ "z": 0.0
+ },
+ {
+ "x": 195.94658166422488,
+ "y": -201.14857037278122,
+ "z": 0.0
+ },
+ {
+ "x": 196.95218704207073,
+ "y": -201.1486520877308,
+ "z": 0.0
+ },
+ {
+ "x": 197.95779241991661,
+ "y": -201.14873380268037,
+ "z": 0.0
+ },
+ {
+ "x": 198.96339779776247,
+ "y": -201.14881551762994,
+ "z": 0.0
+ },
+ {
+ "x": 199.96900317560844,
+ "y": -201.14889723257951,
+ "z": 0.0
+ },
+ {
+ "x": 200.9746085534542,
+ "y": -201.14897894752906,
+ "z": 0.0
+ },
+ {
+ "x": 201.98021393130006,
+ "y": -201.14906066247863,
+ "z": 0.0
+ },
+ {
+ "x": 202.9858193091459,
+ "y": -201.1491423774282,
+ "z": 0.0
+ },
+ {
+ "x": 203.9914246869918,
+ "y": -201.14922409237778,
+ "z": 0.0
+ },
+ {
+ "x": 204.99703006483765,
+ "y": -201.14930580732735,
+ "z": 0.0
+ },
+ {
+ "x": 206.0026354426836,
+ "y": -201.14938752227692,
+ "z": 0.0
+ },
+ {
+ "x": 207.00824082052938,
+ "y": -201.14946923722647,
+ "z": 0.0
+ },
+ {
+ "x": 208.01384619837526,
+ "y": -201.14955095217604,
+ "z": 0.0
+ },
+ {
+ "x": 209.0194515762211,
+ "y": -201.14963266712562,
+ "z": 0.0
+ },
+ {
+ "x": 210.02505695406697,
+ "y": -201.1497143820752,
+ "z": 0.0
+ },
+ {
+ "x": 211.03066233191296,
+ "y": -201.14979609702476,
+ "z": 0.0
+ },
+ {
+ "x": 212.03626770975868,
+ "y": -201.1498778119743,
+ "z": 0.0
+ },
+ {
+ "x": 213.04187308760456,
+ "y": -201.14995952692388,
+ "z": 0.0
+ },
+ {
+ "x": 214.04747846545044,
+ "y": -201.15004124187345,
+ "z": 0.0
+ },
+ {
+ "x": 215.05308384329626,
+ "y": -201.15012295682303,
+ "z": 0.0
+ },
+ {
+ "x": 216.05868922114215,
+ "y": -201.1502046717726,
+ "z": 0.0
+ },
+ {
+ "x": 217.06429459898814,
+ "y": -201.15028638672217,
+ "z": 0.0
+ },
+ {
+ "x": 218.06989997683388,
+ "y": -201.15036810167172,
+ "z": 0.0
+ },
+ {
+ "x": 219.07550535467973,
+ "y": -201.1504498166213,
+ "z": 0.0
+ },
+ {
+ "x": 220.08111073252562,
+ "y": -201.15053153157086,
+ "z": 0.0
+ },
+ {
+ "x": 221.08671611037147,
+ "y": -201.15061324652044,
+ "z": 0.0
+ },
+ {
+ "x": 222.09232148821744,
+ "y": -201.15069496147,
+ "z": 0.0
+ },
+ {
+ "x": 223.0979268660632,
+ "y": -201.15077667641955,
+ "z": 0.0
+ },
+ {
+ "x": 224.10353224390906,
+ "y": -201.15085839136913,
+ "z": 0.0
+ },
+ {
+ "x": 225.1091376217549,
+ "y": -201.1509401063187,
+ "z": 0.0
+ },
+ {
+ "x": 226.1147429996008,
+ "y": -201.15102182126827,
+ "z": 0.0
+ },
+ {
+ "x": 227.12034837744665,
+ "y": -201.15110353621785,
+ "z": 0.0
+ },
+ {
+ "x": 228.1259537552926,
+ "y": -201.15118525116742,
+ "z": 0.0
+ },
+ {
+ "x": 229.13155913313838,
+ "y": -201.15126696611696,
+ "z": 0.0
+ },
+ {
+ "x": 230.13716451098423,
+ "y": -201.15134868106654,
+ "z": 0.0
+ },
+ {
+ "x": 231.1427698888301,
+ "y": -201.1514303960161,
+ "z": 0.0
+ },
+ {
+ "x": 232.14837526667597,
+ "y": -201.15151211096568,
+ "z": 0.0
+ },
+ {
+ "x": 233.15398064452182,
+ "y": -201.15159382591526,
+ "z": 0.0
+ },
+ {
+ "x": 234.1595860223678,
+ "y": -201.15167554086483,
+ "z": 0.0
+ },
+ {
+ "x": 235.16519140021356,
+ "y": -201.15175725581437,
+ "z": 0.0
+ },
+ {
+ "x": 236.1707967780594,
+ "y": -201.15183897076395,
+ "z": 0.0
+ },
+ {
+ "x": 237.17640215590527,
+ "y": -201.15192068571352,
+ "z": 0.0
+ },
+ {
+ "x": 238.18200753375115,
+ "y": -201.1520024006631,
+ "z": 0.0
+ },
+ {
+ "x": 239.1876129115971,
+ "y": -201.15208411561267,
+ "z": 0.0
+ },
+ {
+ "x": 240.19321828944288,
+ "y": -201.1521658305622,
+ "z": 0.0
+ },
+ {
+ "x": 241.19882366728874,
+ "y": -201.15224754551178,
+ "z": 0.0
+ },
+ {
+ "x": 242.2044290451346,
+ "y": -201.15232926046136,
+ "z": 0.0
+ },
+ {
+ "x": 243.21003442298047,
+ "y": -201.15241097541093,
+ "z": 0.0
+ },
+ {
+ "x": 244.21563980082632,
+ "y": -201.1524926903605,
+ "z": 0.0
+ },
+ {
+ "x": 245.2212451786723,
+ "y": -201.15257440531008,
+ "z": 0.0
+ },
+ {
+ "x": 246.22685055651806,
+ "y": -201.15265612025962,
+ "z": 0.0
+ },
+ {
+ "x": 247.2324559343639,
+ "y": -201.1527378352092,
+ "z": 0.0
+ },
+ {
+ "x": 248.23806131220977,
+ "y": -201.15281955015877,
+ "z": 0.0
+ },
+ {
+ "x": 249.24366669005565,
+ "y": -201.15290126510834,
+ "z": 0.0
+ },
+ {
+ "x": 250.2492720679015,
+ "y": -201.1529829800579,
+ "z": 0.0
+ },
+ {
+ "x": 251.25487744574747,
+ "y": -201.1530646950075,
+ "z": 0.0
+ },
+ {
+ "x": 252.26048282359324,
+ "y": -201.15314640995703,
+ "z": 0.0
+ },
+ {
+ "x": 253.2660882014391,
+ "y": -201.1532281249066,
+ "z": 0.0
+ },
+ {
+ "x": 254.27169357928494,
+ "y": -201.15330983985618,
+ "z": 0.0
+ },
+ {
+ "x": 255.27729895713082,
+ "y": -201.15339155480575,
+ "z": 0.0
+ },
+ {
+ "x": 256.28290433497676,
+ "y": -201.15347326975532,
+ "z": 0.0
+ },
+ {
+ "x": 257.2885097128225,
+ "y": -201.15355498470487,
+ "z": 0.0
+ },
+ {
+ "x": 258.29411509066836,
+ "y": -201.15363669965444,
+ "z": 0.0
+ },
+ {
+ "x": 259.29972046851424,
+ "y": -201.15371841460401,
+ "z": 0.0
+ },
+ {
+ "x": 260.3053258463601,
+ "y": -201.1538001295536,
+ "z": 0.0
+ },
+ {
+ "x": 261.310931224206,
+ "y": -201.15388184450316,
+ "z": 0.0
+ },
+ {
+ "x": 262.31653660205194,
+ "y": -201.15396355945273,
+ "z": 0.0
+ },
+ {
+ "x": 263.3221419798977,
+ "y": -201.15404527440228,
+ "z": 0.0
+ },
+ {
+ "x": 264.32774735774353,
+ "y": -201.15412698935185,
+ "z": 0.0
+ },
+ {
+ "x": 265.3333527355894,
+ "y": -201.15420870430142,
+ "z": 0.0
+ },
+ {
+ "x": 266.3389581134353,
+ "y": -201.154290419251,
+ "z": 0.0
+ },
+ {
+ "x": 267.3445634912813,
+ "y": -201.15437213420057,
+ "z": 0.0
+ },
+ {
+ "x": 268.350168869127,
+ "y": -201.15445384915012,
+ "z": 0.0
+ },
+ {
+ "x": 269.3557742469729,
+ "y": -201.1545355640997,
+ "z": 0.0
+ },
+ {
+ "x": 270.3613796248187,
+ "y": -201.15461727904926,
+ "z": 0.0
+ },
+ {
+ "x": 271.3669850026646,
+ "y": -201.15469899399884,
+ "z": 0.0
+ },
+ {
+ "x": 272.3725903805105,
+ "y": -201.1547807089484,
+ "z": 0.0
+ },
+ {
+ "x": 273.37819575835647,
+ "y": -201.15486242389798,
+ "z": 0.0
+ },
+ {
+ "x": 274.3838011362022,
+ "y": -201.15494413884753,
+ "z": 0.0
+ },
+ {
+ "x": 275.38940651404806,
+ "y": -201.1550258537971,
+ "z": 0.0
+ },
+ {
+ "x": 276.3950118918939,
+ "y": -201.15510756874667,
+ "z": 0.0
+ },
+ {
+ "x": 277.40061726973977,
+ "y": -201.15518928369625,
+ "z": 0.0
+ },
+ {
+ "x": 278.40622264758565,
+ "y": -201.15527099864582,
+ "z": 0.0
+ },
+ {
+ "x": 279.41182802543165,
+ "y": -201.1553527135954,
+ "z": 0.0
+ },
+ {
+ "x": 280.4174334032774,
+ "y": -201.15543442854494,
+ "z": 0.0
+ },
+ {
+ "x": 281.42303878112324,
+ "y": -201.1555161434945,
+ "z": 0.0
+ },
+ {
+ "x": 282.42864415896906,
+ "y": -201.15559785844408,
+ "z": 0.0
+ },
+ {
+ "x": 283.43424953681495,
+ "y": -201.15567957339366,
+ "z": 0.0
+ },
+ {
+ "x": 284.43985491466094,
+ "y": -201.15576128834323,
+ "z": 0.0
+ },
+ {
+ "x": 285.4454602925067,
+ "y": -201.15584300329277,
+ "z": 0.0
+ },
+ {
+ "x": 286.4510656703526,
+ "y": -201.15592471824235,
+ "z": 0.0
+ },
+ {
+ "x": 287.4566710481984,
+ "y": -201.15600643319192,
+ "z": 0.0
+ },
+ {
+ "x": 288.46227642604424,
+ "y": -201.1560881481415,
+ "z": 0.0
+ },
+ {
+ "x": 289.4678818038901,
+ "y": -201.15616986309107,
+ "z": 0.0
+ },
+ {
+ "x": 290.4734871817361,
+ "y": -201.15625157804064,
+ "z": 0.0
+ },
+ {
+ "x": 291.4790925595819,
+ "y": -201.15633329299018,
+ "z": 0.0
+ },
+ {
+ "x": 292.48469793742777,
+ "y": -201.15641500793976,
+ "z": 0.0
+ },
+ {
+ "x": 293.4903033152736,
+ "y": -201.15649672288933,
+ "z": 0.0
+ },
+ {
+ "x": 294.4959086931195,
+ "y": -201.1565784378389,
+ "z": 0.0
+ },
+ {
+ "x": 295.5015140709653,
+ "y": -201.15666015278848,
+ "z": 0.0
+ },
+ {
+ "x": 296.5071194488113,
+ "y": -201.15674186773805,
+ "z": 0.0
+ },
+ {
+ "x": 297.51272482665706,
+ "y": -201.1568235826876,
+ "z": 0.0
+ },
+ {
+ "x": 298.51833020450294,
+ "y": -201.15690529763717,
+ "z": 0.0
+ },
+ {
+ "x": 299.52393558234877,
+ "y": -201.15698701258674,
+ "z": 0.0
+ },
+ {
+ "x": 300.52954096019465,
+ "y": -201.1570687275363,
+ "z": 0.0
+ },
+ {
+ "x": 301.5351463380406,
+ "y": -201.1571504424859,
+ "z": 0.0
+ },
+ {
+ "x": 302.54075171588636,
+ "y": -201.15723215743543,
+ "z": 0.0
+ },
+ {
+ "x": 303.54635709373224,
+ "y": -201.157313872385,
+ "z": 0.0
+ },
+ {
+ "x": 304.5519624715781,
+ "y": -201.15739558733458,
+ "z": 0.0
+ },
+ {
+ "x": 305.55756784942395,
+ "y": -201.15747730228415,
+ "z": 0.0
+ },
+ {
+ "x": 306.56317322726983,
+ "y": -201.15755901723372,
+ "z": 0.0
+ },
+ {
+ "x": 307.56877860511577,
+ "y": -201.1576407321833,
+ "z": 0.0
+ },
+ {
+ "x": 308.57438398296154,
+ "y": -201.15772244713284,
+ "z": 0.0
+ },
+ {
+ "x": 309.5799893608074,
+ "y": -201.1578041620824,
+ "z": 0.0
+ },
+ {
+ "x": 310.5855947386533,
+ "y": -201.157885877032,
+ "z": 0.0
+ },
+ {
+ "x": 311.5912001164991,
+ "y": -201.15796759198156,
+ "z": 0.0
+ },
+ {
+ "x": 312.5968054943451,
+ "y": -201.15804930693113,
+ "z": 0.0
+ },
+ {
+ "x": 313.60241087219083,
+ "y": -201.15813102188068,
+ "z": 0.0
+ },
+ {
+ "x": 314.6080162500367,
+ "y": -201.15821273683025,
+ "z": 0.0
+ },
+ {
+ "x": 315.6136216278826,
+ "y": -201.15829445177982,
+ "z": 0.0
+ },
+ {
+ "x": 316.6192270057285,
+ "y": -201.1583761667294,
+ "z": 0.0
+ },
+ {
+ "x": 317.62483238357436,
+ "y": -201.15845788167897,
+ "z": 0.0
+ },
+ {
+ "x": 318.6304377614203,
+ "y": -201.15853959662854,
+ "z": 0.0
+ },
+ {
+ "x": 319.636043139266,
+ "y": -201.1586213115781,
+ "z": 0.0
+ },
+ {
+ "x": 320.6416485171119,
+ "y": -201.15870302652766,
+ "z": 0.0
+ },
+ {
+ "x": 321.64725389495777,
+ "y": -201.15878474147723,
+ "z": 0.0
+ },
+ {
+ "x": 322.65285927280365,
+ "y": -201.1588664564268,
+ "z": 0.0
+ },
+ {
+ "x": 323.65846465064953,
+ "y": -201.15894817137638,
+ "z": 0.0
+ },
+ {
+ "x": 324.6640700284955,
+ "y": -201.15902988632595,
+ "z": 0.0
+ },
+ {
+ "x": 325.66967540634136,
+ "y": -201.1591116012755,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 62,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 101.42000118455115,
+ "y": -197.14088918072804,
+ "z": 0.0
+ },
+ {
+ "x": 102.42560656239702,
+ "y": -197.1409708956776,
+ "z": 0.0
+ },
+ {
+ "x": 103.43121194024287,
+ "y": -197.14105261062718,
+ "z": 0.0
+ },
+ {
+ "x": 104.43681731808874,
+ "y": -197.14113432557673,
+ "z": 0.0
+ },
+ {
+ "x": 105.4424226959346,
+ "y": -197.1412160405263,
+ "z": 0.0
+ },
+ {
+ "x": 106.44802807378046,
+ "y": -197.14129775547588,
+ "z": 0.0
+ },
+ {
+ "x": 107.45363345162632,
+ "y": -197.14137947042545,
+ "z": 0.0
+ },
+ {
+ "x": 108.45923882947218,
+ "y": -197.14146118537502,
+ "z": 0.0
+ },
+ {
+ "x": 109.46484420731804,
+ "y": -197.1415429003246,
+ "z": 0.0
+ },
+ {
+ "x": 110.4704495851639,
+ "y": -197.14162461527414,
+ "z": 0.0
+ },
+ {
+ "x": 111.47605496300976,
+ "y": -197.1417063302237,
+ "z": 0.0
+ },
+ {
+ "x": 112.48166034085563,
+ "y": -197.14178804517329,
+ "z": 0.0
+ },
+ {
+ "x": 113.48726571870148,
+ "y": -197.14186976012286,
+ "z": 0.0
+ },
+ {
+ "x": 114.49287109654733,
+ "y": -197.14195147507243,
+ "z": 0.0
+ },
+ {
+ "x": 115.4984764743932,
+ "y": -197.142033190022,
+ "z": 0.0
+ },
+ {
+ "x": 116.50408185223905,
+ "y": -197.14211490497155,
+ "z": 0.0
+ },
+ {
+ "x": 117.50968723008492,
+ "y": -197.14219661992112,
+ "z": 0.0
+ },
+ {
+ "x": 118.51529260793077,
+ "y": -197.1422783348707,
+ "z": 0.0
+ },
+ {
+ "x": 119.52089798577664,
+ "y": -197.14236004982027,
+ "z": 0.0
+ },
+ {
+ "x": 120.5265033636225,
+ "y": -197.14244176476984,
+ "z": 0.0
+ },
+ {
+ "x": 121.53210874146836,
+ "y": -197.1425234797194,
+ "z": 0.0
+ },
+ {
+ "x": 122.53771411931422,
+ "y": -197.14260519466896,
+ "z": 0.0
+ },
+ {
+ "x": 123.54331949716007,
+ "y": -197.14268690961853,
+ "z": 0.0
+ },
+ {
+ "x": 124.54892487500594,
+ "y": -197.1427686245681,
+ "z": 0.0
+ },
+ {
+ "x": 125.5545302528518,
+ "y": -197.14285033951768,
+ "z": 0.0
+ },
+ {
+ "x": 126.56013563069766,
+ "y": -197.14293205446725,
+ "z": 0.0
+ },
+ {
+ "x": 127.56574100854351,
+ "y": -197.1430137694168,
+ "z": 0.0
+ },
+ {
+ "x": 128.57134638638937,
+ "y": -197.14309548436637,
+ "z": 0.0
+ },
+ {
+ "x": 129.57695176423525,
+ "y": -197.14317719931594,
+ "z": 0.0
+ },
+ {
+ "x": 130.5825571420811,
+ "y": -197.14325891426552,
+ "z": 0.0
+ },
+ {
+ "x": 131.58816251992695,
+ "y": -197.1433406292151,
+ "z": 0.0
+ },
+ {
+ "x": 132.5937678977728,
+ "y": -197.14342234416463,
+ "z": 0.0
+ },
+ {
+ "x": 133.5993732756187,
+ "y": -197.1435040591142,
+ "z": 0.0
+ },
+ {
+ "x": 134.60497865346454,
+ "y": -197.14358577406378,
+ "z": 0.0
+ },
+ {
+ "x": 135.6105840313104,
+ "y": -197.14366748901335,
+ "z": 0.0
+ },
+ {
+ "x": 136.61618940915628,
+ "y": -197.14374920396293,
+ "z": 0.0
+ },
+ {
+ "x": 137.62179478700213,
+ "y": -197.1438309189125,
+ "z": 0.0
+ },
+ {
+ "x": 138.62740016484798,
+ "y": -197.14391263386204,
+ "z": 0.0
+ },
+ {
+ "x": 139.63300554269387,
+ "y": -197.14399434881162,
+ "z": 0.0
+ },
+ {
+ "x": 140.63861092053972,
+ "y": -197.1440760637612,
+ "z": 0.0
+ },
+ {
+ "x": 141.64421629838557,
+ "y": -197.14415777871076,
+ "z": 0.0
+ },
+ {
+ "x": 142.64982167623145,
+ "y": -197.14423949366034,
+ "z": 0.0
+ },
+ {
+ "x": 143.6554270540773,
+ "y": -197.1443212086099,
+ "z": 0.0
+ },
+ {
+ "x": 144.66103243192316,
+ "y": -197.14440292355945,
+ "z": 0.0
+ },
+ {
+ "x": 145.66663780976904,
+ "y": -197.14448463850903,
+ "z": 0.0
+ },
+ {
+ "x": 146.6722431876149,
+ "y": -197.1445663534586,
+ "z": 0.0
+ },
+ {
+ "x": 147.67784856546075,
+ "y": -197.14464806840817,
+ "z": 0.0
+ },
+ {
+ "x": 148.68345394330663,
+ "y": -197.14472978335775,
+ "z": 0.0
+ },
+ {
+ "x": 149.68905932115248,
+ "y": -197.1448114983073,
+ "z": 0.0
+ },
+ {
+ "x": 150.69466469899834,
+ "y": -197.14489321325686,
+ "z": 0.0
+ },
+ {
+ "x": 151.70027007684422,
+ "y": -197.14497492820644,
+ "z": 0.0
+ },
+ {
+ "x": 152.70587545469007,
+ "y": -197.145056643156,
+ "z": 0.0
+ },
+ {
+ "x": 153.71148083253593,
+ "y": -197.14513835810558,
+ "z": 0.0
+ },
+ {
+ "x": 154.7170862103818,
+ "y": -197.14522007305516,
+ "z": 0.0
+ },
+ {
+ "x": 155.72269158822766,
+ "y": -197.1453017880047,
+ "z": 0.0
+ },
+ {
+ "x": 156.72829696607351,
+ "y": -197.14538350295427,
+ "z": 0.0
+ },
+ {
+ "x": 157.7339023439194,
+ "y": -197.14546521790385,
+ "z": 0.0
+ },
+ {
+ "x": 158.73950772176525,
+ "y": -197.14554693285342,
+ "z": 0.0
+ },
+ {
+ "x": 159.74511309961113,
+ "y": -197.145628647803,
+ "z": 0.0
+ },
+ {
+ "x": 160.75071847745699,
+ "y": -197.14571036275257,
+ "z": 0.0
+ },
+ {
+ "x": 161.75632385530284,
+ "y": -197.1457920777021,
+ "z": 0.0
+ },
+ {
+ "x": 162.76192923314872,
+ "y": -197.14587379265168,
+ "z": 0.0
+ },
+ {
+ "x": 163.76753461099457,
+ "y": -197.14595550760126,
+ "z": 0.0
+ },
+ {
+ "x": 164.77313998884046,
+ "y": -197.14603722255083,
+ "z": 0.0
+ },
+ {
+ "x": 165.77874536668628,
+ "y": -197.1461189375004,
+ "z": 0.0
+ },
+ {
+ "x": 166.78435074453216,
+ "y": -197.14620065244995,
+ "z": 0.0
+ },
+ {
+ "x": 167.78995612237802,
+ "y": -197.14628236739952,
+ "z": 0.0
+ },
+ {
+ "x": 168.79556150022387,
+ "y": -197.1463640823491,
+ "z": 0.0
+ },
+ {
+ "x": 169.80116687806975,
+ "y": -197.14644579729867,
+ "z": 0.0
+ },
+ {
+ "x": 170.80677225591563,
+ "y": -197.14652751224824,
+ "z": 0.0
+ },
+ {
+ "x": 171.81237763376146,
+ "y": -197.1466092271978,
+ "z": 0.0
+ },
+ {
+ "x": 172.81798301160734,
+ "y": -197.14669094214736,
+ "z": 0.0
+ },
+ {
+ "x": 173.82358838945322,
+ "y": -197.14677265709693,
+ "z": 0.0
+ },
+ {
+ "x": 174.82919376729905,
+ "y": -197.1468543720465,
+ "z": 0.0
+ },
+ {
+ "x": 175.83479914514493,
+ "y": -197.14693608699608,
+ "z": 0.0
+ },
+ {
+ "x": 176.8404045229908,
+ "y": -197.14701780194565,
+ "z": 0.0
+ },
+ {
+ "x": 177.84600990083663,
+ "y": -197.1470995168952,
+ "z": 0.0
+ },
+ {
+ "x": 178.85161527868252,
+ "y": -197.14718123184477,
+ "z": 0.0
+ },
+ {
+ "x": 179.8572206565284,
+ "y": -197.14726294679434,
+ "z": 0.0
+ },
+ {
+ "x": 180.86282603437425,
+ "y": -197.14734466174392,
+ "z": 0.0
+ },
+ {
+ "x": 181.8684314122201,
+ "y": -197.1474263766935,
+ "z": 0.0
+ },
+ {
+ "x": 182.874036790066,
+ "y": -197.14750809164306,
+ "z": 0.0
+ },
+ {
+ "x": 183.87964216791184,
+ "y": -197.1475898065926,
+ "z": 0.0
+ },
+ {
+ "x": 184.8852475457577,
+ "y": -197.14767152154218,
+ "z": 0.0
+ },
+ {
+ "x": 185.89085292360357,
+ "y": -197.14775323649175,
+ "z": 0.0
+ },
+ {
+ "x": 186.89645830144943,
+ "y": -197.14783495144133,
+ "z": 0.0
+ },
+ {
+ "x": 187.90206367929528,
+ "y": -197.1479166663909,
+ "z": 0.0
+ },
+ {
+ "x": 188.90766905714116,
+ "y": -197.14799838134047,
+ "z": 0.0
+ },
+ {
+ "x": 189.91327443498702,
+ "y": -197.14808009629002,
+ "z": 0.0
+ },
+ {
+ "x": 190.91887981283287,
+ "y": -197.1481618112396,
+ "z": 0.0
+ },
+ {
+ "x": 191.92448519067875,
+ "y": -197.14824352618916,
+ "z": 0.0
+ },
+ {
+ "x": 192.9300905685246,
+ "y": -197.14832524113874,
+ "z": 0.0
+ },
+ {
+ "x": 193.93569594637046,
+ "y": -197.1484069560883,
+ "z": 0.0
+ },
+ {
+ "x": 194.94130132421634,
+ "y": -197.14848867103785,
+ "z": 0.0
+ },
+ {
+ "x": 195.9469067020622,
+ "y": -197.14857038598743,
+ "z": 0.0
+ },
+ {
+ "x": 196.95251207990805,
+ "y": -197.148652100937,
+ "z": 0.0
+ },
+ {
+ "x": 197.95811745775393,
+ "y": -197.14873381588657,
+ "z": 0.0
+ },
+ {
+ "x": 198.96372283559978,
+ "y": -197.14881553083615,
+ "z": 0.0
+ },
+ {
+ "x": 199.96932821344564,
+ "y": -197.14889724578572,
+ "z": 0.0
+ },
+ {
+ "x": 200.97493359129152,
+ "y": -197.14897896073526,
+ "z": 0.0
+ },
+ {
+ "x": 201.98053896913737,
+ "y": -197.14906067568484,
+ "z": 0.0
+ },
+ {
+ "x": 202.98614434698322,
+ "y": -197.1491423906344,
+ "z": 0.0
+ },
+ {
+ "x": 203.9917497248291,
+ "y": -197.14922410558398,
+ "z": 0.0
+ },
+ {
+ "x": 204.99735510267496,
+ "y": -197.14930582053356,
+ "z": 0.0
+ },
+ {
+ "x": 206.0029604805208,
+ "y": -197.14938753548313,
+ "z": 0.0
+ },
+ {
+ "x": 207.0085658583667,
+ "y": -197.14946925043267,
+ "z": 0.0
+ },
+ {
+ "x": 208.01417123621258,
+ "y": -197.14955096538225,
+ "z": 0.0
+ },
+ {
+ "x": 209.0197766140584,
+ "y": -197.14963268033182,
+ "z": 0.0
+ },
+ {
+ "x": 210.02538199190428,
+ "y": -197.1497143952814,
+ "z": 0.0
+ },
+ {
+ "x": 211.03098736975016,
+ "y": -197.14979611023097,
+ "z": 0.0
+ },
+ {
+ "x": 212.036592747596,
+ "y": -197.1498778251805,
+ "z": 0.0
+ },
+ {
+ "x": 213.04219812544187,
+ "y": -197.14995954013008,
+ "z": 0.0
+ },
+ {
+ "x": 214.04780350328775,
+ "y": -197.15004125507966,
+ "z": 0.0
+ },
+ {
+ "x": 215.05340888113358,
+ "y": -197.15012297002923,
+ "z": 0.0
+ },
+ {
+ "x": 216.05901425897946,
+ "y": -197.1502046849788,
+ "z": 0.0
+ },
+ {
+ "x": 217.06461963682534,
+ "y": -197.15028639992838,
+ "z": 0.0
+ },
+ {
+ "x": 218.0702250146712,
+ "y": -197.15036811487792,
+ "z": 0.0
+ },
+ {
+ "x": 219.07583039251705,
+ "y": -197.1504498298275,
+ "z": 0.0
+ },
+ {
+ "x": 220.08143577036293,
+ "y": -197.15053154477707,
+ "z": 0.0
+ },
+ {
+ "x": 221.08704114820878,
+ "y": -197.15061325972664,
+ "z": 0.0
+ },
+ {
+ "x": 222.09264652605464,
+ "y": -197.1506949746762,
+ "z": 0.0
+ },
+ {
+ "x": 223.09825190390052,
+ "y": -197.15077668962576,
+ "z": 0.0
+ },
+ {
+ "x": 224.10385728174637,
+ "y": -197.15085840457533,
+ "z": 0.0
+ },
+ {
+ "x": 225.10946265959223,
+ "y": -197.1509401195249,
+ "z": 0.0
+ },
+ {
+ "x": 226.1150680374381,
+ "y": -197.15102183447448,
+ "z": 0.0
+ },
+ {
+ "x": 227.12067341528396,
+ "y": -197.15110354942405,
+ "z": 0.0
+ },
+ {
+ "x": 228.1262787931298,
+ "y": -197.15118526437362,
+ "z": 0.0
+ },
+ {
+ "x": 229.1318841709757,
+ "y": -197.15126697932317,
+ "z": 0.0
+ },
+ {
+ "x": 230.13748954882155,
+ "y": -197.15134869427274,
+ "z": 0.0
+ },
+ {
+ "x": 231.1430949266674,
+ "y": -197.1514304092223,
+ "z": 0.0
+ },
+ {
+ "x": 232.14870030451328,
+ "y": -197.1515121241719,
+ "z": 0.0
+ },
+ {
+ "x": 233.15430568235914,
+ "y": -197.15159383912146,
+ "z": 0.0
+ },
+ {
+ "x": 234.159911060205,
+ "y": -197.15167555407103,
+ "z": 0.0
+ },
+ {
+ "x": 235.16551643805087,
+ "y": -197.15175726902058,
+ "z": 0.0
+ },
+ {
+ "x": 236.17112181589673,
+ "y": -197.15183898397015,
+ "z": 0.0
+ },
+ {
+ "x": 237.17672719374258,
+ "y": -197.15192069891972,
+ "z": 0.0
+ },
+ {
+ "x": 238.18233257158846,
+ "y": -197.1520024138693,
+ "z": 0.0
+ },
+ {
+ "x": 239.1879379494343,
+ "y": -197.15208412881887,
+ "z": 0.0
+ },
+ {
+ "x": 240.1935433272802,
+ "y": -197.15216584376842,
+ "z": 0.0
+ },
+ {
+ "x": 241.19914870512605,
+ "y": -197.152247558718,
+ "z": 0.0
+ },
+ {
+ "x": 242.2047540829719,
+ "y": -197.15232927366756,
+ "z": 0.0
+ },
+ {
+ "x": 243.21035946081778,
+ "y": -197.15241098861713,
+ "z": 0.0
+ },
+ {
+ "x": 244.21596483866364,
+ "y": -197.1524927035667,
+ "z": 0.0
+ },
+ {
+ "x": 245.2215702165095,
+ "y": -197.15257441851628,
+ "z": 0.0
+ },
+ {
+ "x": 246.22717559435537,
+ "y": -197.15265613346583,
+ "z": 0.0
+ },
+ {
+ "x": 247.23278097220123,
+ "y": -197.1527378484154,
+ "z": 0.0
+ },
+ {
+ "x": 248.23838635004708,
+ "y": -197.15281956336497,
+ "z": 0.0
+ },
+ {
+ "x": 249.24399172789296,
+ "y": -197.15290127831454,
+ "z": 0.0
+ },
+ {
+ "x": 250.24959710573881,
+ "y": -197.15298299326412,
+ "z": 0.0
+ },
+ {
+ "x": 251.25520248358467,
+ "y": -197.1530647082137,
+ "z": 0.0
+ },
+ {
+ "x": 252.26080786143055,
+ "y": -197.15314642316324,
+ "z": 0.0
+ },
+ {
+ "x": 253.2664132392764,
+ "y": -197.1532281381128,
+ "z": 0.0
+ },
+ {
+ "x": 254.27201861712226,
+ "y": -197.15330985306238,
+ "z": 0.0
+ },
+ {
+ "x": 255.27762399496814,
+ "y": -197.15339156801195,
+ "z": 0.0
+ },
+ {
+ "x": 256.283229372814,
+ "y": -197.15347328296153,
+ "z": 0.0
+ },
+ {
+ "x": 257.2888347506598,
+ "y": -197.15355499791107,
+ "z": 0.0
+ },
+ {
+ "x": 258.2944401285057,
+ "y": -197.15363671286065,
+ "z": 0.0
+ },
+ {
+ "x": 259.3000455063516,
+ "y": -197.15371842781022,
+ "z": 0.0
+ },
+ {
+ "x": 260.30565088419746,
+ "y": -197.1538001427598,
+ "z": 0.0
+ },
+ {
+ "x": 261.31125626204334,
+ "y": -197.15388185770937,
+ "z": 0.0
+ },
+ {
+ "x": 262.31686163988917,
+ "y": -197.15396357265894,
+ "z": 0.0
+ },
+ {
+ "x": 263.32246701773505,
+ "y": -197.15404528760848,
+ "z": 0.0
+ },
+ {
+ "x": 264.3280723955809,
+ "y": -197.15412700255806,
+ "z": 0.0
+ },
+ {
+ "x": 265.33367777342676,
+ "y": -197.15420871750763,
+ "z": 0.0
+ },
+ {
+ "x": 266.33928315127264,
+ "y": -197.1542904324572,
+ "z": 0.0
+ },
+ {
+ "x": 267.3448885291185,
+ "y": -197.15437214740678,
+ "z": 0.0
+ },
+ {
+ "x": 268.35049390696435,
+ "y": -197.15445386235632,
+ "z": 0.0
+ },
+ {
+ "x": 269.3560992848102,
+ "y": -197.1545355773059,
+ "z": 0.0
+ },
+ {
+ "x": 270.36170466265605,
+ "y": -197.15461729225547,
+ "z": 0.0
+ },
+ {
+ "x": 271.36731004050193,
+ "y": -197.15469900720504,
+ "z": 0.0
+ },
+ {
+ "x": 272.3729154183478,
+ "y": -197.1547807221546,
+ "z": 0.0
+ },
+ {
+ "x": 273.3785207961937,
+ "y": -197.15486243710419,
+ "z": 0.0
+ },
+ {
+ "x": 274.3841261740395,
+ "y": -197.15494415205373,
+ "z": 0.0
+ },
+ {
+ "x": 275.3897315518854,
+ "y": -197.1550258670033,
+ "z": 0.0
+ },
+ {
+ "x": 276.39533692973123,
+ "y": -197.15510758195288,
+ "z": 0.0
+ },
+ {
+ "x": 277.4009423075771,
+ "y": -197.15518929690245,
+ "z": 0.0
+ },
+ {
+ "x": 278.406547685423,
+ "y": -197.15527101185202,
+ "z": 0.0
+ },
+ {
+ "x": 279.4121530632689,
+ "y": -197.1553527268016,
+ "z": 0.0
+ },
+ {
+ "x": 280.41775844111476,
+ "y": -197.15543444175114,
+ "z": 0.0
+ },
+ {
+ "x": 281.4233638189606,
+ "y": -197.1555161567007,
+ "z": 0.0
+ },
+ {
+ "x": 282.4289691968064,
+ "y": -197.1555978716503,
+ "z": 0.0
+ },
+ {
+ "x": 283.4345745746523,
+ "y": -197.15567958659986,
+ "z": 0.0
+ },
+ {
+ "x": 284.44017995249817,
+ "y": -197.15576130154943,
+ "z": 0.0
+ },
+ {
+ "x": 285.44578533034405,
+ "y": -197.15584301649898,
+ "z": 0.0
+ },
+ {
+ "x": 286.45139070818993,
+ "y": -197.15592473144855,
+ "z": 0.0
+ },
+ {
+ "x": 287.45699608603576,
+ "y": -197.15600644639812,
+ "z": 0.0
+ },
+ {
+ "x": 288.4626014638816,
+ "y": -197.1560881613477,
+ "z": 0.0
+ },
+ {
+ "x": 289.46820684172746,
+ "y": -197.15616987629727,
+ "z": 0.0
+ },
+ {
+ "x": 290.47381221957335,
+ "y": -197.15625159124684,
+ "z": 0.0
+ },
+ {
+ "x": 291.47941759741923,
+ "y": -197.1563333061964,
+ "z": 0.0
+ },
+ {
+ "x": 292.4850229752651,
+ "y": -197.15641502114596,
+ "z": 0.0
+ },
+ {
+ "x": 293.49062835311094,
+ "y": -197.15649673609553,
+ "z": 0.0
+ },
+ {
+ "x": 294.4962337309568,
+ "y": -197.1565784510451,
+ "z": 0.0
+ },
+ {
+ "x": 295.50183910880264,
+ "y": -197.15666016599468,
+ "z": 0.0
+ },
+ {
+ "x": 296.5074444866485,
+ "y": -197.15674188094425,
+ "z": 0.0
+ },
+ {
+ "x": 297.5130498644944,
+ "y": -197.1568235958938,
+ "z": 0.0
+ },
+ {
+ "x": 298.5186552423403,
+ "y": -197.15690531084337,
+ "z": 0.0
+ },
+ {
+ "x": 299.5242606201861,
+ "y": -197.15698702579294,
+ "z": 0.0
+ },
+ {
+ "x": 300.529865998032,
+ "y": -197.15706874074252,
+ "z": 0.0
+ },
+ {
+ "x": 301.5354713758778,
+ "y": -197.1571504556921,
+ "z": 0.0
+ },
+ {
+ "x": 302.5410767537237,
+ "y": -197.15723217064163,
+ "z": 0.0
+ },
+ {
+ "x": 303.5466821315696,
+ "y": -197.1573138855912,
+ "z": 0.0
+ },
+ {
+ "x": 304.55228750941546,
+ "y": -197.15739560054078,
+ "z": 0.0
+ },
+ {
+ "x": 305.5578928872613,
+ "y": -197.15747731549035,
+ "z": 0.0
+ },
+ {
+ "x": 306.56349826510717,
+ "y": -197.15755903043993,
+ "z": 0.0
+ },
+ {
+ "x": 307.569103642953,
+ "y": -197.1576407453895,
+ "z": 0.0
+ },
+ {
+ "x": 308.5747090207989,
+ "y": -197.15772246033904,
+ "z": 0.0
+ },
+ {
+ "x": 309.58031439864476,
+ "y": -197.15780417528862,
+ "z": 0.0
+ },
+ {
+ "x": 310.58591977649064,
+ "y": -197.1578858902382,
+ "z": 0.0
+ },
+ {
+ "x": 311.59152515433647,
+ "y": -197.15796760518776,
+ "z": 0.0
+ },
+ {
+ "x": 312.59713053218235,
+ "y": -197.15804932013734,
+ "z": 0.0
+ },
+ {
+ "x": 313.6027359100282,
+ "y": -197.15813103508688,
+ "z": 0.0
+ },
+ {
+ "x": 314.60834128787405,
+ "y": -197.15821275003645,
+ "z": 0.0
+ },
+ {
+ "x": 315.61394666571994,
+ "y": -197.15829446498603,
+ "z": 0.0
+ },
+ {
+ "x": 316.6195520435658,
+ "y": -197.1583761799356,
+ "z": 0.0
+ },
+ {
+ "x": 317.6251574214117,
+ "y": -197.15845789488517,
+ "z": 0.0
+ },
+ {
+ "x": 318.6307627992575,
+ "y": -197.15853960983475,
+ "z": 0.0
+ },
+ {
+ "x": 319.63636817710335,
+ "y": -197.1586213247843,
+ "z": 0.0
+ },
+ {
+ "x": 320.64197355494923,
+ "y": -197.15870303973387,
+ "z": 0.0
+ },
+ {
+ "x": 321.6475789327951,
+ "y": -197.15878475468344,
+ "z": 0.0
+ },
+ {
+ "x": 322.653184310641,
+ "y": -197.158866469633,
+ "z": 0.0
+ },
+ {
+ "x": 323.6587896884869,
+ "y": -197.15894818458258,
+ "z": 0.0
+ },
+ {
+ "x": 324.6643950663327,
+ "y": -197.15902989953216,
+ "z": 0.0
+ },
+ {
+ "x": 325.6700004441786,
+ "y": -197.1591116144817,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 63,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 325.6701629630972,
+ "y": -195.1591116210848,
+ "z": 0.0
+ },
+ {
+ "x": 324.6645575852513,
+ "y": -195.15902990613526,
+ "z": 0.0
+ },
+ {
+ "x": 323.65895220740555,
+ "y": -195.1589481911857,
+ "z": 0.0
+ },
+ {
+ "x": 322.65334682955967,
+ "y": -195.1588664762361,
+ "z": 0.0
+ },
+ {
+ "x": 321.6477414517138,
+ "y": -195.15878476128654,
+ "z": 0.0
+ },
+ {
+ "x": 320.6421360738679,
+ "y": -195.15870304633697,
+ "z": 0.0
+ },
+ {
+ "x": 319.636530696022,
+ "y": -195.1586213313874,
+ "z": 0.0
+ },
+ {
+ "x": 318.63092531817614,
+ "y": -195.15853961643785,
+ "z": 0.0
+ },
+ {
+ "x": 317.62531994033037,
+ "y": -195.15845790148828,
+ "z": 0.0
+ },
+ {
+ "x": 316.6197145624845,
+ "y": -195.1583761865387,
+ "z": 0.0
+ },
+ {
+ "x": 315.6141091846386,
+ "y": -195.15829447158913,
+ "z": 0.0
+ },
+ {
+ "x": 314.6085038067927,
+ "y": -195.15821275663956,
+ "z": 0.0
+ },
+ {
+ "x": 313.60289842894684,
+ "y": -195.15813104168998,
+ "z": 0.0
+ },
+ {
+ "x": 312.59729305110096,
+ "y": -195.15804932674044,
+ "z": 0.0
+ },
+ {
+ "x": 311.59168767325514,
+ "y": -195.15796761179087,
+ "z": 0.0
+ },
+ {
+ "x": 310.5860822954093,
+ "y": -195.1578858968413,
+ "z": 0.0
+ },
+ {
+ "x": 309.58047691756343,
+ "y": -195.15780418189172,
+ "z": 0.0
+ },
+ {
+ "x": 308.57487153971755,
+ "y": -195.15772246694215,
+ "z": 0.0
+ },
+ {
+ "x": 307.5692661618716,
+ "y": -195.1576407519926,
+ "z": 0.0
+ },
+ {
+ "x": 306.56366078402584,
+ "y": -195.15755903704303,
+ "z": 0.0
+ },
+ {
+ "x": 305.55805540617996,
+ "y": -195.15747732209346,
+ "z": 0.0
+ },
+ {
+ "x": 304.55245002833414,
+ "y": -195.15739560714388,
+ "z": 0.0
+ },
+ {
+ "x": 303.54684465048825,
+ "y": -195.1573138921943,
+ "z": 0.0
+ },
+ {
+ "x": 302.5412392726424,
+ "y": -195.15723217724474,
+ "z": 0.0
+ },
+ {
+ "x": 301.53563389479643,
+ "y": -195.1571504622952,
+ "z": 0.0
+ },
+ {
+ "x": 300.53002851695067,
+ "y": -195.15706874734562,
+ "z": 0.0
+ },
+ {
+ "x": 299.5244231391048,
+ "y": -195.15698703239605,
+ "z": 0.0
+ },
+ {
+ "x": 298.51881776125896,
+ "y": -195.15690531744647,
+ "z": 0.0
+ },
+ {
+ "x": 297.5132123834131,
+ "y": -195.1568236024969,
+ "z": 0.0
+ },
+ {
+ "x": 296.50760700556714,
+ "y": -195.15674188754735,
+ "z": 0.0
+ },
+ {
+ "x": 295.5020016277213,
+ "y": -195.15666017259778,
+ "z": 0.0
+ },
+ {
+ "x": 294.4963962498755,
+ "y": -195.1565784576482,
+ "z": 0.0
+ },
+ {
+ "x": 293.4907908720296,
+ "y": -195.15649674269864,
+ "z": 0.0
+ },
+ {
+ "x": 292.4851854941838,
+ "y": -195.15641502774906,
+ "z": 0.0
+ },
+ {
+ "x": 291.4795801163379,
+ "y": -195.1563333127995,
+ "z": 0.0
+ },
+ {
+ "x": 290.47397473849196,
+ "y": -195.15625159784994,
+ "z": 0.0
+ },
+ {
+ "x": 289.46836936064614,
+ "y": -195.15616988290037,
+ "z": 0.0
+ },
+ {
+ "x": 288.46276398280025,
+ "y": -195.1560881679508,
+ "z": 0.0
+ },
+ {
+ "x": 287.45715860495443,
+ "y": -195.15600645300123,
+ "z": 0.0
+ },
+ {
+ "x": 286.4515532271086,
+ "y": -195.15592473805165,
+ "z": 0.0
+ },
+ {
+ "x": 285.4459478492627,
+ "y": -195.15584302310208,
+ "z": 0.0
+ },
+ {
+ "x": 284.4403424714168,
+ "y": -195.15576130815253,
+ "z": 0.0
+ },
+ {
+ "x": 283.43473709357096,
+ "y": -195.15567959320296,
+ "z": 0.0
+ },
+ {
+ "x": 282.4291317157251,
+ "y": -195.1555978782534,
+ "z": 0.0
+ },
+ {
+ "x": 281.42352633787925,
+ "y": -195.15551616330382,
+ "z": 0.0
+ },
+ {
+ "x": 280.4179209600334,
+ "y": -195.15543444835424,
+ "z": 0.0
+ },
+ {
+ "x": 279.4123155821875,
+ "y": -195.1553527334047,
+ "z": 0.0
+ },
+ {
+ "x": 278.40671020434166,
+ "y": -195.15527101845512,
+ "z": 0.0
+ },
+ {
+ "x": 277.4011048264958,
+ "y": -195.15518930350555,
+ "z": 0.0
+ },
+ {
+ "x": 276.3954994486499,
+ "y": -195.15510758855598,
+ "z": 0.0
+ },
+ {
+ "x": 275.3898940708041,
+ "y": -195.1550258736064,
+ "z": 0.0
+ },
+ {
+ "x": 274.3842886929582,
+ "y": -195.15494415865683,
+ "z": 0.0
+ },
+ {
+ "x": 273.3786833151123,
+ "y": -195.1548624437073,
+ "z": 0.0
+ },
+ {
+ "x": 272.3730779372665,
+ "y": -195.15478072875771,
+ "z": 0.0
+ },
+ {
+ "x": 271.3674725594206,
+ "y": -195.15469901380814,
+ "z": 0.0
+ },
+ {
+ "x": 270.3618671815747,
+ "y": -195.15461729885857,
+ "z": 0.0
+ },
+ {
+ "x": 269.3562618037289,
+ "y": -195.154535583909,
+ "z": 0.0
+ },
+ {
+ "x": 268.350656425883,
+ "y": -195.15445386895942,
+ "z": 0.0
+ },
+ {
+ "x": 267.34505104803713,
+ "y": -195.15437215400988,
+ "z": 0.0
+ },
+ {
+ "x": 266.3394456701913,
+ "y": -195.1542904390603,
+ "z": 0.0
+ },
+ {
+ "x": 265.3338402923454,
+ "y": -195.15420872411073,
+ "z": 0.0
+ },
+ {
+ "x": 264.32823491449955,
+ "y": -195.15412700916116,
+ "z": 0.0
+ },
+ {
+ "x": 263.3226295366537,
+ "y": -195.15404529421158,
+ "z": 0.0
+ },
+ {
+ "x": 262.3170241588078,
+ "y": -195.15396357926204,
+ "z": 0.0
+ },
+ {
+ "x": 261.311418780962,
+ "y": -195.15388186431247,
+ "z": 0.0
+ },
+ {
+ "x": 260.30581340311613,
+ "y": -195.1538001493629,
+ "z": 0.0
+ },
+ {
+ "x": 259.30020802527025,
+ "y": -195.15371843441332,
+ "z": 0.0
+ },
+ {
+ "x": 258.29460264742437,
+ "y": -195.15363671946375,
+ "z": 0.0
+ },
+ {
+ "x": 257.2889972695785,
+ "y": -195.15355500451417,
+ "z": 0.0
+ },
+ {
+ "x": 256.2833918917326,
+ "y": -195.15347328956463,
+ "z": 0.0
+ },
+ {
+ "x": 255.27778651388678,
+ "y": -195.15339157461506,
+ "z": 0.0
+ },
+ {
+ "x": 254.2721811360409,
+ "y": -195.15330985966548,
+ "z": 0.0
+ },
+ {
+ "x": 253.26657575819507,
+ "y": -195.1532281447159,
+ "z": 0.0
+ },
+ {
+ "x": 252.2609703803492,
+ "y": -195.15314642976634,
+ "z": 0.0
+ },
+ {
+ "x": 251.25536500250325,
+ "y": -195.1530647148168,
+ "z": 0.0
+ },
+ {
+ "x": 250.2497596246575,
+ "y": -195.15298299986722,
+ "z": 0.0
+ },
+ {
+ "x": 249.2441542468116,
+ "y": -195.15290128491765,
+ "z": 0.0
+ },
+ {
+ "x": 248.23854886896572,
+ "y": -195.15281956996807,
+ "z": 0.0
+ },
+ {
+ "x": 247.2329434911199,
+ "y": -195.1527378550185,
+ "z": 0.0
+ },
+ {
+ "x": 246.22733811327402,
+ "y": -195.15265614006893,
+ "z": 0.0
+ },
+ {
+ "x": 245.22173273542808,
+ "y": -195.15257442511938,
+ "z": 0.0
+ },
+ {
+ "x": 244.2161273575823,
+ "y": -195.1524927101698,
+ "z": 0.0
+ },
+ {
+ "x": 243.21052197973643,
+ "y": -195.15241099522024,
+ "z": 0.0
+ },
+ {
+ "x": 242.20491660189055,
+ "y": -195.15232928027066,
+ "z": 0.0
+ },
+ {
+ "x": 241.19931122404472,
+ "y": -195.1522475653211,
+ "z": 0.0
+ },
+ {
+ "x": 240.19370584619884,
+ "y": -195.15216585037152,
+ "z": 0.0
+ },
+ {
+ "x": 239.1881004683529,
+ "y": -195.15208413542197,
+ "z": 0.0
+ },
+ {
+ "x": 238.18249509050713,
+ "y": -195.1520024204724,
+ "z": 0.0
+ },
+ {
+ "x": 237.17688971266125,
+ "y": -195.15192070552283,
+ "z": 0.0
+ },
+ {
+ "x": 236.17128433481537,
+ "y": -195.15183899057325,
+ "z": 0.0
+ },
+ {
+ "x": 235.16567895696954,
+ "y": -195.15175727562368,
+ "z": 0.0
+ },
+ {
+ "x": 234.1600735791236,
+ "y": -195.15167556067414,
+ "z": 0.0
+ },
+ {
+ "x": 233.15446820127778,
+ "y": -195.15159384572456,
+ "z": 0.0
+ },
+ {
+ "x": 232.14886282343195,
+ "y": -195.151512130775,
+ "z": 0.0
+ },
+ {
+ "x": 231.14325744558607,
+ "y": -195.15143041582542,
+ "z": 0.0
+ },
+ {
+ "x": 230.1376520677402,
+ "y": -195.15134870087584,
+ "z": 0.0
+ },
+ {
+ "x": 229.13204668989437,
+ "y": -195.15126698592627,
+ "z": 0.0
+ },
+ {
+ "x": 228.12644131204843,
+ "y": -195.15118527097673,
+ "z": 0.0
+ },
+ {
+ "x": 227.1208359342026,
+ "y": -195.15110355602715,
+ "z": 0.0
+ },
+ {
+ "x": 226.11523055635678,
+ "y": -195.15102184107758,
+ "z": 0.0
+ },
+ {
+ "x": 225.1096251785109,
+ "y": -195.150940126128,
+ "z": 0.0
+ },
+ {
+ "x": 224.10401980066501,
+ "y": -195.15085841117843,
+ "z": 0.0
+ },
+ {
+ "x": 223.0984144228192,
+ "y": -195.15077669622886,
+ "z": 0.0
+ },
+ {
+ "x": 222.09280904497325,
+ "y": -195.15069498127932,
+ "z": 0.0
+ },
+ {
+ "x": 221.08720366712743,
+ "y": -195.15061326632974,
+ "z": 0.0
+ },
+ {
+ "x": 220.0815982892816,
+ "y": -195.15053155138017,
+ "z": 0.0
+ },
+ {
+ "x": 219.07599291143572,
+ "y": -195.1504498364306,
+ "z": 0.0
+ },
+ {
+ "x": 218.07038753358984,
+ "y": -195.15036812148102,
+ "z": 0.0
+ },
+ {
+ "x": 217.06478215574396,
+ "y": -195.15028640653148,
+ "z": 0.0
+ },
+ {
+ "x": 216.05917677789813,
+ "y": -195.1502046915819,
+ "z": 0.0
+ },
+ {
+ "x": 215.05357140005225,
+ "y": -195.15012297663233,
+ "z": 0.0
+ },
+ {
+ "x": 214.04796602220642,
+ "y": -195.15004126168276,
+ "z": 0.0
+ },
+ {
+ "x": 213.04236064436054,
+ "y": -195.14995954673319,
+ "z": 0.0
+ },
+ {
+ "x": 212.03675526651466,
+ "y": -195.1498778317836,
+ "z": 0.0
+ },
+ {
+ "x": 211.03114988866878,
+ "y": -195.14979611683407,
+ "z": 0.0
+ },
+ {
+ "x": 210.02554451082295,
+ "y": -195.1497144018845,
+ "z": 0.0
+ },
+ {
+ "x": 209.01993913297707,
+ "y": -195.14963268693492,
+ "z": 0.0
+ },
+ {
+ "x": 208.01433375513125,
+ "y": -195.14955097198535,
+ "z": 0.0
+ },
+ {
+ "x": 207.00872837728537,
+ "y": -195.14946925703578,
+ "z": 0.0
+ },
+ {
+ "x": 206.00312299943943,
+ "y": -195.14938754208623,
+ "z": 0.0
+ },
+ {
+ "x": 204.9975176215936,
+ "y": -195.14930582713666,
+ "z": 0.0
+ },
+ {
+ "x": 203.99191224374778,
+ "y": -195.14922411218708,
+ "z": 0.0
+ },
+ {
+ "x": 202.9863068659019,
+ "y": -195.1491423972375,
+ "z": 0.0
+ },
+ {
+ "x": 201.980701488056,
+ "y": -195.14906068228794,
+ "z": 0.0
+ },
+ {
+ "x": 200.9750961102102,
+ "y": -195.14897896733837,
+ "z": 0.0
+ },
+ {
+ "x": 199.96949073236425,
+ "y": -195.14889725238882,
+ "z": 0.0
+ },
+ {
+ "x": 198.96388535451842,
+ "y": -195.14881553743925,
+ "z": 0.0
+ },
+ {
+ "x": 197.9582799766726,
+ "y": -195.14873382248967,
+ "z": 0.0
+ },
+ {
+ "x": 196.95267459882672,
+ "y": -195.1486521075401,
+ "z": 0.0
+ },
+ {
+ "x": 195.94706922098084,
+ "y": -195.14857039259053,
+ "z": 0.0
+ },
+ {
+ "x": 194.941463843135,
+ "y": -195.14848867764096,
+ "z": 0.0
+ },
+ {
+ "x": 193.93585846528907,
+ "y": -195.1484069626914,
+ "z": 0.0
+ },
+ {
+ "x": 192.93025308744325,
+ "y": -195.14832524774184,
+ "z": 0.0
+ },
+ {
+ "x": 191.92464770959742,
+ "y": -195.14824353279226,
+ "z": 0.0
+ },
+ {
+ "x": 190.91904233175154,
+ "y": -195.1481618178427,
+ "z": 0.0
+ },
+ {
+ "x": 189.91343695390566,
+ "y": -195.14808010289312,
+ "z": 0.0
+ },
+ {
+ "x": 188.90783157605978,
+ "y": -195.14799838794357,
+ "z": 0.0
+ },
+ {
+ "x": 187.90222619821395,
+ "y": -195.147916672994,
+ "z": 0.0
+ },
+ {
+ "x": 186.89662082036807,
+ "y": -195.14783495804443,
+ "z": 0.0
+ },
+ {
+ "x": 185.89101544252225,
+ "y": -195.14775324309485,
+ "z": 0.0
+ },
+ {
+ "x": 184.88541006467636,
+ "y": -195.14767152814528,
+ "z": 0.0
+ },
+ {
+ "x": 183.87980468683048,
+ "y": -195.1475898131957,
+ "z": 0.0
+ },
+ {
+ "x": 182.8741993089846,
+ "y": -195.14750809824616,
+ "z": 0.0
+ },
+ {
+ "x": 181.86859393113878,
+ "y": -195.1474263832966,
+ "z": 0.0
+ },
+ {
+ "x": 180.8629885532929,
+ "y": -195.14734466834702,
+ "z": 0.0
+ },
+ {
+ "x": 179.85738317544707,
+ "y": -195.14726295339744,
+ "z": 0.0
+ },
+ {
+ "x": 178.8517777976012,
+ "y": -195.14718123844787,
+ "z": 0.0
+ },
+ {
+ "x": 177.8461724197553,
+ "y": -195.1470995234983,
+ "z": 0.0
+ },
+ {
+ "x": 176.84056704190942,
+ "y": -195.14701780854875,
+ "z": 0.0
+ },
+ {
+ "x": 175.8349616640636,
+ "y": -195.14693609359918,
+ "z": 0.0
+ },
+ {
+ "x": 174.82935628621772,
+ "y": -195.1468543786496,
+ "z": 0.0
+ },
+ {
+ "x": 173.8237509083719,
+ "y": -195.14677266370003,
+ "z": 0.0
+ },
+ {
+ "x": 172.818145530526,
+ "y": -195.14669094875046,
+ "z": 0.0
+ },
+ {
+ "x": 171.81254015268007,
+ "y": -195.14660923380092,
+ "z": 0.0
+ },
+ {
+ "x": 170.8069347748343,
+ "y": -195.14652751885134,
+ "z": 0.0
+ },
+ {
+ "x": 169.80132939698842,
+ "y": -195.14644580390177,
+ "z": 0.0
+ },
+ {
+ "x": 168.79572401914254,
+ "y": -195.1463640889522,
+ "z": 0.0
+ },
+ {
+ "x": 167.79011864129666,
+ "y": -195.14628237400262,
+ "z": 0.0
+ },
+ {
+ "x": 166.78451326345083,
+ "y": -195.14620065905305,
+ "z": 0.0
+ },
+ {
+ "x": 165.7789078856049,
+ "y": -195.1461189441035,
+ "z": 0.0
+ },
+ {
+ "x": 164.77330250775913,
+ "y": -195.14603722915393,
+ "z": 0.0
+ },
+ {
+ "x": 163.76769712991324,
+ "y": -195.14595551420436,
+ "z": 0.0
+ },
+ {
+ "x": 162.76209175206736,
+ "y": -195.1458737992548,
+ "z": 0.0
+ },
+ {
+ "x": 161.75648637422148,
+ "y": -195.1457920843052,
+ "z": 0.0
+ },
+ {
+ "x": 160.7508809963756,
+ "y": -195.14571036935567,
+ "z": 0.0
+ },
+ {
+ "x": 159.74527561852977,
+ "y": -195.1456286544061,
+ "z": 0.0
+ },
+ {
+ "x": 158.7396702406839,
+ "y": -195.14554693945652,
+ "z": 0.0
+ },
+ {
+ "x": 157.73406486283807,
+ "y": -195.14546522450695,
+ "z": 0.0
+ },
+ {
+ "x": 156.7284594849922,
+ "y": -195.14538350955738,
+ "z": 0.0
+ },
+ {
+ "x": 155.7228541071463,
+ "y": -195.1453017946078,
+ "z": 0.0
+ },
+ {
+ "x": 154.71724872930042,
+ "y": -195.14522007965826,
+ "z": 0.0
+ },
+ {
+ "x": 153.7116433514546,
+ "y": -195.14513836470869,
+ "z": 0.0
+ },
+ {
+ "x": 152.70603797360872,
+ "y": -195.1450566497591,
+ "z": 0.0
+ },
+ {
+ "x": 151.7004325957629,
+ "y": -195.14497493480954,
+ "z": 0.0
+ },
+ {
+ "x": 150.694827217917,
+ "y": -195.14489321985997,
+ "z": 0.0
+ },
+ {
+ "x": 149.68922184007113,
+ "y": -195.1448115049104,
+ "z": 0.0
+ },
+ {
+ "x": 148.68361646222525,
+ "y": -195.14472978996085,
+ "z": 0.0
+ },
+ {
+ "x": 147.67801108437942,
+ "y": -195.14464807501128,
+ "z": 0.0
+ },
+ {
+ "x": 146.67240570653354,
+ "y": -195.1445663600617,
+ "z": 0.0
+ },
+ {
+ "x": 145.6668003286877,
+ "y": -195.14448464511213,
+ "z": 0.0
+ },
+ {
+ "x": 144.66119495084183,
+ "y": -195.14440293016256,
+ "z": 0.0
+ },
+ {
+ "x": 143.6555895729959,
+ "y": -195.144321215213,
+ "z": 0.0
+ },
+ {
+ "x": 142.64998419515013,
+ "y": -195.14423950026344,
+ "z": 0.0
+ },
+ {
+ "x": 141.64437881730424,
+ "y": -195.14415778531387,
+ "z": 0.0
+ },
+ {
+ "x": 140.63877343945836,
+ "y": -195.1440760703643,
+ "z": 0.0
+ },
+ {
+ "x": 139.63316806161254,
+ "y": -195.14399435541472,
+ "z": 0.0
+ },
+ {
+ "x": 138.62756268376666,
+ "y": -195.14391264046515,
+ "z": 0.0
+ },
+ {
+ "x": 137.62195730592072,
+ "y": -195.1438309255156,
+ "z": 0.0
+ },
+ {
+ "x": 136.61635192807495,
+ "y": -195.14374921056603,
+ "z": 0.0
+ },
+ {
+ "x": 135.61074655022907,
+ "y": -195.14366749561646,
+ "z": 0.0
+ },
+ {
+ "x": 134.60514117238318,
+ "y": -195.14358578066688,
+ "z": 0.0
+ },
+ {
+ "x": 133.59953579453736,
+ "y": -195.1435040657173,
+ "z": 0.0
+ },
+ {
+ "x": 132.59393041669148,
+ "y": -195.14342235076774,
+ "z": 0.0
+ },
+ {
+ "x": 131.58832503884554,
+ "y": -195.1433406358182,
+ "z": 0.0
+ },
+ {
+ "x": 130.58271966099977,
+ "y": -195.14325892086862,
+ "z": 0.0
+ },
+ {
+ "x": 129.5771142831539,
+ "y": -195.14317720591905,
+ "z": 0.0
+ },
+ {
+ "x": 128.571508905308,
+ "y": -195.14309549096947,
+ "z": 0.0
+ },
+ {
+ "x": 127.56590352746217,
+ "y": -195.1430137760199,
+ "z": 0.0
+ },
+ {
+ "x": 126.56029814961627,
+ "y": -195.14293206107035,
+ "z": 0.0
+ },
+ {
+ "x": 125.55469277177046,
+ "y": -195.14285034612078,
+ "z": 0.0
+ },
+ {
+ "x": 124.5490873939246,
+ "y": -195.1427686311712,
+ "z": 0.0
+ },
+ {
+ "x": 123.54348201607873,
+ "y": -195.14268691622163,
+ "z": 0.0
+ },
+ {
+ "x": 122.53787663823287,
+ "y": -195.14260520127206,
+ "z": 0.0
+ },
+ {
+ "x": 121.53227126038702,
+ "y": -195.1425234863225,
+ "z": 0.0
+ },
+ {
+ "x": 120.5266658825411,
+ "y": -195.14244177137294,
+ "z": 0.0
+ },
+ {
+ "x": 119.5210605046953,
+ "y": -195.14236005642337,
+ "z": 0.0
+ },
+ {
+ "x": 118.51545512684943,
+ "y": -195.1422783414738,
+ "z": 0.0
+ },
+ {
+ "x": 117.50984974900358,
+ "y": -195.14219662652422,
+ "z": 0.0
+ },
+ {
+ "x": 116.50424437115771,
+ "y": -195.14211491157465,
+ "z": 0.0
+ },
+ {
+ "x": 115.4986389933118,
+ "y": -195.1420331966251,
+ "z": 0.0
+ },
+ {
+ "x": 114.49303361546599,
+ "y": -195.14195148167553,
+ "z": 0.0
+ },
+ {
+ "x": 113.48742823762014,
+ "y": -195.14186976672596,
+ "z": 0.0
+ },
+ {
+ "x": 112.48182285977428,
+ "y": -195.1417880517764,
+ "z": 0.0
+ },
+ {
+ "x": 111.47621748192842,
+ "y": -195.14170633682681,
+ "z": 0.0
+ },
+ {
+ "x": 110.47061210408256,
+ "y": -195.14162462187724,
+ "z": 0.0
+ },
+ {
+ "x": 109.46500672623665,
+ "y": -195.1415429069277,
+ "z": 0.0
+ },
+ {
+ "x": 108.45940134839084,
+ "y": -195.14146119197812,
+ "z": 0.0
+ },
+ {
+ "x": 107.45379597054497,
+ "y": -195.14137947702855,
+ "z": 0.0
+ },
+ {
+ "x": 106.44819059269912,
+ "y": -195.14129776207898,
+ "z": 0.0
+ },
+ {
+ "x": 105.44258521485325,
+ "y": -195.1412160471294,
+ "z": 0.0
+ },
+ {
+ "x": 104.4369798370074,
+ "y": -195.14113433217983,
+ "z": 0.0
+ },
+ {
+ "x": 103.43137445916147,
+ "y": -195.1410526172303,
+ "z": 0.0
+ },
+ {
+ "x": 102.42576908131568,
+ "y": -195.1409709022807,
+ "z": 0.0
+ },
+ {
+ "x": 101.42016370346981,
+ "y": -195.14088918733114,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 64,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 101.4198386656325,
+ "y": -199.14088917412494,
+ "z": 0.0
+ },
+ {
+ "x": 102.42544404347836,
+ "y": -199.1409708890745,
+ "z": 0.0
+ },
+ {
+ "x": 103.43104942132427,
+ "y": -199.14105260402408,
+ "z": 0.0
+ },
+ {
+ "x": 104.43665479917009,
+ "y": -199.14113431897363,
+ "z": 0.0
+ },
+ {
+ "x": 105.44226017701594,
+ "y": -199.1412160339232,
+ "z": 0.0
+ },
+ {
+ "x": 106.4478655548618,
+ "y": -199.14129774887277,
+ "z": 0.0
+ },
+ {
+ "x": 107.45347093270766,
+ "y": -199.14137946382235,
+ "z": 0.0
+ },
+ {
+ "x": 108.45907631055353,
+ "y": -199.14146117877192,
+ "z": 0.0
+ },
+ {
+ "x": 109.46468168839942,
+ "y": -199.1415428937215,
+ "z": 0.0
+ },
+ {
+ "x": 110.47028706624525,
+ "y": -199.14162460867104,
+ "z": 0.0
+ },
+ {
+ "x": 111.4758924440911,
+ "y": -199.1417063236206,
+ "z": 0.0
+ },
+ {
+ "x": 112.48149782193697,
+ "y": -199.14178803857018,
+ "z": 0.0
+ },
+ {
+ "x": 113.48710319978282,
+ "y": -199.14186975351976,
+ "z": 0.0
+ },
+ {
+ "x": 114.49270857762868,
+ "y": -199.14195146846933,
+ "z": 0.0
+ },
+ {
+ "x": 115.4983139554746,
+ "y": -199.1420331834189,
+ "z": 0.0
+ },
+ {
+ "x": 116.5039193333204,
+ "y": -199.14211489836845,
+ "z": 0.0
+ },
+ {
+ "x": 117.50952471116626,
+ "y": -199.14219661331802,
+ "z": 0.0
+ },
+ {
+ "x": 118.51513008901212,
+ "y": -199.1422783282676,
+ "z": 0.0
+ },
+ {
+ "x": 119.52073546685799,
+ "y": -199.14236004321717,
+ "z": 0.0
+ },
+ {
+ "x": 120.5263408447039,
+ "y": -199.14244175816674,
+ "z": 0.0
+ },
+ {
+ "x": 121.5319462225497,
+ "y": -199.14252347311628,
+ "z": 0.0
+ },
+ {
+ "x": 122.53755160039556,
+ "y": -199.14260518806586,
+ "z": 0.0
+ },
+ {
+ "x": 123.54315697824141,
+ "y": -199.14268690301543,
+ "z": 0.0
+ },
+ {
+ "x": 124.54876235608728,
+ "y": -199.142768617965,
+ "z": 0.0
+ },
+ {
+ "x": 125.55436773393315,
+ "y": -199.14285033291458,
+ "z": 0.0
+ },
+ {
+ "x": 126.55997311177904,
+ "y": -199.14293204786415,
+ "z": 0.0
+ },
+ {
+ "x": 127.56557848962485,
+ "y": -199.1430137628137,
+ "z": 0.0
+ },
+ {
+ "x": 128.57118386747072,
+ "y": -199.14309547776327,
+ "z": 0.0
+ },
+ {
+ "x": 129.5767892453166,
+ "y": -199.14317719271284,
+ "z": 0.0
+ },
+ {
+ "x": 130.58239462316243,
+ "y": -199.1432589076624,
+ "z": 0.0
+ },
+ {
+ "x": 131.58800000100837,
+ "y": -199.143340622612,
+ "z": 0.0
+ },
+ {
+ "x": 132.59360537885414,
+ "y": -199.14342233756153,
+ "z": 0.0
+ },
+ {
+ "x": 133.59921075670002,
+ "y": -199.1435040525111,
+ "z": 0.0
+ },
+ {
+ "x": 134.6048161345459,
+ "y": -199.14358576746068,
+ "z": 0.0
+ },
+ {
+ "x": 135.61042151239172,
+ "y": -199.14366748241025,
+ "z": 0.0
+ },
+ {
+ "x": 136.6160268902376,
+ "y": -199.14374919735982,
+ "z": 0.0
+ },
+ {
+ "x": 137.62163226808354,
+ "y": -199.1438309123094,
+ "z": 0.0
+ },
+ {
+ "x": 138.6272376459293,
+ "y": -199.14391262725894,
+ "z": 0.0
+ },
+ {
+ "x": 139.6328430237752,
+ "y": -199.14399434220852,
+ "z": 0.0
+ },
+ {
+ "x": 140.63844840162108,
+ "y": -199.1440760571581,
+ "z": 0.0
+ },
+ {
+ "x": 141.6440537794669,
+ "y": -199.14415777210766,
+ "z": 0.0
+ },
+ {
+ "x": 142.64965915731278,
+ "y": -199.14423948705723,
+ "z": 0.0
+ },
+ {
+ "x": 143.65526453515872,
+ "y": -199.1443212020068,
+ "z": 0.0
+ },
+ {
+ "x": 144.6608699130045,
+ "y": -199.14440291695635,
+ "z": 0.0
+ },
+ {
+ "x": 145.66647529085037,
+ "y": -199.14448463190593,
+ "z": 0.0
+ },
+ {
+ "x": 146.67208066869625,
+ "y": -199.1445663468555,
+ "z": 0.0
+ },
+ {
+ "x": 147.67768604654208,
+ "y": -199.14464806180507,
+ "z": 0.0
+ },
+ {
+ "x": 148.68329142438802,
+ "y": -199.14472977675464,
+ "z": 0.0
+ },
+ {
+ "x": 149.68889680223384,
+ "y": -199.1448114917042,
+ "z": 0.0
+ },
+ {
+ "x": 150.69450218007967,
+ "y": -199.14489320665376,
+ "z": 0.0
+ },
+ {
+ "x": 151.70010755792555,
+ "y": -199.14497492160334,
+ "z": 0.0
+ },
+ {
+ "x": 152.70571293577143,
+ "y": -199.1450566365529,
+ "z": 0.0
+ },
+ {
+ "x": 153.71131831361726,
+ "y": -199.14513835150248,
+ "z": 0.0
+ },
+ {
+ "x": 154.7169236914632,
+ "y": -199.14522006645205,
+ "z": 0.0
+ },
+ {
+ "x": 155.72252906930902,
+ "y": -199.1453017814016,
+ "z": 0.0
+ },
+ {
+ "x": 156.72813444715484,
+ "y": -199.14538349635117,
+ "z": 0.0
+ },
+ {
+ "x": 157.73373982500073,
+ "y": -199.14546521130075,
+ "z": 0.0
+ },
+ {
+ "x": 158.7393452028466,
+ "y": -199.14554692625032,
+ "z": 0.0
+ },
+ {
+ "x": 159.7449505806925,
+ "y": -199.1456286411999,
+ "z": 0.0
+ },
+ {
+ "x": 160.75055595853837,
+ "y": -199.14571035614946,
+ "z": 0.0
+ },
+ {
+ "x": 161.7561613363842,
+ "y": -199.145792071099,
+ "z": 0.0
+ },
+ {
+ "x": 162.76176671423008,
+ "y": -199.14587378604858,
+ "z": 0.0
+ },
+ {
+ "x": 163.7673720920759,
+ "y": -199.14595550099816,
+ "z": 0.0
+ },
+ {
+ "x": 164.77297746992178,
+ "y": -199.14603721594773,
+ "z": 0.0
+ },
+ {
+ "x": 165.77858284776767,
+ "y": -199.1461189308973,
+ "z": 0.0
+ },
+ {
+ "x": 166.7841882256135,
+ "y": -199.14620064584685,
+ "z": 0.0
+ },
+ {
+ "x": 167.78979360345937,
+ "y": -199.14628236079642,
+ "z": 0.0
+ },
+ {
+ "x": 168.7953989813052,
+ "y": -199.146364075746,
+ "z": 0.0
+ },
+ {
+ "x": 169.80100435915108,
+ "y": -199.14644579069557,
+ "z": 0.0
+ },
+ {
+ "x": 170.80660973699696,
+ "y": -199.14652750564514,
+ "z": 0.0
+ },
+ {
+ "x": 171.81221511484284,
+ "y": -199.1466092205947,
+ "z": 0.0
+ },
+ {
+ "x": 172.81782049268867,
+ "y": -199.14669093554426,
+ "z": 0.0
+ },
+ {
+ "x": 173.82342587053455,
+ "y": -199.14677265049383,
+ "z": 0.0
+ },
+ {
+ "x": 174.82903124838037,
+ "y": -199.1468543654434,
+ "z": 0.0
+ },
+ {
+ "x": 175.83463662622626,
+ "y": -199.14693608039298,
+ "z": 0.0
+ },
+ {
+ "x": 176.8402420040722,
+ "y": -199.14701779534255,
+ "z": 0.0
+ },
+ {
+ "x": 177.84584738191796,
+ "y": -199.1470995102921,
+ "z": 0.0
+ },
+ {
+ "x": 178.85145275976384,
+ "y": -199.14718122524167,
+ "z": 0.0
+ },
+ {
+ "x": 179.85705813760973,
+ "y": -199.14726294019124,
+ "z": 0.0
+ },
+ {
+ "x": 180.8626635154556,
+ "y": -199.1473446551408,
+ "z": 0.0
+ },
+ {
+ "x": 181.86826889330143,
+ "y": -199.1474263700904,
+ "z": 0.0
+ },
+ {
+ "x": 182.87387427114737,
+ "y": -199.14750808503996,
+ "z": 0.0
+ },
+ {
+ "x": 183.8794796489932,
+ "y": -199.1475897999895,
+ "z": 0.0
+ },
+ {
+ "x": 184.88508502683902,
+ "y": -199.14767151493908,
+ "z": 0.0
+ },
+ {
+ "x": 185.8906904046849,
+ "y": -199.14775322988865,
+ "z": 0.0
+ },
+ {
+ "x": 186.89629578253079,
+ "y": -199.14783494483822,
+ "z": 0.0
+ },
+ {
+ "x": 187.9019011603766,
+ "y": -199.1479166597878,
+ "z": 0.0
+ },
+ {
+ "x": 188.90750653822255,
+ "y": -199.14799837473737,
+ "z": 0.0
+ },
+ {
+ "x": 189.91311191606837,
+ "y": -199.1480800896869,
+ "z": 0.0
+ },
+ {
+ "x": 190.9187172939142,
+ "y": -199.1481618046365,
+ "z": 0.0
+ },
+ {
+ "x": 191.92432267176008,
+ "y": -199.14824351958606,
+ "z": 0.0
+ },
+ {
+ "x": 192.92992804960596,
+ "y": -199.14832523453563,
+ "z": 0.0
+ },
+ {
+ "x": 193.93553342745184,
+ "y": -199.1484069494852,
+ "z": 0.0
+ },
+ {
+ "x": 194.94113880529767,
+ "y": -199.14848866443475,
+ "z": 0.0
+ },
+ {
+ "x": 195.94674418314355,
+ "y": -199.14857037938432,
+ "z": 0.0
+ },
+ {
+ "x": 196.95234956098938,
+ "y": -199.1486520943339,
+ "z": 0.0
+ },
+ {
+ "x": 197.95795493883526,
+ "y": -199.14873380928347,
+ "z": 0.0
+ },
+ {
+ "x": 198.96356031668114,
+ "y": -199.14881552423304,
+ "z": 0.0
+ },
+ {
+ "x": 199.96916569452702,
+ "y": -199.14889723918262,
+ "z": 0.0
+ },
+ {
+ "x": 200.97477107237285,
+ "y": -199.14897895413216,
+ "z": 0.0
+ },
+ {
+ "x": 201.98037645021873,
+ "y": -199.14906066908173,
+ "z": 0.0
+ },
+ {
+ "x": 202.98598182806455,
+ "y": -199.1491423840313,
+ "z": 0.0
+ },
+ {
+ "x": 203.99158720591043,
+ "y": -199.14922409898088,
+ "z": 0.0
+ },
+ {
+ "x": 204.99719258375632,
+ "y": -199.14930581393045,
+ "z": 0.0
+ },
+ {
+ "x": 206.0027979616022,
+ "y": -199.14938752888003,
+ "z": 0.0
+ },
+ {
+ "x": 207.00840333944802,
+ "y": -199.14946924382957,
+ "z": 0.0
+ },
+ {
+ "x": 208.0140087172939,
+ "y": -199.14955095877914,
+ "z": 0.0
+ },
+ {
+ "x": 209.01961409513973,
+ "y": -199.14963267372872,
+ "z": 0.0
+ },
+ {
+ "x": 210.0252194729856,
+ "y": -199.1497143886783,
+ "z": 0.0
+ },
+ {
+ "x": 211.03082485083155,
+ "y": -199.14979610362786,
+ "z": 0.0
+ },
+ {
+ "x": 212.03643022867732,
+ "y": -199.1498778185774,
+ "z": 0.0
+ },
+ {
+ "x": 213.0420356065232,
+ "y": -199.14995953352698,
+ "z": 0.0
+ },
+ {
+ "x": 214.04764098436908,
+ "y": -199.15004124847655,
+ "z": 0.0
+ },
+ {
+ "x": 215.0532463622149,
+ "y": -199.15012296342613,
+ "z": 0.0
+ },
+ {
+ "x": 216.0588517400608,
+ "y": -199.1502046783757,
+ "z": 0.0
+ },
+ {
+ "x": 217.06445711790673,
+ "y": -199.15028639332527,
+ "z": 0.0
+ },
+ {
+ "x": 218.07006249575255,
+ "y": -199.15036810827482,
+ "z": 0.0
+ },
+ {
+ "x": 219.07566787359838,
+ "y": -199.1504498232244,
+ "z": 0.0
+ },
+ {
+ "x": 220.08127325144426,
+ "y": -199.15053153817396,
+ "z": 0.0
+ },
+ {
+ "x": 221.08687862929014,
+ "y": -199.15061325312354,
+ "z": 0.0
+ },
+ {
+ "x": 222.09248400713602,
+ "y": -199.1506949680731,
+ "z": 0.0
+ },
+ {
+ "x": 223.09808938498185,
+ "y": -199.15077668302266,
+ "z": 0.0
+ },
+ {
+ "x": 224.10369476282773,
+ "y": -199.15085839797223,
+ "z": 0.0
+ },
+ {
+ "x": 225.10930014067355,
+ "y": -199.1509401129218,
+ "z": 0.0
+ },
+ {
+ "x": 226.11490551851944,
+ "y": -199.15102182787138,
+ "z": 0.0
+ },
+ {
+ "x": 227.12051089636532,
+ "y": -199.15110354282095,
+ "z": 0.0
+ },
+ {
+ "x": 228.1261162742112,
+ "y": -199.15118525777052,
+ "z": 0.0
+ },
+ {
+ "x": 229.13172165205702,
+ "y": -199.15126697272007,
+ "z": 0.0
+ },
+ {
+ "x": 230.1373270299029,
+ "y": -199.15134868766964,
+ "z": 0.0
+ },
+ {
+ "x": 231.14293240774873,
+ "y": -199.1514304026192,
+ "z": 0.0
+ },
+ {
+ "x": 232.1485377855946,
+ "y": -199.15151211756879,
+ "z": 0.0
+ },
+ {
+ "x": 233.1541431634405,
+ "y": -199.15159383251836,
+ "z": 0.0
+ },
+ {
+ "x": 234.15974854128638,
+ "y": -199.15167554746793,
+ "z": 0.0
+ },
+ {
+ "x": 235.1653539191322,
+ "y": -199.15175726241748,
+ "z": 0.0
+ },
+ {
+ "x": 236.17095929697808,
+ "y": -199.15183897736705,
+ "z": 0.0
+ },
+ {
+ "x": 237.1765646748239,
+ "y": -199.15192069231662,
+ "z": 0.0
+ },
+ {
+ "x": 238.1821700526698,
+ "y": -199.1520024072662,
+ "z": 0.0
+ },
+ {
+ "x": 239.18777543051573,
+ "y": -199.15208412221577,
+ "z": 0.0
+ },
+ {
+ "x": 240.19338080836155,
+ "y": -199.1521658371653,
+ "z": 0.0
+ },
+ {
+ "x": 241.19898618620738,
+ "y": -199.1522475521149,
+ "z": 0.0
+ },
+ {
+ "x": 242.20459156405326,
+ "y": -199.15232926706446,
+ "z": 0.0
+ },
+ {
+ "x": 243.21019694189914,
+ "y": -199.15241098201403,
+ "z": 0.0
+ },
+ {
+ "x": 244.21580231974497,
+ "y": -199.1524926969636,
+ "z": 0.0
+ },
+ {
+ "x": 245.2214076975909,
+ "y": -199.15257441191318,
+ "z": 0.0
+ },
+ {
+ "x": 246.22701307543673,
+ "y": -199.15265612686272,
+ "z": 0.0
+ },
+ {
+ "x": 247.23261845328256,
+ "y": -199.1527378418123,
+ "z": 0.0
+ },
+ {
+ "x": 248.23822383112844,
+ "y": -199.15281955676187,
+ "z": 0.0
+ },
+ {
+ "x": 249.24382920897432,
+ "y": -199.15290127171144,
+ "z": 0.0
+ },
+ {
+ "x": 250.24943458682014,
+ "y": -199.15298298666102,
+ "z": 0.0
+ },
+ {
+ "x": 251.25503996466608,
+ "y": -199.1530647016106,
+ "z": 0.0
+ },
+ {
+ "x": 252.2606453425119,
+ "y": -199.15314641656013,
+ "z": 0.0
+ },
+ {
+ "x": 253.26625072035773,
+ "y": -199.1532281315097,
+ "z": 0.0
+ },
+ {
+ "x": 254.2718560982036,
+ "y": -199.15330984645928,
+ "z": 0.0
+ },
+ {
+ "x": 255.2774614760495,
+ "y": -199.15339156140885,
+ "z": 0.0
+ },
+ {
+ "x": 256.2830668538954,
+ "y": -199.15347327635843,
+ "z": 0.0
+ },
+ {
+ "x": 257.28867223174115,
+ "y": -199.15355499130797,
+ "z": 0.0
+ },
+ {
+ "x": 258.294277609587,
+ "y": -199.15363670625754,
+ "z": 0.0
+ },
+ {
+ "x": 259.2998829874329,
+ "y": -199.15371842120712,
+ "z": 0.0
+ },
+ {
+ "x": 260.3054883652788,
+ "y": -199.1538001361567,
+ "z": 0.0
+ },
+ {
+ "x": 261.3110937431247,
+ "y": -199.15388185110626,
+ "z": 0.0
+ },
+ {
+ "x": 262.31669912097055,
+ "y": -199.15396356605584,
+ "z": 0.0
+ },
+ {
+ "x": 263.3223044988164,
+ "y": -199.15404528100538,
+ "z": 0.0
+ },
+ {
+ "x": 264.3279098766622,
+ "y": -199.15412699595495,
+ "z": 0.0
+ },
+ {
+ "x": 265.3335152545081,
+ "y": -199.15420871090453,
+ "z": 0.0
+ },
+ {
+ "x": 266.33912063235397,
+ "y": -199.1542904258541,
+ "z": 0.0
+ },
+ {
+ "x": 267.3447260101999,
+ "y": -199.15437214080367,
+ "z": 0.0
+ },
+ {
+ "x": 268.3503313880457,
+ "y": -199.15445385575322,
+ "z": 0.0
+ },
+ {
+ "x": 269.35593676589156,
+ "y": -199.1545355707028,
+ "z": 0.0
+ },
+ {
+ "x": 270.3615421437374,
+ "y": -199.15461728565236,
+ "z": 0.0
+ },
+ {
+ "x": 271.36714752158326,
+ "y": -199.15469900060194,
+ "z": 0.0
+ },
+ {
+ "x": 272.37275289942914,
+ "y": -199.1547807155515,
+ "z": 0.0
+ },
+ {
+ "x": 273.3783582772751,
+ "y": -199.15486243050108,
+ "z": 0.0
+ },
+ {
+ "x": 274.38396365512085,
+ "y": -199.15494414545063,
+ "z": 0.0
+ },
+ {
+ "x": 275.38956903296673,
+ "y": -199.1550258604002,
+ "z": 0.0
+ },
+ {
+ "x": 276.39517441081256,
+ "y": -199.15510757534977,
+ "z": 0.0
+ },
+ {
+ "x": 277.40077978865844,
+ "y": -199.15518929029935,
+ "z": 0.0
+ },
+ {
+ "x": 278.4063851665043,
+ "y": -199.15527100524892,
+ "z": 0.0
+ },
+ {
+ "x": 279.41199054435026,
+ "y": -199.1553527201985,
+ "z": 0.0
+ },
+ {
+ "x": 280.4175959221961,
+ "y": -199.15543443514804,
+ "z": 0.0
+ },
+ {
+ "x": 281.4232013000419,
+ "y": -199.1555161500976,
+ "z": 0.0
+ },
+ {
+ "x": 282.42880667788774,
+ "y": -199.15559786504718,
+ "z": 0.0
+ },
+ {
+ "x": 283.4344120557336,
+ "y": -199.15567957999676,
+ "z": 0.0
+ },
+ {
+ "x": 284.44001743357956,
+ "y": -199.15576129494633,
+ "z": 0.0
+ },
+ {
+ "x": 285.4456228114254,
+ "y": -199.15584300989588,
+ "z": 0.0
+ },
+ {
+ "x": 286.45122818927126,
+ "y": -199.15592472484545,
+ "z": 0.0
+ },
+ {
+ "x": 287.4568335671171,
+ "y": -199.15600643979502,
+ "z": 0.0
+ },
+ {
+ "x": 288.4624389449629,
+ "y": -199.1560881547446,
+ "z": 0.0
+ },
+ {
+ "x": 289.4680443228088,
+ "y": -199.15616986969417,
+ "z": 0.0
+ },
+ {
+ "x": 290.47364970065473,
+ "y": -199.15625158464374,
+ "z": 0.0
+ },
+ {
+ "x": 291.47925507850056,
+ "y": -199.15633329959329,
+ "z": 0.0
+ },
+ {
+ "x": 292.48486045634644,
+ "y": -199.15641501454286,
+ "z": 0.0
+ },
+ {
+ "x": 293.49046583419226,
+ "y": -199.15649672949243,
+ "z": 0.0
+ },
+ {
+ "x": 294.49607121203815,
+ "y": -199.156578444442,
+ "z": 0.0
+ },
+ {
+ "x": 295.50167658988397,
+ "y": -199.15666015939158,
+ "z": 0.0
+ },
+ {
+ "x": 296.5072819677299,
+ "y": -199.15674187434115,
+ "z": 0.0
+ },
+ {
+ "x": 297.51288734557573,
+ "y": -199.1568235892907,
+ "z": 0.0
+ },
+ {
+ "x": 298.5184927234216,
+ "y": -199.15690530424027,
+ "z": 0.0
+ },
+ {
+ "x": 299.52409810126744,
+ "y": -199.15698701918984,
+ "z": 0.0
+ },
+ {
+ "x": 300.5297034791133,
+ "y": -199.15706873413941,
+ "z": 0.0
+ },
+ {
+ "x": 301.5353088569592,
+ "y": -199.157150449089,
+ "z": 0.0
+ },
+ {
+ "x": 302.54091423480503,
+ "y": -199.15723216403853,
+ "z": 0.0
+ },
+ {
+ "x": 303.5465196126509,
+ "y": -199.1573138789881,
+ "z": 0.0
+ },
+ {
+ "x": 304.5521249904968,
+ "y": -199.15739559393768,
+ "z": 0.0
+ },
+ {
+ "x": 305.5577303683426,
+ "y": -199.15747730888725,
+ "z": 0.0
+ },
+ {
+ "x": 306.5633357461885,
+ "y": -199.15755902383682,
+ "z": 0.0
+ },
+ {
+ "x": 307.5689411240344,
+ "y": -199.1576407387864,
+ "z": 0.0
+ },
+ {
+ "x": 308.5745465018802,
+ "y": -199.15772245373594,
+ "z": 0.0
+ },
+ {
+ "x": 309.5801518797261,
+ "y": -199.15780416868552,
+ "z": 0.0
+ },
+ {
+ "x": 310.58575725757197,
+ "y": -199.1578858836351,
+ "z": 0.0
+ },
+ {
+ "x": 311.5913626354178,
+ "y": -199.15796759858466,
+ "z": 0.0
+ },
+ {
+ "x": 312.59696801326373,
+ "y": -199.15804931353424,
+ "z": 0.0
+ },
+ {
+ "x": 313.6025733911095,
+ "y": -199.15813102848378,
+ "z": 0.0
+ },
+ {
+ "x": 314.6081787689554,
+ "y": -199.15821274343335,
+ "z": 0.0
+ },
+ {
+ "x": 315.61378414680127,
+ "y": -199.15829445838293,
+ "z": 0.0
+ },
+ {
+ "x": 316.61938952464715,
+ "y": -199.1583761733325,
+ "z": 0.0
+ },
+ {
+ "x": 317.62499490249303,
+ "y": -199.15845788828207,
+ "z": 0.0
+ },
+ {
+ "x": 318.6306002803389,
+ "y": -199.15853960323165,
+ "z": 0.0
+ },
+ {
+ "x": 319.6362056581847,
+ "y": -199.1586213181812,
+ "z": 0.0
+ },
+ {
+ "x": 320.64181103603056,
+ "y": -199.15870303313076,
+ "z": 0.0
+ },
+ {
+ "x": 321.64741641387644,
+ "y": -199.15878474808034,
+ "z": 0.0
+ },
+ {
+ "x": 322.6530217917223,
+ "y": -199.1588664630299,
+ "z": 0.0
+ },
+ {
+ "x": 323.6586271695682,
+ "y": -199.15894817797948,
+ "z": 0.0
+ },
+ {
+ "x": 324.6642325474141,
+ "y": -199.15902989292906,
+ "z": 0.0
+ },
+ {
+ "x": 325.66983792525997,
+ "y": -199.1591116078786,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 65,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 11.028342463475031,
+ "y": 4.019999671866976,
+ "z": 0.0
+ },
+ {
+ "x": 9.953070070668474,
+ "y": 4.019649230031031,
+ "z": 0.0
+ },
+ {
+ "x": 8.800612790358642,
+ "y": 3.9976050577194115,
+ "z": 0.0
+ },
+ {
+ "x": 7.459285666338035,
+ "y": 3.8888366999628543,
+ "z": 0.0
+ },
+ {
+ "x": 5.97521383867693,
+ "y": 3.6174579798610065,
+ "z": 0.0
+ },
+ {
+ "x": 4.528719668379331,
+ "y": 3.186406110896411,
+ "z": 0.0
+ },
+ {
+ "x": 3.113186224320456,
+ "y": 2.5812645029885717,
+ "z": 0.0
+ },
+ {
+ "x": 1.7875954122404156,
+ "y": 1.8263279175440637,
+ "z": 0.0
+ },
+ {
+ "x": 0.5663901916985239,
+ "y": 0.9406644934610671,
+ "z": 0.0
+ },
+ {
+ "x": -0.590244979393741,
+ "y": -0.13645072900332167,
+ "z": 0.0
+ },
+ {
+ "x": -1.5775183083072448,
+ "y": -1.299702319737953,
+ "z": 0.0
+ },
+ {
+ "x": -2.4352046366311417,
+ "y": -2.593825751303942,
+ "z": 0.0
+ },
+ {
+ "x": -3.148498396979441,
+ "y": -4.074152675533871,
+ "z": 0.0
+ },
+ {
+ "x": -3.6444600059072725,
+ "y": -5.6604724247747775,
+ "z": 0.0
+ },
+ {
+ "x": -3.9150557372144608,
+ "y": -7.187614391929258,
+ "z": 0.0
+ },
+ {
+ "x": -4.022155975422126,
+ "y": -8.641040654230935,
+ "z": 0.0
+ },
+ {
+ "x": -4.02999970255904,
+ "y": -9.958459206173217,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 66,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 3.969999703900145,
+ "y": -9.961540870120729,
+ "z": 0.0
+ },
+ {
+ "x": 3.962984383848893,
+ "y": -9.128414681791984,
+ "z": 0.0
+ },
+ {
+ "x": 3.9868029716624225,
+ "y": -8.436865745719414,
+ "z": 0.0
+ },
+ {
+ "x": 4.050850939410168,
+ "y": -7.847294195033525,
+ "z": 0.0
+ },
+ {
+ "x": 4.141788106296348,
+ "y": -7.368347979421437,
+ "z": 0.0
+ },
+ {
+ "x": 4.314033709673633,
+ "y": -6.8889138464155195,
+ "z": 0.0
+ },
+ {
+ "x": 4.6087026679026915,
+ "y": -6.37224310651337,
+ "z": 0.0
+ },
+ {
+ "x": 4.980163347792317,
+ "y": -5.878449602950986,
+ "z": 0.0
+ },
+ {
+ "x": 5.364000502351587,
+ "y": -5.46112707664768,
+ "z": 0.0
+ },
+ {
+ "x": 5.8620495302655184,
+ "y": -5.058352441057074,
+ "z": 0.0
+ },
+ {
+ "x": 6.386402842845939,
+ "y": -4.718465147362091,
+ "z": 0.0
+ },
+ {
+ "x": 6.933168944995435,
+ "y": -4.443706842145653,
+ "z": 0.0
+ },
+ {
+ "x": 7.537298805651212,
+ "y": -4.228553144012891,
+ "z": 0.0
+ },
+ {
+ "x": 8.160644969253037,
+ "y": -4.0803599426238115,
+ "z": 0.0
+ },
+ {
+ "x": 8.958862123970693,
+ "y": -4.000829610914904,
+ "z": 0.0
+ },
+ {
+ "x": 9.955677349119426,
+ "y": -3.980350345100149,
+ "z": 0.0
+ },
+ {
+ "x": 11.030949741925983,
+ "y": -3.9799999032642037,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 67,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": -0.029999999329447746,
+ "y": -9.960000038146973,
+ "z": 0.0
+ },
+ {
+ "x": -0.029585795786616468,
+ "y": -8.88472766801146,
+ "z": 0.0
+ },
+ {
+ "x": 0.035873617223980664,
+ "y": -7.8122400688243365,
+ "z": 0.0
+ },
+ {
+ "x": 0.2031954667514479,
+ "y": -6.753883309904151,
+ "z": 0.0
+ },
+ {
+ "x": 0.4966448546584533,
+ "y": -5.721250327477654,
+ "z": 0.0
+ },
+ {
+ "x": 0.9394145365212455,
+ "y": -4.741369798859731,
+ "z": 0.0
+ },
+ {
+ "x": 1.5155921797977234,
+ "y": -3.8359727131256616,
+ "z": 0.0
+ },
+ {
+ "x": 2.1949591841992877,
+ "y": -3.0074501659771538,
+ "z": 0.0
+ },
+ {
+ "x": 2.9651953470250554,
+ "y": -2.2602312915933065,
+ "z": 0.0
+ },
+ {
+ "x": 3.824822471252967,
+ "y": -1.6160122617565051,
+ "z": 0.0
+ },
+ {
+ "x": 4.749794533583198,
+ "y": -1.0686003221867595,
+ "z": 0.0
+ },
+ {
+ "x": 5.730944306687383,
+ "y": -0.6286503656246212,
+ "z": 0.0
+ },
+ {
+ "x": 6.756256322164071,
+ "y": -0.3055475820759422,
+ "z": 0.0
+ },
+ {
+ "x": 7.809965317795536,
+ "y": -0.09576162133047841,
+ "z": 0.0
+ },
+ {
+ "x": 8.879737457164667,
+ "y": -0.0016122765977463205,
+ "z": 0.0
+ },
+ {
+ "x": 9.95437370989395,
+ "y": 0.01964944246544118,
+ "z": 0.0
+ },
+ {
+ "x": 11.029646102700507,
+ "y": 0.019999884301386054,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 68,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 11.02899428308777,
+ "y": 2.019999778084181,
+ "z": 0.0
+ },
+ {
+ "x": 9.953721890281212,
+ "y": 2.019649336248236,
+ "z": 0.0
+ },
+ {
+ "x": 8.840175123761654,
+ "y": 1.9979963905608327,
+ "z": 0.0
+ },
+ {
+ "x": 7.634625492066785,
+ "y": 1.8965375393161878,
+ "z": 0.0
+ },
+ {
+ "x": 6.3657350804205,
+ "y": 1.655955198892532,
+ "z": 0.0
+ },
+ {
+ "x": 5.129831987533358,
+ "y": 1.278877872635895,
+ "z": 0.0
+ },
+ {
+ "x": 3.931490378951827,
+ "y": 0.7563320904009061,
+ "z": 0.0
+ },
+ {
+ "x": 2.806208941746691,
+ "y": 0.10515782789377925,
+ "z": 0.0
+ },
+ {
+ "x": 1.7657927693617896,
+ "y": -0.6597833990661197,
+ "z": 0.0
+ },
+ {
+ "x": 0.8023571024027734,
+ "y": -1.5719504474902377,
+ "z": 0.0
+ },
+ {
+ "x": -0.030963064254760697,
+ "y": -2.5678375164318075,
+ "z": 0.0
+ },
+ {
+ "x": -0.7478950500549482,
+ "y": -3.6675977750818367,
+ "z": 0.0
+ },
+ {
+ "x": -1.3259267711604938,
+ "y": -4.897701501505763,
+ "z": 0.0
+ },
+ {
+ "x": -1.7206322695779124,
+ "y": -6.207177867339464,
+ "z": 0.0
+ },
+ {
+ "x": -1.93959105999524,
+ "y": -7.499927230376797,
+ "z": 0.0
+ },
+ {
+ "x": -2.025870885604371,
+ "y": -8.762884161121196,
+ "z": 0.0
+ },
+ {
+ "x": -2.029999850944244,
+ "y": -9.959229622160095,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 69,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 1.9699998522853486,
+ "y": -9.96077045413385,
+ "z": 0.0
+ },
+ {
+ "x": 1.9666992940311383,
+ "y": -9.006571174901723,
+ "z": 0.0
+ },
+ {
+ "x": 2.0113382944432017,
+ "y": -8.124552907271875,
+ "z": 0.0
+ },
+ {
+ "x": 2.127023203080808,
+ "y": -7.300588752468839,
+ "z": 0.0
+ },
+ {
+ "x": 2.3192164804774005,
+ "y": -6.544799153449546,
+ "z": 0.0
+ },
+ {
+ "x": 2.626724123097439,
+ "y": -5.815141822637625,
+ "z": 0.0
+ },
+ {
+ "x": 3.0621474238502073,
+ "y": -5.104107909819516,
+ "z": 0.0
+ },
+ {
+ "x": 3.5875612659958023,
+ "y": -4.44294988446407,
+ "z": 0.0
+ },
+ {
+ "x": 4.164597924688321,
+ "y": -3.8606791841204933,
+ "z": 0.0
+ },
+ {
+ "x": 4.843436000759243,
+ "y": -3.3371823514067893,
+ "z": 0.0
+ },
+ {
+ "x": 5.568098688214569,
+ "y": -2.893532734774425,
+ "z": 0.0
+ },
+ {
+ "x": 6.332056625841409,
+ "y": -2.536178603885137,
+ "z": 0.0
+ },
+ {
+ "x": 7.146777563907642,
+ "y": -2.2670503630444165,
+ "z": 0.0
+ },
+ {
+ "x": 7.985305143524286,
+ "y": -2.088060781977145,
+ "z": 0.0
+ },
+ {
+ "x": 8.919299790567681,
+ "y": -2.001220943756325,
+ "z": 0.0
+ },
+ {
+ "x": 9.955025529506688,
+ "y": -1.980350451317354,
+ "z": 0.0
+ },
+ {
+ "x": 11.030297922313245,
+ "y": -1.9800000094814088,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 70,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 384.1736658134914,
+ "y": -332.60889681208965,
+ "z": 0.0
+ },
+ {
+ "x": 385.2643279115696,
+ "y": -332.58344691864033,
+ "z": 0.0
+ },
+ {
+ "x": 386.62477890205395,
+ "y": -332.46711385713115,
+ "z": 0.0
+ },
+ {
+ "x": 388.11199738649975,
+ "y": -332.1915900435458,
+ "z": 0.0
+ },
+ {
+ "x": 389.56266099323636,
+ "y": -331.7604566938843,
+ "z": 0.0
+ },
+ {
+ "x": 390.99555684282876,
+ "y": -331.1497265885555,
+ "z": 0.0
+ },
+ {
+ "x": 392.32475767360006,
+ "y": -330.39944230918036,
+ "z": 0.0
+ },
+ {
+ "x": 393.55519954086054,
+ "y": -329.5203187020522,
+ "z": 0.0
+ },
+ {
+ "x": 394.7013785390999,
+ "y": -328.49147913981506,
+ "z": 0.0
+ },
+ {
+ "x": 395.7435380994426,
+ "y": -327.29875989133785,
+ "z": 0.0
+ },
+ {
+ "x": 396.6346132755301,
+ "y": -325.97213713418074,
+ "z": 0.0
+ },
+ {
+ "x": 397.34968153032514,
+ "y": -324.5427275788562,
+ "z": 0.0
+ },
+ {
+ "x": 397.8771365105912,
+ "y": -323.0335278027845,
+ "z": 0.0
+ },
+ {
+ "x": 398.2083233275286,
+ "y": -321.4688127703625,
+ "z": 0.0
+ },
+ {
+ "x": 398.34184677749806,
+ "y": -319.89331026646045,
+ "z": 0.0
+ },
+ {
+ "x": 398.35000580137364,
+ "y": -318.5384233132525,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 71,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 390.3500064056576,
+ "y": -318.541532741435,
+ "z": 0.0
+ },
+ {
+ "x": 390.35901385763646,
+ "y": -319.36949868433095,
+ "z": 0.0
+ },
+ {
+ "x": 390.3496352343571,
+ "y": -319.97180861063424,
+ "z": 0.0
+ },
+ {
+ "x": 390.27293211969754,
+ "y": -320.54835666551554,
+ "z": 0.0
+ },
+ {
+ "x": 390.123631148747,
+ "y": -321.1099159203329,
+ "z": 0.0
+ },
+ {
+ "x": 389.9042235497951,
+ "y": -321.64757309375756,
+ "z": 0.0
+ },
+ {
+ "x": 389.61826346121734,
+ "y": -322.15278956434275,
+ "z": 0.0
+ },
+ {
+ "x": 389.259771012167,
+ "y": -322.62727352244224,
+ "z": 0.0
+ },
+ {
+ "x": 388.8089051340767,
+ "y": -323.0803894008771,
+ "z": 0.0
+ },
+ {
+ "x": 388.2842881070022,
+ "y": -323.4947623251842,
+ "z": 0.0
+ },
+ {
+ "x": 387.7306371533386,
+ "y": -323.84628223529455,
+ "z": 0.0
+ },
+ {
+ "x": 387.1707397701482,
+ "y": -324.1264071222257,
+ "z": 0.0
+ },
+ {
+ "x": 386.53881093627876,
+ "y": -324.34779731344116,
+ "z": 0.0
+ },
+ {
+ "x": 385.8877456964572,
+ "y": -324.5011373285537,
+ "z": 0.0
+ },
+ {
+ "x": 385.0777038952716,
+ "y": -324.585623997586,
+ "z": 0.0
+ },
+ {
+ "x": 383.98704179719346,
+ "y": -324.61107389103535,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 72,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 394.3500061035156,
+ "y": -318.53997802734375,
+ "z": 0.0
+ },
+ {
+ "x": 394.35043031756726,
+ "y": -319.6314044753957,
+ "z": 0.0
+ },
+ {
+ "x": 394.27897928094285,
+ "y": -320.72031069049837,
+ "z": 0.0
+ },
+ {
+ "x": 394.07503431514436,
+ "y": -321.79094223415,
+ "z": 0.0
+ },
+ {
+ "x": 393.73665633953607,
+ "y": -322.82632174959457,
+ "z": 0.0
+ },
+ {
+ "x": 393.2694184126626,
+ "y": -323.80985511396915,
+ "z": 0.0
+ },
+ {
+ "x": 392.68090078033,
+ "y": -324.7257747278403,
+ "z": 0.0
+ },
+ {
+ "x": 391.98057477563344,
+ "y": -325.55937633112865,
+ "z": 0.0
+ },
+ {
+ "x": 391.18205233746863,
+ "y": -326.30035405146464,
+ "z": 0.0
+ },
+ {
+ "x": 390.30452289030114,
+ "y": -326.94710231718227,
+ "z": 0.0
+ },
+ {
+ "x": 389.3630969980837,
+ "y": -327.498004411925,
+ "z": 0.0
+ },
+ {
+ "x": 388.3667003816923,
+ "y": -327.943431908055,
+ "z": 0.0
+ },
+ {
+ "x": 387.32540416138926,
+ "y": -328.26969367849347,
+ "z": 0.0
+ },
+ {
+ "x": 386.2562622992556,
+ "y": -328.4841255928424,
+ "z": 0.0
+ },
+ {
+ "x": 385.1710159034206,
+ "y": -328.5845354581132,
+ "z": 0.0
+ },
+ {
+ "x": 384.08035380534244,
+ "y": -328.6099853515625,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 73,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 384.1270098094169,
+ "y": -330.60944108182605,
+ "z": 0.0
+ },
+ {
+ "x": 385.21767190749506,
+ "y": -330.5839911883768,
+ "z": 0.0
+ },
+ {
+ "x": 386.44052060065474,
+ "y": -330.4756197249868,
+ "z": 0.0
+ },
+ {
+ "x": 387.71870077394453,
+ "y": -330.23064186101965,
+ "z": 0.0
+ },
+ {
+ "x": 388.96468068746435,
+ "y": -329.85194430096965,
+ "z": 0.0
+ },
+ {
+ "x": 390.1793269204562,
+ "y": -329.32386550024023,
+ "z": 0.0
+ },
+ {
+ "x": 391.3146402819506,
+ "y": -328.6732723131813,
+ "z": 0.0
+ },
+ {
+ "x": 392.3686259391646,
+ "y": -327.91033637675844,
+ "z": 0.0
+ },
+ {
+ "x": 393.3409766573667,
+ "y": -327.02542773547185,
+ "z": 0.0
+ },
+ {
+ "x": 394.2122194398863,
+ "y": -326.0122673095891,
+ "z": 0.0
+ },
+ {
+ "x": 394.95201584409637,
+ "y": -324.89099612407495,
+ "z": 0.0
+ },
+ {
+ "x": 395.5431689349306,
+ "y": -323.68452466422536,
+ "z": 0.0
+ },
+ {
+ "x": 395.97608541286775,
+ "y": -322.41223501846724,
+ "z": 0.0
+ },
+ {
+ "x": 396.24365130423575,
+ "y": -321.0945617304304,
+ "z": 0.0
+ },
+ {
+ "x": 396.34613854753263,
+ "y": -319.76235737092804,
+ "z": 0.0
+ },
+ {
+ "x": 396.35000595244463,
+ "y": -318.5392006702981,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 74,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 392.3500062545866,
+ "y": -318.5407553843894,
+ "z": 0.0
+ },
+ {
+ "x": 392.3547220876019,
+ "y": -319.50045157986335,
+ "z": 0.0
+ },
+ {
+ "x": 392.31430725764994,
+ "y": -320.3460596505663,
+ "z": 0.0
+ },
+ {
+ "x": 392.173983217421,
+ "y": -321.1696494498328,
+ "z": 0.0
+ },
+ {
+ "x": 391.93014374414156,
+ "y": -321.9681188349638,
+ "z": 0.0
+ },
+ {
+ "x": 391.58682098122887,
+ "y": -322.72871410386335,
+ "z": 0.0
+ },
+ {
+ "x": 391.14958212077363,
+ "y": -323.4392821460915,
+ "z": 0.0
+ },
+ {
+ "x": 390.6201728939002,
+ "y": -324.09332492678544,
+ "z": 0.0
+ },
+ {
+ "x": 389.9954787357727,
+ "y": -324.69037172617084,
+ "z": 0.0
+ },
+ {
+ "x": 389.2944054986517,
+ "y": -325.2209323211832,
+ "z": 0.0
+ },
+ {
+ "x": 388.54686707571113,
+ "y": -325.6721433236098,
+ "z": 0.0
+ },
+ {
+ "x": 387.7687200759202,
+ "y": -326.03491951514036,
+ "z": 0.0
+ },
+ {
+ "x": 386.932107548834,
+ "y": -326.3087454959673,
+ "z": 0.0
+ },
+ {
+ "x": 386.0720039978564,
+ "y": -326.492631460698,
+ "z": 0.0
+ },
+ {
+ "x": 385.12435989934613,
+ "y": -326.5850797278496,
+ "z": 0.0
+ },
+ {
+ "x": 384.033697801268,
+ "y": -326.61052962129895,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 75,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 4.009999965684669,
+ "y": -317.6005283434444,
+ "z": 0.0
+ },
+ {
+ "x": 4.010130803211286,
+ "y": -316.59844355295434,
+ "z": 0.0
+ },
+ {
+ "x": 4.0102616407379035,
+ "y": -315.59635876246426,
+ "z": 0.0
+ },
+ {
+ "x": 4.010392478264521,
+ "y": -314.5942739719742,
+ "z": 0.0
+ },
+ {
+ "x": 4.010523315791139,
+ "y": -313.5921891814841,
+ "z": 0.0
+ },
+ {
+ "x": 4.010654153317756,
+ "y": -312.59010439099404,
+ "z": 0.0
+ },
+ {
+ "x": 4.010784990844374,
+ "y": -311.58801960050397,
+ "z": 0.0
+ },
+ {
+ "x": 4.010915828370991,
+ "y": -310.5859348100139,
+ "z": 0.0
+ },
+ {
+ "x": 4.0110466658976085,
+ "y": -309.5838500195239,
+ "z": 0.0
+ },
+ {
+ "x": 4.011177503424226,
+ "y": -308.5817652290338,
+ "z": 0.0
+ },
+ {
+ "x": 4.011308340950843,
+ "y": -307.57968043854373,
+ "z": 0.0
+ },
+ {
+ "x": 4.0114391784774615,
+ "y": -306.57759564805366,
+ "z": 0.0
+ },
+ {
+ "x": 4.011570016004079,
+ "y": -305.5755108575636,
+ "z": 0.0
+ },
+ {
+ "x": 4.011700853530696,
+ "y": -304.5734260670735,
+ "z": 0.0
+ },
+ {
+ "x": 4.0118316910573135,
+ "y": -303.57134127658344,
+ "z": 0.0
+ },
+ {
+ "x": 4.011962528583931,
+ "y": -302.5692564860934,
+ "z": 0.0
+ },
+ {
+ "x": 4.012093366110548,
+ "y": -301.56717169560335,
+ "z": 0.0
+ },
+ {
+ "x": 4.012224203637166,
+ "y": -300.5650869051133,
+ "z": 0.0
+ },
+ {
+ "x": 4.012355041163783,
+ "y": -299.5630021146232,
+ "z": 0.0
+ },
+ {
+ "x": 4.012485878690401,
+ "y": -298.56091732413313,
+ "z": 0.0
+ },
+ {
+ "x": 4.0126167162170185,
+ "y": -297.55883253364306,
+ "z": 0.0
+ },
+ {
+ "x": 4.012747553743636,
+ "y": -296.556747743153,
+ "z": 0.0
+ },
+ {
+ "x": 4.012878391270253,
+ "y": -295.5546629526629,
+ "z": 0.0
+ },
+ {
+ "x": 4.013009228796871,
+ "y": -294.55257816217284,
+ "z": 0.0
+ },
+ {
+ "x": 4.013140066323488,
+ "y": -293.5504933716828,
+ "z": 0.0
+ },
+ {
+ "x": 4.013270903850105,
+ "y": -292.54840858119275,
+ "z": 0.0
+ },
+ {
+ "x": 4.013401741376724,
+ "y": -291.5463237907027,
+ "z": 0.0
+ },
+ {
+ "x": 4.013532578903341,
+ "y": -290.5442390002126,
+ "z": 0.0
+ },
+ {
+ "x": 4.013663416429958,
+ "y": -289.5421542097225,
+ "z": 0.0
+ },
+ {
+ "x": 4.013794253956576,
+ "y": -288.54006941923245,
+ "z": 0.0
+ },
+ {
+ "x": 4.013925091483193,
+ "y": -287.5379846287424,
+ "z": 0.0
+ },
+ {
+ "x": 4.01405592900981,
+ "y": -286.5358998382523,
+ "z": 0.0
+ },
+ {
+ "x": 4.014186766536428,
+ "y": -285.53381504776223,
+ "z": 0.0
+ },
+ {
+ "x": 4.014317604063046,
+ "y": -284.53173025727216,
+ "z": 0.0
+ },
+ {
+ "x": 4.014448441589663,
+ "y": -283.5296454667821,
+ "z": 0.0
+ },
+ {
+ "x": 4.014579279116281,
+ "y": -282.527560676292,
+ "z": 0.0
+ },
+ {
+ "x": 4.014710116642898,
+ "y": -281.52547588580194,
+ "z": 0.0
+ },
+ {
+ "x": 4.014840954169515,
+ "y": -280.52339109531187,
+ "z": 0.0
+ },
+ {
+ "x": 4.014971791696133,
+ "y": -279.5213063048218,
+ "z": 0.0
+ },
+ {
+ "x": 4.01510262922275,
+ "y": -278.5192215143317,
+ "z": 0.0
+ },
+ {
+ "x": 4.015233466749367,
+ "y": -277.5171367238417,
+ "z": 0.0
+ },
+ {
+ "x": 4.015364304275986,
+ "y": -276.51505193335163,
+ "z": 0.0
+ },
+ {
+ "x": 4.015495141802603,
+ "y": -275.51296714286156,
+ "z": 0.0
+ },
+ {
+ "x": 4.01562597932922,
+ "y": -274.5108823523715,
+ "z": 0.0
+ },
+ {
+ "x": 4.015756816855838,
+ "y": -273.5087975618814,
+ "z": 0.0
+ },
+ {
+ "x": 4.015887654382455,
+ "y": -272.50671277139134,
+ "z": 0.0
+ },
+ {
+ "x": 4.0160184919090725,
+ "y": -271.50462798090126,
+ "z": 0.0
+ },
+ {
+ "x": 4.01614932943569,
+ "y": -270.50254319041125,
+ "z": 0.0
+ },
+ {
+ "x": 4.016280166962308,
+ "y": -269.5004583999212,
+ "z": 0.0
+ },
+ {
+ "x": 4.016411004488925,
+ "y": -268.4983736094311,
+ "z": 0.0
+ },
+ {
+ "x": 4.016541842015543,
+ "y": -267.496288818941,
+ "z": 0.0
+ },
+ {
+ "x": 4.01667267954216,
+ "y": -266.49420402845095,
+ "z": 0.0
+ },
+ {
+ "x": 4.0168035170687775,
+ "y": -265.4921192379609,
+ "z": 0.0
+ },
+ {
+ "x": 4.016934354595395,
+ "y": -264.49003444747086,
+ "z": 0.0
+ },
+ {
+ "x": 4.017065192122012,
+ "y": -263.48794965698085,
+ "z": 0.0
+ },
+ {
+ "x": 4.0171960296486295,
+ "y": -262.4858648664908,
+ "z": 0.0
+ },
+ {
+ "x": 4.017326867175248,
+ "y": -261.48378007600076,
+ "z": 0.0
+ },
+ {
+ "x": 4.017457704701865,
+ "y": -260.48169528551074,
+ "z": 0.0
+ },
+ {
+ "x": 4.0175885422284825,
+ "y": -259.47961049502067,
+ "z": 0.0
+ },
+ {
+ "x": 4.0177193797551,
+ "y": -258.47752570453065,
+ "z": 0.0
+ },
+ {
+ "x": 4.017850217281717,
+ "y": -257.4754409140406,
+ "z": 0.0
+ },
+ {
+ "x": 4.017981054808335,
+ "y": -256.4733561235505,
+ "z": 0.0
+ },
+ {
+ "x": 4.018111892334951,
+ "y": -255.4712713330605,
+ "z": 0.0
+ },
+ {
+ "x": 4.018242729861569,
+ "y": -254.46918654257047,
+ "z": 0.0
+ },
+ {
+ "x": 4.018373567388187,
+ "y": -253.46710175208042,
+ "z": 0.0
+ },
+ {
+ "x": 4.018504404914805,
+ "y": -252.4650169615904,
+ "z": 0.0
+ },
+ {
+ "x": 4.018635242441421,
+ "y": -251.46293217110036,
+ "z": 0.0
+ },
+ {
+ "x": 4.018766079968039,
+ "y": -250.46084738061032,
+ "z": 0.0
+ },
+ {
+ "x": 4.018896917494656,
+ "y": -249.45876259012027,
+ "z": 0.0
+ },
+ {
+ "x": 4.019027755021273,
+ "y": -248.45667779963023,
+ "z": 0.0
+ },
+ {
+ "x": 4.019158592547892,
+ "y": -247.4545930091402,
+ "z": 0.0
+ },
+ {
+ "x": 4.01928943007451,
+ "y": -246.45250821865014,
+ "z": 0.0
+ },
+ {
+ "x": 4.019420267601126,
+ "y": -245.4504234281601,
+ "z": 0.0
+ },
+ {
+ "x": 4.019551105127745,
+ "y": -244.44833863767008,
+ "z": 0.0
+ },
+ {
+ "x": 4.019681942654361,
+ "y": -243.44625384718003,
+ "z": 0.0
+ },
+ {
+ "x": 4.019812780180978,
+ "y": -242.44416905669,
+ "z": 0.0
+ },
+ {
+ "x": 4.019943617707596,
+ "y": -241.44208426619994,
+ "z": 0.0
+ },
+ {
+ "x": 4.0197019046914795,
+ "y": -240.4385127574555,
+ "z": 0.0
+ },
+ {
+ "x": 4.019178091099026,
+ "y": -239.43530342597631,
+ "z": 0.0
+ },
+ {
+ "x": 4.018654706806054,
+ "y": -238.43321876362546,
+ "z": 0.0
+ },
+ {
+ "x": 4.018131322513082,
+ "y": -237.4311341012746,
+ "z": 0.0
+ },
+ {
+ "x": 4.0176079382201095,
+ "y": -236.42904943892378,
+ "z": 0.0
+ },
+ {
+ "x": 4.017084553927138,
+ "y": -235.42696477657293,
+ "z": 0.0
+ },
+ {
+ "x": 4.016561169634166,
+ "y": -234.42488011422208,
+ "z": 0.0
+ },
+ {
+ "x": 4.016037785341194,
+ "y": -233.42279545187122,
+ "z": 0.0
+ },
+ {
+ "x": 4.015514401048222,
+ "y": -232.42071078952037,
+ "z": 0.0
+ },
+ {
+ "x": 4.01499101675525,
+ "y": -231.41862612716957,
+ "z": 0.0
+ },
+ {
+ "x": 4.014467632462277,
+ "y": -230.41654146481872,
+ "z": 0.0
+ },
+ {
+ "x": 4.013944248169305,
+ "y": -229.41445680246787,
+ "z": 0.0
+ },
+ {
+ "x": 4.013420863876333,
+ "y": -228.41237214011704,
+ "z": 0.0
+ },
+ {
+ "x": 4.012897479583361,
+ "y": -227.4102874777662,
+ "z": 0.0
+ },
+ {
+ "x": 4.012374095290389,
+ "y": -226.40820281541534,
+ "z": 0.0
+ },
+ {
+ "x": 4.011850710997417,
+ "y": -225.40611815306448,
+ "z": 0.0
+ },
+ {
+ "x": 4.0113273267044445,
+ "y": -224.40403349071363,
+ "z": 0.0
+ },
+ {
+ "x": 4.0108039424114725,
+ "y": -223.4019488283628,
+ "z": 0.0
+ },
+ {
+ "x": 4.010280558118501,
+ "y": -222.39986416601195,
+ "z": 0.0
+ },
+ {
+ "x": 4.009757173825529,
+ "y": -221.3977795036611,
+ "z": 0.0
+ },
+ {
+ "x": 4.009233789532557,
+ "y": -220.39569484131027,
+ "z": 0.0
+ },
+ {
+ "x": 4.008710405239585,
+ "y": -219.39361017895945,
+ "z": 0.0
+ },
+ {
+ "x": 4.008187020946612,
+ "y": -218.3915255166086,
+ "z": 0.0
+ },
+ {
+ "x": 4.00766363665364,
+ "y": -217.38944085425774,
+ "z": 0.0
+ },
+ {
+ "x": 4.007140252360668,
+ "y": -216.3873561919069,
+ "z": 0.0
+ },
+ {
+ "x": 4.006616868067696,
+ "y": -215.38527152955606,
+ "z": 0.0
+ },
+ {
+ "x": 4.006093483774724,
+ "y": -214.3831868672052,
+ "z": 0.0
+ },
+ {
+ "x": 4.005570099481752,
+ "y": -213.38110220485436,
+ "z": 0.0
+ },
+ {
+ "x": 4.005046715188779,
+ "y": -212.37901754250353,
+ "z": 0.0
+ },
+ {
+ "x": 4.0045233308958075,
+ "y": -211.37693288015268,
+ "z": 0.0
+ },
+ {
+ "x": 4.0039999466028355,
+ "y": -210.37484821780183,
+ "z": 0.0
+ },
+ {
+ "x": 4.003476562309864,
+ "y": -209.37276355545097,
+ "z": 0.0
+ },
+ {
+ "x": 4.002953178016892,
+ "y": -208.37067889310012,
+ "z": 0.0
+ },
+ {
+ "x": 4.002429793723919,
+ "y": -207.3685942307493,
+ "z": 0.0
+ },
+ {
+ "x": 4.001906409430947,
+ "y": -206.36650956839847,
+ "z": 0.0
+ },
+ {
+ "x": 4.001383025137975,
+ "y": -205.36442490604762,
+ "z": 0.0
+ },
+ {
+ "x": 4.000859640845003,
+ "y": -204.3623402436968,
+ "z": 0.0
+ },
+ {
+ "x": 4.000336256552031,
+ "y": -203.36025558134594,
+ "z": 0.0
+ },
+ {
+ "x": 3.9998128722590587,
+ "y": -202.35817091899509,
+ "z": 0.0
+ },
+ {
+ "x": 3.9992894879660867,
+ "y": -201.35608625664423,
+ "z": 0.0
+ },
+ {
+ "x": 3.998766103673115,
+ "y": -200.35400159429338,
+ "z": 0.0
+ },
+ {
+ "x": 3.9982427193801424,
+ "y": -199.35191693194255,
+ "z": 0.0
+ },
+ {
+ "x": 3.9977193350871705,
+ "y": -198.3498322695917,
+ "z": 0.0
+ },
+ {
+ "x": 3.9971959507941985,
+ "y": -197.34774760724085,
+ "z": 0.0
+ },
+ {
+ "x": 3.996672566501226,
+ "y": -196.34566294489002,
+ "z": 0.0
+ },
+ {
+ "x": 3.996149182208254,
+ "y": -195.34357828253917,
+ "z": 0.0
+ },
+ {
+ "x": 3.9956257979152823,
+ "y": -194.34149362018834,
+ "z": 0.0
+ },
+ {
+ "x": 3.99510241362231,
+ "y": -193.3394089578375,
+ "z": 0.0
+ },
+ {
+ "x": 3.994579029329338,
+ "y": -192.33732429548664,
+ "z": 0.0
+ },
+ {
+ "x": 3.994055645036366,
+ "y": -191.3352396331358,
+ "z": 0.0
+ },
+ {
+ "x": 3.9935322607433936,
+ "y": -190.33315497078496,
+ "z": 0.0
+ },
+ {
+ "x": 3.9930088764504217,
+ "y": -189.3310703084341,
+ "z": 0.0
+ },
+ {
+ "x": 3.9924854921574493,
+ "y": -188.32898564608328,
+ "z": 0.0
+ },
+ {
+ "x": 3.9919621078644774,
+ "y": -187.32690098373243,
+ "z": 0.0
+ },
+ {
+ "x": 3.9914387235715054,
+ "y": -186.32481632138158,
+ "z": 0.0
+ },
+ {
+ "x": 3.990915339278533,
+ "y": -185.32273165903072,
+ "z": 0.0
+ },
+ {
+ "x": 3.990391954985561,
+ "y": -184.32064699667987,
+ "z": 0.0
+ },
+ {
+ "x": 3.989868570692589,
+ "y": -183.31856233432904,
+ "z": 0.0
+ },
+ {
+ "x": 3.9893451863996168,
+ "y": -182.3164776719782,
+ "z": 0.0
+ },
+ {
+ "x": 3.988821802106645,
+ "y": -181.31439300962737,
+ "z": 0.0
+ },
+ {
+ "x": 3.988298417813673,
+ "y": -180.31230834727654,
+ "z": 0.0
+ },
+ {
+ "x": 3.9877750335207005,
+ "y": -179.3102236849257,
+ "z": 0.0
+ },
+ {
+ "x": 3.9872516492277286,
+ "y": -178.30813902257484,
+ "z": 0.0
+ },
+ {
+ "x": 3.9867282649347566,
+ "y": -177.30605436022398,
+ "z": 0.0
+ },
+ {
+ "x": 3.9862048806417842,
+ "y": -176.30396969787313,
+ "z": 0.0
+ },
+ {
+ "x": 3.9856814963488123,
+ "y": -175.3018850355223,
+ "z": 0.0
+ },
+ {
+ "x": 3.9851581120558404,
+ "y": -174.29980037317145,
+ "z": 0.0
+ },
+ {
+ "x": 3.984634727762868,
+ "y": -173.2977157108206,
+ "z": 0.0
+ },
+ {
+ "x": 3.984111343469896,
+ "y": -172.29563104846977,
+ "z": 0.0
+ },
+ {
+ "x": 3.983587959176924,
+ "y": -171.29354638611892,
+ "z": 0.0
+ },
+ {
+ "x": 3.9830645748839517,
+ "y": -170.29146172376807,
+ "z": 0.0
+ },
+ {
+ "x": 3.9825411905909798,
+ "y": -169.28937706141724,
+ "z": 0.0
+ },
+ {
+ "x": 3.982017806298008,
+ "y": -168.2872923990664,
+ "z": 0.0
+ },
+ {
+ "x": 3.9814944220050354,
+ "y": -167.28520773671556,
+ "z": 0.0
+ },
+ {
+ "x": 3.9809710377120635,
+ "y": -166.2831230743647,
+ "z": 0.0
+ },
+ {
+ "x": 3.9804476534190916,
+ "y": -165.28103841201386,
+ "z": 0.0
+ },
+ {
+ "x": 3.979924269126119,
+ "y": -164.27895374966303,
+ "z": 0.0
+ },
+ {
+ "x": 3.9794008848331472,
+ "y": -163.27686908731218,
+ "z": 0.0
+ },
+ {
+ "x": 3.9788775005401753,
+ "y": -162.27478442496133,
+ "z": 0.0
+ },
+ {
+ "x": 3.978354116247203,
+ "y": -161.27269976261047,
+ "z": 0.0
+ },
+ {
+ "x": 3.977830731954231,
+ "y": -160.27061510025962,
+ "z": 0.0
+ },
+ {
+ "x": 3.977307347661259,
+ "y": -159.2685304379088,
+ "z": 0.0
+ },
+ {
+ "x": 3.9767839633682867,
+ "y": -158.26644577555794,
+ "z": 0.0
+ },
+ {
+ "x": 3.9762605790753147,
+ "y": -157.2643611132071,
+ "z": 0.0
+ },
+ {
+ "x": 3.9757371947823428,
+ "y": -156.2622764508563,
+ "z": 0.0
+ },
+ {
+ "x": 3.9752138104893704,
+ "y": -155.26019178850544,
+ "z": 0.0
+ },
+ {
+ "x": 3.9746904261963985,
+ "y": -154.25810712615458,
+ "z": 0.0
+ },
+ {
+ "x": 3.9741670419034265,
+ "y": -153.25602246380373,
+ "z": 0.0
+ },
+ {
+ "x": 3.973643657610454,
+ "y": -152.25393780145288,
+ "z": 0.0
+ },
+ {
+ "x": 3.973120273317482,
+ "y": -151.25185313910205,
+ "z": 0.0
+ },
+ {
+ "x": 3.9725968890245102,
+ "y": -150.2497684767512,
+ "z": 0.0
+ },
+ {
+ "x": 3.972073504731538,
+ "y": -149.24768381440035,
+ "z": 0.0
+ },
+ {
+ "x": 3.971550120438566,
+ "y": -148.24559915204952,
+ "z": 0.0
+ },
+ {
+ "x": 3.9710267361455935,
+ "y": -147.24351448969867,
+ "z": 0.0
+ },
+ {
+ "x": 3.9705033518526216,
+ "y": -146.24142982734782,
+ "z": 0.0
+ },
+ {
+ "x": 3.9699799675596497,
+ "y": -145.23934516499696,
+ "z": 0.0
+ },
+ {
+ "x": 3.9694565832666773,
+ "y": -144.23726050264614,
+ "z": 0.0
+ },
+ {
+ "x": 3.9689331989737053,
+ "y": -143.2351758402953,
+ "z": 0.0
+ },
+ {
+ "x": 3.9684098146807334,
+ "y": -142.23309117794446,
+ "z": 0.0
+ },
+ {
+ "x": 3.967886430387761,
+ "y": -141.2310065155936,
+ "z": 0.0
+ },
+ {
+ "x": 3.967363046094789,
+ "y": -140.22892185324278,
+ "z": 0.0
+ },
+ {
+ "x": 3.966839661801817,
+ "y": -139.22683719089193,
+ "z": 0.0
+ },
+ {
+ "x": 3.9663162775088447,
+ "y": -138.22475252854107,
+ "z": 0.0
+ },
+ {
+ "x": 3.965792893215873,
+ "y": -137.22266786619022,
+ "z": 0.0
+ },
+ {
+ "x": 3.965269508922901,
+ "y": -136.22058320383937,
+ "z": 0.0
+ },
+ {
+ "x": 3.9647461246299285,
+ "y": -135.21849854148851,
+ "z": 0.0
+ },
+ {
+ "x": 3.9642227403369565,
+ "y": -134.21641387913766,
+ "z": 0.0
+ },
+ {
+ "x": 3.9636993560439846,
+ "y": -133.21432921678678,
+ "z": 0.0
+ },
+ {
+ "x": 3.963175971751012,
+ "y": -132.21224455443593,
+ "z": 0.0
+ },
+ {
+ "x": 3.9626525874580403,
+ "y": -131.21015989208507,
+ "z": 0.0
+ },
+ {
+ "x": 3.9621292031650683,
+ "y": -130.20807522973422,
+ "z": 0.0
+ },
+ {
+ "x": 3.961605818872096,
+ "y": -129.20599056738337,
+ "z": 0.0
+ },
+ {
+ "x": 3.961082434579124,
+ "y": -128.2039059050325,
+ "z": 0.0
+ },
+ {
+ "x": 3.9605590502861516,
+ "y": -127.20182124268165,
+ "z": 0.0
+ },
+ {
+ "x": 3.9600356659931797,
+ "y": -126.19973658033079,
+ "z": 0.0
+ },
+ {
+ "x": 3.9595122817002077,
+ "y": -125.19765191797993,
+ "z": 0.0
+ },
+ {
+ "x": 3.9589888974072354,
+ "y": -124.19556725562907,
+ "z": 0.0
+ },
+ {
+ "x": 3.9584655131142634,
+ "y": -123.19348259327822,
+ "z": 0.0
+ },
+ {
+ "x": 3.9579421288212915,
+ "y": -122.19139793092735,
+ "z": 0.0
+ },
+ {
+ "x": 3.957418744528319,
+ "y": -121.18931326857648,
+ "z": 0.0
+ },
+ {
+ "x": 3.956895360235347,
+ "y": -120.18722860622564,
+ "z": 0.0
+ },
+ {
+ "x": 3.956371975942375,
+ "y": -119.18514394387479,
+ "z": 0.0
+ },
+ {
+ "x": 3.955848591649403,
+ "y": -118.18305928152392,
+ "z": 0.0
+ },
+ {
+ "x": 3.955325207356431,
+ "y": -117.18097461917306,
+ "z": 0.0
+ },
+ {
+ "x": 3.954801823063459,
+ "y": -116.1788899568222,
+ "z": 0.0
+ },
+ {
+ "x": 3.9542784387704866,
+ "y": -115.17680529447135,
+ "z": 0.0
+ },
+ {
+ "x": 3.9537550544775146,
+ "y": -114.1747206321205,
+ "z": 0.0
+ },
+ {
+ "x": 3.9532316701845422,
+ "y": -113.17263596976963,
+ "z": 0.0
+ },
+ {
+ "x": 3.9527082858915703,
+ "y": -112.17055130741878,
+ "z": 0.0
+ },
+ {
+ "x": 3.9521849015985984,
+ "y": -111.16846664506792,
+ "z": 0.0
+ },
+ {
+ "x": 3.951661517305626,
+ "y": -110.16638198271706,
+ "z": 0.0
+ },
+ {
+ "x": 3.951138133012654,
+ "y": -109.16429732036619,
+ "z": 0.0
+ },
+ {
+ "x": 3.950614748719682,
+ "y": -108.16221265801535,
+ "z": 0.0
+ },
+ {
+ "x": 3.9500913644267097,
+ "y": -107.1601279956645,
+ "z": 0.0
+ },
+ {
+ "x": 3.9495679801337378,
+ "y": -106.15804333331363,
+ "z": 0.0
+ },
+ {
+ "x": 3.949044595840766,
+ "y": -105.15595867096276,
+ "z": 0.0
+ },
+ {
+ "x": 3.9485212115477935,
+ "y": -104.15387400861191,
+ "z": 0.0
+ },
+ {
+ "x": 3.9479978272548215,
+ "y": -103.15178934626105,
+ "z": 0.0
+ },
+ {
+ "x": 3.9474744429618496,
+ "y": -102.1497046839102,
+ "z": 0.0
+ },
+ {
+ "x": 3.946951058668877,
+ "y": -101.14762002155933,
+ "z": 0.0
+ },
+ {
+ "x": 3.9464276743759052,
+ "y": -100.14553535920848,
+ "z": 0.0
+ },
+ {
+ "x": 3.945904290082933,
+ "y": -99.14345069685763,
+ "z": 0.0
+ },
+ {
+ "x": 3.945380905789961,
+ "y": -98.14136603450676,
+ "z": 0.0
+ },
+ {
+ "x": 3.944857521496989,
+ "y": -97.13928137215589,
+ "z": 0.0
+ },
+ {
+ "x": 3.9443341372040166,
+ "y": -96.13719670980505,
+ "z": 0.0
+ },
+ {
+ "x": 3.9438107529110447,
+ "y": -95.1351120474542,
+ "z": 0.0
+ },
+ {
+ "x": 3.9432873686180727,
+ "y": -94.13302738510333,
+ "z": 0.0
+ },
+ {
+ "x": 3.9427639843251003,
+ "y": -93.13094272275247,
+ "z": 0.0
+ },
+ {
+ "x": 3.9422406000321284,
+ "y": -92.12885806040161,
+ "z": 0.0
+ },
+ {
+ "x": 3.9417172157391565,
+ "y": -91.12677339805077,
+ "z": 0.0
+ },
+ {
+ "x": 3.941193831446184,
+ "y": -90.1246887356999,
+ "z": 0.0
+ },
+ {
+ "x": 3.940670447153212,
+ "y": -89.12260407334904,
+ "z": 0.0
+ },
+ {
+ "x": 3.94014706286024,
+ "y": -88.12051941099818,
+ "z": 0.0
+ },
+ {
+ "x": 3.9402771144979183,
+ "y": -87.12104091873772,
+ "z": 0.0
+ },
+ {
+ "x": 3.9406628622236557,
+ "y": -86.11997994611951,
+ "z": 0.0
+ },
+ {
+ "x": 3.9410488732983464,
+ "y": -85.1178952214353,
+ "z": 0.0
+ },
+ {
+ "x": 3.941434884373037,
+ "y": -84.11581049675112,
+ "z": 0.0
+ },
+ {
+ "x": 3.941820895447728,
+ "y": -83.11372577206693,
+ "z": 0.0
+ },
+ {
+ "x": 3.9422069065224186,
+ "y": -82.11164104738273,
+ "z": 0.0
+ },
+ {
+ "x": 3.942592917597109,
+ "y": -81.10955632269852,
+ "z": 0.0
+ },
+ {
+ "x": 3.9429789286717996,
+ "y": -80.10747159801434,
+ "z": 0.0
+ },
+ {
+ "x": 3.9433649397464903,
+ "y": -79.10538687333015,
+ "z": 0.0
+ },
+ {
+ "x": 3.943750950821181,
+ "y": -78.10330214864595,
+ "z": 0.0
+ },
+ {
+ "x": 3.9441369618958717,
+ "y": -77.10121742396174,
+ "z": 0.0
+ },
+ {
+ "x": 3.9445229729705624,
+ "y": -76.09913269927756,
+ "z": 0.0
+ },
+ {
+ "x": 3.9449089840452527,
+ "y": -75.09704797459337,
+ "z": 0.0
+ },
+ {
+ "x": 3.9452949951199434,
+ "y": -74.09496324990917,
+ "z": 0.0
+ },
+ {
+ "x": 3.945681006194634,
+ "y": -73.09287852522498,
+ "z": 0.0
+ },
+ {
+ "x": 3.946067017269325,
+ "y": -72.09079380054078,
+ "z": 0.0
+ },
+ {
+ "x": 3.9464530283440156,
+ "y": -71.08870907585658,
+ "z": 0.0
+ },
+ {
+ "x": 3.9468390394187063,
+ "y": -70.08662435117239,
+ "z": 0.0
+ },
+ {
+ "x": 3.9472250504933966,
+ "y": -69.0845396264882,
+ "z": 0.0
+ },
+ {
+ "x": 3.9476110615680873,
+ "y": -68.082454901804,
+ "z": 0.0
+ },
+ {
+ "x": 3.947997072642778,
+ "y": -67.0803701771198,
+ "z": 0.0
+ },
+ {
+ "x": 3.9483830837174687,
+ "y": -66.07828545243561,
+ "z": 0.0
+ },
+ {
+ "x": 3.9487690947921594,
+ "y": -65.07620072775141,
+ "z": 0.0
+ },
+ {
+ "x": 3.94915510586685,
+ "y": -64.07411600306722,
+ "z": 0.0
+ },
+ {
+ "x": 3.949541116941541,
+ "y": -63.072031278383015,
+ "z": 0.0
+ },
+ {
+ "x": 3.949927128016231,
+ "y": -62.06994655369882,
+ "z": 0.0
+ },
+ {
+ "x": 3.950313139090922,
+ "y": -61.067861829014625,
+ "z": 0.0
+ },
+ {
+ "x": 3.9506991501656126,
+ "y": -60.06577710433043,
+ "z": 0.0
+ },
+ {
+ "x": 3.9510851612403033,
+ "y": -59.063692379646234,
+ "z": 0.0
+ },
+ {
+ "x": 3.951471172314994,
+ "y": -58.06160765496204,
+ "z": 0.0
+ },
+ {
+ "x": 3.9518571833896847,
+ "y": -57.05952293027784,
+ "z": 0.0
+ },
+ {
+ "x": 3.952243194464375,
+ "y": -56.05743820559365,
+ "z": 0.0
+ },
+ {
+ "x": 3.9526292055390657,
+ "y": -55.055353480909446,
+ "z": 0.0
+ },
+ {
+ "x": 3.9530152166137564,
+ "y": -54.05326875622525,
+ "z": 0.0
+ },
+ {
+ "x": 3.953401227688447,
+ "y": -53.051184031541055,
+ "z": 0.0
+ },
+ {
+ "x": 3.953787238763138,
+ "y": -52.04909930685686,
+ "z": 0.0
+ },
+ {
+ "x": 3.9541732498378286,
+ "y": -51.047014582172665,
+ "z": 0.0
+ },
+ {
+ "x": 3.954559260912519,
+ "y": -50.04492985748847,
+ "z": 0.0
+ },
+ {
+ "x": 3.9549452719872096,
+ "y": -49.042845132804274,
+ "z": 0.0
+ },
+ {
+ "x": 3.9553312830619003,
+ "y": -48.04076040812008,
+ "z": 0.0
+ },
+ {
+ "x": 3.955717294136591,
+ "y": -47.03867568343588,
+ "z": 0.0
+ },
+ {
+ "x": 3.9561033052112817,
+ "y": -46.03659095875169,
+ "z": 0.0
+ },
+ {
+ "x": 3.9564893162859724,
+ "y": -45.03450623406749,
+ "z": 0.0
+ },
+ {
+ "x": 3.956875327360663,
+ "y": -44.0324215093833,
+ "z": 0.0
+ },
+ {
+ "x": 3.9572613384353534,
+ "y": -43.0303367846991,
+ "z": 0.0
+ },
+ {
+ "x": 3.957647349510044,
+ "y": -42.02825206001491,
+ "z": 0.0
+ },
+ {
+ "x": 3.958033360584735,
+ "y": -41.02616733533071,
+ "z": 0.0
+ },
+ {
+ "x": 3.9584193716594256,
+ "y": -40.02408261064652,
+ "z": 0.0
+ },
+ {
+ "x": 3.9588053827341163,
+ "y": -39.02199788596233,
+ "z": 0.0
+ },
+ {
+ "x": 3.959191393808807,
+ "y": -38.01991316127813,
+ "z": 0.0
+ },
+ {
+ "x": 3.9595774048834973,
+ "y": -37.017828436593945,
+ "z": 0.0
+ },
+ {
+ "x": 3.959963415958188,
+ "y": -36.01574371190975,
+ "z": 0.0
+ },
+ {
+ "x": 3.9603494270328787,
+ "y": -35.01365898722556,
+ "z": 0.0
+ },
+ {
+ "x": 3.9607354381075695,
+ "y": -34.011574262541366,
+ "z": 0.0
+ },
+ {
+ "x": 3.96112144918226,
+ "y": -33.00948953785717,
+ "z": 0.0
+ },
+ {
+ "x": 3.961507460256951,
+ "y": -32.00740481317298,
+ "z": 0.0
+ },
+ {
+ "x": 3.961893471331641,
+ "y": -31.00532008848879,
+ "z": 0.0
+ },
+ {
+ "x": 3.962279482406332,
+ "y": -30.003235363804595,
+ "z": 0.0
+ },
+ {
+ "x": 3.9626654934810226,
+ "y": -29.001150639120404,
+ "z": 0.0
+ },
+ {
+ "x": 3.9630515045557133,
+ "y": -27.999065914436212,
+ "z": 0.0
+ },
+ {
+ "x": 3.963437515630404,
+ "y": -26.99698118975202,
+ "z": 0.0
+ },
+ {
+ "x": 3.9638235267050947,
+ "y": -25.99489646506783,
+ "z": 0.0
+ },
+ {
+ "x": 3.964209537779785,
+ "y": -24.992811740383633,
+ "z": 0.0
+ },
+ {
+ "x": 3.9645955488544757,
+ "y": -23.99072701569944,
+ "z": 0.0
+ },
+ {
+ "x": 3.9649815599291665,
+ "y": -22.988642291015246,
+ "z": 0.0
+ },
+ {
+ "x": 3.965367571003857,
+ "y": -21.98655756633105,
+ "z": 0.0
+ },
+ {
+ "x": 3.965753582078548,
+ "y": -20.98447284164686,
+ "z": 0.0
+ },
+ {
+ "x": 3.9661395931532386,
+ "y": -19.982388116962664,
+ "z": 0.0
+ },
+ {
+ "x": 3.966525604227929,
+ "y": -18.98030339227847,
+ "z": 0.0
+ },
+ {
+ "x": 3.9669116153026196,
+ "y": -17.978218667594277,
+ "z": 0.0
+ },
+ {
+ "x": 3.9672976263773103,
+ "y": -16.97613394291008,
+ "z": 0.0
+ },
+ {
+ "x": 3.967683637452001,
+ "y": -15.97404921822589,
+ "z": 0.0
+ },
+ {
+ "x": 3.9680696485266918,
+ "y": -14.971964493541696,
+ "z": 0.0
+ },
+ {
+ "x": 3.9684556596013825,
+ "y": -13.969879768857503,
+ "z": 0.0
+ },
+ {
+ "x": 3.9688416706760727,
+ "y": -12.96779504417331,
+ "z": 0.0
+ },
+ {
+ "x": 3.9692276817507635,
+ "y": -11.965710319489116,
+ "z": 0.0
+ },
+ {
+ "x": 3.969613692825454,
+ "y": -10.963625594804922,
+ "z": 0.0
+ },
+ {
+ "x": 3.969999703900145,
+ "y": -9.961540870120729,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 76,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": -4.02999970255904,
+ "y": -9.958459206173217,
+ "z": 0.0
+ },
+ {
+ "x": -4.030385713633731,
+ "y": -10.96054393085741,
+ "z": 0.0
+ },
+ {
+ "x": -4.030771724708422,
+ "y": -11.962628655541604,
+ "z": 0.0
+ },
+ {
+ "x": -4.031157735783112,
+ "y": -12.964713380225797,
+ "z": 0.0
+ },
+ {
+ "x": -4.031543746857803,
+ "y": -13.96679810490999,
+ "z": 0.0
+ },
+ {
+ "x": -4.0319297579324935,
+ "y": -14.968882829594184,
+ "z": 0.0
+ },
+ {
+ "x": -4.032315769007185,
+ "y": -15.970967554278378,
+ "z": 0.0
+ },
+ {
+ "x": -4.032701780081875,
+ "y": -16.97305227896257,
+ "z": 0.0
+ },
+ {
+ "x": -4.033087791156565,
+ "y": -17.975137003646765,
+ "z": 0.0
+ },
+ {
+ "x": -4.033473802231256,
+ "y": -18.977221728330957,
+ "z": 0.0
+ },
+ {
+ "x": -4.033859813305947,
+ "y": -19.979306453015152,
+ "z": 0.0
+ },
+ {
+ "x": -4.034245824380638,
+ "y": -20.981391177699347,
+ "z": 0.0
+ },
+ {
+ "x": -4.034631835455328,
+ "y": -21.98347590238354,
+ "z": 0.0
+ },
+ {
+ "x": -4.035017846530018,
+ "y": -22.985560627067734,
+ "z": 0.0
+ },
+ {
+ "x": -4.0354038576047095,
+ "y": -23.98764535175193,
+ "z": 0.0
+ },
+ {
+ "x": -4.0357898686794,
+ "y": -24.98973007643612,
+ "z": 0.0
+ },
+ {
+ "x": -4.036175879754091,
+ "y": -25.991814801120317,
+ "z": 0.0
+ },
+ {
+ "x": -4.036561890828781,
+ "y": -26.99389952580451,
+ "z": 0.0
+ },
+ {
+ "x": -4.036947901903472,
+ "y": -27.9959842504887,
+ "z": 0.0
+ },
+ {
+ "x": -4.037333912978163,
+ "y": -28.99806897517289,
+ "z": 0.0
+ },
+ {
+ "x": -4.037719924052853,
+ "y": -30.000153699857083,
+ "z": 0.0
+ },
+ {
+ "x": -4.038105935127544,
+ "y": -31.00223842454128,
+ "z": 0.0
+ },
+ {
+ "x": -4.038491946202234,
+ "y": -32.00432314922547,
+ "z": 0.0
+ },
+ {
+ "x": -4.038877957276926,
+ "y": -33.00640787390966,
+ "z": 0.0
+ },
+ {
+ "x": -4.039263968351616,
+ "y": -34.008492598593854,
+ "z": 0.0
+ },
+ {
+ "x": -4.039649979426306,
+ "y": -35.01057732327805,
+ "z": 0.0
+ },
+ {
+ "x": -4.040035990500997,
+ "y": -36.01266204796224,
+ "z": 0.0
+ },
+ {
+ "x": -4.0404220015756875,
+ "y": -37.01474677264643,
+ "z": 0.0
+ },
+ {
+ "x": -4.040808012650379,
+ "y": -38.01683149733062,
+ "z": 0.0
+ },
+ {
+ "x": -4.041194023725069,
+ "y": -39.018916222014816,
+ "z": 0.0
+ },
+ {
+ "x": -4.04158003479976,
+ "y": -40.02100094669901,
+ "z": 0.0
+ },
+ {
+ "x": -4.04196604587445,
+ "y": -41.0230856713832,
+ "z": 0.0
+ },
+ {
+ "x": -4.042352056949141,
+ "y": -42.025170396067395,
+ "z": 0.0
+ },
+ {
+ "x": -4.042738068023832,
+ "y": -43.02725512075159,
+ "z": 0.0
+ },
+ {
+ "x": -4.043124079098522,
+ "y": -44.029339845435786,
+ "z": 0.0
+ },
+ {
+ "x": -4.043510090173213,
+ "y": -45.03142457011998,
+ "z": 0.0
+ },
+ {
+ "x": -4.0438961012479036,
+ "y": -46.033509294804176,
+ "z": 0.0
+ },
+ {
+ "x": -4.044282112322595,
+ "y": -47.03559401948837,
+ "z": 0.0
+ },
+ {
+ "x": -4.044668123397285,
+ "y": -48.03767874417257,
+ "z": 0.0
+ },
+ {
+ "x": -4.045054134471975,
+ "y": -49.03976346885676,
+ "z": 0.0
+ },
+ {
+ "x": -4.045440145546666,
+ "y": -50.04184819354096,
+ "z": 0.0
+ },
+ {
+ "x": -4.045826156621357,
+ "y": -51.04393291822515,
+ "z": 0.0
+ },
+ {
+ "x": -4.046212167696048,
+ "y": -52.04601764290935,
+ "z": 0.0
+ },
+ {
+ "x": -4.046598178770738,
+ "y": -53.04810236759354,
+ "z": 0.0
+ },
+ {
+ "x": -4.046984189845428,
+ "y": -54.05018709227774,
+ "z": 0.0
+ },
+ {
+ "x": -4.04737020092012,
+ "y": -55.052271816961934,
+ "z": 0.0
+ },
+ {
+ "x": -4.04775621199481,
+ "y": -56.054356541646136,
+ "z": 0.0
+ },
+ {
+ "x": -4.048142223069501,
+ "y": -57.05644126633033,
+ "z": 0.0
+ },
+ {
+ "x": -4.048528234144191,
+ "y": -58.05852599101453,
+ "z": 0.0
+ },
+ {
+ "x": -4.048914245218882,
+ "y": -59.06061071569872,
+ "z": 0.0
+ },
+ {
+ "x": -4.049300256293573,
+ "y": -60.06269544038292,
+ "z": 0.0
+ },
+ {
+ "x": -4.049686267368263,
+ "y": -61.06478016506711,
+ "z": 0.0
+ },
+ {
+ "x": -4.050072278442954,
+ "y": -62.06686488975131,
+ "z": 0.0
+ },
+ {
+ "x": -4.050458289517644,
+ "y": -63.0689496144355,
+ "z": 0.0
+ },
+ {
+ "x": -4.050844300592336,
+ "y": -64.0710343391197,
+ "z": 0.0
+ },
+ {
+ "x": -4.051230311667026,
+ "y": -65.0731190638039,
+ "z": 0.0
+ },
+ {
+ "x": -4.051616322741716,
+ "y": -66.0752037884881,
+ "z": 0.0
+ },
+ {
+ "x": -4.052002333816407,
+ "y": -67.07728851317229,
+ "z": 0.0
+ },
+ {
+ "x": -4.052388344891098,
+ "y": -68.07937323785649,
+ "z": 0.0
+ },
+ {
+ "x": -4.052774355965789,
+ "y": -69.08145796254068,
+ "z": 0.0
+ },
+ {
+ "x": -4.053160367040479,
+ "y": -70.08354268722488,
+ "z": 0.0
+ },
+ {
+ "x": -4.05354637811517,
+ "y": -71.08562741190907,
+ "z": 0.0
+ },
+ {
+ "x": -4.05393238918986,
+ "y": -72.08771213659327,
+ "z": 0.0
+ },
+ {
+ "x": -4.054318400264551,
+ "y": -73.08979686127746,
+ "z": 0.0
+ },
+ {
+ "x": -4.054704411339242,
+ "y": -74.09188158596166,
+ "z": 0.0
+ },
+ {
+ "x": -4.055090422413932,
+ "y": -75.09396631064585,
+ "z": 0.0
+ },
+ {
+ "x": -4.055476433488623,
+ "y": -76.09605103533005,
+ "z": 0.0
+ },
+ {
+ "x": -4.055862444563314,
+ "y": -77.09813576001423,
+ "z": 0.0
+ },
+ {
+ "x": -4.056248455638005,
+ "y": -78.10022048469844,
+ "z": 0.0
+ },
+ {
+ "x": -4.056634466712695,
+ "y": -79.10230520938264,
+ "z": 0.0
+ },
+ {
+ "x": -4.057020477787385,
+ "y": -80.10438993406683,
+ "z": 0.0
+ },
+ {
+ "x": -4.057406488862076,
+ "y": -81.10647465875101,
+ "z": 0.0
+ },
+ {
+ "x": -4.057792499936767,
+ "y": -82.10855938343522,
+ "z": 0.0
+ },
+ {
+ "x": -4.058178511011458,
+ "y": -83.11064410811942,
+ "z": 0.0
+ },
+ {
+ "x": -4.058564522086148,
+ "y": -84.11272883280361,
+ "z": 0.0
+ },
+ {
+ "x": -4.058950533160838,
+ "y": -85.11481355748779,
+ "z": 0.0
+ },
+ {
+ "x": -4.05933654423553,
+ "y": -86.116898282172,
+ "z": 0.0
+ },
+ {
+ "x": -4.059722818659173,
+ "y": -87.12000675892219,
+ "z": 0.0
+ },
+ {
+ "x": -4.059851845969695,
+ "y": -88.12469777429422,
+ "z": 0.0
+ },
+ {
+ "x": -4.059328461676723,
+ "y": -89.12678243664507,
+ "z": 0.0
+ },
+ {
+ "x": -4.058805077383751,
+ "y": -90.12886709899594,
+ "z": 0.0
+ },
+ {
+ "x": -4.0582816930907795,
+ "y": -91.13095176134681,
+ "z": 0.0
+ },
+ {
+ "x": -4.0577583087978075,
+ "y": -92.13303642369765,
+ "z": 0.0
+ },
+ {
+ "x": -4.057234924504835,
+ "y": -93.1351210860485,
+ "z": 0.0
+ },
+ {
+ "x": -4.056711540211863,
+ "y": -94.13720574839937,
+ "z": 0.0
+ },
+ {
+ "x": -4.056188155918891,
+ "y": -95.13929041075023,
+ "z": 0.0
+ },
+ {
+ "x": -4.055664771625919,
+ "y": -96.14137507310109,
+ "z": 0.0
+ },
+ {
+ "x": -4.055141387332947,
+ "y": -97.14345973545193,
+ "z": 0.0
+ },
+ {
+ "x": -4.054618003039974,
+ "y": -98.1455443978028,
+ "z": 0.0
+ },
+ {
+ "x": -4.054094618747002,
+ "y": -99.14762906015366,
+ "z": 0.0
+ },
+ {
+ "x": -4.05357123445403,
+ "y": -100.14971372250452,
+ "z": 0.0
+ },
+ {
+ "x": -4.053047850161058,
+ "y": -101.15179838485537,
+ "z": 0.0
+ },
+ {
+ "x": -4.052524465868086,
+ "y": -102.15388304720624,
+ "z": 0.0
+ },
+ {
+ "x": -4.052001081575114,
+ "y": -103.15596770955709,
+ "z": 0.0
+ },
+ {
+ "x": -4.051477697282142,
+ "y": -104.15805237190794,
+ "z": 0.0
+ },
+ {
+ "x": -4.05095431298917,
+ "y": -105.1601370342588,
+ "z": 0.0
+ },
+ {
+ "x": -4.050430928696198,
+ "y": -106.16222169660966,
+ "z": 0.0
+ },
+ {
+ "x": -4.049907544403226,
+ "y": -107.16430635896053,
+ "z": 0.0
+ },
+ {
+ "x": -4.049384160110254,
+ "y": -108.16639102131138,
+ "z": 0.0
+ },
+ {
+ "x": -4.048860775817281,
+ "y": -109.16847568366222,
+ "z": 0.0
+ },
+ {
+ "x": -4.048337391524309,
+ "y": -110.17056034601309,
+ "z": 0.0
+ },
+ {
+ "x": -4.047814007231337,
+ "y": -111.17264500836396,
+ "z": 0.0
+ },
+ {
+ "x": -4.047290622938365,
+ "y": -112.17472967071481,
+ "z": 0.0
+ },
+ {
+ "x": -4.046767238645393,
+ "y": -113.17681433306566,
+ "z": 0.0
+ },
+ {
+ "x": -4.046243854352421,
+ "y": -114.17889899541653,
+ "z": 0.0
+ },
+ {
+ "x": -4.0457204700594485,
+ "y": -115.18098365776738,
+ "z": 0.0
+ },
+ {
+ "x": -4.0451970857664765,
+ "y": -116.18306832011824,
+ "z": 0.0
+ },
+ {
+ "x": -4.044673701473505,
+ "y": -117.18515298246909,
+ "z": 0.0
+ },
+ {
+ "x": -4.044150317180533,
+ "y": -118.18723764481996,
+ "z": 0.0
+ },
+ {
+ "x": -4.043626932887561,
+ "y": -119.18932230717083,
+ "z": 0.0
+ },
+ {
+ "x": -4.043103548594589,
+ "y": -120.19140696952168,
+ "z": 0.0
+ },
+ {
+ "x": -4.042580164301616,
+ "y": -121.19349163187252,
+ "z": 0.0
+ },
+ {
+ "x": -4.042056780008644,
+ "y": -122.19557629422339,
+ "z": 0.0
+ },
+ {
+ "x": -4.041533395715672,
+ "y": -123.19766095657425,
+ "z": 0.0
+ },
+ {
+ "x": -4.0410100114227,
+ "y": -124.1997456189251,
+ "z": 0.0
+ },
+ {
+ "x": -4.040486627129728,
+ "y": -125.20183028127596,
+ "z": 0.0
+ },
+ {
+ "x": -4.039963242836755,
+ "y": -126.20391494362683,
+ "z": 0.0
+ },
+ {
+ "x": -4.039439858543783,
+ "y": -127.20599960597768,
+ "z": 0.0
+ },
+ {
+ "x": -4.0389164742508115,
+ "y": -128.20808426832855,
+ "z": 0.0
+ },
+ {
+ "x": -4.0383930899578395,
+ "y": -129.2101689306794,
+ "z": 0.0
+ },
+ {
+ "x": -4.037869705664868,
+ "y": -130.21225359303025,
+ "z": 0.0
+ },
+ {
+ "x": -4.037346321371896,
+ "y": -131.2143382553811,
+ "z": 0.0
+ },
+ {
+ "x": -4.036822937078923,
+ "y": -132.21642291773196,
+ "z": 0.0
+ },
+ {
+ "x": -4.036299552785951,
+ "y": -133.21850758008281,
+ "z": 0.0
+ },
+ {
+ "x": -4.035776168492979,
+ "y": -134.2205922424337,
+ "z": 0.0
+ },
+ {
+ "x": -4.035252784200007,
+ "y": -135.22267690478455,
+ "z": 0.0
+ },
+ {
+ "x": -4.034729399907035,
+ "y": -136.2247615671354,
+ "z": 0.0
+ },
+ {
+ "x": -4.034206015614062,
+ "y": -137.22684622948626,
+ "z": 0.0
+ },
+ {
+ "x": -4.03368263132109,
+ "y": -138.2289308918371,
+ "z": 0.0
+ },
+ {
+ "x": -4.033159247028118,
+ "y": -139.23101555418796,
+ "z": 0.0
+ },
+ {
+ "x": -4.032635862735146,
+ "y": -140.23310021653882,
+ "z": 0.0
+ },
+ {
+ "x": -4.0321124784421745,
+ "y": -141.23518487888964,
+ "z": 0.0
+ },
+ {
+ "x": -4.0315890941492025,
+ "y": -142.2372695412405,
+ "z": 0.0
+ },
+ {
+ "x": -4.03106570985623,
+ "y": -143.23935420359135,
+ "z": 0.0
+ },
+ {
+ "x": -4.030542325563258,
+ "y": -144.24143886594217,
+ "z": 0.0
+ },
+ {
+ "x": -4.030018941270286,
+ "y": -145.243523528293,
+ "z": 0.0
+ },
+ {
+ "x": -4.029495556977314,
+ "y": -146.24560819064385,
+ "z": 0.0
+ },
+ {
+ "x": -4.028972172684342,
+ "y": -147.2476928529947,
+ "z": 0.0
+ },
+ {
+ "x": -4.02844878839137,
+ "y": -148.24977751534556,
+ "z": 0.0
+ },
+ {
+ "x": -4.027925404098397,
+ "y": -149.25186217769638,
+ "z": 0.0
+ },
+ {
+ "x": -4.027402019805425,
+ "y": -150.25394684004723,
+ "z": 0.0
+ },
+ {
+ "x": -4.026878635512453,
+ "y": -151.2560315023981,
+ "z": 0.0
+ },
+ {
+ "x": -4.026355251219481,
+ "y": -152.2581161647489,
+ "z": 0.0
+ },
+ {
+ "x": -4.025831866926509,
+ "y": -153.26020082709977,
+ "z": 0.0
+ },
+ {
+ "x": -4.0253084826335375,
+ "y": -154.26228548945062,
+ "z": 0.0
+ },
+ {
+ "x": -4.024785098340565,
+ "y": -155.26437015180147,
+ "z": 0.0
+ },
+ {
+ "x": -4.024261714047593,
+ "y": -156.26645481415233,
+ "z": 0.0
+ },
+ {
+ "x": -4.023738329754621,
+ "y": -157.26853947650312,
+ "z": 0.0
+ },
+ {
+ "x": -4.023214945461649,
+ "y": -158.27062413885398,
+ "z": 0.0
+ },
+ {
+ "x": -4.022691561168677,
+ "y": -159.27270880120483,
+ "z": 0.0
+ },
+ {
+ "x": -4.022168176875705,
+ "y": -160.27479346355565,
+ "z": 0.0
+ },
+ {
+ "x": -4.021644792582732,
+ "y": -161.2768781259065,
+ "z": 0.0
+ },
+ {
+ "x": -4.02112140828976,
+ "y": -162.27896278825736,
+ "z": 0.0
+ },
+ {
+ "x": -4.020598023996788,
+ "y": -163.2810474506082,
+ "z": 0.0
+ },
+ {
+ "x": -4.020074639703816,
+ "y": -164.28313211295907,
+ "z": 0.0
+ },
+ {
+ "x": -4.019551255410844,
+ "y": -165.2852167753099,
+ "z": 0.0
+ },
+ {
+ "x": -4.019027871117872,
+ "y": -166.28730143766074,
+ "z": 0.0
+ },
+ {
+ "x": -4.0185044868249,
+ "y": -167.2893861000116,
+ "z": 0.0
+ },
+ {
+ "x": -4.017981102531928,
+ "y": -168.29147076236242,
+ "z": 0.0
+ },
+ {
+ "x": -4.017457718238956,
+ "y": -169.29355542471328,
+ "z": 0.0
+ },
+ {
+ "x": -4.016934333945984,
+ "y": -170.2956400870641,
+ "z": 0.0
+ },
+ {
+ "x": -4.016410949653012,
+ "y": -171.29772474941495,
+ "z": 0.0
+ },
+ {
+ "x": -4.015887565360039,
+ "y": -172.2998094117658,
+ "z": 0.0
+ },
+ {
+ "x": -4.015364181067067,
+ "y": -173.30189407411663,
+ "z": 0.0
+ },
+ {
+ "x": -4.014840796774095,
+ "y": -174.30397873646749,
+ "z": 0.0
+ },
+ {
+ "x": -4.014317412481123,
+ "y": -175.30606339881834,
+ "z": 0.0
+ },
+ {
+ "x": -4.013794028188151,
+ "y": -176.30814806116916,
+ "z": 0.0
+ },
+ {
+ "x": -4.013270643895179,
+ "y": -177.31023272352002,
+ "z": 0.0
+ },
+ {
+ "x": -4.0127472596022065,
+ "y": -178.31231738587087,
+ "z": 0.0
+ },
+ {
+ "x": -4.0122238753092345,
+ "y": -179.31440204822172,
+ "z": 0.0
+ },
+ {
+ "x": -4.011700491016263,
+ "y": -180.31648671057258,
+ "z": 0.0
+ },
+ {
+ "x": -4.011177106723291,
+ "y": -181.3185713729234,
+ "z": 0.0
+ },
+ {
+ "x": -4.010653722430319,
+ "y": -182.32065603527423,
+ "z": 0.0
+ },
+ {
+ "x": -4.010130338137347,
+ "y": -183.32274069762508,
+ "z": 0.0
+ },
+ {
+ "x": -4.009606953844374,
+ "y": -184.3248253599759,
+ "z": 0.0
+ },
+ {
+ "x": -4.009083569551402,
+ "y": -185.32691002232676,
+ "z": 0.0
+ },
+ {
+ "x": -4.00856018525843,
+ "y": -186.3289946846776,
+ "z": 0.0
+ },
+ {
+ "x": -4.008036800965458,
+ "y": -187.33107934702846,
+ "z": 0.0
+ },
+ {
+ "x": -4.007513416672486,
+ "y": -188.33316400937932,
+ "z": 0.0
+ },
+ {
+ "x": -4.006990032379514,
+ "y": -189.33524867173014,
+ "z": 0.0
+ },
+ {
+ "x": -4.006466648086541,
+ "y": -190.337333334081,
+ "z": 0.0
+ },
+ {
+ "x": -4.0059432637935695,
+ "y": -191.33941799643185,
+ "z": 0.0
+ },
+ {
+ "x": -4.0054198795005975,
+ "y": -192.34150265878267,
+ "z": 0.0
+ },
+ {
+ "x": -4.004896495207626,
+ "y": -193.34358732113353,
+ "z": 0.0
+ },
+ {
+ "x": -4.004373110914654,
+ "y": -194.34567198348438,
+ "z": 0.0
+ },
+ {
+ "x": -4.003849726621682,
+ "y": -195.3477566458352,
+ "z": 0.0
+ },
+ {
+ "x": -4.003326342328709,
+ "y": -196.34984130818606,
+ "z": 0.0
+ },
+ {
+ "x": -4.002802958035737,
+ "y": -197.35192597053688,
+ "z": 0.0
+ },
+ {
+ "x": -4.002279573742765,
+ "y": -198.35401063288774,
+ "z": 0.0
+ },
+ {
+ "x": -4.001756189449793,
+ "y": -199.3560952952386,
+ "z": 0.0
+ },
+ {
+ "x": -4.001232805156821,
+ "y": -200.3581799575894,
+ "z": 0.0
+ },
+ {
+ "x": -4.000709420863849,
+ "y": -201.36026461994027,
+ "z": 0.0
+ },
+ {
+ "x": -4.000186036570876,
+ "y": -202.36234928229112,
+ "z": 0.0
+ },
+ {
+ "x": -3.9996626522779044,
+ "y": -203.36443394464197,
+ "z": 0.0
+ },
+ {
+ "x": -3.9991392679849325,
+ "y": -204.36651860699283,
+ "z": 0.0
+ },
+ {
+ "x": -3.9986158836919605,
+ "y": -205.36860326934365,
+ "z": 0.0
+ },
+ {
+ "x": -3.998092499398988,
+ "y": -206.3706879316945,
+ "z": 0.0
+ },
+ {
+ "x": -3.997569115106016,
+ "y": -207.37277259404533,
+ "z": 0.0
+ },
+ {
+ "x": -3.9970457308130443,
+ "y": -208.37485725639615,
+ "z": 0.0
+ },
+ {
+ "x": -3.996522346520072,
+ "y": -209.376941918747,
+ "z": 0.0
+ },
+ {
+ "x": -3.9959989622271,
+ "y": -210.37902658109786,
+ "z": 0.0
+ },
+ {
+ "x": -3.995475577934128,
+ "y": -211.38111124344871,
+ "z": 0.0
+ },
+ {
+ "x": -3.9949521936411556,
+ "y": -212.38319590579957,
+ "z": 0.0
+ },
+ {
+ "x": -3.9944288093481837,
+ "y": -213.3852805681504,
+ "z": 0.0
+ },
+ {
+ "x": -3.9939054250552117,
+ "y": -214.38736523050125,
+ "z": 0.0
+ },
+ {
+ "x": -3.9933820407622393,
+ "y": -215.3894498928521,
+ "z": 0.0
+ },
+ {
+ "x": -3.9928586564692674,
+ "y": -216.39153455520292,
+ "z": 0.0
+ },
+ {
+ "x": -3.9923352721762955,
+ "y": -217.39361921755378,
+ "z": 0.0
+ },
+ {
+ "x": -3.991811887883323,
+ "y": -218.39570387990463,
+ "z": 0.0
+ },
+ {
+ "x": -3.991288503590351,
+ "y": -219.39778854225548,
+ "z": 0.0
+ },
+ {
+ "x": -3.990765119297379,
+ "y": -220.3998732046063,
+ "z": 0.0
+ },
+ {
+ "x": -3.990241735004407,
+ "y": -221.40195786695713,
+ "z": 0.0
+ },
+ {
+ "x": -3.989718350711435,
+ "y": -222.404042529308,
+ "z": 0.0
+ },
+ {
+ "x": -3.989194966418463,
+ "y": -223.40612719165884,
+ "z": 0.0
+ },
+ {
+ "x": -3.9886715821254906,
+ "y": -224.40821185400966,
+ "z": 0.0
+ },
+ {
+ "x": -3.9881481978325186,
+ "y": -225.41029651636052,
+ "z": 0.0
+ },
+ {
+ "x": -3.9876248135395467,
+ "y": -226.41238117871137,
+ "z": 0.0
+ },
+ {
+ "x": -3.9871014292465743,
+ "y": -227.41446584106222,
+ "z": 0.0
+ },
+ {
+ "x": -3.9865780449536024,
+ "y": -228.41655050341308,
+ "z": 0.0
+ },
+ {
+ "x": -3.9860546606606304,
+ "y": -229.4186351657639,
+ "z": 0.0
+ },
+ {
+ "x": -3.985531276367658,
+ "y": -230.42071982811476,
+ "z": 0.0
+ },
+ {
+ "x": -3.985007892074686,
+ "y": -231.4228044904656,
+ "z": 0.0
+ },
+ {
+ "x": -3.984484507781714,
+ "y": -232.4248891528164,
+ "z": 0.0
+ },
+ {
+ "x": -3.9839611234887418,
+ "y": -233.42697381516726,
+ "z": 0.0
+ },
+ {
+ "x": -3.98343773919577,
+ "y": -234.4290584775181,
+ "z": 0.0
+ },
+ {
+ "x": -3.9829143549027974,
+ "y": -235.43114313986896,
+ "z": 0.0
+ },
+ {
+ "x": -3.9823909706098255,
+ "y": -236.43322780221982,
+ "z": 0.0
+ },
+ {
+ "x": -3.9818675863168536,
+ "y": -237.43531246457064,
+ "z": 0.0
+ },
+ {
+ "x": -3.981344202023881,
+ "y": -238.4373971269215,
+ "z": 0.0
+ },
+ {
+ "x": -3.9808208177309092,
+ "y": -239.43948178927235,
+ "z": 0.0
+ },
+ {
+ "x": -3.980297862737418,
+ "y": -240.44044178249482,
+ "z": 0.0
+ },
+ {
+ "x": -3.9800563141031873,
+ "y": -241.4410397436067,
+ "z": 0.0
+ },
+ {
+ "x": -3.9801871516298046,
+ "y": -242.44312453409674,
+ "z": 0.0
+ },
+ {
+ "x": -3.980317989156422,
+ "y": -243.44520932458678,
+ "z": 0.0
+ },
+ {
+ "x": -3.9804488266830402,
+ "y": -244.44729411507683,
+ "z": 0.0
+ },
+ {
+ "x": -3.980579664209657,
+ "y": -245.44937890556685,
+ "z": 0.0
+ },
+ {
+ "x": -3.9807105017362754,
+ "y": -246.4514636960569,
+ "z": 0.0
+ },
+ {
+ "x": -3.9808413392628927,
+ "y": -247.45354848654696,
+ "z": 0.0
+ },
+ {
+ "x": -3.980972176789509,
+ "y": -248.45563327703698,
+ "z": 0.0
+ },
+ {
+ "x": -3.981103014316127,
+ "y": -249.45771806752703,
+ "z": 0.0
+ },
+ {
+ "x": -3.9812338518427444,
+ "y": -250.45980285801707,
+ "z": 0.0
+ },
+ {
+ "x": -3.9813646893693617,
+ "y": -251.46188764850712,
+ "z": 0.0
+ },
+ {
+ "x": -3.98149552689598,
+ "y": -252.46397243899716,
+ "z": 0.0
+ },
+ {
+ "x": -3.981626364422597,
+ "y": -253.46605722948718,
+ "z": 0.0
+ },
+ {
+ "x": -3.9817572019492142,
+ "y": -254.46814201997722,
+ "z": 0.0
+ },
+ {
+ "x": -3.9818880394758316,
+ "y": -255.47022681046727,
+ "z": 0.0
+ },
+ {
+ "x": -3.98201887700245,
+ "y": -256.47231160095725,
+ "z": 0.0
+ },
+ {
+ "x": -3.9821497145290676,
+ "y": -257.4743963914473,
+ "z": 0.0
+ },
+ {
+ "x": -3.982280552055685,
+ "y": -258.4764811819374,
+ "z": 0.0
+ },
+ {
+ "x": -3.9824113895823023,
+ "y": -259.4785659724274,
+ "z": 0.0
+ },
+ {
+ "x": -3.98254222710892,
+ "y": -260.4806507629175,
+ "z": 0.0
+ },
+ {
+ "x": -3.9826730646355375,
+ "y": -261.4827355534075,
+ "z": 0.0
+ },
+ {
+ "x": -3.982803902162155,
+ "y": -262.4848203438975,
+ "z": 0.0
+ },
+ {
+ "x": -3.982934739688772,
+ "y": -263.4869051343876,
+ "z": 0.0
+ },
+ {
+ "x": -3.98306557721539,
+ "y": -264.4889899248776,
+ "z": 0.0
+ },
+ {
+ "x": -3.9831964147420074,
+ "y": -265.49107471536763,
+ "z": 0.0
+ },
+ {
+ "x": -3.9833272522686247,
+ "y": -266.4931595058577,
+ "z": 0.0
+ },
+ {
+ "x": -3.983458089795242,
+ "y": -267.4952442963478,
+ "z": 0.0
+ },
+ {
+ "x": -3.98358892732186,
+ "y": -268.49732908683785,
+ "z": 0.0
+ },
+ {
+ "x": -3.9837197648484772,
+ "y": -269.4994138773279,
+ "z": 0.0
+ },
+ {
+ "x": -3.9838506023750946,
+ "y": -270.501498667818,
+ "z": 0.0
+ },
+ {
+ "x": -3.983981439901712,
+ "y": -271.503583458308,
+ "z": 0.0
+ },
+ {
+ "x": -3.9841122774283297,
+ "y": -272.5056682487981,
+ "z": 0.0
+ },
+ {
+ "x": -3.984243114954947,
+ "y": -273.50775303928816,
+ "z": 0.0
+ },
+ {
+ "x": -3.9843739524815645,
+ "y": -274.50983782977823,
+ "z": 0.0
+ },
+ {
+ "x": -3.9845047900081823,
+ "y": -275.5119226202683,
+ "z": 0.0
+ },
+ {
+ "x": -3.9846356275347996,
+ "y": -276.5140074107584,
+ "z": 0.0
+ },
+ {
+ "x": -3.984766465061417,
+ "y": -277.51609220124845,
+ "z": 0.0
+ },
+ {
+ "x": -3.9848973025880343,
+ "y": -278.51817699173847,
+ "z": 0.0
+ },
+ {
+ "x": -3.985028140114652,
+ "y": -279.52026178222854,
+ "z": 0.0
+ },
+ {
+ "x": -3.9851589776412695,
+ "y": -280.5223465727186,
+ "z": 0.0
+ },
+ {
+ "x": -3.985289815167887,
+ "y": -281.5244313632087,
+ "z": 0.0
+ },
+ {
+ "x": -3.985420652694504,
+ "y": -282.52651615369876,
+ "z": 0.0
+ },
+ {
+ "x": -3.985551490221122,
+ "y": -283.52860094418884,
+ "z": 0.0
+ },
+ {
+ "x": -3.9856823277477393,
+ "y": -284.5306857346789,
+ "z": 0.0
+ },
+ {
+ "x": -3.9858131652743567,
+ "y": -285.532770525169,
+ "z": 0.0
+ },
+ {
+ "x": -3.9859440028009745,
+ "y": -286.53485531565906,
+ "z": 0.0
+ },
+ {
+ "x": -3.986074840327592,
+ "y": -287.53694010614913,
+ "z": 0.0
+ },
+ {
+ "x": -3.986205677854209,
+ "y": -288.5390248966392,
+ "z": 0.0
+ },
+ {
+ "x": -3.9863365153808266,
+ "y": -289.5411096871293,
+ "z": 0.0
+ },
+ {
+ "x": -3.9864673529074444,
+ "y": -290.54319447761935,
+ "z": 0.0
+ },
+ {
+ "x": -3.9865981904340617,
+ "y": -291.5452792681094,
+ "z": 0.0
+ },
+ {
+ "x": -3.986729027960679,
+ "y": -292.5473640585995,
+ "z": 0.0
+ },
+ {
+ "x": -3.9868598654872964,
+ "y": -293.5494488490896,
+ "z": 0.0
+ },
+ {
+ "x": -3.9869907030139142,
+ "y": -294.5515336395796,
+ "z": 0.0
+ },
+ {
+ "x": -3.9871215405405316,
+ "y": -295.55361843006966,
+ "z": 0.0
+ },
+ {
+ "x": -3.987252378067149,
+ "y": -296.55570322055974,
+ "z": 0.0
+ },
+ {
+ "x": -3.9873832155937663,
+ "y": -297.5577880110498,
+ "z": 0.0
+ },
+ {
+ "x": -3.987514053120384,
+ "y": -298.5598728015399,
+ "z": 0.0
+ },
+ {
+ "x": -3.9876448906470014,
+ "y": -299.56195759202996,
+ "z": 0.0
+ },
+ {
+ "x": -3.987775728173619,
+ "y": -300.56404238252003,
+ "z": 0.0
+ },
+ {
+ "x": -3.9879065657002366,
+ "y": -301.5661271730101,
+ "z": 0.0
+ },
+ {
+ "x": -3.988037403226854,
+ "y": -302.5682119635002,
+ "z": 0.0
+ },
+ {
+ "x": -3.9881682407534713,
+ "y": -303.5702967539902,
+ "z": 0.0
+ },
+ {
+ "x": -3.9882990782800887,
+ "y": -304.57238154448027,
+ "z": 0.0
+ },
+ {
+ "x": -3.9884299158067065,
+ "y": -305.57446633497034,
+ "z": 0.0
+ },
+ {
+ "x": -3.988560753333324,
+ "y": -306.5765511254604,
+ "z": 0.0
+ },
+ {
+ "x": -3.988691590859941,
+ "y": -307.5786359159505,
+ "z": 0.0
+ },
+ {
+ "x": -3.9888224283865585,
+ "y": -308.58072070644056,
+ "z": 0.0
+ },
+ {
+ "x": -3.9889532659131763,
+ "y": -309.58280549693063,
+ "z": 0.0
+ },
+ {
+ "x": -3.9890841034397937,
+ "y": -310.58489028742065,
+ "z": 0.0
+ },
+ {
+ "x": -3.989214940966411,
+ "y": -311.5869750779107,
+ "z": 0.0
+ },
+ {
+ "x": -3.989345778493029,
+ "y": -312.5890598684008,
+ "z": 0.0
+ },
+ {
+ "x": -3.989476616019646,
+ "y": -313.59114465889087,
+ "z": 0.0
+ },
+ {
+ "x": -3.9896074535462636,
+ "y": -314.59322944938094,
+ "z": 0.0
+ },
+ {
+ "x": -3.989738291072881,
+ "y": -315.595314239871,
+ "z": 0.0
+ },
+ {
+ "x": -3.9898691285994987,
+ "y": -316.5973990303611,
+ "z": 0.0
+ },
+ {
+ "x": -3.989999966126116,
+ "y": -317.59948382085116,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 77,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": -0.029999999329447746,
+ "y": -9.960000038146973,
+ "z": 0.0
+ },
+ {
+ "x": -0.030386010404138394,
+ "y": -10.962084762831166,
+ "z": 0.0
+ },
+ {
+ "x": -0.030772021478829036,
+ "y": -11.96416948751536,
+ "z": 0.0
+ },
+ {
+ "x": -0.031158032553519684,
+ "y": -12.966254212199553,
+ "z": 0.0
+ },
+ {
+ "x": -0.031544043628210325,
+ "y": -13.968338936883747,
+ "z": 0.0
+ },
+ {
+ "x": -0.03193005470290097,
+ "y": -14.97042366156794,
+ "z": 0.0
+ },
+ {
+ "x": -0.03231606577759162,
+ "y": -15.972508386252134,
+ "z": 0.0
+ },
+ {
+ "x": -0.03270207685228226,
+ "y": -16.974593110936326,
+ "z": 0.0
+ },
+ {
+ "x": -0.03308808792697291,
+ "y": -17.97667783562052,
+ "z": 0.0
+ },
+ {
+ "x": -0.03347409900166356,
+ "y": -18.978762560304713,
+ "z": 0.0
+ },
+ {
+ "x": -0.033860110076354206,
+ "y": -19.980847284988908,
+ "z": 0.0
+ },
+ {
+ "x": -0.03424612115104485,
+ "y": -20.982932009673103,
+ "z": 0.0
+ },
+ {
+ "x": -0.034632132225735496,
+ "y": -21.985016734357295,
+ "z": 0.0
+ },
+ {
+ "x": -0.035018143300426144,
+ "y": -22.98710145904149,
+ "z": 0.0
+ },
+ {
+ "x": -0.035404154375116785,
+ "y": -23.989186183725685,
+ "z": 0.0
+ },
+ {
+ "x": -0.03579016544980743,
+ "y": -24.991270908409877,
+ "z": 0.0
+ },
+ {
+ "x": -0.03617617652449808,
+ "y": -25.993355633094072,
+ "z": 0.0
+ },
+ {
+ "x": -0.03656218759918872,
+ "y": -26.995440357778264,
+ "z": 0.0
+ },
+ {
+ "x": -0.03694819867387937,
+ "y": -27.997525082462456,
+ "z": 0.0
+ },
+ {
+ "x": -0.03733420974857001,
+ "y": -28.999609807146648,
+ "z": 0.0
+ },
+ {
+ "x": -0.03772022082326066,
+ "y": -30.00169453183084,
+ "z": 0.0
+ },
+ {
+ "x": -0.0381062318979513,
+ "y": -31.003779256515035,
+ "z": 0.0
+ },
+ {
+ "x": -0.03849224297264195,
+ "y": -32.00586398119923,
+ "z": 0.0
+ },
+ {
+ "x": -0.03887825404733259,
+ "y": -33.007948705883415,
+ "z": 0.0
+ },
+ {
+ "x": -0.03926426512202324,
+ "y": -34.01003343056761,
+ "z": 0.0
+ },
+ {
+ "x": -0.039650276196713886,
+ "y": -35.012118155251805,
+ "z": 0.0
+ },
+ {
+ "x": -0.04003628727140453,
+ "y": -36.01420287993599,
+ "z": 0.0
+ },
+ {
+ "x": -0.040422298346095176,
+ "y": -37.01628760462019,
+ "z": 0.0
+ },
+ {
+ "x": -0.040808309420785824,
+ "y": -38.01837232930438,
+ "z": 0.0
+ },
+ {
+ "x": -0.041194320495476465,
+ "y": -39.02045705398857,
+ "z": 0.0
+ },
+ {
+ "x": -0.04158033157016711,
+ "y": -40.02254177867277,
+ "z": 0.0
+ },
+ {
+ "x": -0.041966342644857754,
+ "y": -41.024626503356956,
+ "z": 0.0
+ },
+ {
+ "x": -0.0423523537195484,
+ "y": -42.02671122804115,
+ "z": 0.0
+ },
+ {
+ "x": -0.04273836479423905,
+ "y": -43.028795952725346,
+ "z": 0.0
+ },
+ {
+ "x": -0.04312437586892969,
+ "y": -44.03088067740954,
+ "z": 0.0
+ },
+ {
+ "x": -0.04351038694362034,
+ "y": -45.03296540209374,
+ "z": 0.0
+ },
+ {
+ "x": -0.04389639801831098,
+ "y": -46.03505012677793,
+ "z": 0.0
+ },
+ {
+ "x": -0.04428240909300163,
+ "y": -47.03713485146213,
+ "z": 0.0
+ },
+ {
+ "x": -0.04466842016769228,
+ "y": -48.03921957614632,
+ "z": 0.0
+ },
+ {
+ "x": -0.045054431242382925,
+ "y": -49.04130430083052,
+ "z": 0.0
+ },
+ {
+ "x": -0.04544044231707357,
+ "y": -50.04338902551471,
+ "z": 0.0
+ },
+ {
+ "x": -0.04582645339176422,
+ "y": -51.04547375019891,
+ "z": 0.0
+ },
+ {
+ "x": -0.04621246446645486,
+ "y": -52.047558474883104,
+ "z": 0.0
+ },
+ {
+ "x": -0.04659847554114551,
+ "y": -53.0496431995673,
+ "z": 0.0
+ },
+ {
+ "x": -0.04698448661583616,
+ "y": -54.051727924251495,
+ "z": 0.0
+ },
+ {
+ "x": -0.0473704976905268,
+ "y": -55.05381264893569,
+ "z": 0.0
+ },
+ {
+ "x": -0.04775650876521745,
+ "y": -56.05589737361989,
+ "z": 0.0
+ },
+ {
+ "x": -0.0481425198399081,
+ "y": -57.05798209830409,
+ "z": 0.0
+ },
+ {
+ "x": -0.048528530914598744,
+ "y": -58.06006682298828,
+ "z": 0.0
+ },
+ {
+ "x": -0.04891454198928939,
+ "y": -59.06215154767248,
+ "z": 0.0
+ },
+ {
+ "x": -0.04930055306398004,
+ "y": -60.06423627235667,
+ "z": 0.0
+ },
+ {
+ "x": -0.04968656413867068,
+ "y": -61.06632099704087,
+ "z": 0.0
+ },
+ {
+ "x": -0.05007257521336133,
+ "y": -62.068405721725064,
+ "z": 0.0
+ },
+ {
+ "x": -0.05045858628805198,
+ "y": -63.07049044640926,
+ "z": 0.0
+ },
+ {
+ "x": -0.050844597362742626,
+ "y": -64.07257517109346,
+ "z": 0.0
+ },
+ {
+ "x": -0.051230608437433274,
+ "y": -65.07465989577766,
+ "z": 0.0
+ },
+ {
+ "x": -0.05161661951212392,
+ "y": -66.07674462046185,
+ "z": 0.0
+ },
+ {
+ "x": -0.05200263058681456,
+ "y": -67.07882934514605,
+ "z": 0.0
+ },
+ {
+ "x": -0.05238864166150521,
+ "y": -68.08091406983024,
+ "z": 0.0
+ },
+ {
+ "x": -0.05277465273619586,
+ "y": -69.08299879451444,
+ "z": 0.0
+ },
+ {
+ "x": -0.0531606638108865,
+ "y": -70.08508351919863,
+ "z": 0.0
+ },
+ {
+ "x": -0.05354667488557715,
+ "y": -71.08716824388283,
+ "z": 0.0
+ },
+ {
+ "x": -0.0539326859602678,
+ "y": -72.08925296856702,
+ "z": 0.0
+ },
+ {
+ "x": -0.05431869703495844,
+ "y": -73.09133769325122,
+ "z": 0.0
+ },
+ {
+ "x": -0.054704708109649086,
+ "y": -74.09342241793541,
+ "z": 0.0
+ },
+ {
+ "x": -0.055090719184339734,
+ "y": -75.09550714261961,
+ "z": 0.0
+ },
+ {
+ "x": -0.05547673025903038,
+ "y": -76.0975918673038,
+ "z": 0.0
+ },
+ {
+ "x": -0.05586274133372103,
+ "y": -77.09967659198799,
+ "z": 0.0
+ },
+ {
+ "x": -0.05624875240841167,
+ "y": -78.1017613166722,
+ "z": 0.0
+ },
+ {
+ "x": -0.05663476348310232,
+ "y": -79.10384604135639,
+ "z": 0.0
+ },
+ {
+ "x": -0.05702077455779297,
+ "y": -80.10593076604059,
+ "z": 0.0
+ },
+ {
+ "x": -0.05740678563248361,
+ "y": -81.10801549072477,
+ "z": 0.0
+ },
+ {
+ "x": -0.05779279670717426,
+ "y": -82.11010021540898,
+ "z": 0.0
+ },
+ {
+ "x": -0.05817880778186491,
+ "y": -83.11218494009317,
+ "z": 0.0
+ },
+ {
+ "x": -0.05856481885655555,
+ "y": -84.11426966477737,
+ "z": 0.0
+ },
+ {
+ "x": -0.058950829931246194,
+ "y": -85.11635438946155,
+ "z": 0.0
+ },
+ {
+ "x": -0.05933684100593684,
+ "y": -86.11843911414576,
+ "z": 0.0
+ },
+ {
+ "x": -0.05972285208062749,
+ "y": -87.12052383882995,
+ "z": 0.0
+ },
+ {
+ "x": -0.059852391554727755,
+ "y": -88.1226085926462,
+ "z": 0.0
+ },
+ {
+ "x": -0.05932900726175566,
+ "y": -89.12469325499706,
+ "z": 0.0
+ },
+ {
+ "x": -0.058805622968783555,
+ "y": -90.12677791734792,
+ "z": 0.0
+ },
+ {
+ "x": -0.058282238675811456,
+ "y": -91.12886257969879,
+ "z": 0.0
+ },
+ {
+ "x": -0.05775885438283937,
+ "y": -92.13094724204963,
+ "z": 0.0
+ },
+ {
+ "x": -0.05723547008986727,
+ "y": -93.13303190440048,
+ "z": 0.0
+ },
+ {
+ "x": -0.05671208579689516,
+ "y": -94.13511656675135,
+ "z": 0.0
+ },
+ {
+ "x": -0.05618870150392306,
+ "y": -95.13720122910222,
+ "z": 0.0
+ },
+ {
+ "x": -0.055665317210950964,
+ "y": -96.13928589145307,
+ "z": 0.0
+ },
+ {
+ "x": -0.05514193291797887,
+ "y": -97.14137055380391,
+ "z": 0.0
+ },
+ {
+ "x": -0.054618548625006764,
+ "y": -98.14345521615478,
+ "z": 0.0
+ },
+ {
+ "x": -0.05409516433203466,
+ "y": -99.14553987850564,
+ "z": 0.0
+ },
+ {
+ "x": -0.053571780039062565,
+ "y": -100.1476245408565,
+ "z": 0.0
+ },
+ {
+ "x": -0.05304839574609047,
+ "y": -101.14970920320735,
+ "z": 0.0
+ },
+ {
+ "x": -0.05252501145311837,
+ "y": -102.15179386555822,
+ "z": 0.0
+ },
+ {
+ "x": -0.05200162716014627,
+ "y": -103.15387852790907,
+ "z": 0.0
+ },
+ {
+ "x": -0.05147824286717417,
+ "y": -104.15596319025992,
+ "z": 0.0
+ },
+ {
+ "x": -0.05095485857420208,
+ "y": -105.15804785261078,
+ "z": 0.0
+ },
+ {
+ "x": -0.050431474281229974,
+ "y": -106.16013251496165,
+ "z": 0.0
+ },
+ {
+ "x": -0.04990808998825787,
+ "y": -107.16221717731251,
+ "z": 0.0
+ },
+ {
+ "x": -0.04938470569528578,
+ "y": -108.16430183966337,
+ "z": 0.0
+ },
+ {
+ "x": -0.04886132140231368,
+ "y": -109.1663865020142,
+ "z": 0.0
+ },
+ {
+ "x": -0.04833793710934158,
+ "y": -110.16847116436507,
+ "z": 0.0
+ },
+ {
+ "x": -0.04781455281636948,
+ "y": -111.17055582671594,
+ "z": 0.0
+ },
+ {
+ "x": -0.04729116852339738,
+ "y": -112.1726404890668,
+ "z": 0.0
+ },
+ {
+ "x": -0.04676778423042528,
+ "y": -113.17472515141765,
+ "z": 0.0
+ },
+ {
+ "x": -0.04624439993745318,
+ "y": -114.17680981376851,
+ "z": 0.0
+ },
+ {
+ "x": -0.04572101564448108,
+ "y": -115.17889447611937,
+ "z": 0.0
+ },
+ {
+ "x": -0.045197631351508984,
+ "y": -116.18097913847022,
+ "z": 0.0
+ },
+ {
+ "x": -0.04467424705853689,
+ "y": -117.18306380082107,
+ "z": 0.0
+ },
+ {
+ "x": -0.044150862765564784,
+ "y": -118.18514846317194,
+ "z": 0.0
+ },
+ {
+ "x": -0.043627478472592685,
+ "y": -119.18723312552281,
+ "z": 0.0
+ },
+ {
+ "x": -0.043104094179620585,
+ "y": -120.18931778787366,
+ "z": 0.0
+ },
+ {
+ "x": -0.0425807098866485,
+ "y": -121.1914024502245,
+ "z": 0.0
+ },
+ {
+ "x": -0.0420573255936764,
+ "y": -122.19348711257537,
+ "z": 0.0
+ },
+ {
+ "x": -0.041533941300704286,
+ "y": -123.19557177492624,
+ "z": 0.0
+ },
+ {
+ "x": -0.04101055700773219,
+ "y": -124.19765643727709,
+ "z": 0.0
+ },
+ {
+ "x": -0.0404871727147601,
+ "y": -125.19974109962794,
+ "z": 0.0
+ },
+ {
+ "x": -0.039963788421787994,
+ "y": -126.20182576197881,
+ "z": 0.0
+ },
+ {
+ "x": -0.039440404128815894,
+ "y": -127.20391042432966,
+ "z": 0.0
+ },
+ {
+ "x": -0.0389170198358438,
+ "y": -128.20599508668053,
+ "z": 0.0
+ },
+ {
+ "x": -0.0383936355428717,
+ "y": -129.20807974903138,
+ "z": 0.0
+ },
+ {
+ "x": -0.0378702512498996,
+ "y": -130.21016441138224,
+ "z": 0.0
+ },
+ {
+ "x": -0.0373468669569275,
+ "y": -131.2122490737331,
+ "z": 0.0
+ },
+ {
+ "x": -0.0368234826639554,
+ "y": -132.21433373608394,
+ "z": 0.0
+ },
+ {
+ "x": -0.03630009837098331,
+ "y": -133.2164183984348,
+ "z": 0.0
+ },
+ {
+ "x": -0.0357767140780112,
+ "y": -134.21850306078568,
+ "z": 0.0
+ },
+ {
+ "x": -0.0352533297850391,
+ "y": -135.22058772313653,
+ "z": 0.0
+ },
+ {
+ "x": -0.034729945492067,
+ "y": -136.22267238548739,
+ "z": 0.0
+ },
+ {
+ "x": -0.03420656119909491,
+ "y": -137.22475704783824,
+ "z": 0.0
+ },
+ {
+ "x": -0.03368317690612281,
+ "y": -138.2268417101891,
+ "z": 0.0
+ },
+ {
+ "x": -0.03315979261315071,
+ "y": -139.22892637253995,
+ "z": 0.0
+ },
+ {
+ "x": -0.032636408320178625,
+ "y": -140.2310110348908,
+ "z": 0.0
+ },
+ {
+ "x": -0.03211302402720654,
+ "y": -141.23309569724162,
+ "z": 0.0
+ },
+ {
+ "x": -0.03158963973423444,
+ "y": -142.23518035959248,
+ "z": 0.0
+ },
+ {
+ "x": -0.03106625544126235,
+ "y": -143.23726502194333,
+ "z": 0.0
+ },
+ {
+ "x": -0.03054287114829027,
+ "y": -144.23934968429415,
+ "z": 0.0
+ },
+ {
+ "x": -0.03001948685531817,
+ "y": -145.24143434664498,
+ "z": 0.0
+ },
+ {
+ "x": -0.029496102562346072,
+ "y": -146.24351900899583,
+ "z": 0.0
+ },
+ {
+ "x": -0.028972718269373976,
+ "y": -147.2456036713467,
+ "z": 0.0
+ },
+ {
+ "x": -0.028449333976401887,
+ "y": -148.24768833369754,
+ "z": 0.0
+ },
+ {
+ "x": -0.0279259496834298,
+ "y": -149.24977299604836,
+ "z": 0.0
+ },
+ {
+ "x": -0.027402565390457705,
+ "y": -150.25185765839922,
+ "z": 0.0
+ },
+ {
+ "x": -0.026879181097485615,
+ "y": -151.25394232075007,
+ "z": 0.0
+ },
+ {
+ "x": -0.026355796804513533,
+ "y": -152.2560269831009,
+ "z": 0.0
+ },
+ {
+ "x": -0.025832412511541437,
+ "y": -153.25811164545175,
+ "z": 0.0
+ },
+ {
+ "x": -0.02530902821856935,
+ "y": -154.2601963078026,
+ "z": 0.0
+ },
+ {
+ "x": -0.024785643925597255,
+ "y": -155.26228097015345,
+ "z": 0.0
+ },
+ {
+ "x": -0.024262259632625155,
+ "y": -156.2643656325043,
+ "z": 0.0
+ },
+ {
+ "x": -0.02373887533965308,
+ "y": -157.2664502948551,
+ "z": 0.0
+ },
+ {
+ "x": -0.023215491046680976,
+ "y": -158.26853495720596,
+ "z": 0.0
+ },
+ {
+ "x": -0.022692106753708877,
+ "y": -159.2706196195568,
+ "z": 0.0
+ },
+ {
+ "x": -0.022168722460736805,
+ "y": -160.27270428190764,
+ "z": 0.0
+ },
+ {
+ "x": -0.02164533816776471,
+ "y": -161.2747889442585,
+ "z": 0.0
+ },
+ {
+ "x": -0.02112195387479261,
+ "y": -162.27687360660934,
+ "z": 0.0
+ },
+ {
+ "x": -0.02059856958182052,
+ "y": -163.2789582689602,
+ "z": 0.0
+ },
+ {
+ "x": -0.020075185288848416,
+ "y": -164.28104293131105,
+ "z": 0.0
+ },
+ {
+ "x": -0.019551800995876334,
+ "y": -165.28312759366187,
+ "z": 0.0
+ },
+ {
+ "x": -0.019028416702904248,
+ "y": -166.28521225601273,
+ "z": 0.0
+ },
+ {
+ "x": -0.018505032409932155,
+ "y": -167.28729691836358,
+ "z": 0.0
+ },
+ {
+ "x": -0.01798164811696007,
+ "y": -168.2893815807144,
+ "z": 0.0
+ },
+ {
+ "x": -0.01745826382398798,
+ "y": -169.29146624306526,
+ "z": 0.0
+ },
+ {
+ "x": -0.016934879531015877,
+ "y": -170.29355090541608,
+ "z": 0.0
+ },
+ {
+ "x": -0.01641149523804378,
+ "y": -171.29563556776694,
+ "z": 0.0
+ },
+ {
+ "x": -0.01588811094507169,
+ "y": -172.2977202301178,
+ "z": 0.0
+ },
+ {
+ "x": -0.015364726652099606,
+ "y": -173.29980489246861,
+ "z": 0.0
+ },
+ {
+ "x": -0.014841342359127515,
+ "y": -174.30188955481947,
+ "z": 0.0
+ },
+ {
+ "x": -0.014317958066155425,
+ "y": -175.30397421717032,
+ "z": 0.0
+ },
+ {
+ "x": -0.013794573773183338,
+ "y": -176.30605887952115,
+ "z": 0.0
+ },
+ {
+ "x": -0.01327118948021124,
+ "y": -177.308143541872,
+ "z": 0.0
+ },
+ {
+ "x": -0.01274780518723915,
+ "y": -178.31022820422285,
+ "z": 0.0
+ },
+ {
+ "x": -0.012224420894267046,
+ "y": -179.3123128665737,
+ "z": 0.0
+ },
+ {
+ "x": -0.011701036601294953,
+ "y": -180.31439752892456,
+ "z": 0.0
+ },
+ {
+ "x": -0.011177652308322879,
+ "y": -181.31648219127538,
+ "z": 0.0
+ },
+ {
+ "x": -0.010654268015350778,
+ "y": -182.3185668536262,
+ "z": 0.0
+ },
+ {
+ "x": -0.010130883722378678,
+ "y": -183.32065151597706,
+ "z": 0.0
+ },
+ {
+ "x": -0.009607499429406606,
+ "y": -184.3227361783279,
+ "z": 0.0
+ },
+ {
+ "x": -0.009084115136434505,
+ "y": -185.32482084067874,
+ "z": 0.0
+ },
+ {
+ "x": -0.008560730843462412,
+ "y": -186.3269055030296,
+ "z": 0.0
+ },
+ {
+ "x": -0.008037346550490324,
+ "y": -187.32899016538045,
+ "z": 0.0
+ },
+ {
+ "x": -0.007513962257518224,
+ "y": -188.3310748277313,
+ "z": 0.0
+ },
+ {
+ "x": -0.006990577964546139,
+ "y": -189.33315949008212,
+ "z": 0.0
+ },
+ {
+ "x": -0.00646719367157405,
+ "y": -190.33524415243298,
+ "z": 0.0
+ },
+ {
+ "x": -0.005943809378601944,
+ "y": -191.33732881478383,
+ "z": 0.0
+ },
+ {
+ "x": -0.005420425085629872,
+ "y": -192.33941347713466,
+ "z": 0.0
+ },
+ {
+ "x": -0.004897040792657784,
+ "y": -193.3414981394855,
+ "z": 0.0
+ },
+ {
+ "x": -0.00437365649968567,
+ "y": -194.34358280183636,
+ "z": 0.0
+ },
+ {
+ "x": -0.003850272206713584,
+ "y": -195.3456674641872,
+ "z": 0.0
+ },
+ {
+ "x": -0.003326887913741497,
+ "y": -196.34775212653804,
+ "z": 0.0
+ },
+ {
+ "x": -0.0028035036207694035,
+ "y": -197.34983678888887,
+ "z": 0.0
+ },
+ {
+ "x": -0.0022801193277973172,
+ "y": -198.35192145123972,
+ "z": 0.0
+ },
+ {
+ "x": -0.001756735034825231,
+ "y": -199.35400611359057,
+ "z": 0.0
+ },
+ {
+ "x": -0.0012333507418531237,
+ "y": -200.3560907759414,
+ "z": 0.0
+ },
+ {
+ "x": -0.0007099664488810368,
+ "y": -201.35817543829225,
+ "z": 0.0
+ },
+ {
+ "x": -0.0001865821559089505,
+ "y": -202.3602601006431,
+ "z": 0.0
+ },
+ {
+ "x": 0.00033680213706315724,
+ "y": -203.36234476299396,
+ "z": 0.0
+ },
+ {
+ "x": 0.0008601864300352446,
+ "y": -204.3644294253448,
+ "z": 0.0
+ },
+ {
+ "x": 0.00138357072300733,
+ "y": -205.36651408769563,
+ "z": 0.0
+ },
+ {
+ "x": 0.0019069550159794308,
+ "y": -206.3685987500465,
+ "z": 0.0
+ },
+ {
+ "x": 0.002430339308951518,
+ "y": -207.3706834123973,
+ "z": 0.0
+ },
+ {
+ "x": 0.002953723601923583,
+ "y": -208.37276807474814,
+ "z": 0.0
+ },
+ {
+ "x": 0.003477107894895689,
+ "y": -209.374852737099,
+ "z": 0.0
+ },
+ {
+ "x": 0.004000492187867783,
+ "y": -210.37693739944984,
+ "z": 0.0
+ },
+ {
+ "x": 0.00452387648083989,
+ "y": -211.3790220618007,
+ "z": 0.0
+ },
+ {
+ "x": 0.0050472607738119854,
+ "y": -212.38110672415155,
+ "z": 0.0
+ },
+ {
+ "x": 0.005570645066784064,
+ "y": -213.38319138650238,
+ "z": 0.0
+ },
+ {
+ "x": 0.006094029359756146,
+ "y": -214.38527604885323,
+ "z": 0.0
+ },
+ {
+ "x": 0.00661741365272825,
+ "y": -215.38736071120408,
+ "z": 0.0
+ },
+ {
+ "x": 0.0071407979457003305,
+ "y": -216.3894453735549,
+ "z": 0.0
+ },
+ {
+ "x": 0.007664182238672424,
+ "y": -217.39153003590576,
+ "z": 0.0
+ },
+ {
+ "x": 0.008187566531644517,
+ "y": -218.3936146982566,
+ "z": 0.0
+ },
+ {
+ "x": 0.008710950824616611,
+ "y": -219.39569936060747,
+ "z": 0.0
+ },
+ {
+ "x": 0.009234335117588716,
+ "y": -220.3977840229583,
+ "z": 0.0
+ },
+ {
+ "x": 0.009757719410560787,
+ "y": -221.39986868530912,
+ "z": 0.0
+ },
+ {
+ "x": 0.010281103703532888,
+ "y": -222.40195334765997,
+ "z": 0.0
+ },
+ {
+ "x": 0.010804487996504976,
+ "y": -223.40403801001082,
+ "z": 0.0
+ },
+ {
+ "x": 0.011327872289477061,
+ "y": -224.40612267236165,
+ "z": 0.0
+ },
+ {
+ "x": 0.01185125658244916,
+ "y": -225.4082073347125,
+ "z": 0.0
+ },
+ {
+ "x": 0.012374640875421252,
+ "y": -226.41029199706335,
+ "z": 0.0
+ },
+ {
+ "x": 0.012898025168393347,
+ "y": -227.4123766594142,
+ "z": 0.0
+ },
+ {
+ "x": 0.01342140946136544,
+ "y": -228.41446132176506,
+ "z": 0.0
+ },
+ {
+ "x": 0.013944793754337529,
+ "y": -229.41654598411588,
+ "z": 0.0
+ },
+ {
+ "x": 0.014468178047309627,
+ "y": -230.41863064646674,
+ "z": 0.0
+ },
+ {
+ "x": 0.01499156234028172,
+ "y": -231.4207153088176,
+ "z": 0.0
+ },
+ {
+ "x": 0.015514946633253798,
+ "y": -232.4227999711684,
+ "z": 0.0
+ },
+ {
+ "x": 0.01603833092622589,
+ "y": -233.42488463351924,
+ "z": 0.0
+ },
+ {
+ "x": 0.016561715219197987,
+ "y": -234.4269692958701,
+ "z": 0.0
+ },
+ {
+ "x": 0.01708509951217009,
+ "y": -235.42905395822095,
+ "z": 0.0
+ },
+ {
+ "x": 0.01760848380514218,
+ "y": -236.4311386205718,
+ "z": 0.0
+ },
+ {
+ "x": 0.018131868098114262,
+ "y": -237.43322328292263,
+ "z": 0.0
+ },
+ {
+ "x": 0.01865525239108635,
+ "y": -238.43530794527348,
+ "z": 0.0
+ },
+ {
+ "x": 0.019178636684058448,
+ "y": -239.43739260762433,
+ "z": 0.0
+ },
+ {
+ "x": 0.019702020977030534,
+ "y": -240.43947726997516,
+ "z": 0.0
+ },
+ {
+ "x": 0.01994365180220445,
+ "y": -241.44156200490332,
+ "z": 0.0
+ },
+ {
+ "x": 0.019812814275586975,
+ "y": -242.44364679539336,
+ "z": 0.0
+ },
+ {
+ "x": 0.0196819767489695,
+ "y": -243.4457315858834,
+ "z": 0.0
+ },
+ {
+ "x": 0.01955113922235203,
+ "y": -244.44781637637345,
+ "z": 0.0
+ },
+ {
+ "x": 0.01942030169573456,
+ "y": -245.44990116686347,
+ "z": 0.0
+ },
+ {
+ "x": 0.019289464169117088,
+ "y": -246.45198595735351,
+ "z": 0.0
+ },
+ {
+ "x": 0.019158626642499614,
+ "y": -247.4540707478436,
+ "z": 0.0
+ },
+ {
+ "x": 0.019027789115882147,
+ "y": -248.4561555383336,
+ "z": 0.0
+ },
+ {
+ "x": 0.018896951589264674,
+ "y": -249.45824032882365,
+ "z": 0.0
+ },
+ {
+ "x": 0.0187661140626472,
+ "y": -250.4603251193137,
+ "z": 0.0
+ },
+ {
+ "x": 0.018635276536029727,
+ "y": -251.46240990980374,
+ "z": 0.0
+ },
+ {
+ "x": 0.018504439009412253,
+ "y": -252.46449470029378,
+ "z": 0.0
+ },
+ {
+ "x": 0.01837360148279479,
+ "y": -253.4665794907838,
+ "z": 0.0
+ },
+ {
+ "x": 0.018242763956177317,
+ "y": -254.46866428127385,
+ "z": 0.0
+ },
+ {
+ "x": 0.018111926429559843,
+ "y": -255.4707490717639,
+ "z": 0.0
+ },
+ {
+ "x": 0.017981088902942376,
+ "y": -256.4728338622539,
+ "z": 0.0
+ },
+ {
+ "x": 0.0178502513763249,
+ "y": -257.47491865274395,
+ "z": 0.0
+ },
+ {
+ "x": 0.017719413849707426,
+ "y": -258.477003443234,
+ "z": 0.0
+ },
+ {
+ "x": 0.017588576323089952,
+ "y": -259.47908823372404,
+ "z": 0.0
+ },
+ {
+ "x": 0.017457738796472482,
+ "y": -260.4811730242141,
+ "z": 0.0
+ },
+ {
+ "x": 0.017326901269855012,
+ "y": -261.48325781470413,
+ "z": 0.0
+ },
+ {
+ "x": 0.01719606374323754,
+ "y": -262.48534260519415,
+ "z": 0.0
+ },
+ {
+ "x": 0.017065226216620065,
+ "y": -263.4874273956842,
+ "z": 0.0
+ },
+ {
+ "x": 0.016934388690002602,
+ "y": -264.48951218617424,
+ "z": 0.0
+ },
+ {
+ "x": 0.016803551163385128,
+ "y": -265.49159697666425,
+ "z": 0.0
+ },
+ {
+ "x": 0.01667271363676765,
+ "y": -266.4936817671543,
+ "z": 0.0
+ },
+ {
+ "x": 0.016541876110150174,
+ "y": -267.4957665576444,
+ "z": 0.0
+ },
+ {
+ "x": 0.016411038583532694,
+ "y": -268.4978513481345,
+ "z": 0.0
+ },
+ {
+ "x": 0.01628020105691522,
+ "y": -269.49993613862455,
+ "z": 0.0
+ },
+ {
+ "x": 0.016149363530297743,
+ "y": -270.5020209291146,
+ "z": 0.0
+ },
+ {
+ "x": 0.016018526003680273,
+ "y": -271.50410571960464,
+ "z": 0.0
+ },
+ {
+ "x": 0.015887688477062796,
+ "y": -272.5061905100947,
+ "z": 0.0
+ },
+ {
+ "x": 0.015756850950445322,
+ "y": -273.5082753005848,
+ "z": 0.0
+ },
+ {
+ "x": 0.01562601342382785,
+ "y": -274.51036009107486,
+ "z": 0.0
+ },
+ {
+ "x": 0.01549517589721037,
+ "y": -275.51244488156493,
+ "z": 0.0
+ },
+ {
+ "x": 0.015364338370592895,
+ "y": -276.514529672055,
+ "z": 0.0
+ },
+ {
+ "x": 0.015233500843975418,
+ "y": -277.5166144625451,
+ "z": 0.0
+ },
+ {
+ "x": 0.015102663317357948,
+ "y": -278.5186992530351,
+ "z": 0.0
+ },
+ {
+ "x": 0.01497182579074047,
+ "y": -279.52078404352517,
+ "z": 0.0
+ },
+ {
+ "x": 0.014840988264122999,
+ "y": -280.52286883401524,
+ "z": 0.0
+ },
+ {
+ "x": 0.014710150737505518,
+ "y": -281.5249536245053,
+ "z": 0.0
+ },
+ {
+ "x": 0.014579313210888043,
+ "y": -282.5270384149954,
+ "z": 0.0
+ },
+ {
+ "x": 0.01444847568427057,
+ "y": -283.52912320548546,
+ "z": 0.0
+ },
+ {
+ "x": 0.01431763815765309,
+ "y": -284.53120799597554,
+ "z": 0.0
+ },
+ {
+ "x": 0.014186800631035616,
+ "y": -285.5332927864656,
+ "z": 0.0
+ },
+ {
+ "x": 0.014055963104418139,
+ "y": -286.5353775769557,
+ "z": 0.0
+ },
+ {
+ "x": 0.013925125577800668,
+ "y": -287.53746236744576,
+ "z": 0.0
+ },
+ {
+ "x": 0.013794288051183191,
+ "y": -288.53954715793583,
+ "z": 0.0
+ },
+ {
+ "x": 0.013663450524565718,
+ "y": -289.5416319484259,
+ "z": 0.0
+ },
+ {
+ "x": 0.01353261299794824,
+ "y": -290.543716738916,
+ "z": 0.0
+ },
+ {
+ "x": 0.013401775471330764,
+ "y": -291.54580152940605,
+ "z": 0.0
+ },
+ {
+ "x": 0.01327093794471329,
+ "y": -292.5478863198961,
+ "z": 0.0
+ },
+ {
+ "x": 0.013140100418095813,
+ "y": -293.5499711103862,
+ "z": 0.0
+ },
+ {
+ "x": 0.013009262891478343,
+ "y": -294.5520559008762,
+ "z": 0.0
+ },
+ {
+ "x": 0.012878425364860866,
+ "y": -295.5541406913663,
+ "z": 0.0
+ },
+ {
+ "x": 0.012747587838243389,
+ "y": -296.55622548185636,
+ "z": 0.0
+ },
+ {
+ "x": 0.01261675031162591,
+ "y": -297.55831027234643,
+ "z": 0.0
+ },
+ {
+ "x": 0.012485912785008433,
+ "y": -298.5603950628365,
+ "z": 0.0
+ },
+ {
+ "x": 0.01235507525839096,
+ "y": -299.5624798533266,
+ "z": 0.0
+ },
+ {
+ "x": 0.012224237731773488,
+ "y": -300.56456464381665,
+ "z": 0.0
+ },
+ {
+ "x": 0.012093400205156011,
+ "y": -301.5666494343067,
+ "z": 0.0
+ },
+ {
+ "x": 0.011962562678538534,
+ "y": -302.5687342247968,
+ "z": 0.0
+ },
+ {
+ "x": 0.011831725151921064,
+ "y": -303.5708190152868,
+ "z": 0.0
+ },
+ {
+ "x": 0.011700887625303587,
+ "y": -304.5729038057769,
+ "z": 0.0
+ },
+ {
+ "x": 0.01157005009868611,
+ "y": -305.57498859626696,
+ "z": 0.0
+ },
+ {
+ "x": 0.011439212572068633,
+ "y": -306.57707338675704,
+ "z": 0.0
+ },
+ {
+ "x": 0.011308375045451156,
+ "y": -307.5791581772471,
+ "z": 0.0
+ },
+ {
+ "x": 0.011177537518833684,
+ "y": -308.5812429677372,
+ "z": 0.0
+ },
+ {
+ "x": 0.011046699992216202,
+ "y": -309.58332775822726,
+ "z": 0.0
+ },
+ {
+ "x": 0.010915862465598737,
+ "y": -310.5854125487173,
+ "z": 0.0
+ },
+ {
+ "x": 0.010785024938981261,
+ "y": -311.58749733920735,
+ "z": 0.0
+ },
+ {
+ "x": 0.010654187412363784,
+ "y": -312.5895821296974,
+ "z": 0.0
+ },
+ {
+ "x": 0.010523349885746306,
+ "y": -313.5916669201875,
+ "z": 0.0
+ },
+ {
+ "x": 0.010392512359128829,
+ "y": -314.59375171067757,
+ "z": 0.0
+ },
+ {
+ "x": 0.010261674832511353,
+ "y": -315.59583650116764,
+ "z": 0.0
+ },
+ {
+ "x": 0.010130837305893875,
+ "y": -316.5979212916577,
+ "z": 0.0
+ },
+ {
+ "x": 0.0099999997792764,
+ "y": -317.6000060821478,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 78,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 2.009999982731973,
+ "y": -317.6002672127961,
+ "z": 0.0
+ },
+ {
+ "x": 2.01013082025859,
+ "y": -316.598182422306,
+ "z": 0.0
+ },
+ {
+ "x": 2.0102616577852075,
+ "y": -315.59609763181595,
+ "z": 0.0
+ },
+ {
+ "x": 2.010392495311825,
+ "y": -314.5940128413259,
+ "z": 0.0
+ },
+ {
+ "x": 2.0105233328384426,
+ "y": -313.5919280508358,
+ "z": 0.0
+ },
+ {
+ "x": 2.01065417036506,
+ "y": -312.58984326034573,
+ "z": 0.0
+ },
+ {
+ "x": 2.0107850078916774,
+ "y": -311.58775846985566,
+ "z": 0.0
+ },
+ {
+ "x": 2.010915845418295,
+ "y": -310.5856736793656,
+ "z": 0.0
+ },
+ {
+ "x": 2.0110466829449125,
+ "y": -309.58358888887557,
+ "z": 0.0
+ },
+ {
+ "x": 2.01117752047153,
+ "y": -308.5815040983855,
+ "z": 0.0
+ },
+ {
+ "x": 2.0113083579981472,
+ "y": -307.5794193078954,
+ "z": 0.0
+ },
+ {
+ "x": 2.011439195524765,
+ "y": -306.57733451740535,
+ "z": 0.0
+ },
+ {
+ "x": 2.0115700330513824,
+ "y": -305.5752497269153,
+ "z": 0.0
+ },
+ {
+ "x": 2.0117008705779997,
+ "y": -304.5731649364252,
+ "z": 0.0
+ },
+ {
+ "x": 2.011831708104617,
+ "y": -303.5710801459351,
+ "z": 0.0
+ },
+ {
+ "x": 2.011962545631235,
+ "y": -302.5689953554451,
+ "z": 0.0
+ },
+ {
+ "x": 2.0120933831578522,
+ "y": -301.56691056495504,
+ "z": 0.0
+ },
+ {
+ "x": 2.0122242206844696,
+ "y": -300.56482577446496,
+ "z": 0.0
+ },
+ {
+ "x": 2.012355058211087,
+ "y": -299.5627409839749,
+ "z": 0.0
+ },
+ {
+ "x": 2.0124858957377048,
+ "y": -298.5606561934848,
+ "z": 0.0
+ },
+ {
+ "x": 2.012616733264322,
+ "y": -297.55857140299474,
+ "z": 0.0
+ },
+ {
+ "x": 2.0127475707909395,
+ "y": -296.55648661250467,
+ "z": 0.0
+ },
+ {
+ "x": 2.0128784083175573,
+ "y": -295.5544018220146,
+ "z": 0.0
+ },
+ {
+ "x": 2.0130092458441746,
+ "y": -294.5523170315245,
+ "z": 0.0
+ },
+ {
+ "x": 2.013140083370792,
+ "y": -293.5502322410345,
+ "z": 0.0
+ },
+ {
+ "x": 2.0132709208974093,
+ "y": -292.54814745054443,
+ "z": 0.0
+ },
+ {
+ "x": 2.013401758424027,
+ "y": -291.54606266005436,
+ "z": 0.0
+ },
+ {
+ "x": 2.0135325959506445,
+ "y": -290.5439778695643,
+ "z": 0.0
+ },
+ {
+ "x": 2.013663433477262,
+ "y": -289.5418930790742,
+ "z": 0.0
+ },
+ {
+ "x": 2.013794271003879,
+ "y": -288.53980828858414,
+ "z": 0.0
+ },
+ {
+ "x": 2.013925108530497,
+ "y": -287.53772349809407,
+ "z": 0.0
+ },
+ {
+ "x": 2.0140559460571144,
+ "y": -286.535638707604,
+ "z": 0.0
+ },
+ {
+ "x": 2.0141867835837317,
+ "y": -285.5335539171139,
+ "z": 0.0
+ },
+ {
+ "x": 2.0143176211103495,
+ "y": -284.53146912662385,
+ "z": 0.0
+ },
+ {
+ "x": 2.014448458636967,
+ "y": -283.5293843361338,
+ "z": 0.0
+ },
+ {
+ "x": 2.014579296163584,
+ "y": -282.5272995456437,
+ "z": 0.0
+ },
+ {
+ "x": 2.0147101336902016,
+ "y": -281.5252147551536,
+ "z": 0.0
+ },
+ {
+ "x": 2.0148409712168194,
+ "y": -280.52312996466355,
+ "z": 0.0
+ },
+ {
+ "x": 2.0149718087434367,
+ "y": -279.5210451741735,
+ "z": 0.0
+ },
+ {
+ "x": 2.015102646270054,
+ "y": -278.5189603836834,
+ "z": 0.0
+ },
+ {
+ "x": 2.0152334837966714,
+ "y": -277.5168755931934,
+ "z": 0.0
+ },
+ {
+ "x": 2.0153643213232892,
+ "y": -276.5147908027033,
+ "z": 0.0
+ },
+ {
+ "x": 2.0154951588499066,
+ "y": -275.51270601221324,
+ "z": 0.0
+ },
+ {
+ "x": 2.015625996376524,
+ "y": -274.51062122172317,
+ "z": 0.0
+ },
+ {
+ "x": 2.0157568339031418,
+ "y": -273.5085364312331,
+ "z": 0.0
+ },
+ {
+ "x": 2.015887671429759,
+ "y": -272.506451640743,
+ "z": 0.0
+ },
+ {
+ "x": 2.0160185089563765,
+ "y": -271.50436685025295,
+ "z": 0.0
+ },
+ {
+ "x": 2.016149346482994,
+ "y": -270.50228205976293,
+ "z": 0.0
+ },
+ {
+ "x": 2.0162801840096116,
+ "y": -269.50019726927286,
+ "z": 0.0
+ },
+ {
+ "x": 2.016411021536229,
+ "y": -268.4981124787828,
+ "z": 0.0
+ },
+ {
+ "x": 2.0165418590628463,
+ "y": -267.4960276882927,
+ "z": 0.0
+ },
+ {
+ "x": 2.0166726965894637,
+ "y": -266.49394289780264,
+ "z": 0.0
+ },
+ {
+ "x": 2.0168035341160815,
+ "y": -265.49185810731257,
+ "z": 0.0
+ },
+ {
+ "x": 2.016934371642699,
+ "y": -264.48977331682255,
+ "z": 0.0
+ },
+ {
+ "x": 2.017065209169316,
+ "y": -263.48768852633253,
+ "z": 0.0
+ },
+ {
+ "x": 2.0171960466959336,
+ "y": -262.48560373584246,
+ "z": 0.0
+ },
+ {
+ "x": 2.0173268842225514,
+ "y": -261.48351894535244,
+ "z": 0.0
+ },
+ {
+ "x": 2.0174577217491687,
+ "y": -260.4814341548624,
+ "z": 0.0
+ },
+ {
+ "x": 2.017588559275786,
+ "y": -259.47934936437235,
+ "z": 0.0
+ },
+ {
+ "x": 2.0177193968024034,
+ "y": -258.47726457388234,
+ "z": 0.0
+ },
+ {
+ "x": 2.017850234329021,
+ "y": -257.47517978339226,
+ "z": 0.0
+ },
+ {
+ "x": 2.0179810718556386,
+ "y": -256.4730949929022,
+ "z": 0.0
+ },
+ {
+ "x": 2.0181119093822555,
+ "y": -255.4710102024122,
+ "z": 0.0
+ },
+ {
+ "x": 2.0182427469088733,
+ "y": -254.46892541192216,
+ "z": 0.0
+ },
+ {
+ "x": 2.0183735844354906,
+ "y": -253.4668406214321,
+ "z": 0.0
+ },
+ {
+ "x": 2.0185044219621084,
+ "y": -252.4647558309421,
+ "z": 0.0
+ },
+ {
+ "x": 2.0186352594887254,
+ "y": -251.46267104045205,
+ "z": 0.0
+ },
+ {
+ "x": 2.018766097015343,
+ "y": -250.460586249962,
+ "z": 0.0
+ },
+ {
+ "x": 2.0188969345419605,
+ "y": -249.45850145947196,
+ "z": 0.0
+ },
+ {
+ "x": 2.019027772068578,
+ "y": -248.45641666898192,
+ "z": 0.0
+ },
+ {
+ "x": 2.0191586095951957,
+ "y": -247.4543318784919,
+ "z": 0.0
+ },
+ {
+ "x": 2.0192894471218135,
+ "y": -246.45224708800183,
+ "z": 0.0
+ },
+ {
+ "x": 2.0194202846484304,
+ "y": -245.45016229751178,
+ "z": 0.0
+ },
+ {
+ "x": 2.019551122175048,
+ "y": -244.44807750702176,
+ "z": 0.0
+ },
+ {
+ "x": 2.019681959701665,
+ "y": -243.44599271653172,
+ "z": 0.0
+ },
+ {
+ "x": 2.019812797228283,
+ "y": -242.44390792604167,
+ "z": 0.0
+ },
+ {
+ "x": 2.0199436347549002,
+ "y": -241.44182313555163,
+ "z": 0.0
+ },
+ {
+ "x": 2.019701962834255,
+ "y": -240.43899501371533,
+ "z": 0.0
+ },
+ {
+ "x": 2.0191783638915424,
+ "y": -239.4363480168003,
+ "z": 0.0
+ },
+ {
+ "x": 2.0186549795985704,
+ "y": -238.43426335444946,
+ "z": 0.0
+ },
+ {
+ "x": 2.0181315953055985,
+ "y": -237.4321786920986,
+ "z": 0.0
+ },
+ {
+ "x": 2.0176082110126257,
+ "y": -236.4300940297478,
+ "z": 0.0
+ },
+ {
+ "x": 2.0170848267196537,
+ "y": -235.42800936739695,
+ "z": 0.0
+ },
+ {
+ "x": 2.016561442426682,
+ "y": -234.4259247050461,
+ "z": 0.0
+ },
+ {
+ "x": 2.01603805813371,
+ "y": -233.42384004269525,
+ "z": 0.0
+ },
+ {
+ "x": 2.015514673840738,
+ "y": -232.4217553803444,
+ "z": 0.0
+ },
+ {
+ "x": 2.014991289547766,
+ "y": -231.4196707179936,
+ "z": 0.0
+ },
+ {
+ "x": 2.014467905254793,
+ "y": -230.41758605564274,
+ "z": 0.0
+ },
+ {
+ "x": 2.013944520961821,
+ "y": -229.4155013932919,
+ "z": 0.0
+ },
+ {
+ "x": 2.0134211366688493,
+ "y": -228.41341673094104,
+ "z": 0.0
+ },
+ {
+ "x": 2.0128977523758773,
+ "y": -227.41133206859018,
+ "z": 0.0
+ },
+ {
+ "x": 2.0123743680829054,
+ "y": -226.40924740623933,
+ "z": 0.0
+ },
+ {
+ "x": 2.0118509837899334,
+ "y": -225.40716274388848,
+ "z": 0.0
+ },
+ {
+ "x": 2.0113275994969606,
+ "y": -224.40507808153762,
+ "z": 0.0
+ },
+ {
+ "x": 2.0108042152039887,
+ "y": -223.40299341918683,
+ "z": 0.0
+ },
+ {
+ "x": 2.0102808309110167,
+ "y": -222.40090875683597,
+ "z": 0.0
+ },
+ {
+ "x": 2.009757446618045,
+ "y": -221.39882409448512,
+ "z": 0.0
+ },
+ {
+ "x": 2.009234062325073,
+ "y": -220.39673943213427,
+ "z": 0.0
+ },
+ {
+ "x": 2.008710678032101,
+ "y": -219.39465476978347,
+ "z": 0.0
+ },
+ {
+ "x": 2.008187293739128,
+ "y": -218.39257010743262,
+ "z": 0.0
+ },
+ {
+ "x": 2.007663909446156,
+ "y": -217.39048544508177,
+ "z": 0.0
+ },
+ {
+ "x": 2.007140525153184,
+ "y": -216.3884007827309,
+ "z": 0.0
+ },
+ {
+ "x": 2.0066171408602123,
+ "y": -215.38631612038006,
+ "z": 0.0
+ },
+ {
+ "x": 2.0060937565672403,
+ "y": -214.3842314580292,
+ "z": 0.0
+ },
+ {
+ "x": 2.0055703722742684,
+ "y": -213.38214679567835,
+ "z": 0.0
+ },
+ {
+ "x": 2.0050469879812955,
+ "y": -212.38006213332756,
+ "z": 0.0
+ },
+ {
+ "x": 2.0045236036883236,
+ "y": -211.3779774709767,
+ "z": 0.0
+ },
+ {
+ "x": 2.0040002193953517,
+ "y": -210.37589280862585,
+ "z": 0.0
+ },
+ {
+ "x": 2.0034768351023797,
+ "y": -209.373808146275,
+ "z": 0.0
+ },
+ {
+ "x": 2.002953450809408,
+ "y": -208.37172348392414,
+ "z": 0.0
+ },
+ {
+ "x": 2.002430066516435,
+ "y": -207.3696388215733,
+ "z": 0.0
+ },
+ {
+ "x": 2.001906682223463,
+ "y": -206.3675541592225,
+ "z": 0.0
+ },
+ {
+ "x": 2.001383297930491,
+ "y": -205.36546949687164,
+ "z": 0.0
+ },
+ {
+ "x": 2.000859913637519,
+ "y": -204.3633848345208,
+ "z": 0.0
+ },
+ {
+ "x": 2.000336529344547,
+ "y": -203.36130017216993,
+ "z": 0.0
+ },
+ {
+ "x": 1.9998131450515748,
+ "y": -202.35921550981908,
+ "z": 0.0
+ },
+ {
+ "x": 1.9992897607586029,
+ "y": -201.35713084746823,
+ "z": 0.0
+ },
+ {
+ "x": 1.998766376465631,
+ "y": -200.35504618511737,
+ "z": 0.0
+ },
+ {
+ "x": 1.9982429921726585,
+ "y": -199.35296152276658,
+ "z": 0.0
+ },
+ {
+ "x": 1.9977196078796866,
+ "y": -198.35087686041572,
+ "z": 0.0
+ },
+ {
+ "x": 1.9971962235867147,
+ "y": -197.34879219806487,
+ "z": 0.0
+ },
+ {
+ "x": 1.9966728392937423,
+ "y": -196.34670753571402,
+ "z": 0.0
+ },
+ {
+ "x": 1.9961494550007703,
+ "y": -195.34462287336316,
+ "z": 0.0
+ },
+ {
+ "x": 1.9956260707077984,
+ "y": -194.34253821101237,
+ "z": 0.0
+ },
+ {
+ "x": 1.995102686414826,
+ "y": -193.34045354866151,
+ "z": 0.0
+ },
+ {
+ "x": 1.994579302121854,
+ "y": -192.33836888631066,
+ "z": 0.0
+ },
+ {
+ "x": 1.9940559178288821,
+ "y": -191.3362842239598,
+ "z": 0.0
+ },
+ {
+ "x": 1.9935325335359098,
+ "y": -190.33419956160895,
+ "z": 0.0
+ },
+ {
+ "x": 1.9930091492429378,
+ "y": -189.3321148992581,
+ "z": 0.0
+ },
+ {
+ "x": 1.9924857649499654,
+ "y": -188.3300302369073,
+ "z": 0.0
+ },
+ {
+ "x": 1.9919623806569935,
+ "y": -187.32794557455645,
+ "z": 0.0
+ },
+ {
+ "x": 1.9914389963640216,
+ "y": -186.3258609122056,
+ "z": 0.0
+ },
+ {
+ "x": 1.9909156120710492,
+ "y": -185.32377624985475,
+ "z": 0.0
+ },
+ {
+ "x": 1.9903922277780772,
+ "y": -184.3216915875039,
+ "z": 0.0
+ },
+ {
+ "x": 1.9898688434851053,
+ "y": -183.31960692515304,
+ "z": 0.0
+ },
+ {
+ "x": 1.989345459192133,
+ "y": -182.31752226280219,
+ "z": 0.0
+ },
+ {
+ "x": 1.988822074899161,
+ "y": -181.3154376004514,
+ "z": 0.0
+ },
+ {
+ "x": 1.988298690606189,
+ "y": -180.31335293810054,
+ "z": 0.0
+ },
+ {
+ "x": 1.9877753063132166,
+ "y": -179.31126827574968,
+ "z": 0.0
+ },
+ {
+ "x": 1.9872519220202447,
+ "y": -178.30918361339883,
+ "z": 0.0
+ },
+ {
+ "x": 1.9867285377272728,
+ "y": -177.30709895104798,
+ "z": 0.0
+ },
+ {
+ "x": 1.9862051534343004,
+ "y": -176.30501428869712,
+ "z": 0.0
+ },
+ {
+ "x": 1.9856817691413284,
+ "y": -175.30292962634633,
+ "z": 0.0
+ },
+ {
+ "x": 1.9851583848483565,
+ "y": -174.30084496399547,
+ "z": 0.0
+ },
+ {
+ "x": 1.984635000555384,
+ "y": -173.29876030164462,
+ "z": 0.0
+ },
+ {
+ "x": 1.9841116162624122,
+ "y": -172.29667563929377,
+ "z": 0.0
+ },
+ {
+ "x": 1.9835882319694402,
+ "y": -171.2945909769429,
+ "z": 0.0
+ },
+ {
+ "x": 1.9830648476764678,
+ "y": -170.29250631459206,
+ "z": 0.0
+ },
+ {
+ "x": 1.982541463383496,
+ "y": -169.29042165224126,
+ "z": 0.0
+ },
+ {
+ "x": 1.982018079090524,
+ "y": -168.2883369898904,
+ "z": 0.0
+ },
+ {
+ "x": 1.9814946947975516,
+ "y": -167.28625232753956,
+ "z": 0.0
+ },
+ {
+ "x": 1.9809713105045796,
+ "y": -166.2841676651887,
+ "z": 0.0
+ },
+ {
+ "x": 1.9804479262116077,
+ "y": -165.28208300283785,
+ "z": 0.0
+ },
+ {
+ "x": 1.9799245419186353,
+ "y": -164.27999834048705,
+ "z": 0.0
+ },
+ {
+ "x": 1.9794011576256634,
+ "y": -163.2779136781362,
+ "z": 0.0
+ },
+ {
+ "x": 1.9788777733326914,
+ "y": -162.27582901578535,
+ "z": 0.0
+ },
+ {
+ "x": 1.978354389039719,
+ "y": -161.2737443534345,
+ "z": 0.0
+ },
+ {
+ "x": 1.9778310047467471,
+ "y": -160.27165969108364,
+ "z": 0.0
+ },
+ {
+ "x": 1.9773076204537752,
+ "y": -159.2695750287328,
+ "z": 0.0
+ },
+ {
+ "x": 1.9767842361608028,
+ "y": -158.26749036638194,
+ "z": 0.0
+ },
+ {
+ "x": 1.9762608518678308,
+ "y": -157.26540570403108,
+ "z": 0.0
+ },
+ {
+ "x": 1.975737467574859,
+ "y": -156.26332104168029,
+ "z": 0.0
+ },
+ {
+ "x": 1.9752140832818865,
+ "y": -155.26123637932943,
+ "z": 0.0
+ },
+ {
+ "x": 1.9746906989889146,
+ "y": -154.25915171697858,
+ "z": 0.0
+ },
+ {
+ "x": 1.9741673146959426,
+ "y": -153.25706705462773,
+ "z": 0.0
+ },
+ {
+ "x": 1.9736439304029703,
+ "y": -152.25498239227687,
+ "z": 0.0
+ },
+ {
+ "x": 1.9731205461099983,
+ "y": -151.25289772992608,
+ "z": 0.0
+ },
+ {
+ "x": 1.9725971618170264,
+ "y": -150.25081306757522,
+ "z": 0.0
+ },
+ {
+ "x": 1.972073777524054,
+ "y": -149.24872840522437,
+ "z": 0.0
+ },
+ {
+ "x": 1.971550393231082,
+ "y": -148.24664374287352,
+ "z": 0.0
+ },
+ {
+ "x": 1.9710270089381097,
+ "y": -147.24455908052266,
+ "z": 0.0
+ },
+ {
+ "x": 1.9705036246451377,
+ "y": -146.2424744181718,
+ "z": 0.0
+ },
+ {
+ "x": 1.9699802403521658,
+ "y": -145.24038975582096,
+ "z": 0.0
+ },
+ {
+ "x": 1.9694568560591934,
+ "y": -144.23830509347016,
+ "z": 0.0
+ },
+ {
+ "x": 1.9689334717662215,
+ "y": -143.2362204311193,
+ "z": 0.0
+ },
+ {
+ "x": 1.9684100874732495,
+ "y": -142.23413576876845,
+ "z": 0.0
+ },
+ {
+ "x": 1.9678867031802771,
+ "y": -141.2320511064176,
+ "z": 0.0
+ },
+ {
+ "x": 1.9673633188873052,
+ "y": -140.2299664440668,
+ "z": 0.0
+ },
+ {
+ "x": 1.9668399345943333,
+ "y": -139.22788178171595,
+ "z": 0.0
+ },
+ {
+ "x": 1.9663165503013609,
+ "y": -138.2257971193651,
+ "z": 0.0
+ },
+ {
+ "x": 1.965793166008389,
+ "y": -137.22371245701424,
+ "z": 0.0
+ },
+ {
+ "x": 1.965269781715417,
+ "y": -136.2216277946634,
+ "z": 0.0
+ },
+ {
+ "x": 1.9647463974224446,
+ "y": -135.21954313231254,
+ "z": 0.0
+ },
+ {
+ "x": 1.9642230131294727,
+ "y": -134.21745846996168,
+ "z": 0.0
+ },
+ {
+ "x": 1.9636996288365007,
+ "y": -133.21537380761077,
+ "z": 0.0
+ },
+ {
+ "x": 1.9631762445435283,
+ "y": -132.21328914525992,
+ "z": 0.0
+ },
+ {
+ "x": 1.9626528602505564,
+ "y": -131.21120448290907,
+ "z": 0.0
+ },
+ {
+ "x": 1.9621294759575845,
+ "y": -130.20911982055821,
+ "z": 0.0
+ },
+ {
+ "x": 1.961606091664612,
+ "y": -129.20703515820736,
+ "z": 0.0
+ },
+ {
+ "x": 1.9610827073716401,
+ "y": -128.2049504958565,
+ "z": 0.0
+ },
+ {
+ "x": 1.9605593230786678,
+ "y": -127.20286583350565,
+ "z": 0.0
+ },
+ {
+ "x": 1.9600359387856958,
+ "y": -126.2007811711548,
+ "z": 0.0
+ },
+ {
+ "x": 1.9595125544927239,
+ "y": -125.19869650880393,
+ "z": 0.0
+ },
+ {
+ "x": 1.9589891701997515,
+ "y": -124.19661184645308,
+ "z": 0.0
+ },
+ {
+ "x": 1.9584657859067796,
+ "y": -123.19452718410223,
+ "z": 0.0
+ },
+ {
+ "x": 1.9579424016138076,
+ "y": -122.19244252175136,
+ "z": 0.0
+ },
+ {
+ "x": 1.9574190173208352,
+ "y": -121.19035785940049,
+ "z": 0.0
+ },
+ {
+ "x": 1.9568956330278633,
+ "y": -120.18827319704965,
+ "z": 0.0
+ },
+ {
+ "x": 1.9563722487348914,
+ "y": -119.1861885346988,
+ "z": 0.0
+ },
+ {
+ "x": 1.955848864441919,
+ "y": -118.18410387234793,
+ "z": 0.0
+ },
+ {
+ "x": 1.955325480148947,
+ "y": -117.18201920999707,
+ "z": 0.0
+ },
+ {
+ "x": 1.954802095855975,
+ "y": -116.17993454764621,
+ "z": 0.0
+ },
+ {
+ "x": 1.9542787115630027,
+ "y": -115.17784988529536,
+ "z": 0.0
+ },
+ {
+ "x": 1.9537553272700308,
+ "y": -114.1757652229445,
+ "z": 0.0
+ },
+ {
+ "x": 1.9532319429770584,
+ "y": -113.17368056059364,
+ "z": 0.0
+ },
+ {
+ "x": 1.9527085586840864,
+ "y": -112.17159589824278,
+ "z": 0.0
+ },
+ {
+ "x": 1.9521851743911145,
+ "y": -111.16951123589193,
+ "z": 0.0
+ },
+ {
+ "x": 1.9516617900981421,
+ "y": -110.16742657354106,
+ "z": 0.0
+ },
+ {
+ "x": 1.9511384058051702,
+ "y": -109.1653419111902,
+ "z": 0.0
+ },
+ {
+ "x": 1.9506150215121982,
+ "y": -108.16325724883936,
+ "z": 0.0
+ },
+ {
+ "x": 1.9500916372192258,
+ "y": -107.1611725864885,
+ "z": 0.0
+ },
+ {
+ "x": 1.949568252926254,
+ "y": -106.15908792413764,
+ "z": 0.0
+ },
+ {
+ "x": 1.949044868633282,
+ "y": -105.15700326178677,
+ "z": 0.0
+ },
+ {
+ "x": 1.9485214843403096,
+ "y": -104.15491859943592,
+ "z": 0.0
+ },
+ {
+ "x": 1.9479981000473376,
+ "y": -103.15283393708506,
+ "z": 0.0
+ },
+ {
+ "x": 1.9474747157543657,
+ "y": -102.15074927473421,
+ "z": 0.0
+ },
+ {
+ "x": 1.9469513314613933,
+ "y": -101.14866461238334,
+ "z": 0.0
+ },
+ {
+ "x": 1.9464279471684214,
+ "y": -100.14657995003249,
+ "z": 0.0
+ },
+ {
+ "x": 1.945904562875449,
+ "y": -99.14449528768164,
+ "z": 0.0
+ },
+ {
+ "x": 1.945381178582477,
+ "y": -98.14241062533077,
+ "z": 0.0
+ },
+ {
+ "x": 1.9448577942895051,
+ "y": -97.1403259629799,
+ "z": 0.0
+ },
+ {
+ "x": 1.9443344099965327,
+ "y": -96.13824130062906,
+ "z": 0.0
+ },
+ {
+ "x": 1.9438110257035608,
+ "y": -95.13615663827821,
+ "z": 0.0
+ },
+ {
+ "x": 1.9432876414105889,
+ "y": -94.13407197592734,
+ "z": 0.0
+ },
+ {
+ "x": 1.9427642571176165,
+ "y": -93.13198731357647,
+ "z": 0.0
+ },
+ {
+ "x": 1.9422408728246445,
+ "y": -92.12990265122562,
+ "z": 0.0
+ },
+ {
+ "x": 1.9417174885316726,
+ "y": -91.12781798887478,
+ "z": 0.0
+ },
+ {
+ "x": 1.9411941042387002,
+ "y": -90.12573332652391,
+ "z": 0.0
+ },
+ {
+ "x": 1.9406707199457283,
+ "y": -89.12364866417305,
+ "z": 0.0
+ },
+ {
+ "x": 1.9401473356527563,
+ "y": -88.1215640018222,
+ "z": 0.0
+ },
+ {
+ "x": 1.9402771312086453,
+ "y": -87.12078237878384,
+ "z": 0.0
+ },
+ {
+ "x": 1.9406630106088594,
+ "y": -86.11920953013264,
+ "z": 0.0
+ },
+ {
+ "x": 1.94104902168355,
+ "y": -85.11712480544843,
+ "z": 0.0
+ },
+ {
+ "x": 1.9414350327582408,
+ "y": -84.11504008076425,
+ "z": 0.0
+ },
+ {
+ "x": 1.9418210438329315,
+ "y": -83.11295535608005,
+ "z": 0.0
+ },
+ {
+ "x": 1.9422070549076222,
+ "y": -82.11087063139585,
+ "z": 0.0
+ },
+ {
+ "x": 1.9425930659823125,
+ "y": -81.10878590671165,
+ "z": 0.0
+ },
+ {
+ "x": 1.9429790770570032,
+ "y": -80.10670118202746,
+ "z": 0.0
+ },
+ {
+ "x": 1.943365088131694,
+ "y": -79.10461645734327,
+ "z": 0.0
+ },
+ {
+ "x": 1.9437510992063847,
+ "y": -78.10253173265907,
+ "z": 0.0
+ },
+ {
+ "x": 1.9441371102810754,
+ "y": -77.10044700797486,
+ "z": 0.0
+ },
+ {
+ "x": 1.944523121355766,
+ "y": -76.09836228329068,
+ "z": 0.0
+ },
+ {
+ "x": 1.9449091324304564,
+ "y": -75.09627755860649,
+ "z": 0.0
+ },
+ {
+ "x": 1.945295143505147,
+ "y": -74.09419283392229,
+ "z": 0.0
+ },
+ {
+ "x": 1.9456811545798378,
+ "y": -73.0921081092381,
+ "z": 0.0
+ },
+ {
+ "x": 1.9460671656545285,
+ "y": -72.0900233845539,
+ "z": 0.0
+ },
+ {
+ "x": 1.9464531767292192,
+ "y": -71.0879386598697,
+ "z": 0.0
+ },
+ {
+ "x": 1.94683918780391,
+ "y": -70.08585393518551,
+ "z": 0.0
+ },
+ {
+ "x": 1.9472251988786002,
+ "y": -69.08376921050132,
+ "z": 0.0
+ },
+ {
+ "x": 1.947611209953291,
+ "y": -68.08168448581712,
+ "z": 0.0
+ },
+ {
+ "x": 1.9479972210279817,
+ "y": -67.07959976113293,
+ "z": 0.0
+ },
+ {
+ "x": 1.9483832321026724,
+ "y": -66.07751503644873,
+ "z": 0.0
+ },
+ {
+ "x": 1.948769243177363,
+ "y": -65.07543031176453,
+ "z": 0.0
+ },
+ {
+ "x": 1.9491552542520538,
+ "y": -64.07334558708034,
+ "z": 0.0
+ },
+ {
+ "x": 1.9495412653267445,
+ "y": -63.07126086239614,
+ "z": 0.0
+ },
+ {
+ "x": 1.9499272764014348,
+ "y": -62.06917613771194,
+ "z": 0.0
+ },
+ {
+ "x": 1.9503132874761255,
+ "y": -61.06709141302775,
+ "z": 0.0
+ },
+ {
+ "x": 1.9506992985508163,
+ "y": -60.06500668834355,
+ "z": 0.0
+ },
+ {
+ "x": 1.951085309625507,
+ "y": -59.062921963659356,
+ "z": 0.0
+ },
+ {
+ "x": 1.9514713207001977,
+ "y": -58.06083723897516,
+ "z": 0.0
+ },
+ {
+ "x": 1.9518573317748884,
+ "y": -57.058752514290966,
+ "z": 0.0
+ },
+ {
+ "x": 1.9522433428495787,
+ "y": -56.05666778960677,
+ "z": 0.0
+ },
+ {
+ "x": 1.9526293539242694,
+ "y": -55.05458306492257,
+ "z": 0.0
+ },
+ {
+ "x": 1.9530153649989601,
+ "y": -54.05249834023837,
+ "z": 0.0
+ },
+ {
+ "x": 1.9534013760736508,
+ "y": -53.05041361555418,
+ "z": 0.0
+ },
+ {
+ "x": 1.9537873871483415,
+ "y": -52.04832889086998,
+ "z": 0.0
+ },
+ {
+ "x": 1.9541733982230323,
+ "y": -51.04624416618579,
+ "z": 0.0
+ },
+ {
+ "x": 1.9545594092977225,
+ "y": -50.04415944150159,
+ "z": 0.0
+ },
+ {
+ "x": 1.9549454203724133,
+ "y": -49.042074716817396,
+ "z": 0.0
+ },
+ {
+ "x": 1.955331431447104,
+ "y": -48.0399899921332,
+ "z": 0.0
+ },
+ {
+ "x": 1.9557174425217947,
+ "y": -47.037905267449005,
+ "z": 0.0
+ },
+ {
+ "x": 1.9561034535964854,
+ "y": -46.03582054276481,
+ "z": 0.0
+ },
+ {
+ "x": 1.9564894646711761,
+ "y": -45.033735818080615,
+ "z": 0.0
+ },
+ {
+ "x": 1.9568754757458668,
+ "y": -44.03165109339642,
+ "z": 0.0
+ },
+ {
+ "x": 1.9572614868205571,
+ "y": -43.029566368712224,
+ "z": 0.0
+ },
+ {
+ "x": 1.9576474978952478,
+ "y": -42.02748164402803,
+ "z": 0.0
+ },
+ {
+ "x": 1.9580335089699386,
+ "y": -41.025396919343834,
+ "z": 0.0
+ },
+ {
+ "x": 1.9584195200446293,
+ "y": -40.023312194659646,
+ "z": 0.0
+ },
+ {
+ "x": 1.95880553111932,
+ "y": -39.02122746997545,
+ "z": 0.0
+ },
+ {
+ "x": 1.9591915421940107,
+ "y": -38.019142745291255,
+ "z": 0.0
+ },
+ {
+ "x": 1.959577553268701,
+ "y": -37.01705802060707,
+ "z": 0.0
+ },
+ {
+ "x": 1.9599635643433917,
+ "y": -36.01497329592287,
+ "z": 0.0
+ },
+ {
+ "x": 1.9603495754180824,
+ "y": -35.01288857123868,
+ "z": 0.0
+ },
+ {
+ "x": 1.9607355864927731,
+ "y": -34.01080384655449,
+ "z": 0.0
+ },
+ {
+ "x": 1.9611215975674638,
+ "y": -33.00871912187029,
+ "z": 0.0
+ },
+ {
+ "x": 1.9615076086421546,
+ "y": -32.006634397186104,
+ "z": 0.0
+ },
+ {
+ "x": 1.9618936197168448,
+ "y": -31.004549672501913,
+ "z": 0.0
+ },
+ {
+ "x": 1.9622796307915356,
+ "y": -30.002464947817717,
+ "z": 0.0
+ },
+ {
+ "x": 1.9626656418662263,
+ "y": -29.000380223133526,
+ "z": 0.0
+ },
+ {
+ "x": 1.963051652940917,
+ "y": -27.998295498449334,
+ "z": 0.0
+ },
+ {
+ "x": 1.9634376640156077,
+ "y": -26.996210773765142,
+ "z": 0.0
+ },
+ {
+ "x": 1.9638236750902984,
+ "y": -25.99412604908095,
+ "z": 0.0
+ },
+ {
+ "x": 1.9642096861649887,
+ "y": -24.992041324396755,
+ "z": 0.0
+ },
+ {
+ "x": 1.9645956972396794,
+ "y": -23.989956599712563,
+ "z": 0.0
+ },
+ {
+ "x": 1.9649817083143701,
+ "y": -22.987871875028368,
+ "z": 0.0
+ },
+ {
+ "x": 1.9653677193890609,
+ "y": -21.985787150344173,
+ "z": 0.0
+ },
+ {
+ "x": 1.9657537304637516,
+ "y": -20.98370242565998,
+ "z": 0.0
+ },
+ {
+ "x": 1.9661397415384423,
+ "y": -19.981617700975786,
+ "z": 0.0
+ },
+ {
+ "x": 1.9665257526131326,
+ "y": -18.97953297629159,
+ "z": 0.0
+ },
+ {
+ "x": 1.9669117636878233,
+ "y": -17.9774482516074,
+ "z": 0.0
+ },
+ {
+ "x": 1.967297774762514,
+ "y": -16.975363526923203,
+ "z": 0.0
+ },
+ {
+ "x": 1.9676837858372047,
+ "y": -15.973278802239012,
+ "z": 0.0
+ },
+ {
+ "x": 1.9680697969118954,
+ "y": -14.971194077554818,
+ "z": 0.0
+ },
+ {
+ "x": 1.9684558079865861,
+ "y": -13.969109352870625,
+ "z": 0.0
+ },
+ {
+ "x": 1.9688418190612764,
+ "y": -12.967024628186431,
+ "z": 0.0
+ },
+ {
+ "x": 1.9692278301359671,
+ "y": -11.964939903502238,
+ "z": 0.0
+ },
+ {
+ "x": 1.9696138412106579,
+ "y": -10.962855178818044,
+ "z": 0.0
+ },
+ {
+ "x": 1.9699998522853486,
+ "y": -9.96077045413385,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 79,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": -2.029999850944244,
+ "y": -9.959229622160095,
+ "z": 0.0
+ },
+ {
+ "x": -2.0303858620189343,
+ "y": -10.961314346844288,
+ "z": 0.0
+ },
+ {
+ "x": -2.0307718730936255,
+ "y": -11.963399071528482,
+ "z": 0.0
+ },
+ {
+ "x": -2.0311578841683158,
+ "y": -12.965483796212675,
+ "z": 0.0
+ },
+ {
+ "x": -2.031543895243007,
+ "y": -13.967568520896869,
+ "z": 0.0
+ },
+ {
+ "x": -2.031929906317697,
+ "y": -14.969653245581062,
+ "z": 0.0
+ },
+ {
+ "x": -2.0323159173923884,
+ "y": -15.971737970265256,
+ "z": 0.0
+ },
+ {
+ "x": -2.0327019284670786,
+ "y": -16.973822694949448,
+ "z": 0.0
+ },
+ {
+ "x": -2.033087939541769,
+ "y": -17.975907419633643,
+ "z": 0.0
+ },
+ {
+ "x": -2.03347395061646,
+ "y": -18.977992144317835,
+ "z": 0.0
+ },
+ {
+ "x": -2.0338599616911504,
+ "y": -19.98007686900203,
+ "z": 0.0
+ },
+ {
+ "x": -2.0342459727658415,
+ "y": -20.982161593686225,
+ "z": 0.0
+ },
+ {
+ "x": -2.034631983840532,
+ "y": -21.984246318370417,
+ "z": 0.0
+ },
+ {
+ "x": -2.035017994915222,
+ "y": -22.986331043054612,
+ "z": 0.0
+ },
+ {
+ "x": -2.0354040059899132,
+ "y": -23.988415767738807,
+ "z": 0.0
+ },
+ {
+ "x": -2.0357900170646035,
+ "y": -24.990500492423,
+ "z": 0.0
+ },
+ {
+ "x": -2.0361760281392947,
+ "y": -25.992585217107194,
+ "z": 0.0
+ },
+ {
+ "x": -2.036562039213985,
+ "y": -26.994669941791386,
+ "z": 0.0
+ },
+ {
+ "x": -2.036948050288676,
+ "y": -27.996754666475578,
+ "z": 0.0
+ },
+ {
+ "x": -2.0373340613633664,
+ "y": -28.99883939115977,
+ "z": 0.0
+ },
+ {
+ "x": -2.0377200724380566,
+ "y": -30.00092411584396,
+ "z": 0.0
+ },
+ {
+ "x": -2.038106083512748,
+ "y": -31.003008840528157,
+ "z": 0.0
+ },
+ {
+ "x": -2.038492094587438,
+ "y": -32.00509356521235,
+ "z": 0.0
+ },
+ {
+ "x": -2.0388781056621292,
+ "y": -33.00717828989654,
+ "z": 0.0
+ },
+ {
+ "x": -2.0392641167368195,
+ "y": -34.00926301458073,
+ "z": 0.0
+ },
+ {
+ "x": -2.03965012781151,
+ "y": -35.01134773926493,
+ "z": 0.0
+ },
+ {
+ "x": -2.040036138886201,
+ "y": -36.013432463949115,
+ "z": 0.0
+ },
+ {
+ "x": -2.040422149960891,
+ "y": -37.01551718863331,
+ "z": 0.0
+ },
+ {
+ "x": -2.0408081610355824,
+ "y": -38.0176019133175,
+ "z": 0.0
+ },
+ {
+ "x": -2.0411941721102727,
+ "y": -39.019686638001694,
+ "z": 0.0
+ },
+ {
+ "x": -2.041580183184964,
+ "y": -40.02177136268589,
+ "z": 0.0
+ },
+ {
+ "x": -2.041966194259654,
+ "y": -41.02385608737008,
+ "z": 0.0
+ },
+ {
+ "x": -2.0423522053343444,
+ "y": -42.02594081205427,
+ "z": 0.0
+ },
+ {
+ "x": -2.0427382164090355,
+ "y": -43.02802553673847,
+ "z": 0.0
+ },
+ {
+ "x": -2.043124227483726,
+ "y": -44.030110261422664,
+ "z": 0.0
+ },
+ {
+ "x": -2.043510238558417,
+ "y": -45.03219498610686,
+ "z": 0.0
+ },
+ {
+ "x": -2.0438962496331072,
+ "y": -46.034279710791054,
+ "z": 0.0
+ },
+ {
+ "x": -2.0442822607077984,
+ "y": -47.03636443547525,
+ "z": 0.0
+ },
+ {
+ "x": -2.0446682717824887,
+ "y": -48.038449160159445,
+ "z": 0.0
+ },
+ {
+ "x": -2.045054282857179,
+ "y": -49.04053388484364,
+ "z": 0.0
+ },
+ {
+ "x": -2.04544029393187,
+ "y": -50.042618609527835,
+ "z": 0.0
+ },
+ {
+ "x": -2.0458263050065604,
+ "y": -51.04470333421203,
+ "z": 0.0
+ },
+ {
+ "x": -2.0462123160812515,
+ "y": -52.046788058896226,
+ "z": 0.0
+ },
+ {
+ "x": -2.046598327155942,
+ "y": -53.04887278358042,
+ "z": 0.0
+ },
+ {
+ "x": -2.046984338230632,
+ "y": -54.05095750826462,
+ "z": 0.0
+ },
+ {
+ "x": -2.0473703493053232,
+ "y": -55.05304223294881,
+ "z": 0.0
+ },
+ {
+ "x": -2.0477563603800135,
+ "y": -56.055126957633014,
+ "z": 0.0
+ },
+ {
+ "x": -2.0481423714547047,
+ "y": -57.05721168231721,
+ "z": 0.0
+ },
+ {
+ "x": -2.048528382529395,
+ "y": -58.059296407001405,
+ "z": 0.0
+ },
+ {
+ "x": -2.048914393604086,
+ "y": -59.0613811316856,
+ "z": 0.0
+ },
+ {
+ "x": -2.0493004046787764,
+ "y": -60.063465856369795,
+ "z": 0.0
+ },
+ {
+ "x": -2.0496864157534667,
+ "y": -61.06555058105399,
+ "z": 0.0
+ },
+ {
+ "x": -2.050072426828158,
+ "y": -62.067635305738186,
+ "z": 0.0
+ },
+ {
+ "x": -2.050458437902848,
+ "y": -63.06972003042238,
+ "z": 0.0
+ },
+ {
+ "x": -2.0508444489775393,
+ "y": -64.07180475510658,
+ "z": 0.0
+ },
+ {
+ "x": -2.0512304600522295,
+ "y": -65.07388947979078,
+ "z": 0.0
+ },
+ {
+ "x": -2.05161647112692,
+ "y": -66.07597420447497,
+ "z": 0.0
+ },
+ {
+ "x": -2.052002482201611,
+ "y": -67.07805892915917,
+ "z": 0.0
+ },
+ {
+ "x": -2.0523884932763012,
+ "y": -68.08014365384336,
+ "z": 0.0
+ },
+ {
+ "x": -2.0527745043509924,
+ "y": -69.08222837852756,
+ "z": 0.0
+ },
+ {
+ "x": -2.0531605154256827,
+ "y": -70.08431310321176,
+ "z": 0.0
+ },
+ {
+ "x": -2.053546526500374,
+ "y": -71.08639782789595,
+ "z": 0.0
+ },
+ {
+ "x": -2.053932537575064,
+ "y": -72.08848255258015,
+ "z": 0.0
+ },
+ {
+ "x": -2.0543185486497544,
+ "y": -73.09056727726434,
+ "z": 0.0
+ },
+ {
+ "x": -2.0547045597244455,
+ "y": -74.09265200194854,
+ "z": 0.0
+ },
+ {
+ "x": -2.055090570799136,
+ "y": -75.09473672663273,
+ "z": 0.0
+ },
+ {
+ "x": -2.055476581873827,
+ "y": -76.09682145131693,
+ "z": 0.0
+ },
+ {
+ "x": -2.0558625929485173,
+ "y": -77.09890617600111,
+ "z": 0.0
+ },
+ {
+ "x": -2.0562486040232084,
+ "y": -78.10099090068532,
+ "z": 0.0
+ },
+ {
+ "x": -2.0566346150978987,
+ "y": -79.10307562536951,
+ "z": 0.0
+ },
+ {
+ "x": -2.057020626172589,
+ "y": -80.10516035005371,
+ "z": 0.0
+ },
+ {
+ "x": -2.05740663724728,
+ "y": -81.10724507473789,
+ "z": 0.0
+ },
+ {
+ "x": -2.0577926483219704,
+ "y": -82.1093297994221,
+ "z": 0.0
+ },
+ {
+ "x": -2.0581786593966616,
+ "y": -83.1114145241063,
+ "z": 0.0
+ },
+ {
+ "x": -2.058564670471352,
+ "y": -84.11349924879049,
+ "z": 0.0
+ },
+ {
+ "x": -2.058950681546042,
+ "y": -85.11558397347467,
+ "z": 0.0
+ },
+ {
+ "x": -2.0593366926207333,
+ "y": -86.11766869815888,
+ "z": 0.0
+ },
+ {
+ "x": -2.0597228353699,
+ "y": -87.12026529887606,
+ "z": 0.0
+ },
+ {
+ "x": -2.0598521187622114,
+ "y": -88.12365318347021,
+ "z": 0.0
+ },
+ {
+ "x": -2.0593287344692395,
+ "y": -89.12573784582106,
+ "z": 0.0
+ },
+ {
+ "x": -2.0588053501762675,
+ "y": -90.12782250817193,
+ "z": 0.0
+ },
+ {
+ "x": -2.0582819658832956,
+ "y": -91.1299071705228,
+ "z": 0.0
+ },
+ {
+ "x": -2.0577585815903237,
+ "y": -92.13199183287364,
+ "z": 0.0
+ },
+ {
+ "x": -2.057235197297351,
+ "y": -93.13407649522449,
+ "z": 0.0
+ },
+ {
+ "x": -2.056711813004379,
+ "y": -94.13616115757536,
+ "z": 0.0
+ },
+ {
+ "x": -2.056188428711407,
+ "y": -95.13824581992623,
+ "z": 0.0
+ },
+ {
+ "x": -2.055665044418435,
+ "y": -96.14033048227708,
+ "z": 0.0
+ },
+ {
+ "x": -2.055141660125463,
+ "y": -97.14241514462792,
+ "z": 0.0
+ },
+ {
+ "x": -2.0546182758324902,
+ "y": -98.14449980697879,
+ "z": 0.0
+ },
+ {
+ "x": -2.0540948915395183,
+ "y": -99.14658446932965,
+ "z": 0.0
+ },
+ {
+ "x": -2.0535715072465464,
+ "y": -100.1486691316805,
+ "z": 0.0
+ },
+ {
+ "x": -2.0530481229535744,
+ "y": -101.15075379403136,
+ "z": 0.0
+ },
+ {
+ "x": -2.0525247386606025,
+ "y": -102.15283845638223,
+ "z": 0.0
+ },
+ {
+ "x": -2.0520013543676305,
+ "y": -103.15492311873308,
+ "z": 0.0
+ },
+ {
+ "x": -2.0514779700746577,
+ "y": -104.15700778108393,
+ "z": 0.0
+ },
+ {
+ "x": -2.0509545857816858,
+ "y": -105.15909244343479,
+ "z": 0.0
+ },
+ {
+ "x": -2.050431201488714,
+ "y": -106.16117710578565,
+ "z": 0.0
+ },
+ {
+ "x": -2.049907817195742,
+ "y": -107.16326176813652,
+ "z": 0.0
+ },
+ {
+ "x": -2.04938443290277,
+ "y": -108.16534643048738,
+ "z": 0.0
+ },
+ {
+ "x": -2.048861048609797,
+ "y": -109.16743109283821,
+ "z": 0.0
+ },
+ {
+ "x": -2.048337664316825,
+ "y": -110.16951575518908,
+ "z": 0.0
+ },
+ {
+ "x": -2.0478142800238532,
+ "y": -111.17160041753995,
+ "z": 0.0
+ },
+ {
+ "x": -2.0472908957308813,
+ "y": -112.1736850798908,
+ "z": 0.0
+ },
+ {
+ "x": -2.0467675114379094,
+ "y": -113.17576974224166,
+ "z": 0.0
+ },
+ {
+ "x": -2.0462441271449374,
+ "y": -114.17785440459252,
+ "z": 0.0
+ },
+ {
+ "x": -2.0457207428519646,
+ "y": -115.17993906694338,
+ "z": 0.0
+ },
+ {
+ "x": -2.0451973585589927,
+ "y": -116.18202372929423,
+ "z": 0.0
+ },
+ {
+ "x": -2.0446739742660207,
+ "y": -117.18410839164508,
+ "z": 0.0
+ },
+ {
+ "x": -2.0441505899730488,
+ "y": -118.18619305399595,
+ "z": 0.0
+ },
+ {
+ "x": -2.043627205680077,
+ "y": -119.18827771634682,
+ "z": 0.0
+ },
+ {
+ "x": -2.043103821387105,
+ "y": -120.19036237869767,
+ "z": 0.0
+ },
+ {
+ "x": -2.042580437094132,
+ "y": -121.19244704104851,
+ "z": 0.0
+ },
+ {
+ "x": -2.04205705280116,
+ "y": -122.19453170339938,
+ "z": 0.0
+ },
+ {
+ "x": -2.041533668508188,
+ "y": -123.19661636575024,
+ "z": 0.0
+ },
+ {
+ "x": -2.0410102842152162,
+ "y": -124.1987010281011,
+ "z": 0.0
+ },
+ {
+ "x": -2.0404868999222443,
+ "y": -125.20078569045195,
+ "z": 0.0
+ },
+ {
+ "x": -2.0399635156292715,
+ "y": -126.20287035280282,
+ "z": 0.0
+ },
+ {
+ "x": -2.0394401313362995,
+ "y": -127.20495501515367,
+ "z": 0.0
+ },
+ {
+ "x": -2.0389167470433276,
+ "y": -128.20703967750455,
+ "z": 0.0
+ },
+ {
+ "x": -2.0383933627503557,
+ "y": -129.2091243398554,
+ "z": 0.0
+ },
+ {
+ "x": -2.0378699784573837,
+ "y": -130.21120900220626,
+ "z": 0.0
+ },
+ {
+ "x": -2.0373465941644118,
+ "y": -131.2132936645571,
+ "z": 0.0
+ },
+ {
+ "x": -2.036823209871439,
+ "y": -132.21537832690797,
+ "z": 0.0
+ },
+ {
+ "x": -2.036299825578467,
+ "y": -133.21746298925882,
+ "z": 0.0
+ },
+ {
+ "x": -2.035776441285495,
+ "y": -134.21954765160967,
+ "z": 0.0
+ },
+ {
+ "x": -2.035253056992523,
+ "y": -135.22163231396053,
+ "z": 0.0
+ },
+ {
+ "x": -2.034729672699551,
+ "y": -136.22371697631138,
+ "z": 0.0
+ },
+ {
+ "x": -2.0342062884065784,
+ "y": -137.22580163866223,
+ "z": 0.0
+ },
+ {
+ "x": -2.0336829041136064,
+ "y": -138.2278863010131,
+ "z": 0.0
+ },
+ {
+ "x": -2.0331595198206345,
+ "y": -139.22997096336394,
+ "z": 0.0
+ },
+ {
+ "x": -2.0326361355276625,
+ "y": -140.2320556257148,
+ "z": 0.0
+ },
+ {
+ "x": -2.0321127512346906,
+ "y": -141.23414028806565,
+ "z": 0.0
+ },
+ {
+ "x": -2.0315893669417187,
+ "y": -142.2362249504165,
+ "z": 0.0
+ },
+ {
+ "x": -2.031065982648746,
+ "y": -143.23830961276735,
+ "z": 0.0
+ },
+ {
+ "x": -2.030542598355774,
+ "y": -144.24039427511815,
+ "z": 0.0
+ },
+ {
+ "x": -2.030019214062802,
+ "y": -145.242478937469,
+ "z": 0.0
+ },
+ {
+ "x": -2.02949582976983,
+ "y": -146.24456359981986,
+ "z": 0.0
+ },
+ {
+ "x": -2.028972445476858,
+ "y": -147.2466482621707,
+ "z": 0.0
+ },
+ {
+ "x": -2.028449061183886,
+ "y": -148.24873292452156,
+ "z": 0.0
+ },
+ {
+ "x": -2.0279256768909133,
+ "y": -149.25081758687236,
+ "z": 0.0
+ },
+ {
+ "x": -2.0274022925979414,
+ "y": -150.2529022492232,
+ "z": 0.0
+ },
+ {
+ "x": -2.0268789083049694,
+ "y": -151.25498691157406,
+ "z": 0.0
+ },
+ {
+ "x": -2.0263555240119975,
+ "y": -152.25707157392492,
+ "z": 0.0
+ },
+ {
+ "x": -2.0258321397190255,
+ "y": -153.25915623627577,
+ "z": 0.0
+ },
+ {
+ "x": -2.0253087554260536,
+ "y": -154.26124089862662,
+ "z": 0.0
+ },
+ {
+ "x": -2.0247853711330808,
+ "y": -155.26332556097748,
+ "z": 0.0
+ },
+ {
+ "x": -2.024261986840109,
+ "y": -156.26541022332833,
+ "z": 0.0
+ },
+ {
+ "x": -2.023738602547137,
+ "y": -157.26749488567913,
+ "z": 0.0
+ },
+ {
+ "x": -2.023215218254165,
+ "y": -158.26957954802998,
+ "z": 0.0
+ },
+ {
+ "x": -2.022691833961193,
+ "y": -159.27166421038083,
+ "z": 0.0
+ },
+ {
+ "x": -2.022168449668221,
+ "y": -160.27374887273163,
+ "z": 0.0
+ },
+ {
+ "x": -2.0216450653752482,
+ "y": -161.27583353508248,
+ "z": 0.0
+ },
+ {
+ "x": -2.0211216810822763,
+ "y": -162.27791819743334,
+ "z": 0.0
+ },
+ {
+ "x": -2.0205982967893044,
+ "y": -163.2800028597842,
+ "z": 0.0
+ },
+ {
+ "x": -2.0200749124963324,
+ "y": -164.28208752213504,
+ "z": 0.0
+ },
+ {
+ "x": -2.0195515282033605,
+ "y": -165.2841721844859,
+ "z": 0.0
+ },
+ {
+ "x": -2.0190281439103885,
+ "y": -166.28625684683675,
+ "z": 0.0
+ },
+ {
+ "x": -2.0185047596174157,
+ "y": -167.2883415091876,
+ "z": 0.0
+ },
+ {
+ "x": -2.0179813753244438,
+ "y": -168.2904261715384,
+ "z": 0.0
+ },
+ {
+ "x": -2.017457991031472,
+ "y": -169.29251083388925,
+ "z": 0.0
+ },
+ {
+ "x": -2.0169346067385,
+ "y": -170.2945954962401,
+ "z": 0.0
+ },
+ {
+ "x": -2.016411222445528,
+ "y": -171.29668015859096,
+ "z": 0.0
+ },
+ {
+ "x": -2.015887838152555,
+ "y": -172.2987648209418,
+ "z": 0.0
+ },
+ {
+ "x": -2.015364453859583,
+ "y": -173.3008494832926,
+ "z": 0.0
+ },
+ {
+ "x": -2.0148410695666112,
+ "y": -174.30293414564346,
+ "z": 0.0
+ },
+ {
+ "x": -2.0143176852736393,
+ "y": -175.30501880799432,
+ "z": 0.0
+ },
+ {
+ "x": -2.0137943009806674,
+ "y": -176.30710347034517,
+ "z": 0.0
+ },
+ {
+ "x": -2.0132709166876954,
+ "y": -177.30918813269602,
+ "z": 0.0
+ },
+ {
+ "x": -2.0127475323947226,
+ "y": -178.31127279504688,
+ "z": 0.0
+ },
+ {
+ "x": -2.0122241481017507,
+ "y": -179.31335745739773,
+ "z": 0.0
+ },
+ {
+ "x": -2.0117007638087787,
+ "y": -180.31544211974858,
+ "z": 0.0
+ },
+ {
+ "x": -2.0111773795158068,
+ "y": -181.31752678209938,
+ "z": 0.0
+ },
+ {
+ "x": -2.010653995222835,
+ "y": -182.31961144445023,
+ "z": 0.0
+ },
+ {
+ "x": -2.010130610929863,
+ "y": -183.32169610680108,
+ "z": 0.0
+ },
+ {
+ "x": -2.00960722663689,
+ "y": -184.32378076915188,
+ "z": 0.0
+ },
+ {
+ "x": -2.009083842343918,
+ "y": -185.32586543150273,
+ "z": 0.0
+ },
+ {
+ "x": -2.008560458050946,
+ "y": -186.3279500938536,
+ "z": 0.0
+ },
+ {
+ "x": -2.0080370737579742,
+ "y": -187.33003475620444,
+ "z": 0.0
+ },
+ {
+ "x": -2.0075136894650023,
+ "y": -188.3321194185553,
+ "z": 0.0
+ },
+ {
+ "x": -2.0069903051720304,
+ "y": -189.33420408090615,
+ "z": 0.0
+ },
+ {
+ "x": -2.0064669208790575,
+ "y": -190.336288743257,
+ "z": 0.0
+ },
+ {
+ "x": -2.0059435365860856,
+ "y": -191.33837340560785,
+ "z": 0.0
+ },
+ {
+ "x": -2.0054201522931137,
+ "y": -192.34045806795865,
+ "z": 0.0
+ },
+ {
+ "x": -2.0048967680001417,
+ "y": -193.3425427303095,
+ "z": 0.0
+ },
+ {
+ "x": -2.0043733837071698,
+ "y": -194.34462739266036,
+ "z": 0.0
+ },
+ {
+ "x": -2.003849999414198,
+ "y": -195.3467120550112,
+ "z": 0.0
+ },
+ {
+ "x": -2.003326615121225,
+ "y": -196.34879671736206,
+ "z": 0.0
+ },
+ {
+ "x": -2.002803230828253,
+ "y": -197.35088137971286,
+ "z": 0.0
+ },
+ {
+ "x": -2.002279846535281,
+ "y": -198.3529660420637,
+ "z": 0.0
+ },
+ {
+ "x": -2.001756462242309,
+ "y": -199.35505070441457,
+ "z": 0.0
+ },
+ {
+ "x": -2.0012330779493372,
+ "y": -200.35713536676542,
+ "z": 0.0
+ },
+ {
+ "x": -2.0007096936563653,
+ "y": -201.35922002911627,
+ "z": 0.0
+ },
+ {
+ "x": -2.0001863093633925,
+ "y": -202.36130469146713,
+ "z": 0.0
+ },
+ {
+ "x": -1.9996629250704205,
+ "y": -203.36338935381798,
+ "z": 0.0
+ },
+ {
+ "x": -1.9991395407774486,
+ "y": -204.36547401616883,
+ "z": 0.0
+ },
+ {
+ "x": -1.9986161564844767,
+ "y": -205.36755867851963,
+ "z": 0.0
+ },
+ {
+ "x": -1.9980927721915043,
+ "y": -206.36964334087048,
+ "z": 0.0
+ },
+ {
+ "x": -1.9975693878985323,
+ "y": -207.37172800322134,
+ "z": 0.0
+ },
+ {
+ "x": -1.9970460036055604,
+ "y": -208.37381266557213,
+ "z": 0.0
+ },
+ {
+ "x": -1.996522619312588,
+ "y": -209.37589732792298,
+ "z": 0.0
+ },
+ {
+ "x": -1.995999235019616,
+ "y": -210.37798199027384,
+ "z": 0.0
+ },
+ {
+ "x": -1.9954758507266441,
+ "y": -211.3800666526247,
+ "z": 0.0
+ },
+ {
+ "x": -1.9949524664336717,
+ "y": -212.38215131497554,
+ "z": 0.0
+ },
+ {
+ "x": -1.9944290821406998,
+ "y": -213.3842359773264,
+ "z": 0.0
+ },
+ {
+ "x": -1.9939056978477279,
+ "y": -214.38632063967725,
+ "z": 0.0
+ },
+ {
+ "x": -1.9933823135547555,
+ "y": -215.3884053020281,
+ "z": 0.0
+ },
+ {
+ "x": -1.9928589292617835,
+ "y": -216.3904899643789,
+ "z": 0.0
+ },
+ {
+ "x": -1.9923355449688116,
+ "y": -217.39257462672975,
+ "z": 0.0
+ },
+ {
+ "x": -1.9918121606758392,
+ "y": -218.3946592890806,
+ "z": 0.0
+ },
+ {
+ "x": -1.9912887763828673,
+ "y": -219.39674395143146,
+ "z": 0.0
+ },
+ {
+ "x": -1.9907653920898953,
+ "y": -220.3988286137823,
+ "z": 0.0
+ },
+ {
+ "x": -1.990242007796923,
+ "y": -221.4009132761331,
+ "z": 0.0
+ },
+ {
+ "x": -1.989718623503951,
+ "y": -222.40299793848396,
+ "z": 0.0
+ },
+ {
+ "x": -1.989195239210979,
+ "y": -223.40508260083482,
+ "z": 0.0
+ },
+ {
+ "x": -1.9886718549180067,
+ "y": -224.40716726318567,
+ "z": 0.0
+ },
+ {
+ "x": -1.9881484706250347,
+ "y": -225.40925192553652,
+ "z": 0.0
+ },
+ {
+ "x": -1.9876250863320628,
+ "y": -226.41133658788738,
+ "z": 0.0
+ },
+ {
+ "x": -1.9871017020390904,
+ "y": -227.41342125023823,
+ "z": 0.0
+ },
+ {
+ "x": -1.9865783177461185,
+ "y": -228.41550591258908,
+ "z": 0.0
+ },
+ {
+ "x": -1.9860549334531465,
+ "y": -229.41759057493988,
+ "z": 0.0
+ },
+ {
+ "x": -1.9855315491601742,
+ "y": -230.41967523729073,
+ "z": 0.0
+ },
+ {
+ "x": -1.9850081648672022,
+ "y": -231.4217598996416,
+ "z": 0.0
+ },
+ {
+ "x": -1.9844847805742303,
+ "y": -232.42384456199238,
+ "z": 0.0
+ },
+ {
+ "x": -1.983961396281258,
+ "y": -233.42592922434324,
+ "z": 0.0
+ },
+ {
+ "x": -1.983438011988286,
+ "y": -234.4280138866941,
+ "z": 0.0
+ },
+ {
+ "x": -1.9829146276953136,
+ "y": -235.43009854904494,
+ "z": 0.0
+ },
+ {
+ "x": -1.9823912434023416,
+ "y": -236.4321832113958,
+ "z": 0.0
+ },
+ {
+ "x": -1.9818678591093697,
+ "y": -237.43426787374665,
+ "z": 0.0
+ },
+ {
+ "x": -1.9813444748163973,
+ "y": -238.4363525360975,
+ "z": 0.0
+ },
+ {
+ "x": -1.9808210905234254,
+ "y": -239.43843719844836,
+ "z": 0.0
+ },
+ {
+ "x": -1.9802979208801939,
+ "y": -240.439959526235,
+ "z": 0.0
+ },
+ {
+ "x": -1.9800563311504915,
+ "y": -241.441300874255,
+ "z": 0.0
+ },
+ {
+ "x": -1.9801871686771089,
+ "y": -242.44338566474505,
+ "z": 0.0
+ },
+ {
+ "x": -1.9803180062037262,
+ "y": -243.4454704552351,
+ "z": 0.0
+ },
+ {
+ "x": -1.980448843730344,
+ "y": -244.44755524572514,
+ "z": 0.0
+ },
+ {
+ "x": -1.9805796812569614,
+ "y": -245.44964003621516,
+ "z": 0.0
+ },
+ {
+ "x": -1.9807105187835792,
+ "y": -246.4517248267052,
+ "z": 0.0
+ },
+ {
+ "x": -1.9808413563101965,
+ "y": -247.45380961719528,
+ "z": 0.0
+ },
+ {
+ "x": -1.9809721938368134,
+ "y": -248.4558944076853,
+ "z": 0.0
+ },
+ {
+ "x": -1.9811030313634312,
+ "y": -249.45797919817534,
+ "z": 0.0
+ },
+ {
+ "x": -1.9812338688900486,
+ "y": -250.46006398866538,
+ "z": 0.0
+ },
+ {
+ "x": -1.981364706416666,
+ "y": -251.46214877915543,
+ "z": 0.0
+ },
+ {
+ "x": -1.9814955439432838,
+ "y": -252.46423356964547,
+ "z": 0.0
+ },
+ {
+ "x": -1.981626381469901,
+ "y": -253.4663183601355,
+ "z": 0.0
+ },
+ {
+ "x": -1.9817572189965185,
+ "y": -254.46840315062553,
+ "z": 0.0
+ },
+ {
+ "x": -1.9818880565231358,
+ "y": -255.47048794111558,
+ "z": 0.0
+ },
+ {
+ "x": -1.9820188940497536,
+ "y": -256.47257273160557,
+ "z": 0.0
+ },
+ {
+ "x": -1.9821497315763714,
+ "y": -257.47465752209564,
+ "z": 0.0
+ },
+ {
+ "x": -1.9822805691029888,
+ "y": -258.4767423125857,
+ "z": 0.0
+ },
+ {
+ "x": -1.9824114066296061,
+ "y": -259.47882710307573,
+ "z": 0.0
+ },
+ {
+ "x": -1.982542244156224,
+ "y": -260.4809118935658,
+ "z": 0.0
+ },
+ {
+ "x": -1.9826730816828413,
+ "y": -261.4829966840558,
+ "z": 0.0
+ },
+ {
+ "x": -1.9828039192094586,
+ "y": -262.48508147454584,
+ "z": 0.0
+ },
+ {
+ "x": -1.982934756736076,
+ "y": -263.4871662650359,
+ "z": 0.0
+ },
+ {
+ "x": -1.9830655942626938,
+ "y": -264.4892510555259,
+ "z": 0.0
+ },
+ {
+ "x": -1.9831964317893112,
+ "y": -265.49133584601594,
+ "z": 0.0
+ },
+ {
+ "x": -1.9833272693159285,
+ "y": -266.493420636506,
+ "z": 0.0
+ },
+ {
+ "x": -1.9834581068425459,
+ "y": -267.4955054269961,
+ "z": 0.0
+ },
+ {
+ "x": -1.9835889443691637,
+ "y": -268.49759021748616,
+ "z": 0.0
+ },
+ {
+ "x": -1.983719781895781,
+ "y": -269.49967500797624,
+ "z": 0.0
+ },
+ {
+ "x": -1.9838506194223984,
+ "y": -270.5017597984663,
+ "z": 0.0
+ },
+ {
+ "x": -1.9839814569490157,
+ "y": -271.5038445889563,
+ "z": 0.0
+ },
+ {
+ "x": -1.9841122944756335,
+ "y": -272.5059293794464,
+ "z": 0.0
+ },
+ {
+ "x": -1.9842431320022509,
+ "y": -273.5080141699365,
+ "z": 0.0
+ },
+ {
+ "x": -1.9843739695288682,
+ "y": -274.51009896042655,
+ "z": 0.0
+ },
+ {
+ "x": -1.984504807055486,
+ "y": -275.5121837509166,
+ "z": 0.0
+ },
+ {
+ "x": -1.9846356445821034,
+ "y": -276.5142685414067,
+ "z": 0.0
+ },
+ {
+ "x": -1.9847664821087208,
+ "y": -277.51635333189677,
+ "z": 0.0
+ },
+ {
+ "x": -1.984897319635338,
+ "y": -278.5184381223868,
+ "z": 0.0
+ },
+ {
+ "x": -1.985028157161956,
+ "y": -279.52052291287686,
+ "z": 0.0
+ },
+ {
+ "x": -1.9851589946885733,
+ "y": -280.52260770336693,
+ "z": 0.0
+ },
+ {
+ "x": -1.9852898322151906,
+ "y": -281.524692493857,
+ "z": 0.0
+ },
+ {
+ "x": -1.985420669741808,
+ "y": -282.5267772843471,
+ "z": 0.0
+ },
+ {
+ "x": -1.9855515072684258,
+ "y": -283.52886207483715,
+ "z": 0.0
+ },
+ {
+ "x": -1.9856823447950431,
+ "y": -284.5309468653272,
+ "z": 0.0
+ },
+ {
+ "x": -1.9858131823216605,
+ "y": -285.5330316558173,
+ "z": 0.0
+ },
+ {
+ "x": -1.9859440198482783,
+ "y": -286.53511644630737,
+ "z": 0.0
+ },
+ {
+ "x": -1.9860748573748956,
+ "y": -287.53720123679744,
+ "z": 0.0
+ },
+ {
+ "x": -1.986205694901513,
+ "y": -288.5392860272875,
+ "z": 0.0
+ },
+ {
+ "x": -1.9863365324281304,
+ "y": -289.5413708177776,
+ "z": 0.0
+ },
+ {
+ "x": -1.9864673699547482,
+ "y": -290.54345560826766,
+ "z": 0.0
+ },
+ {
+ "x": -1.9865982074813655,
+ "y": -291.54554039875774,
+ "z": 0.0
+ },
+ {
+ "x": -1.9867290450079829,
+ "y": -292.5476251892478,
+ "z": 0.0
+ },
+ {
+ "x": -1.9868598825346002,
+ "y": -293.5497099797379,
+ "z": 0.0
+ },
+ {
+ "x": -1.986990720061218,
+ "y": -294.5517947702279,
+ "z": 0.0
+ },
+ {
+ "x": -1.9871215575878354,
+ "y": -295.553879560718,
+ "z": 0.0
+ },
+ {
+ "x": -1.9872523951144527,
+ "y": -296.55596435120805,
+ "z": 0.0
+ },
+ {
+ "x": -1.98738323264107,
+ "y": -297.5580491416981,
+ "z": 0.0
+ },
+ {
+ "x": -1.9875140701676879,
+ "y": -298.5601339321882,
+ "z": 0.0
+ },
+ {
+ "x": -1.9876449076943052,
+ "y": -299.56221872267827,
+ "z": 0.0
+ },
+ {
+ "x": -1.9877757452209226,
+ "y": -300.56430351316834,
+ "z": 0.0
+ },
+ {
+ "x": -1.9879065827475404,
+ "y": -301.5663883036584,
+ "z": 0.0
+ },
+ {
+ "x": -1.9880374202741578,
+ "y": -302.5684730941485,
+ "z": 0.0
+ },
+ {
+ "x": -1.988168257800775,
+ "y": -303.5705578846385,
+ "z": 0.0
+ },
+ {
+ "x": -1.9882990953273925,
+ "y": -304.5726426751286,
+ "z": 0.0
+ },
+ {
+ "x": -1.9884299328540103,
+ "y": -305.57472746561865,
+ "z": 0.0
+ },
+ {
+ "x": -1.9885607703806276,
+ "y": -306.5768122561087,
+ "z": 0.0
+ },
+ {
+ "x": -1.988691607907245,
+ "y": -307.5788970465988,
+ "z": 0.0
+ },
+ {
+ "x": -1.9888224454338623,
+ "y": -308.58098183708887,
+ "z": 0.0
+ },
+ {
+ "x": -1.9889532829604801,
+ "y": -309.58306662757894,
+ "z": 0.0
+ },
+ {
+ "x": -1.9890841204870975,
+ "y": -310.58515141806896,
+ "z": 0.0
+ },
+ {
+ "x": -1.9892149580137148,
+ "y": -311.58723620855903,
+ "z": 0.0
+ },
+ {
+ "x": -1.9893457955403326,
+ "y": -312.5893209990491,
+ "z": 0.0
+ },
+ {
+ "x": -1.98947663306695,
+ "y": -313.5914057895392,
+ "z": 0.0
+ },
+ {
+ "x": -1.9896074705935674,
+ "y": -314.59349058002925,
+ "z": 0.0
+ },
+ {
+ "x": -1.9897383081201847,
+ "y": -315.5955753705193,
+ "z": 0.0
+ },
+ {
+ "x": -1.9898691456468025,
+ "y": -316.5976601610094,
+ "z": 0.0
+ },
+ {
+ "x": -1.9899999831734199,
+ "y": -317.5997449514995,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 80,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 340.8718824984497,
+ "y": -46.422407556799655,
+ "z": 0.0
+ },
+ {
+ "x": 340.8724973815697,
+ "y": -45.40440774249774,
+ "z": 0.0
+ },
+ {
+ "x": 340.8731122646897,
+ "y": -44.38640792819581,
+ "z": 0.0
+ },
+ {
+ "x": 340.87372714780986,
+ "y": -43.36840811389433,
+ "z": 0.0
+ },
+ {
+ "x": 340.8743420309299,
+ "y": -42.35040829959196,
+ "z": 0.0
+ },
+ {
+ "x": 340.8749569140499,
+ "y": -41.33240848529005,
+ "z": 0.0
+ },
+ {
+ "x": 340.8755717971699,
+ "y": -40.314408670988115,
+ "z": 0.0
+ },
+ {
+ "x": 340.87618668029,
+ "y": -39.29640885668642,
+ "z": 0.0
+ },
+ {
+ "x": 340.8768015634101,
+ "y": -38.2784090423845,
+ "z": 0.0
+ },
+ {
+ "x": 340.8774164465301,
+ "y": -37.26040922808235,
+ "z": 0.0
+ },
+ {
+ "x": 340.8780313296501,
+ "y": -36.24240941378043,
+ "z": 0.0
+ },
+ {
+ "x": 340.8786462127702,
+ "y": -35.22440959947873,
+ "z": 0.0
+ },
+ {
+ "x": 340.87926109589023,
+ "y": -34.20640978517658,
+ "z": 0.0
+ },
+ {
+ "x": 340.8798759790103,
+ "y": -33.188409970874886,
+ "z": 0.0
+ },
+ {
+ "x": 340.88049086213033,
+ "y": -32.170410156572736,
+ "z": 0.0
+ },
+ {
+ "x": 340.8811057452504,
+ "y": -31.15241034227104,
+ "z": 0.0
+ },
+ {
+ "x": 340.88172062837043,
+ "y": -30.134410527968893,
+ "z": 0.0
+ },
+ {
+ "x": 340.88233551149045,
+ "y": -29.11641071366697,
+ "z": 0.0
+ },
+ {
+ "x": 340.88295039461053,
+ "y": -28.098410899365273,
+ "z": 0.0
+ },
+ {
+ "x": 340.8835652777306,
+ "y": -27.08041108506335,
+ "z": 0.0
+ },
+ {
+ "x": 340.88418016085063,
+ "y": -26.062411270761203,
+ "z": 0.0
+ },
+ {
+ "x": 340.88479504397066,
+ "y": -25.04441145645928,
+ "z": 0.0
+ },
+ {
+ "x": 340.88540992709073,
+ "y": -24.02641164215758,
+ "z": 0.0
+ },
+ {
+ "x": 340.8860248102108,
+ "y": -23.008411827855657,
+ "z": 0.0
+ },
+ {
+ "x": 340.88663969333084,
+ "y": -21.99041201355351,
+ "z": 0.0
+ },
+ {
+ "x": 340.88725457645086,
+ "y": -20.97241219925159,
+ "z": 0.0
+ },
+ {
+ "x": 340.88786945957094,
+ "y": -19.95441238494989,
+ "z": 0.0
+ },
+ {
+ "x": 340.88848434269096,
+ "y": -18.936412570647743,
+ "z": 0.0
+ },
+ {
+ "x": 340.88909922581104,
+ "y": -17.918412756346047,
+ "z": 0.0
+ },
+ {
+ "x": 340.88971410893106,
+ "y": -16.9004129420439,
+ "z": 0.0
+ },
+ {
+ "x": 340.89032899205114,
+ "y": -15.882413127742202,
+ "z": 0.0
+ },
+ {
+ "x": 340.89094387517116,
+ "y": -14.864413313440057,
+ "z": 0.0
+ },
+ {
+ "x": 340.8915587582912,
+ "y": -13.846413499138135,
+ "z": 0.0
+ },
+ {
+ "x": 340.89217364141126,
+ "y": -12.828413684836438,
+ "z": 0.0
+ },
+ {
+ "x": 340.89278852453134,
+ "y": -11.810413870534514,
+ "z": 0.0
+ },
+ {
+ "x": 340.89340340765136,
+ "y": -10.792414056232369,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 81,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 332.89340486696824,
+ "y": -10.787581968845162,
+ "z": 0.0
+ },
+ {
+ "x": 332.8927899838482,
+ "y": -11.80558178314686,
+ "z": 0.0
+ },
+ {
+ "x": 332.89217510072814,
+ "y": -12.823581597448783,
+ "z": 0.0
+ },
+ {
+ "x": 332.89156021760806,
+ "y": -13.841581411750928,
+ "z": 0.0
+ },
+ {
+ "x": 332.89094533448804,
+ "y": -14.85958122605285,
+ "z": 0.0
+ },
+ {
+ "x": 332.890330451368,
+ "y": -15.877581040354547,
+ "z": 0.0
+ },
+ {
+ "x": 332.88971556824794,
+ "y": -16.895580854656693,
+ "z": 0.0
+ },
+ {
+ "x": 332.8891006851279,
+ "y": -17.913580668958392,
+ "z": 0.0
+ },
+ {
+ "x": 332.88848580200784,
+ "y": -18.931580483260536,
+ "z": 0.0
+ },
+ {
+ "x": 332.8878709188878,
+ "y": -19.949580297562235,
+ "z": 0.0
+ },
+ {
+ "x": 332.88725603576773,
+ "y": -20.967580111864383,
+ "z": 0.0
+ },
+ {
+ "x": 332.8866411526477,
+ "y": -21.985579926166302,
+ "z": 0.0
+ },
+ {
+ "x": 332.8860262695277,
+ "y": -23.003579740468002,
+ "z": 0.0
+ },
+ {
+ "x": 332.8854113864076,
+ "y": -24.021579554769925,
+ "z": 0.0
+ },
+ {
+ "x": 332.88479650328753,
+ "y": -25.039579369072072,
+ "z": 0.0
+ },
+ {
+ "x": 332.8841816201675,
+ "y": -26.057579183373996,
+ "z": 0.0
+ },
+ {
+ "x": 332.8835667370475,
+ "y": -27.075578997675695,
+ "z": 0.0
+ },
+ {
+ "x": 332.8829518539274,
+ "y": -28.09357881197762,
+ "z": 0.0
+ },
+ {
+ "x": 332.88233697080733,
+ "y": -29.111578626279762,
+ "z": 0.0
+ },
+ {
+ "x": 332.8817220876873,
+ "y": -30.129578440581685,
+ "z": 0.0
+ },
+ {
+ "x": 332.8811072045673,
+ "y": -31.147578254883385,
+ "z": 0.0
+ },
+ {
+ "x": 332.8804923214472,
+ "y": -32.165578069185536,
+ "z": 0.0
+ },
+ {
+ "x": 332.8798774383272,
+ "y": -33.18357788348723,
+ "z": 0.0
+ },
+ {
+ "x": 332.8792625552071,
+ "y": -34.20157769778938,
+ "z": 0.0
+ },
+ {
+ "x": 332.8786476720871,
+ "y": -35.21957751209108,
+ "z": 0.0
+ },
+ {
+ "x": 332.878032788967,
+ "y": -36.23757732639323,
+ "z": 0.0
+ },
+ {
+ "x": 332.877417905847,
+ "y": -37.25557714069515,
+ "z": 0.0
+ },
+ {
+ "x": 332.87680302272696,
+ "y": -38.27357695499685,
+ "z": 0.0
+ },
+ {
+ "x": 332.8761881396069,
+ "y": -39.291576769298764,
+ "z": 0.0
+ },
+ {
+ "x": 332.8755732564868,
+ "y": -40.309576583600915,
+ "z": 0.0
+ },
+ {
+ "x": 332.8749583733668,
+ "y": -41.32757639790284,
+ "z": 0.0
+ },
+ {
+ "x": 332.87434349024676,
+ "y": -42.34557621220476,
+ "z": 0.0
+ },
+ {
+ "x": 332.87372860712674,
+ "y": -43.36357602650624,
+ "z": 0.0
+ },
+ {
+ "x": 332.8731137240066,
+ "y": -44.38157584080861,
+ "z": 0.0
+ },
+ {
+ "x": 332.8724988408866,
+ "y": -45.399575655110525,
+ "z": 0.0
+ },
+ {
+ "x": 332.87188395776656,
+ "y": -46.41757546941244,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 82,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 336.8934041373098,
+ "y": -10.789998012538765,
+ "z": 0.0
+ },
+ {
+ "x": 336.8927892541898,
+ "y": -11.807997826840687,
+ "z": 0.0
+ },
+ {
+ "x": 336.8921743710697,
+ "y": -12.82599764114261,
+ "z": 0.0
+ },
+ {
+ "x": 336.8915594879496,
+ "y": -13.843997455444532,
+ "z": 0.0
+ },
+ {
+ "x": 336.8909446048296,
+ "y": -14.861997269746453,
+ "z": 0.0
+ },
+ {
+ "x": 336.8903297217096,
+ "y": -15.879997084048375,
+ "z": 0.0
+ },
+ {
+ "x": 336.8897148385895,
+ "y": -16.897996898350296,
+ "z": 0.0
+ },
+ {
+ "x": 336.8890999554695,
+ "y": -17.91599671265222,
+ "z": 0.0
+ },
+ {
+ "x": 336.8884850723494,
+ "y": -18.93399652695414,
+ "z": 0.0
+ },
+ {
+ "x": 336.8878701892294,
+ "y": -19.951996341256063,
+ "z": 0.0
+ },
+ {
+ "x": 336.8872553061093,
+ "y": -20.969996155557986,
+ "z": 0.0
+ },
+ {
+ "x": 336.8866404229893,
+ "y": -21.987995969859906,
+ "z": 0.0
+ },
+ {
+ "x": 336.88602553986925,
+ "y": -23.00599578416183,
+ "z": 0.0
+ },
+ {
+ "x": 336.8854106567492,
+ "y": -24.023995598463753,
+ "z": 0.0
+ },
+ {
+ "x": 336.8847957736291,
+ "y": -25.041995412765676,
+ "z": 0.0
+ },
+ {
+ "x": 336.88418089050907,
+ "y": -26.0599952270676,
+ "z": 0.0
+ },
+ {
+ "x": 336.88356600738905,
+ "y": -27.077995041369523,
+ "z": 0.0
+ },
+ {
+ "x": 336.88295112426897,
+ "y": -28.095994855671446,
+ "z": 0.0
+ },
+ {
+ "x": 336.8823362411489,
+ "y": -29.113994669973366,
+ "z": 0.0
+ },
+ {
+ "x": 336.88172135802887,
+ "y": -30.13199448427529,
+ "z": 0.0
+ },
+ {
+ "x": 336.88110647490885,
+ "y": -31.149994298577212,
+ "z": 0.0
+ },
+ {
+ "x": 336.88049159178877,
+ "y": -32.167994112879136,
+ "z": 0.0
+ },
+ {
+ "x": 336.87987670866875,
+ "y": -33.18599392718106,
+ "z": 0.0
+ },
+ {
+ "x": 336.87926182554867,
+ "y": -34.20399374148298,
+ "z": 0.0
+ },
+ {
+ "x": 336.87864694242865,
+ "y": -35.221993555784906,
+ "z": 0.0
+ },
+ {
+ "x": 336.87803205930857,
+ "y": -36.23999337008683,
+ "z": 0.0
+ },
+ {
+ "x": 336.87741717618854,
+ "y": -37.25799318438875,
+ "z": 0.0
+ },
+ {
+ "x": 336.8768022930685,
+ "y": -38.275992998690676,
+ "z": 0.0
+ },
+ {
+ "x": 336.87618740994844,
+ "y": -39.29399281299259,
+ "z": 0.0
+ },
+ {
+ "x": 336.87557252682836,
+ "y": -40.311992627294515,
+ "z": 0.0
+ },
+ {
+ "x": 336.87495764370834,
+ "y": -41.329992441596445,
+ "z": 0.0
+ },
+ {
+ "x": 336.8743427605883,
+ "y": -42.34799225589836,
+ "z": 0.0
+ },
+ {
+ "x": 336.8737278774683,
+ "y": -43.365992070200285,
+ "z": 0.0
+ },
+ {
+ "x": 336.87311299434816,
+ "y": -44.38399188450221,
+ "z": 0.0
+ },
+ {
+ "x": 336.87249811122814,
+ "y": -45.40199169880413,
+ "z": 0.0
+ },
+ {
+ "x": 336.8718832281081,
+ "y": -46.41999151310605,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 83,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 338.87188286327887,
+ "y": -46.42119953495285,
+ "z": 0.0
+ },
+ {
+ "x": 338.87249774639895,
+ "y": -45.40319972065093,
+ "z": 0.0
+ },
+ {
+ "x": 338.8731126295189,
+ "y": -44.38519990634901,
+ "z": 0.0
+ },
+ {
+ "x": 338.8737275126391,
+ "y": -43.36720009204731,
+ "z": 0.0
+ },
+ {
+ "x": 338.8743423957591,
+ "y": -42.34920027774516,
+ "z": 0.0
+ },
+ {
+ "x": 338.87495727887915,
+ "y": -41.33120046344325,
+ "z": 0.0
+ },
+ {
+ "x": 338.8755721619991,
+ "y": -40.313200649141315,
+ "z": 0.0
+ },
+ {
+ "x": 338.8761870451192,
+ "y": -39.295200834839505,
+ "z": 0.0
+ },
+ {
+ "x": 338.8768019282393,
+ "y": -38.27720102053759,
+ "z": 0.0
+ },
+ {
+ "x": 338.87741681135935,
+ "y": -37.25920120623555,
+ "z": 0.0
+ },
+ {
+ "x": 338.8780316944793,
+ "y": -36.24120139193363,
+ "z": 0.0
+ },
+ {
+ "x": 338.8786465775994,
+ "y": -35.22320157763182,
+ "z": 0.0
+ },
+ {
+ "x": 338.8792614607195,
+ "y": -34.20520176332978,
+ "z": 0.0
+ },
+ {
+ "x": 338.87987634383956,
+ "y": -33.18720194902797,
+ "z": 0.0
+ },
+ {
+ "x": 338.8804912269595,
+ "y": -32.169202134725936,
+ "z": 0.0
+ },
+ {
+ "x": 338.8811061100796,
+ "y": -31.151202320424126,
+ "z": 0.0
+ },
+ {
+ "x": 338.8817209931997,
+ "y": -30.13320250612209,
+ "z": 0.0
+ },
+ {
+ "x": 338.88233587631964,
+ "y": -29.115202691820166,
+ "z": 0.0
+ },
+ {
+ "x": 338.8829507594397,
+ "y": -28.09720287751836,
+ "z": 0.0
+ },
+ {
+ "x": 338.8835656425598,
+ "y": -27.079203063216436,
+ "z": 0.0
+ },
+ {
+ "x": 338.8841805256799,
+ "y": -26.061203248914403,
+ "z": 0.0
+ },
+ {
+ "x": 338.88479540879985,
+ "y": -25.04320343461248,
+ "z": 0.0
+ },
+ {
+ "x": 338.8854102919199,
+ "y": -24.025203620310666,
+ "z": 0.0
+ },
+ {
+ "x": 338.88602517504,
+ "y": -23.007203806008743,
+ "z": 0.0
+ },
+ {
+ "x": 338.8866400581601,
+ "y": -21.98920399170671,
+ "z": 0.0
+ },
+ {
+ "x": 338.88725494128005,
+ "y": -20.971204177404786,
+ "z": 0.0
+ },
+ {
+ "x": 338.8878698244001,
+ "y": -19.953204363102977,
+ "z": 0.0
+ },
+ {
+ "x": 338.8884847075202,
+ "y": -18.93520454880094,
+ "z": 0.0
+ },
+ {
+ "x": 338.8890995906403,
+ "y": -17.917204734499133,
+ "z": 0.0
+ },
+ {
+ "x": 338.88971447376025,
+ "y": -16.8992049201971,
+ "z": 0.0
+ },
+ {
+ "x": 338.89032935688033,
+ "y": -15.881205105895289,
+ "z": 0.0
+ },
+ {
+ "x": 338.8909442400004,
+ "y": -14.863205291593255,
+ "z": 0.0
+ },
+ {
+ "x": 338.8915591231204,
+ "y": -13.845205477291334,
+ "z": 0.0
+ },
+ {
+ "x": 338.89217400624045,
+ "y": -12.827205662989524,
+ "z": 0.0
+ },
+ {
+ "x": 338.89278888936053,
+ "y": -11.8092058486876,
+ "z": 0.0
+ },
+ {
+ "x": 338.8934037724806,
+ "y": -10.791206034385567,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 84,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 334.893404502139,
+ "y": -10.788789990691964,
+ "z": 0.0
+ },
+ {
+ "x": 334.892789619019,
+ "y": -11.806789804993773,
+ "z": 0.0
+ },
+ {
+ "x": 334.89217473589895,
+ "y": -12.824789619295696,
+ "z": 0.0
+ },
+ {
+ "x": 334.89155985277887,
+ "y": -13.84278943359773,
+ "z": 0.0
+ },
+ {
+ "x": 334.8909449696588,
+ "y": -14.860789247899651,
+ "z": 0.0
+ },
+ {
+ "x": 334.8903300865388,
+ "y": -15.878789062201461,
+ "z": 0.0
+ },
+ {
+ "x": 334.88971520341875,
+ "y": -16.896788876503493,
+ "z": 0.0
+ },
+ {
+ "x": 334.88910032029867,
+ "y": -17.914788690805306,
+ "z": 0.0
+ },
+ {
+ "x": 334.8884854371786,
+ "y": -18.93278850510734,
+ "z": 0.0
+ },
+ {
+ "x": 334.8878705540586,
+ "y": -19.95078831940915,
+ "z": 0.0
+ },
+ {
+ "x": 334.88725567093854,
+ "y": -20.968788133711186,
+ "z": 0.0
+ },
+ {
+ "x": 334.88664078781846,
+ "y": -21.986787948013102,
+ "z": 0.0
+ },
+ {
+ "x": 334.8860259046985,
+ "y": -23.004787762314916,
+ "z": 0.0
+ },
+ {
+ "x": 334.8854110215784,
+ "y": -24.02278757661684,
+ "z": 0.0
+ },
+ {
+ "x": 334.88479613845834,
+ "y": -25.040787390918872,
+ "z": 0.0
+ },
+ {
+ "x": 334.88418125533826,
+ "y": -26.058787205220796,
+ "z": 0.0
+ },
+ {
+ "x": 334.8835663722183,
+ "y": -27.07678701952261,
+ "z": 0.0
+ },
+ {
+ "x": 334.8829514890982,
+ "y": -28.094786833824532,
+ "z": 0.0
+ },
+ {
+ "x": 334.88233660597814,
+ "y": -29.112786648126566,
+ "z": 0.0
+ },
+ {
+ "x": 334.88172172285806,
+ "y": -30.13078646242849,
+ "z": 0.0
+ },
+ {
+ "x": 334.8811068397381,
+ "y": -31.1487862767303,
+ "z": 0.0
+ },
+ {
+ "x": 334.880491956618,
+ "y": -32.166786091032336,
+ "z": 0.0
+ },
+ {
+ "x": 334.87987707349794,
+ "y": -33.184785905334145,
+ "z": 0.0
+ },
+ {
+ "x": 334.87926219037786,
+ "y": -34.20278571963618,
+ "z": 0.0
+ },
+ {
+ "x": 334.8786473072579,
+ "y": -35.22078553393799,
+ "z": 0.0
+ },
+ {
+ "x": 334.8780324241378,
+ "y": -36.23878534824003,
+ "z": 0.0
+ },
+ {
+ "x": 334.87741754101773,
+ "y": -37.25678516254195,
+ "z": 0.0
+ },
+ {
+ "x": 334.87680265789777,
+ "y": -38.27478497684376,
+ "z": 0.0
+ },
+ {
+ "x": 334.8761877747777,
+ "y": -39.29278479114568,
+ "z": 0.0
+ },
+ {
+ "x": 334.8755728916576,
+ "y": -40.310784605447715,
+ "z": 0.0
+ },
+ {
+ "x": 334.87495800853753,
+ "y": -41.32878441974964,
+ "z": 0.0
+ },
+ {
+ "x": 334.87434312541757,
+ "y": -42.34678423405156,
+ "z": 0.0
+ },
+ {
+ "x": 334.8737282422975,
+ "y": -43.36478404835326,
+ "z": 0.0
+ },
+ {
+ "x": 334.8731133591774,
+ "y": -44.38278386265541,
+ "z": 0.0
+ },
+ {
+ "x": 334.87249847605733,
+ "y": -45.40078367695733,
+ "z": 0.0
+ },
+ {
+ "x": 334.87188359293737,
+ "y": -46.41878349125925,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 85,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 340.8270890483683,
+ "y": -120.582394028932,
+ "z": 0.0
+ },
+ {
+ "x": 340.827699573135,
+ "y": -119.57160989958834,
+ "z": 0.0
+ },
+ {
+ "x": 340.82831009790175,
+ "y": -118.56082577024468,
+ "z": 0.0
+ },
+ {
+ "x": 340.8289206226685,
+ "y": -117.55004164090101,
+ "z": 0.0
+ },
+ {
+ "x": 340.8295311474352,
+ "y": -116.53925751155735,
+ "z": 0.0
+ },
+ {
+ "x": 340.8301416722019,
+ "y": -115.52847338221346,
+ "z": 0.0
+ },
+ {
+ "x": 340.8307521969686,
+ "y": -114.51768925287003,
+ "z": 0.0
+ },
+ {
+ "x": 340.83136272173533,
+ "y": -113.50690512352637,
+ "z": 0.0
+ },
+ {
+ "x": 340.83197324650206,
+ "y": -112.4961209941827,
+ "z": 0.0
+ },
+ {
+ "x": 340.8325837712688,
+ "y": -111.48533686483904,
+ "z": 0.0
+ },
+ {
+ "x": 340.8331942960355,
+ "y": -110.47455273549538,
+ "z": 0.0
+ },
+ {
+ "x": 340.8338048208022,
+ "y": -109.46376860615149,
+ "z": 0.0
+ },
+ {
+ "x": 340.8344153455689,
+ "y": -108.45298447680806,
+ "z": 0.0
+ },
+ {
+ "x": 340.83502587033564,
+ "y": -107.4422003474644,
+ "z": 0.0
+ },
+ {
+ "x": 340.83563639510237,
+ "y": -106.43141621812073,
+ "z": 0.0
+ },
+ {
+ "x": 340.8362469198691,
+ "y": -105.42063208877707,
+ "z": 0.0
+ },
+ {
+ "x": 340.83685744463577,
+ "y": -104.40984795943318,
+ "z": 0.0
+ },
+ {
+ "x": 340.8374679694025,
+ "y": -103.39906383008974,
+ "z": 0.0
+ },
+ {
+ "x": 340.8380784941692,
+ "y": -102.38827970074608,
+ "z": 0.0
+ },
+ {
+ "x": 340.83868901893595,
+ "y": -101.37749557140242,
+ "z": 0.0
+ },
+ {
+ "x": 340.8392995437027,
+ "y": -100.36671144205877,
+ "z": 0.0
+ },
+ {
+ "x": 340.8399100684694,
+ "y": -99.35592731271511,
+ "z": 0.0
+ },
+ {
+ "x": 340.84052059323614,
+ "y": -98.34514318337145,
+ "z": 0.0
+ },
+ {
+ "x": 340.84113111800286,
+ "y": -97.3343590540278,
+ "z": 0.0
+ },
+ {
+ "x": 340.84174164276953,
+ "y": -96.32357492468391,
+ "z": 0.0
+ },
+ {
+ "x": 340.84235216753626,
+ "y": -95.31279079534048,
+ "z": 0.0
+ },
+ {
+ "x": 340.842962692303,
+ "y": -94.30200666599681,
+ "z": 0.0
+ },
+ {
+ "x": 340.8435732170697,
+ "y": -93.29122253665317,
+ "z": 0.0
+ },
+ {
+ "x": 340.84418374183645,
+ "y": -92.2804384073095,
+ "z": 0.0
+ },
+ {
+ "x": 340.8447942666031,
+ "y": -91.26965427796561,
+ "z": 0.0
+ },
+ {
+ "x": 340.84540479136984,
+ "y": -90.25887014862218,
+ "z": 0.0
+ },
+ {
+ "x": 340.8460153161366,
+ "y": -89.24808601927853,
+ "z": 0.0
+ },
+ {
+ "x": 340.8466258409033,
+ "y": -88.23730188993487,
+ "z": 0.0
+ },
+ {
+ "x": 340.84723636567,
+ "y": -87.22651776059121,
+ "z": 0.0
+ },
+ {
+ "x": 340.84784689043676,
+ "y": -86.21573363124755,
+ "z": 0.0
+ },
+ {
+ "x": 340.8484574152035,
+ "y": -85.2049495019039,
+ "z": 0.0
+ },
+ {
+ "x": 340.84906793997015,
+ "y": -84.19416537256001,
+ "z": 0.0
+ },
+ {
+ "x": 340.84967846473694,
+ "y": -83.1833812432168,
+ "z": 0.0
+ },
+ {
+ "x": 340.8502889895036,
+ "y": -82.1725971138727,
+ "z": 0.0
+ },
+ {
+ "x": 340.85089951427034,
+ "y": -81.16181298452926,
+ "z": 0.0
+ },
+ {
+ "x": 340.85151003903707,
+ "y": -80.1510288551856,
+ "z": 0.0
+ },
+ {
+ "x": 340.85212056380374,
+ "y": -79.14024472584171,
+ "z": 0.0
+ },
+ {
+ "x": 340.85273108857047,
+ "y": -78.12946059649829,
+ "z": 0.0
+ },
+ {
+ "x": 340.8533416133372,
+ "y": -77.11867646715463,
+ "z": 0.0
+ },
+ {
+ "x": 340.8539521381039,
+ "y": -76.10789233781097,
+ "z": 0.0
+ },
+ {
+ "x": 340.85456266287065,
+ "y": -75.0971082084673,
+ "z": 0.0
+ },
+ {
+ "x": 340.8551731876374,
+ "y": -74.08632407912366,
+ "z": 0.0
+ },
+ {
+ "x": 340.8557837124041,
+ "y": -73.07553994978,
+ "z": 0.0
+ },
+ {
+ "x": 340.85639423717083,
+ "y": -72.06475582043633,
+ "z": 0.0
+ },
+ {
+ "x": 340.8570047619375,
+ "y": -71.05397169109244,
+ "z": 0.0
+ },
+ {
+ "x": 340.8576152867043,
+ "y": -70.04318756174925,
+ "z": 0.0
+ },
+ {
+ "x": 340.85822581147096,
+ "y": -69.03240343240513,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 86,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 332.85822727078784,
+ "y": -69.0275713450181,
+ "z": 0.0
+ },
+ {
+ "x": 332.85761674602116,
+ "y": -70.03835547436131,
+ "z": 0.0
+ },
+ {
+ "x": 332.8570062212544,
+ "y": -71.04913960370541,
+ "z": 0.0
+ },
+ {
+ "x": 332.8563956964877,
+ "y": -72.05992373304885,
+ "z": 0.0
+ },
+ {
+ "x": 332.855785171721,
+ "y": -73.07070786239251,
+ "z": 0.0
+ },
+ {
+ "x": 332.85517464695425,
+ "y": -74.08149199173617,
+ "z": 0.0
+ },
+ {
+ "x": 332.8545641221875,
+ "y": -75.09227612107982,
+ "z": 0.0
+ },
+ {
+ "x": 332.8539535974208,
+ "y": -76.10306025042348,
+ "z": 0.0
+ },
+ {
+ "x": 332.85334307265407,
+ "y": -77.11384437976714,
+ "z": 0.0
+ },
+ {
+ "x": 332.85273254788734,
+ "y": -78.1246285091108,
+ "z": 0.0
+ },
+ {
+ "x": 332.8521220231206,
+ "y": -79.13541263845468,
+ "z": 0.0
+ },
+ {
+ "x": 332.85151149835394,
+ "y": -80.14619676779812,
+ "z": 0.0
+ },
+ {
+ "x": 332.8509009735872,
+ "y": -81.15698089714178,
+ "z": 0.0
+ },
+ {
+ "x": 332.8502904488205,
+ "y": -82.16776502648567,
+ "z": 0.0
+ },
+ {
+ "x": 332.8496799240538,
+ "y": -83.17854915582886,
+ "z": 0.0
+ },
+ {
+ "x": 332.84906939928703,
+ "y": -84.18933328517298,
+ "z": 0.0
+ },
+ {
+ "x": 332.84845887452036,
+ "y": -85.20011741451641,
+ "z": 0.0
+ },
+ {
+ "x": 332.84784834975363,
+ "y": -86.21090154386006,
+ "z": 0.0
+ },
+ {
+ "x": 332.8472378249869,
+ "y": -87.22168567320372,
+ "z": 0.0
+ },
+ {
+ "x": 332.8466273002202,
+ "y": -88.23246980254739,
+ "z": 0.0
+ },
+ {
+ "x": 332.84601677545345,
+ "y": -89.24325393189105,
+ "z": 0.0
+ },
+ {
+ "x": 332.8454062506867,
+ "y": -90.2540380612347,
+ "z": 0.0
+ },
+ {
+ "x": 332.84479572592,
+ "y": -91.26482219057858,
+ "z": 0.0
+ },
+ {
+ "x": 332.8441852011533,
+ "y": -92.27560631992202,
+ "z": 0.0
+ },
+ {
+ "x": 332.8435746763866,
+ "y": -93.28639044926568,
+ "z": 0.0
+ },
+ {
+ "x": 332.84296415161987,
+ "y": -94.29717457860933,
+ "z": 0.0
+ },
+ {
+ "x": 332.84235362685314,
+ "y": -95.30795870795299,
+ "z": 0.0
+ },
+ {
+ "x": 332.8417431020864,
+ "y": -96.31874283729688,
+ "z": 0.0
+ },
+ {
+ "x": 332.84113257731974,
+ "y": -97.32952696664032,
+ "z": 0.0
+ },
+ {
+ "x": 332.840522052553,
+ "y": -98.34031109598396,
+ "z": 0.0
+ },
+ {
+ "x": 332.8399115277863,
+ "y": -99.35109522532763,
+ "z": 0.0
+ },
+ {
+ "x": 332.83930100301956,
+ "y": -100.36187935467129,
+ "z": 0.0
+ },
+ {
+ "x": 332.83869047825283,
+ "y": -101.37266348401494,
+ "z": 0.0
+ },
+ {
+ "x": 332.8380799534861,
+ "y": -102.3834476133586,
+ "z": 0.0
+ },
+ {
+ "x": 332.8374694287194,
+ "y": -103.39423174270226,
+ "z": 0.0
+ },
+ {
+ "x": 332.83685890395265,
+ "y": -104.40501587204615,
+ "z": 0.0
+ },
+ {
+ "x": 332.836248379186,
+ "y": -105.41580000138958,
+ "z": 0.0
+ },
+ {
+ "x": 332.83563785441925,
+ "y": -106.42658413073325,
+ "z": 0.0
+ },
+ {
+ "x": 332.8350273296525,
+ "y": -107.43736826007691,
+ "z": 0.0
+ },
+ {
+ "x": 332.8344168048858,
+ "y": -108.44815238942057,
+ "z": 0.0
+ },
+ {
+ "x": 332.83380628011906,
+ "y": -109.45893651876446,
+ "z": 0.0
+ },
+ {
+ "x": 332.8331957553524,
+ "y": -110.4697206481079,
+ "z": 0.0
+ },
+ {
+ "x": 332.83258523058566,
+ "y": -111.48050477745156,
+ "z": 0.0
+ },
+ {
+ "x": 332.83197470581894,
+ "y": -112.49128890679522,
+ "z": 0.0
+ },
+ {
+ "x": 332.8313641810522,
+ "y": -113.50207303613888,
+ "z": 0.0
+ },
+ {
+ "x": 332.8307536562855,
+ "y": -114.51285716548254,
+ "z": 0.0
+ },
+ {
+ "x": 332.83014313151875,
+ "y": -115.52364129482643,
+ "z": 0.0
+ },
+ {
+ "x": 332.8295326067521,
+ "y": -116.53442542416987,
+ "z": 0.0
+ },
+ {
+ "x": 332.82892208198535,
+ "y": -117.54520955351353,
+ "z": 0.0
+ },
+ {
+ "x": 332.8283115572186,
+ "y": -118.55599368285719,
+ "z": 0.0
+ },
+ {
+ "x": 332.8277010324519,
+ "y": -119.56677781220085,
+ "z": 0.0
+ },
+ {
+ "x": 332.82709050768517,
+ "y": -120.57756194154452,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 87,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 336.8582265411294,
+ "y": -69.02998738871162,
+ "z": 0.0
+ },
+ {
+ "x": 336.8576160163627,
+ "y": -70.04077151805528,
+ "z": 0.0
+ },
+ {
+ "x": 336.85700549159594,
+ "y": -71.05155564739893,
+ "z": 0.0
+ },
+ {
+ "x": 336.85639496682927,
+ "y": -72.06233977674259,
+ "z": 0.0
+ },
+ {
+ "x": 336.85578444206254,
+ "y": -73.07312390608625,
+ "z": 0.0
+ },
+ {
+ "x": 336.8551739172958,
+ "y": -74.08390803542991,
+ "z": 0.0
+ },
+ {
+ "x": 336.8545633925291,
+ "y": -75.09469216477356,
+ "z": 0.0
+ },
+ {
+ "x": 336.85395286776236,
+ "y": -76.10547629411722,
+ "z": 0.0
+ },
+ {
+ "x": 336.85334234299563,
+ "y": -77.11626042346089,
+ "z": 0.0
+ },
+ {
+ "x": 336.8527318182289,
+ "y": -78.12704455280455,
+ "z": 0.0
+ },
+ {
+ "x": 336.8521212934622,
+ "y": -79.1378286821482,
+ "z": 0.0
+ },
+ {
+ "x": 336.8515107686955,
+ "y": -80.14861281149186,
+ "z": 0.0
+ },
+ {
+ "x": 336.8509002439288,
+ "y": -81.15939694083552,
+ "z": 0.0
+ },
+ {
+ "x": 336.85028971916205,
+ "y": -82.17018107017918,
+ "z": 0.0
+ },
+ {
+ "x": 336.8496791943954,
+ "y": -83.18096519952283,
+ "z": 0.0
+ },
+ {
+ "x": 336.8490686696286,
+ "y": -84.19174932886649,
+ "z": 0.0
+ },
+ {
+ "x": 336.8484581448619,
+ "y": -85.20253345821016,
+ "z": 0.0
+ },
+ {
+ "x": 336.8478476200952,
+ "y": -86.2133175875538,
+ "z": 0.0
+ },
+ {
+ "x": 336.84723709532847,
+ "y": -87.22410171689747,
+ "z": 0.0
+ },
+ {
+ "x": 336.84662657056174,
+ "y": -88.23488584624113,
+ "z": 0.0
+ },
+ {
+ "x": 336.846016045795,
+ "y": -89.24566997558479,
+ "z": 0.0
+ },
+ {
+ "x": 336.8454055210283,
+ "y": -90.25645410492844,
+ "z": 0.0
+ },
+ {
+ "x": 336.84479499626156,
+ "y": -91.2672382342721,
+ "z": 0.0
+ },
+ {
+ "x": 336.8441844714949,
+ "y": -92.27802236361576,
+ "z": 0.0
+ },
+ {
+ "x": 336.84357394672816,
+ "y": -93.28880649295942,
+ "z": 0.0
+ },
+ {
+ "x": 336.84296342196143,
+ "y": -94.29959062230307,
+ "z": 0.0
+ },
+ {
+ "x": 336.8423528971947,
+ "y": -95.31037475164673,
+ "z": 0.0
+ },
+ {
+ "x": 336.841742372428,
+ "y": -96.3211588809904,
+ "z": 0.0
+ },
+ {
+ "x": 336.8411318476613,
+ "y": -97.33194301033406,
+ "z": 0.0
+ },
+ {
+ "x": 336.8405213228946,
+ "y": -98.3427271396777,
+ "z": 0.0
+ },
+ {
+ "x": 336.83991079812785,
+ "y": -99.35351126902137,
+ "z": 0.0
+ },
+ {
+ "x": 336.8393002733611,
+ "y": -100.36429539836503,
+ "z": 0.0
+ },
+ {
+ "x": 336.8386897485944,
+ "y": -101.37507952770868,
+ "z": 0.0
+ },
+ {
+ "x": 336.83807922382766,
+ "y": -102.38586365705234,
+ "z": 0.0
+ },
+ {
+ "x": 336.83746869906093,
+ "y": -103.396647786396,
+ "z": 0.0
+ },
+ {
+ "x": 336.8368581742942,
+ "y": -104.40743191573966,
+ "z": 0.0
+ },
+ {
+ "x": 336.83624764952754,
+ "y": -105.41821604508333,
+ "z": 0.0
+ },
+ {
+ "x": 336.8356371247608,
+ "y": -106.42900017442699,
+ "z": 0.0
+ },
+ {
+ "x": 336.8350265999941,
+ "y": -107.43978430377065,
+ "z": 0.0
+ },
+ {
+ "x": 336.83441607522735,
+ "y": -108.45056843311431,
+ "z": 0.0
+ },
+ {
+ "x": 336.8338055504606,
+ "y": -109.46135256245798,
+ "z": 0.0
+ },
+ {
+ "x": 336.83319502569395,
+ "y": -110.47213669180164,
+ "z": 0.0
+ },
+ {
+ "x": 336.8325845009272,
+ "y": -111.4829208211453,
+ "z": 0.0
+ },
+ {
+ "x": 336.8319739761605,
+ "y": -112.49370495048896,
+ "z": 0.0
+ },
+ {
+ "x": 336.83136345139377,
+ "y": -113.50448907983262,
+ "z": 0.0
+ },
+ {
+ "x": 336.83075292662704,
+ "y": -114.51527320917629,
+ "z": 0.0
+ },
+ {
+ "x": 336.8301424018603,
+ "y": -115.52605733851995,
+ "z": 0.0
+ },
+ {
+ "x": 336.82953187709364,
+ "y": -116.53684146786361,
+ "z": 0.0
+ },
+ {
+ "x": 336.8289213523269,
+ "y": -117.54762559720727,
+ "z": 0.0
+ },
+ {
+ "x": 336.8283108275602,
+ "y": -118.55840972655093,
+ "z": 0.0
+ },
+ {
+ "x": 336.82770030279346,
+ "y": -119.5691938558946,
+ "z": 0.0
+ },
+ {
+ "x": 336.82708977802673,
+ "y": -120.57997798523826,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 88,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 338.82708941319754,
+ "y": -120.58118600708514,
+ "z": 0.0
+ },
+ {
+ "x": 338.8276999379642,
+ "y": -119.57040187774146,
+ "z": 0.0
+ },
+ {
+ "x": 338.828310462731,
+ "y": -118.55961774839781,
+ "z": 0.0
+ },
+ {
+ "x": 338.82892098749767,
+ "y": -117.54883361905414,
+ "z": 0.0
+ },
+ {
+ "x": 338.82953151226445,
+ "y": -116.53804948971049,
+ "z": 0.0
+ },
+ {
+ "x": 338.8301420370311,
+ "y": -115.5272653603667,
+ "z": 0.0
+ },
+ {
+ "x": 338.8307525617978,
+ "y": -114.51648123102316,
+ "z": 0.0
+ },
+ {
+ "x": 338.8313630865646,
+ "y": -113.50569710167949,
+ "z": 0.0
+ },
+ {
+ "x": 338.83197361133125,
+ "y": -112.49491297233584,
+ "z": 0.0
+ },
+ {
+ "x": 338.83258413609803,
+ "y": -111.48412884299216,
+ "z": 0.0
+ },
+ {
+ "x": 338.8331946608647,
+ "y": -110.47334471364852,
+ "z": 0.0
+ },
+ {
+ "x": 338.8338051856314,
+ "y": -109.46256058430473,
+ "z": 0.0
+ },
+ {
+ "x": 338.83441571039816,
+ "y": -108.45177645496119,
+ "z": 0.0
+ },
+ {
+ "x": 338.83502623516483,
+ "y": -107.44099232561751,
+ "z": 0.0
+ },
+ {
+ "x": 338.8356367599316,
+ "y": -106.43020819627387,
+ "z": 0.0
+ },
+ {
+ "x": 338.8362472846983,
+ "y": -105.41942406693019,
+ "z": 0.0
+ },
+ {
+ "x": 338.83685780946496,
+ "y": -104.40863993758643,
+ "z": 0.0
+ },
+ {
+ "x": 338.83746833423174,
+ "y": -103.39785580824287,
+ "z": 0.0
+ },
+ {
+ "x": 338.8380788589984,
+ "y": -102.38707167889922,
+ "z": 0.0
+ },
+ {
+ "x": 338.8386893837652,
+ "y": -101.37628754955554,
+ "z": 0.0
+ },
+ {
+ "x": 338.83929990853187,
+ "y": -100.3655034202119,
+ "z": 0.0
+ },
+ {
+ "x": 338.83991043329866,
+ "y": -99.35471929086825,
+ "z": 0.0
+ },
+ {
+ "x": 338.8405209580653,
+ "y": -98.34393516152457,
+ "z": 0.0
+ },
+ {
+ "x": 338.8411314828321,
+ "y": -97.33315103218092,
+ "z": 0.0
+ },
+ {
+ "x": 338.8417420075988,
+ "y": -96.32236690283716,
+ "z": 0.0
+ },
+ {
+ "x": 338.84235253236545,
+ "y": -95.3115827734936,
+ "z": 0.0
+ },
+ {
+ "x": 338.84296305713224,
+ "y": -94.30079864414995,
+ "z": 0.0
+ },
+ {
+ "x": 338.8435735818989,
+ "y": -93.2900145148063,
+ "z": 0.0
+ },
+ {
+ "x": 338.8441841066657,
+ "y": -92.27923038546263,
+ "z": 0.0
+ },
+ {
+ "x": 338.84479463143236,
+ "y": -91.26844625611886,
+ "z": 0.0
+ },
+ {
+ "x": 338.84540515619904,
+ "y": -90.2576621267753,
+ "z": 0.0
+ },
+ {
+ "x": 338.8460156809658,
+ "y": -89.24687799743165,
+ "z": 0.0
+ },
+ {
+ "x": 338.8466262057325,
+ "y": -88.236093868088,
+ "z": 0.0
+ },
+ {
+ "x": 338.8472367304993,
+ "y": -87.22530973874433,
+ "z": 0.0
+ },
+ {
+ "x": 338.84784725526595,
+ "y": -86.21452560940068,
+ "z": 0.0
+ },
+ {
+ "x": 338.84845778003273,
+ "y": -85.20374148005703,
+ "z": 0.0
+ },
+ {
+ "x": 338.8490683047994,
+ "y": -84.19295735071324,
+ "z": 0.0
+ },
+ {
+ "x": 338.8496788295662,
+ "y": -83.18217322136982,
+ "z": 0.0
+ },
+ {
+ "x": 338.85028935433286,
+ "y": -82.17138909202595,
+ "z": 0.0
+ },
+ {
+ "x": 338.85089987909953,
+ "y": -81.16060496268238,
+ "z": 0.0
+ },
+ {
+ "x": 338.8515104038663,
+ "y": -80.14982083333874,
+ "z": 0.0
+ },
+ {
+ "x": 338.852120928633,
+ "y": -79.13903670399495,
+ "z": 0.0
+ },
+ {
+ "x": 338.85273145339966,
+ "y": -78.12825257465141,
+ "z": 0.0
+ },
+ {
+ "x": 338.85334197816644,
+ "y": -77.11746844530776,
+ "z": 0.0
+ },
+ {
+ "x": 338.8539525029331,
+ "y": -76.10668431596409,
+ "z": 0.0
+ },
+ {
+ "x": 338.8545630276999,
+ "y": -75.09590018662044,
+ "z": 0.0
+ },
+ {
+ "x": 338.85517355246657,
+ "y": -74.08511605727679,
+ "z": 0.0
+ },
+ {
+ "x": 338.85578407723335,
+ "y": -73.07433192793312,
+ "z": 0.0
+ },
+ {
+ "x": 338.856394602,
+ "y": -72.06354779858947,
+ "z": 0.0
+ },
+ {
+ "x": 338.8570051267667,
+ "y": -71.05276366924568,
+ "z": 0.0
+ },
+ {
+ "x": 338.8576156515335,
+ "y": -70.04197953990226,
+ "z": 0.0
+ },
+ {
+ "x": 338.85822617630015,
+ "y": -69.03119541055838,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 89,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 334.85822690595865,
+ "y": -69.02877936686485,
+ "z": 0.0
+ },
+ {
+ "x": 334.857616381192,
+ "y": -70.0395634962083,
+ "z": 0.0
+ },
+ {
+ "x": 334.8570058564252,
+ "y": -71.05034762555218,
+ "z": 0.0
+ },
+ {
+ "x": 334.8563953316585,
+ "y": -72.06113175489571,
+ "z": 0.0
+ },
+ {
+ "x": 334.85578480689173,
+ "y": -73.07191588423939,
+ "z": 0.0
+ },
+ {
+ "x": 334.85517428212506,
+ "y": -74.08270001358304,
+ "z": 0.0
+ },
+ {
+ "x": 334.8545637573583,
+ "y": -75.09348414292668,
+ "z": 0.0
+ },
+ {
+ "x": 334.8539532325916,
+ "y": -76.10426827227036,
+ "z": 0.0
+ },
+ {
+ "x": 334.8533427078248,
+ "y": -77.11505240161401,
+ "z": 0.0
+ },
+ {
+ "x": 334.85273218305815,
+ "y": -78.12583653095768,
+ "z": 0.0
+ },
+ {
+ "x": 334.85212165829137,
+ "y": -79.13662066030145,
+ "z": 0.0
+ },
+ {
+ "x": 334.8515111335247,
+ "y": -80.14740478964498,
+ "z": 0.0
+ },
+ {
+ "x": 334.850900608758,
+ "y": -81.15818891898866,
+ "z": 0.0
+ },
+ {
+ "x": 334.85029008399124,
+ "y": -82.16897304833242,
+ "z": 0.0
+ },
+ {
+ "x": 334.84967955922457,
+ "y": -83.17975717767584,
+ "z": 0.0
+ },
+ {
+ "x": 334.8490690344578,
+ "y": -84.19054130701974,
+ "z": 0.0
+ },
+ {
+ "x": 334.8484585096911,
+ "y": -85.20132543636328,
+ "z": 0.0
+ },
+ {
+ "x": 334.84784798492444,
+ "y": -86.21210956570692,
+ "z": 0.0
+ },
+ {
+ "x": 334.84723746015766,
+ "y": -87.2228936950506,
+ "z": 0.0
+ },
+ {
+ "x": 334.846626935391,
+ "y": -88.23367782439425,
+ "z": 0.0
+ },
+ {
+ "x": 334.8460164106242,
+ "y": -89.24446195373793,
+ "z": 0.0
+ },
+ {
+ "x": 334.84540588585753,
+ "y": -90.25524608308157,
+ "z": 0.0
+ },
+ {
+ "x": 334.84479536109075,
+ "y": -91.26603021242533,
+ "z": 0.0
+ },
+ {
+ "x": 334.8441848363241,
+ "y": -92.2768143417689,
+ "z": 0.0
+ },
+ {
+ "x": 334.8435743115574,
+ "y": -93.28759847111255,
+ "z": 0.0
+ },
+ {
+ "x": 334.8429637867906,
+ "y": -94.2983826004562,
+ "z": 0.0
+ },
+ {
+ "x": 334.84235326202395,
+ "y": -95.30916672979987,
+ "z": 0.0
+ },
+ {
+ "x": 334.84174273725716,
+ "y": -96.31995085914363,
+ "z": 0.0
+ },
+ {
+ "x": 334.8411322124905,
+ "y": -97.3307349884872,
+ "z": 0.0
+ },
+ {
+ "x": 334.8405216877238,
+ "y": -98.34151911783084,
+ "z": 0.0
+ },
+ {
+ "x": 334.83991116295704,
+ "y": -99.35230324717449,
+ "z": 0.0
+ },
+ {
+ "x": 334.83930063819037,
+ "y": -100.36308737651817,
+ "z": 0.0
+ },
+ {
+ "x": 334.8386901134236,
+ "y": -101.37387150586181,
+ "z": 0.0
+ },
+ {
+ "x": 334.8380795886569,
+ "y": -102.38465563520546,
+ "z": 0.0
+ },
+ {
+ "x": 334.8374690638901,
+ "y": -103.39543976454914,
+ "z": 0.0
+ },
+ {
+ "x": 334.83685853912345,
+ "y": -104.4062238938929,
+ "z": 0.0
+ },
+ {
+ "x": 334.8362480143568,
+ "y": -105.41700802323646,
+ "z": 0.0
+ },
+ {
+ "x": 334.83563748959,
+ "y": -106.42779215258011,
+ "z": 0.0
+ },
+ {
+ "x": 334.8350269648233,
+ "y": -107.43857628192379,
+ "z": 0.0
+ },
+ {
+ "x": 334.83441644005654,
+ "y": -108.44936041126743,
+ "z": 0.0
+ },
+ {
+ "x": 334.8338059152899,
+ "y": -109.46014454061122,
+ "z": 0.0
+ },
+ {
+ "x": 334.8331953905232,
+ "y": -110.47092866995476,
+ "z": 0.0
+ },
+ {
+ "x": 334.8325848657564,
+ "y": -111.48171279929844,
+ "z": 0.0
+ },
+ {
+ "x": 334.83197434098975,
+ "y": -112.49249692864208,
+ "z": 0.0
+ },
+ {
+ "x": 334.83136381622296,
+ "y": -113.50328105798576,
+ "z": 0.0
+ },
+ {
+ "x": 334.8307532914563,
+ "y": -114.51406518732941,
+ "z": 0.0
+ },
+ {
+ "x": 334.8301427666895,
+ "y": -115.5248493166732,
+ "z": 0.0
+ },
+ {
+ "x": 334.82953224192283,
+ "y": -116.53563344601673,
+ "z": 0.0
+ },
+ {
+ "x": 334.82892171715616,
+ "y": -117.54641757536041,
+ "z": 0.0
+ },
+ {
+ "x": 334.8283111923894,
+ "y": -118.55720170470406,
+ "z": 0.0
+ },
+ {
+ "x": 334.8277006676227,
+ "y": -119.56798583404773,
+ "z": 0.0
+ },
+ {
+ "x": 334.8270901428559,
+ "y": -120.57876996339138,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 90,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 340.78778605758094,
+ "y": -185.65238215921298,
+ "z": 0.0
+ },
+ {
+ "x": 340.7884045058386,
+ "y": -184.62847990696335,
+ "z": 0.0
+ },
+ {
+ "x": 340.78902295409637,
+ "y": -183.60457765471395,
+ "z": 0.0
+ },
+ {
+ "x": 340.789641402354,
+ "y": -182.5806754024639,
+ "z": 0.0
+ },
+ {
+ "x": 340.7902598506117,
+ "y": -181.5567731502145,
+ "z": 0.0
+ },
+ {
+ "x": 340.7908782988694,
+ "y": -180.5328708979651,
+ "z": 0.0
+ },
+ {
+ "x": 340.7914967471271,
+ "y": -179.50896864571524,
+ "z": 0.0
+ },
+ {
+ "x": 340.7921151953848,
+ "y": -178.48506639346562,
+ "z": 0.0
+ },
+ {
+ "x": 340.79273364364246,
+ "y": -177.461164141216,
+ "z": 0.0
+ },
+ {
+ "x": 340.79335209190015,
+ "y": -176.4372618889664,
+ "z": 0.0
+ },
+ {
+ "x": 340.7939705401579,
+ "y": -175.413359636717,
+ "z": 0.0
+ },
+ {
+ "x": 340.79458898841557,
+ "y": -174.38945738446714,
+ "z": 0.0
+ },
+ {
+ "x": 340.79520743667325,
+ "y": -173.3655551322175,
+ "z": 0.0
+ },
+ {
+ "x": 340.79582588493093,
+ "y": -172.34165287996788,
+ "z": 0.0
+ },
+ {
+ "x": 340.7964443331886,
+ "y": -171.31775062771825,
+ "z": 0.0
+ },
+ {
+ "x": 340.79706278144636,
+ "y": -170.29384837546888,
+ "z": 0.0
+ },
+ {
+ "x": 340.79768122970404,
+ "y": -169.26994612321903,
+ "z": 0.0
+ },
+ {
+ "x": 340.7982996779617,
+ "y": -168.2460438709694,
+ "z": 0.0
+ },
+ {
+ "x": 340.7989181262194,
+ "y": -167.22214161871977,
+ "z": 0.0
+ },
+ {
+ "x": 340.7995365744771,
+ "y": -166.19823936647015,
+ "z": 0.0
+ },
+ {
+ "x": 340.8001550227348,
+ "y": -165.17433711422075,
+ "z": 0.0
+ },
+ {
+ "x": 340.8007734709925,
+ "y": -164.1504348619709,
+ "z": 0.0
+ },
+ {
+ "x": 340.8013919192502,
+ "y": -163.1265326097213,
+ "z": 0.0
+ },
+ {
+ "x": 340.80201036750793,
+ "y": -162.1026303574719,
+ "z": 0.0
+ },
+ {
+ "x": 340.8026288157656,
+ "y": -161.07872810522204,
+ "z": 0.0
+ },
+ {
+ "x": 340.8032472640233,
+ "y": -160.0548258529724,
+ "z": 0.0
+ },
+ {
+ "x": 340.803865712281,
+ "y": -159.0309236007228,
+ "z": 0.0
+ },
+ {
+ "x": 340.80448416053866,
+ "y": -158.0070213484732,
+ "z": 0.0
+ },
+ {
+ "x": 340.8051026087964,
+ "y": -156.9831190962238,
+ "z": 0.0
+ },
+ {
+ "x": 340.8057210570541,
+ "y": -155.95921684397393,
+ "z": 0.0
+ },
+ {
+ "x": 340.80633950531177,
+ "y": -154.9353145917243,
+ "z": 0.0
+ },
+ {
+ "x": 340.80695795356945,
+ "y": -153.91141233947468,
+ "z": 0.0
+ },
+ {
+ "x": 340.80757640182713,
+ "y": -152.88751008722505,
+ "z": 0.0
+ },
+ {
+ "x": 340.8081948500849,
+ "y": -151.86360783497565,
+ "z": 0.0
+ },
+ {
+ "x": 340.80881329834256,
+ "y": -150.83970558272583,
+ "z": 0.0
+ },
+ {
+ "x": 340.80943174660024,
+ "y": -149.8158033304762,
+ "z": 0.0
+ },
+ {
+ "x": 340.8100501948579,
+ "y": -148.79190107822657,
+ "z": 0.0
+ },
+ {
+ "x": 340.8106686431156,
+ "y": -147.76799882597695,
+ "z": 0.0
+ },
+ {
+ "x": 340.81128709137334,
+ "y": -146.74409657372755,
+ "z": 0.0
+ },
+ {
+ "x": 340.81190553963097,
+ "y": -145.7201943214775,
+ "z": 0.0
+ },
+ {
+ "x": 340.8125239878887,
+ "y": -144.69629206922832,
+ "z": 0.0
+ },
+ {
+ "x": 340.8131424361464,
+ "y": -143.67238981697847,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 91,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 332.81314389546327,
+ "y": -143.66755772959112,
+ "z": 0.0
+ },
+ {
+ "x": 332.8125254472056,
+ "y": -144.69145998184052,
+ "z": 0.0
+ },
+ {
+ "x": 332.81190699894785,
+ "y": -145.7153622340906,
+ "z": 0.0
+ },
+ {
+ "x": 332.8112885506902,
+ "y": -146.73926448633975,
+ "z": 0.0
+ },
+ {
+ "x": 332.8106701024325,
+ "y": -147.7631667385896,
+ "z": 0.0
+ },
+ {
+ "x": 332.8100516541748,
+ "y": -148.78706899083923,
+ "z": 0.0
+ },
+ {
+ "x": 332.8094332059171,
+ "y": -149.81097124308886,
+ "z": 0.0
+ },
+ {
+ "x": 332.80881475765943,
+ "y": -150.83487349533848,
+ "z": 0.0
+ },
+ {
+ "x": 332.80819630940175,
+ "y": -151.85877574758786,
+ "z": 0.0
+ },
+ {
+ "x": 332.807577861144,
+ "y": -152.8826779998377,
+ "z": 0.0
+ },
+ {
+ "x": 332.80695941288633,
+ "y": -153.90658025208734,
+ "z": 0.0
+ },
+ {
+ "x": 332.80634096462865,
+ "y": -154.93048250433696,
+ "z": 0.0
+ },
+ {
+ "x": 332.80572251637096,
+ "y": -155.9543847565866,
+ "z": 0.0
+ },
+ {
+ "x": 332.8051040681133,
+ "y": -156.978287008836,
+ "z": 0.0
+ },
+ {
+ "x": 332.80448561985554,
+ "y": -158.00218926108585,
+ "z": 0.0
+ },
+ {
+ "x": 332.80386717159786,
+ "y": -159.02609151333544,
+ "z": 0.0
+ },
+ {
+ "x": 332.8032487233402,
+ "y": -160.04999376558507,
+ "z": 0.0
+ },
+ {
+ "x": 332.8026302750825,
+ "y": -161.0738960178347,
+ "z": 0.0
+ },
+ {
+ "x": 332.8020118268248,
+ "y": -162.0977982700841,
+ "z": 0.0
+ },
+ {
+ "x": 332.80139337856707,
+ "y": -163.12170052233395,
+ "z": 0.0
+ },
+ {
+ "x": 332.8007749303094,
+ "y": -164.14560277458355,
+ "z": 0.0
+ },
+ {
+ "x": 332.8001564820517,
+ "y": -165.16950502683295,
+ "z": 0.0
+ },
+ {
+ "x": 332.79953803379397,
+ "y": -166.1934072790828,
+ "z": 0.0
+ },
+ {
+ "x": 332.7989195855363,
+ "y": -167.21730953133243,
+ "z": 0.0
+ },
+ {
+ "x": 332.7983011372786,
+ "y": -168.24121178358206,
+ "z": 0.0
+ },
+ {
+ "x": 332.7976826890209,
+ "y": -169.2651140358317,
+ "z": 0.0
+ },
+ {
+ "x": 332.79706424076323,
+ "y": -170.2890162880811,
+ "z": 0.0
+ },
+ {
+ "x": 332.7964457925055,
+ "y": -171.3129185403309,
+ "z": 0.0
+ },
+ {
+ "x": 332.7958273442478,
+ "y": -172.33682079258054,
+ "z": 0.0
+ },
+ {
+ "x": 332.79520889599013,
+ "y": -173.36072304483017,
+ "z": 0.0
+ },
+ {
+ "x": 332.79459044773245,
+ "y": -174.3846252970798,
+ "z": 0.0
+ },
+ {
+ "x": 332.79397199947476,
+ "y": -175.4085275493292,
+ "z": 0.0
+ },
+ {
+ "x": 332.793353551217,
+ "y": -176.43242980157905,
+ "z": 0.0
+ },
+ {
+ "x": 332.79273510295934,
+ "y": -177.45633205382865,
+ "z": 0.0
+ },
+ {
+ "x": 332.79211665470166,
+ "y": -178.48023430607827,
+ "z": 0.0
+ },
+ {
+ "x": 332.791498206444,
+ "y": -179.5041365583279,
+ "z": 0.0
+ },
+ {
+ "x": 332.7908797581863,
+ "y": -180.5280388105773,
+ "z": 0.0
+ },
+ {
+ "x": 332.79026130992855,
+ "y": -181.55194106282715,
+ "z": 0.0
+ },
+ {
+ "x": 332.78964286167087,
+ "y": -182.575843315077,
+ "z": 0.0
+ },
+ {
+ "x": 332.78902441341324,
+ "y": -183.59974556732615,
+ "z": 0.0
+ },
+ {
+ "x": 332.7884059651555,
+ "y": -184.623647819576,
+ "z": 0.0
+ },
+ {
+ "x": 332.7877875168978,
+ "y": -185.64755007182563,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 92,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 336.81314316580483,
+ "y": -143.6699737732848,
+ "z": 0.0
+ },
+ {
+ "x": 336.81252471754715,
+ "y": -144.69387602553442,
+ "z": 0.0
+ },
+ {
+ "x": 336.8119062692894,
+ "y": -145.71777827778405,
+ "z": 0.0
+ },
+ {
+ "x": 336.8112878210318,
+ "y": -146.74168053003365,
+ "z": 0.0
+ },
+ {
+ "x": 336.81066937277404,
+ "y": -147.76558278228327,
+ "z": 0.0
+ },
+ {
+ "x": 336.81005092451636,
+ "y": -148.7894850345329,
+ "z": 0.0
+ },
+ {
+ "x": 336.8094324762587,
+ "y": -149.81338728678253,
+ "z": 0.0
+ },
+ {
+ "x": 336.808814028001,
+ "y": -150.83728953903216,
+ "z": 0.0
+ },
+ {
+ "x": 336.8081955797433,
+ "y": -151.86119179128175,
+ "z": 0.0
+ },
+ {
+ "x": 336.8075771314856,
+ "y": -152.88509404353138,
+ "z": 0.0
+ },
+ {
+ "x": 336.8069586832279,
+ "y": -153.908996295781,
+ "z": 0.0
+ },
+ {
+ "x": 336.8063402349702,
+ "y": -154.93289854803064,
+ "z": 0.0
+ },
+ {
+ "x": 336.8057217867125,
+ "y": -155.95680080028026,
+ "z": 0.0
+ },
+ {
+ "x": 336.80510333845484,
+ "y": -156.9807030525299,
+ "z": 0.0
+ },
+ {
+ "x": 336.8044848901971,
+ "y": -158.00460530477952,
+ "z": 0.0
+ },
+ {
+ "x": 336.8038664419394,
+ "y": -159.02850755702912,
+ "z": 0.0
+ },
+ {
+ "x": 336.80324799368174,
+ "y": -160.05240980927874,
+ "z": 0.0
+ },
+ {
+ "x": 336.80262954542405,
+ "y": -161.07631206152837,
+ "z": 0.0
+ },
+ {
+ "x": 336.80201109716637,
+ "y": -162.100214313778,
+ "z": 0.0
+ },
+ {
+ "x": 336.80139264890863,
+ "y": -163.12411656602762,
+ "z": 0.0
+ },
+ {
+ "x": 336.80077420065095,
+ "y": -164.14801881827722,
+ "z": 0.0
+ },
+ {
+ "x": 336.80015575239327,
+ "y": -165.17192107052685,
+ "z": 0.0
+ },
+ {
+ "x": 336.7995373041355,
+ "y": -166.19582332277648,
+ "z": 0.0
+ },
+ {
+ "x": 336.79891885587784,
+ "y": -167.2197255750261,
+ "z": 0.0
+ },
+ {
+ "x": 336.79830040762016,
+ "y": -168.24362782727573,
+ "z": 0.0
+ },
+ {
+ "x": 336.7976819593625,
+ "y": -169.26753007952536,
+ "z": 0.0
+ },
+ {
+ "x": 336.7970635111048,
+ "y": -170.29143233177498,
+ "z": 0.0
+ },
+ {
+ "x": 336.79644506284706,
+ "y": -171.31533458402458,
+ "z": 0.0
+ },
+ {
+ "x": 336.7958266145894,
+ "y": -172.3392368362742,
+ "z": 0.0
+ },
+ {
+ "x": 336.7952081663317,
+ "y": -173.36313908852384,
+ "z": 0.0
+ },
+ {
+ "x": 336.794589718074,
+ "y": -174.38704134077346,
+ "z": 0.0
+ },
+ {
+ "x": 336.7939712698163,
+ "y": -175.4109435930231,
+ "z": 0.0
+ },
+ {
+ "x": 336.7933528215586,
+ "y": -176.43484584527272,
+ "z": 0.0
+ },
+ {
+ "x": 336.7927343733009,
+ "y": -177.45874809752232,
+ "z": 0.0
+ },
+ {
+ "x": 336.7921159250432,
+ "y": -178.48265034977194,
+ "z": 0.0
+ },
+ {
+ "x": 336.79149747678554,
+ "y": -179.50655260202157,
+ "z": 0.0
+ },
+ {
+ "x": 336.79087902852785,
+ "y": -180.5304548542712,
+ "z": 0.0
+ },
+ {
+ "x": 336.7902605802701,
+ "y": -181.55435710652083,
+ "z": 0.0
+ },
+ {
+ "x": 336.78964213201243,
+ "y": -182.57825935877045,
+ "z": 0.0
+ },
+ {
+ "x": 336.7890236837548,
+ "y": -183.60216161102005,
+ "z": 0.0
+ },
+ {
+ "x": 336.78840523549707,
+ "y": -184.62606386326968,
+ "z": 0.0
+ },
+ {
+ "x": 336.7877867872394,
+ "y": -185.6499661155193,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 93,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 338.78778642241014,
+ "y": -185.65117413736613,
+ "z": 0.0
+ },
+ {
+ "x": 338.7884048706678,
+ "y": -184.6272718851165,
+ "z": 0.0
+ },
+ {
+ "x": 338.7890233189256,
+ "y": -183.603369632867,
+ "z": 0.0
+ },
+ {
+ "x": 338.7896417671832,
+ "y": -182.5794673806172,
+ "z": 0.0
+ },
+ {
+ "x": 338.79026021544087,
+ "y": -181.55556512836768,
+ "z": 0.0
+ },
+ {
+ "x": 338.79087866369866,
+ "y": -180.53166287611816,
+ "z": 0.0
+ },
+ {
+ "x": 338.79149711195635,
+ "y": -179.50776062386842,
+ "z": 0.0
+ },
+ {
+ "x": 338.79211556021403,
+ "y": -178.4838583716188,
+ "z": 0.0
+ },
+ {
+ "x": 338.7927340084717,
+ "y": -177.45995611936917,
+ "z": 0.0
+ },
+ {
+ "x": 338.7933524567294,
+ "y": -176.43605386711954,
+ "z": 0.0
+ },
+ {
+ "x": 338.7939709049871,
+ "y": -175.41215161487003,
+ "z": 0.0
+ },
+ {
+ "x": 338.79458935324476,
+ "y": -174.3882493626203,
+ "z": 0.0
+ },
+ {
+ "x": 338.79520780150244,
+ "y": -173.36434711037066,
+ "z": 0.0
+ },
+ {
+ "x": 338.7958262497601,
+ "y": -172.34044485812103,
+ "z": 0.0
+ },
+ {
+ "x": 338.7964446980178,
+ "y": -171.3165426058714,
+ "z": 0.0
+ },
+ {
+ "x": 338.7970631462756,
+ "y": -170.29264035362195,
+ "z": 0.0
+ },
+ {
+ "x": 338.7976815945333,
+ "y": -169.2687381013722,
+ "z": 0.0
+ },
+ {
+ "x": 338.79830004279097,
+ "y": -168.24483584912258,
+ "z": 0.0
+ },
+ {
+ "x": 338.79891849104865,
+ "y": -167.22093359687295,
+ "z": 0.0
+ },
+ {
+ "x": 338.79953693930634,
+ "y": -166.19703134462333,
+ "z": 0.0
+ },
+ {
+ "x": 338.800155387564,
+ "y": -165.1731290923738,
+ "z": 0.0
+ },
+ {
+ "x": 338.8007738358217,
+ "y": -164.14922684012407,
+ "z": 0.0
+ },
+ {
+ "x": 338.8013922840794,
+ "y": -163.12532458787445,
+ "z": 0.0
+ },
+ {
+ "x": 338.8020107323372,
+ "y": -162.10142233562493,
+ "z": 0.0
+ },
+ {
+ "x": 338.80262918059486,
+ "y": -161.0775200833752,
+ "z": 0.0
+ },
+ {
+ "x": 338.80324762885255,
+ "y": -160.05361783112556,
+ "z": 0.0
+ },
+ {
+ "x": 338.80386607711023,
+ "y": -159.02971557887594,
+ "z": 0.0
+ },
+ {
+ "x": 338.8044845253679,
+ "y": -158.00581332662637,
+ "z": 0.0
+ },
+ {
+ "x": 338.8051029736256,
+ "y": -156.98191107437685,
+ "z": 0.0
+ },
+ {
+ "x": 338.8057214218833,
+ "y": -155.9580088221271,
+ "z": 0.0
+ },
+ {
+ "x": 338.80633987014096,
+ "y": -154.93410656987749,
+ "z": 0.0
+ },
+ {
+ "x": 338.80695831839864,
+ "y": -153.91020431762786,
+ "z": 0.0
+ },
+ {
+ "x": 338.8075767666563,
+ "y": -152.88630206537823,
+ "z": 0.0
+ },
+ {
+ "x": 338.8081952149141,
+ "y": -151.86239981312872,
+ "z": 0.0
+ },
+ {
+ "x": 338.8088136631718,
+ "y": -150.83849756087898,
+ "z": 0.0
+ },
+ {
+ "x": 338.8094321114295,
+ "y": -149.81459530862935,
+ "z": 0.0
+ },
+ {
+ "x": 338.81005055968717,
+ "y": -148.79069305637972,
+ "z": 0.0
+ },
+ {
+ "x": 338.81066900794485,
+ "y": -147.7667908041301,
+ "z": 0.0
+ },
+ {
+ "x": 338.81128745620254,
+ "y": -146.74288855188058,
+ "z": 0.0
+ },
+ {
+ "x": 338.8119059044602,
+ "y": -145.71898629963079,
+ "z": 0.0
+ },
+ {
+ "x": 338.8125243527179,
+ "y": -144.69508404738139,
+ "z": 0.0
+ },
+ {
+ "x": 338.8131428009756,
+ "y": -143.67118179513164,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 94,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 334.8131435306341,
+ "y": -143.66876575143795,
+ "z": 0.0
+ },
+ {
+ "x": 334.8125250823764,
+ "y": -144.69266800368746,
+ "z": 0.0
+ },
+ {
+ "x": 334.8119066341186,
+ "y": -145.7165702559373,
+ "z": 0.0
+ },
+ {
+ "x": 334.81128818586103,
+ "y": -146.7404725081867,
+ "z": 0.0
+ },
+ {
+ "x": 334.81066973760323,
+ "y": -147.76437476043645,
+ "z": 0.0
+ },
+ {
+ "x": 334.81005128934555,
+ "y": -148.78827701268608,
+ "z": 0.0
+ },
+ {
+ "x": 334.80943284108787,
+ "y": -149.8121792649357,
+ "z": 0.0
+ },
+ {
+ "x": 334.8088143928302,
+ "y": -150.83608151718533,
+ "z": 0.0
+ },
+ {
+ "x": 334.8081959445725,
+ "y": -151.8599837694348,
+ "z": 0.0
+ },
+ {
+ "x": 334.8075774963148,
+ "y": -152.88388602168453,
+ "z": 0.0
+ },
+ {
+ "x": 334.80695904805714,
+ "y": -153.90778827393416,
+ "z": 0.0
+ },
+ {
+ "x": 334.80634059979946,
+ "y": -154.9316905261838,
+ "z": 0.0
+ },
+ {
+ "x": 334.8057221515418,
+ "y": -155.9555927784334,
+ "z": 0.0
+ },
+ {
+ "x": 334.8051037032841,
+ "y": -156.97949503068293,
+ "z": 0.0
+ },
+ {
+ "x": 334.8044852550263,
+ "y": -158.00339728293267,
+ "z": 0.0
+ },
+ {
+ "x": 334.8038668067686,
+ "y": -159.0272995351823,
+ "z": 0.0
+ },
+ {
+ "x": 334.8032483585109,
+ "y": -160.05120178743192,
+ "z": 0.0
+ },
+ {
+ "x": 334.80262991025324,
+ "y": -161.07510403968155,
+ "z": 0.0
+ },
+ {
+ "x": 334.80201146199556,
+ "y": -162.09900629193106,
+ "z": 0.0
+ },
+ {
+ "x": 334.8013930137379,
+ "y": -163.1229085441808,
+ "z": 0.0
+ },
+ {
+ "x": 334.8007745654802,
+ "y": -164.14681079643037,
+ "z": 0.0
+ },
+ {
+ "x": 334.8001561172225,
+ "y": -165.1707130486799,
+ "z": 0.0
+ },
+ {
+ "x": 334.7995376689647,
+ "y": -166.19461530092963,
+ "z": 0.0
+ },
+ {
+ "x": 334.79891922070703,
+ "y": -167.21851755317925,
+ "z": 0.0
+ },
+ {
+ "x": 334.79830077244935,
+ "y": -168.24241980542888,
+ "z": 0.0
+ },
+ {
+ "x": 334.79768232419167,
+ "y": -169.2663220576785,
+ "z": 0.0
+ },
+ {
+ "x": 334.797063875934,
+ "y": -170.29022430992802,
+ "z": 0.0
+ },
+ {
+ "x": 334.7964454276763,
+ "y": -171.31412656217776,
+ "z": 0.0
+ },
+ {
+ "x": 334.7958269794186,
+ "y": -172.3380288144274,
+ "z": 0.0
+ },
+ {
+ "x": 334.79520853116094,
+ "y": -173.36193106667702,
+ "z": 0.0
+ },
+ {
+ "x": 334.79459008290326,
+ "y": -174.38583331892664,
+ "z": 0.0
+ },
+ {
+ "x": 334.7939716346456,
+ "y": -175.40973557117616,
+ "z": 0.0
+ },
+ {
+ "x": 334.7933531863878,
+ "y": -176.4336378234259,
+ "z": 0.0
+ },
+ {
+ "x": 334.7927347381301,
+ "y": -177.45754007567547,
+ "z": 0.0
+ },
+ {
+ "x": 334.7921162898724,
+ "y": -178.4814423279251,
+ "z": 0.0
+ },
+ {
+ "x": 334.7914978416147,
+ "y": -179.50534458017472,
+ "z": 0.0
+ },
+ {
+ "x": 334.79087939335705,
+ "y": -180.52924683242423,
+ "z": 0.0
+ },
+ {
+ "x": 334.79026094509936,
+ "y": -181.55314908467398,
+ "z": 0.0
+ },
+ {
+ "x": 334.7896424968417,
+ "y": -182.57705133692372,
+ "z": 0.0
+ },
+ {
+ "x": 334.789024048584,
+ "y": -183.60095358917312,
+ "z": 0.0
+ },
+ {
+ "x": 334.7884056003263,
+ "y": -184.62485584142286,
+ "z": 0.0
+ },
+ {
+ "x": 334.78778715206863,
+ "y": -185.64875809367248,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 95,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 340.70817741787323,
+ "y": -317.4523581169669,
+ "z": 0.0
+ },
+ {
+ "x": 340.70878871079753,
+ "y": -316.44030222681437,
+ "z": 0.0
+ },
+ {
+ "x": 340.7094000037218,
+ "y": -315.4282463366616,
+ "z": 0.0
+ },
+ {
+ "x": 340.7100112966461,
+ "y": -314.4161904465093,
+ "z": 0.0
+ },
+ {
+ "x": 340.7106225895704,
+ "y": -313.4041345563567,
+ "z": 0.0
+ },
+ {
+ "x": 340.71123388249464,
+ "y": -312.392078666204,
+ "z": 0.0
+ },
+ {
+ "x": 340.71184517541894,
+ "y": -311.3800227760517,
+ "z": 0.0
+ },
+ {
+ "x": 340.7124564683432,
+ "y": -310.3679668858989,
+ "z": 0.0
+ },
+ {
+ "x": 340.7130677612675,
+ "y": -309.3559109957466,
+ "z": 0.0
+ },
+ {
+ "x": 340.71367905419174,
+ "y": -308.34385510559383,
+ "z": 0.0
+ },
+ {
+ "x": 340.71429034711605,
+ "y": -307.33179921544155,
+ "z": 0.0
+ },
+ {
+ "x": 340.7149016400403,
+ "y": -306.3197433252888,
+ "z": 0.0
+ },
+ {
+ "x": 340.7155129329646,
+ "y": -305.3076874351365,
+ "z": 0.0
+ },
+ {
+ "x": 340.7161242258889,
+ "y": -304.29563154498396,
+ "z": 0.0
+ },
+ {
+ "x": 340.71673551881315,
+ "y": -303.28357565483117,
+ "z": 0.0
+ },
+ {
+ "x": 340.71734681173746,
+ "y": -302.2715197646789,
+ "z": 0.0
+ },
+ {
+ "x": 340.7179581046617,
+ "y": -301.25946387452615,
+ "z": 0.0
+ },
+ {
+ "x": 340.718569397586,
+ "y": -300.2474079843738,
+ "z": 0.0
+ },
+ {
+ "x": 340.71918069051026,
+ "y": -299.23535209422107,
+ "z": 0.0
+ },
+ {
+ "x": 340.71979198343456,
+ "y": -298.22329620406873,
+ "z": 0.0
+ },
+ {
+ "x": 340.7204032763588,
+ "y": -297.211240313916,
+ "z": 0.0
+ },
+ {
+ "x": 340.7210145692831,
+ "y": -296.1991844237637,
+ "z": 0.0
+ },
+ {
+ "x": 340.7216258622074,
+ "y": -295.18712853361114,
+ "z": 0.0
+ },
+ {
+ "x": 340.72223715513167,
+ "y": -294.1750726434584,
+ "z": 0.0
+ },
+ {
+ "x": 340.72284844805597,
+ "y": -293.16301675330607,
+ "z": 0.0
+ },
+ {
+ "x": 340.7234597409802,
+ "y": -292.15096086315333,
+ "z": 0.0
+ },
+ {
+ "x": 340.7240710339045,
+ "y": -291.13890497300105,
+ "z": 0.0
+ },
+ {
+ "x": 340.72468232682877,
+ "y": -290.12684908284825,
+ "z": 0.0
+ },
+ {
+ "x": 340.7252936197531,
+ "y": -289.11479319269597,
+ "z": 0.0
+ },
+ {
+ "x": 340.7259049126773,
+ "y": -288.10273730254323,
+ "z": 0.0
+ },
+ {
+ "x": 340.7265162056016,
+ "y": -287.0906814123909,
+ "z": 0.0
+ },
+ {
+ "x": 340.72712749852593,
+ "y": -286.0786255222384,
+ "z": 0.0
+ },
+ {
+ "x": 340.7277387914502,
+ "y": -285.0665696320856,
+ "z": 0.0
+ },
+ {
+ "x": 340.7283500843745,
+ "y": -284.0545137419333,
+ "z": 0.0
+ },
+ {
+ "x": 340.72896137729873,
+ "y": -283.04245785178057,
+ "z": 0.0
+ },
+ {
+ "x": 340.72957267022304,
+ "y": -282.03040196162823,
+ "z": 0.0
+ },
+ {
+ "x": 340.7301839631473,
+ "y": -281.0183460714755,
+ "z": 0.0
+ },
+ {
+ "x": 340.7307952560716,
+ "y": -280.00629018132315,
+ "z": 0.0
+ },
+ {
+ "x": 340.73140654899584,
+ "y": -278.9942342911704,
+ "z": 0.0
+ },
+ {
+ "x": 340.73201784192014,
+ "y": -277.98217840101813,
+ "z": 0.0
+ },
+ {
+ "x": 340.73262913484444,
+ "y": -276.97012251086556,
+ "z": 0.0
+ },
+ {
+ "x": 340.7332404277687,
+ "y": -275.9580666207128,
+ "z": 0.0
+ },
+ {
+ "x": 340.733851720693,
+ "y": -274.94601073056054,
+ "z": 0.0
+ },
+ {
+ "x": 340.73446301361724,
+ "y": -273.93395484040775,
+ "z": 0.0
+ },
+ {
+ "x": 340.73507430654155,
+ "y": -272.92189895025547,
+ "z": 0.0
+ },
+ {
+ "x": 340.7356855994658,
+ "y": -271.9098430601027,
+ "z": 0.0
+ },
+ {
+ "x": 340.7362968923901,
+ "y": -270.8977871699504,
+ "z": 0.0
+ },
+ {
+ "x": 340.7369081853144,
+ "y": -269.8857312797978,
+ "z": 0.0
+ },
+ {
+ "x": 340.73751947823865,
+ "y": -268.8736753896451,
+ "z": 0.0
+ },
+ {
+ "x": 340.73813077116296,
+ "y": -267.86161949949275,
+ "z": 0.0
+ },
+ {
+ "x": 340.7387420640872,
+ "y": -266.84956360934,
+ "z": 0.0
+ },
+ {
+ "x": 340.7393533570115,
+ "y": -265.83750771918767,
+ "z": 0.0
+ },
+ {
+ "x": 340.73996464993576,
+ "y": -264.82545182903493,
+ "z": 0.0
+ },
+ {
+ "x": 340.74057594286006,
+ "y": -263.8133959388826,
+ "z": 0.0
+ },
+ {
+ "x": 340.7411872357843,
+ "y": -262.80134004872986,
+ "z": 0.0
+ },
+ {
+ "x": 340.7417985287086,
+ "y": -261.7892841585775,
+ "z": 0.0
+ },
+ {
+ "x": 340.7424098216329,
+ "y": -260.777228268425,
+ "z": 0.0
+ },
+ {
+ "x": 340.74302111455717,
+ "y": -259.7651723782722,
+ "z": 0.0
+ },
+ {
+ "x": 340.74363240748147,
+ "y": -258.75311648811993,
+ "z": 0.0
+ },
+ {
+ "x": 340.7442437004057,
+ "y": -257.74106059796713,
+ "z": 0.0
+ },
+ {
+ "x": 340.74485499333,
+ "y": -256.72900470781485,
+ "z": 0.0
+ },
+ {
+ "x": 340.74546628625427,
+ "y": -255.71694881766206,
+ "z": 0.0
+ },
+ {
+ "x": 340.7460775791786,
+ "y": -254.70489292750975,
+ "z": 0.0
+ },
+ {
+ "x": 340.7466888721028,
+ "y": -253.69283703735698,
+ "z": 0.0
+ },
+ {
+ "x": 340.7473001650271,
+ "y": -252.68078114720467,
+ "z": 0.0
+ },
+ {
+ "x": 340.74791145795143,
+ "y": -251.66872525705213,
+ "z": 0.0
+ },
+ {
+ "x": 340.7485227508757,
+ "y": -250.65666936689937,
+ "z": 0.0
+ },
+ {
+ "x": 340.7491340438,
+ "y": -249.64461347674705,
+ "z": 0.0
+ },
+ {
+ "x": 340.74974533672423,
+ "y": -248.6325575865943,
+ "z": 0.0
+ },
+ {
+ "x": 340.75035662964854,
+ "y": -247.62050169644198,
+ "z": 0.0
+ },
+ {
+ "x": 340.7509679225728,
+ "y": -246.6084458062892,
+ "z": 0.0
+ },
+ {
+ "x": 340.7515792154971,
+ "y": -245.5963899161369,
+ "z": 0.0
+ },
+ {
+ "x": 340.75219050842134,
+ "y": -244.58433402598413,
+ "z": 0.0
+ },
+ {
+ "x": 340.75280180134564,
+ "y": -243.57227813583182,
+ "z": 0.0
+ },
+ {
+ "x": 340.75341309426994,
+ "y": -242.56022224567928,
+ "z": 0.0
+ },
+ {
+ "x": 340.7540243871942,
+ "y": -241.54816635552652,
+ "z": 0.0
+ },
+ {
+ "x": 340.7546356801185,
+ "y": -240.5361104653742,
+ "z": 0.0
+ },
+ {
+ "x": 340.75524697304274,
+ "y": -239.52405457522144,
+ "z": 0.0
+ },
+ {
+ "x": 340.75585826596705,
+ "y": -238.51199868506913,
+ "z": 0.0
+ },
+ {
+ "x": 340.7564695588913,
+ "y": -237.49994279491636,
+ "z": 0.0
+ },
+ {
+ "x": 340.7570808518156,
+ "y": -236.48788690476405,
+ "z": 0.0
+ },
+ {
+ "x": 340.75769214473985,
+ "y": -235.4758310146113,
+ "z": 0.0
+ },
+ {
+ "x": 340.75830343766415,
+ "y": -234.46377512445898,
+ "z": 0.0
+ },
+ {
+ "x": 340.75891473058846,
+ "y": -233.45171923430644,
+ "z": 0.0
+ },
+ {
+ "x": 340.7595260235127,
+ "y": -232.43966334415367,
+ "z": 0.0
+ },
+ {
+ "x": 340.760137316437,
+ "y": -231.42760745400136,
+ "z": 0.0
+ },
+ {
+ "x": 340.76074860936126,
+ "y": -230.4155515638486,
+ "z": 0.0
+ },
+ {
+ "x": 340.76135990228556,
+ "y": -229.40349567369628,
+ "z": 0.0
+ },
+ {
+ "x": 340.7619711952098,
+ "y": -228.39143978354352,
+ "z": 0.0
+ },
+ {
+ "x": 340.7625824881341,
+ "y": -227.3793838933912,
+ "z": 0.0
+ },
+ {
+ "x": 340.7631937810584,
+ "y": -226.36732800323867,
+ "z": 0.0
+ },
+ {
+ "x": 340.76380507398267,
+ "y": -225.3552721130859,
+ "z": 0.0
+ },
+ {
+ "x": 340.76441636690697,
+ "y": -224.3432162229336,
+ "z": 0.0
+ },
+ {
+ "x": 340.7650276598312,
+ "y": -223.33116033278083,
+ "z": 0.0
+ },
+ {
+ "x": 340.7656389527555,
+ "y": -222.31910444262851,
+ "z": 0.0
+ },
+ {
+ "x": 340.76625024567977,
+ "y": -221.30704855247575,
+ "z": 0.0
+ },
+ {
+ "x": 340.7668615386041,
+ "y": -220.29499266232344,
+ "z": 0.0
+ },
+ {
+ "x": 340.7674728315283,
+ "y": -219.28293677217067,
+ "z": 0.0
+ },
+ {
+ "x": 340.7680841244526,
+ "y": -218.27088088201836,
+ "z": 0.0
+ },
+ {
+ "x": 340.76869541737693,
+ "y": -217.25882499186582,
+ "z": 0.0
+ },
+ {
+ "x": 340.7693067103012,
+ "y": -216.24676910171306,
+ "z": 0.0
+ },
+ {
+ "x": 340.7699180032255,
+ "y": -215.23471321156075,
+ "z": 0.0
+ },
+ {
+ "x": 340.77052929614973,
+ "y": -214.22265732140798,
+ "z": 0.0
+ },
+ {
+ "x": 340.77114058907404,
+ "y": -213.21060143125567,
+ "z": 0.0
+ },
+ {
+ "x": 340.7717518819983,
+ "y": -212.1985455411029,
+ "z": 0.0
+ },
+ {
+ "x": 340.7723631749226,
+ "y": -211.1864896509506,
+ "z": 0.0
+ },
+ {
+ "x": 340.77297446784684,
+ "y": -210.17443376079783,
+ "z": 0.0
+ },
+ {
+ "x": 340.77358576077114,
+ "y": -209.1623778706455,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 96,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 332.773587220088,
+ "y": -209.1575457832579,
+ "z": 0.0
+ },
+ {
+ "x": 332.7729759271637,
+ "y": -210.16960167341065,
+ "z": 0.0
+ },
+ {
+ "x": 332.77236463423947,
+ "y": -211.18165756356296,
+ "z": 0.0
+ },
+ {
+ "x": 332.77175334131516,
+ "y": -212.19371345371573,
+ "z": 0.0
+ },
+ {
+ "x": 332.7711420483909,
+ "y": -213.20576934386804,
+ "z": 0.0
+ },
+ {
+ "x": 332.7705307554666,
+ "y": -214.2178252340208,
+ "z": 0.0
+ },
+ {
+ "x": 332.76991946254236,
+ "y": -215.22988112417312,
+ "z": 0.0
+ },
+ {
+ "x": 332.76930816961806,
+ "y": -216.24193701432588,
+ "z": 0.0
+ },
+ {
+ "x": 332.7686968766938,
+ "y": -217.2539929044782,
+ "z": 0.0
+ },
+ {
+ "x": 332.7680855837695,
+ "y": -218.26604879463073,
+ "z": 0.0
+ },
+ {
+ "x": 332.7674742908452,
+ "y": -219.2781046847835,
+ "z": 0.0
+ },
+ {
+ "x": 332.76686299792095,
+ "y": -220.2901605749358,
+ "z": 0.0
+ },
+ {
+ "x": 332.76625170499665,
+ "y": -221.30221646508858,
+ "z": 0.0
+ },
+ {
+ "x": 332.7656404120724,
+ "y": -222.3142723552409,
+ "z": 0.0
+ },
+ {
+ "x": 332.7650291191481,
+ "y": -223.32632824539365,
+ "z": 0.0
+ },
+ {
+ "x": 332.76441782622385,
+ "y": -224.33838413554597,
+ "z": 0.0
+ },
+ {
+ "x": 332.76380653329954,
+ "y": -225.35044002569873,
+ "z": 0.0
+ },
+ {
+ "x": 332.7631952403753,
+ "y": -226.36249591585104,
+ "z": 0.0
+ },
+ {
+ "x": 332.762583947451,
+ "y": -227.37455180600358,
+ "z": 0.0
+ },
+ {
+ "x": 332.7619726545267,
+ "y": -228.38660769615635,
+ "z": 0.0
+ },
+ {
+ "x": 332.76136136160244,
+ "y": -229.39866358630866,
+ "z": 0.0
+ },
+ {
+ "x": 332.76075006867813,
+ "y": -230.41071947646142,
+ "z": 0.0
+ },
+ {
+ "x": 332.7601387757539,
+ "y": -231.42277536661373,
+ "z": 0.0
+ },
+ {
+ "x": 332.7595274828296,
+ "y": -232.4348312567665,
+ "z": 0.0
+ },
+ {
+ "x": 332.75891618990534,
+ "y": -233.4468871469188,
+ "z": 0.0
+ },
+ {
+ "x": 332.75830489698103,
+ "y": -234.45894303707135,
+ "z": 0.0
+ },
+ {
+ "x": 332.7576936040567,
+ "y": -235.47099892722412,
+ "z": 0.0
+ },
+ {
+ "x": 332.7570823111325,
+ "y": -236.48305481737643,
+ "z": 0.0
+ },
+ {
+ "x": 332.7564710182082,
+ "y": -237.4951107075292,
+ "z": 0.0
+ },
+ {
+ "x": 332.7558597252839,
+ "y": -238.5071665976815,
+ "z": 0.0
+ },
+ {
+ "x": 332.7552484323596,
+ "y": -239.51922248783427,
+ "z": 0.0
+ },
+ {
+ "x": 332.7546371394354,
+ "y": -240.53127837798658,
+ "z": 0.0
+ },
+ {
+ "x": 332.75402584651107,
+ "y": -241.54333426813935,
+ "z": 0.0
+ },
+ {
+ "x": 332.7534145535868,
+ "y": -242.55539015829166,
+ "z": 0.0
+ },
+ {
+ "x": 332.7528032606625,
+ "y": -243.5674460484442,
+ "z": 0.0
+ },
+ {
+ "x": 332.7521919677382,
+ "y": -244.57950193859696,
+ "z": 0.0
+ },
+ {
+ "x": 332.75158067481397,
+ "y": -245.59155782874927,
+ "z": 0.0
+ },
+ {
+ "x": 332.75096938188966,
+ "y": -246.60361371890204,
+ "z": 0.0
+ },
+ {
+ "x": 332.7503580889654,
+ "y": -247.61566960905435,
+ "z": 0.0
+ },
+ {
+ "x": 332.7497467960411,
+ "y": -248.62772549920712,
+ "z": 0.0
+ },
+ {
+ "x": 332.74913550311686,
+ "y": -249.63978138935943,
+ "z": 0.0
+ },
+ {
+ "x": 332.74852421019256,
+ "y": -250.6518372795122,
+ "z": 0.0
+ },
+ {
+ "x": 332.7479129172683,
+ "y": -251.6638931696645,
+ "z": 0.0
+ },
+ {
+ "x": 332.747301624344,
+ "y": -252.67594905981704,
+ "z": 0.0
+ },
+ {
+ "x": 332.7466903314197,
+ "y": -253.6880049499698,
+ "z": 0.0
+ },
+ {
+ "x": 332.74607903849545,
+ "y": -254.70006084012212,
+ "z": 0.0
+ },
+ {
+ "x": 332.74546774557115,
+ "y": -255.7121167302749,
+ "z": 0.0
+ },
+ {
+ "x": 332.7448564526469,
+ "y": -256.7241726204272,
+ "z": 0.0
+ },
+ {
+ "x": 332.7442451597226,
+ "y": -257.73622851057996,
+ "z": 0.0
+ },
+ {
+ "x": 332.74363386679835,
+ "y": -258.7482844007323,
+ "z": 0.0
+ },
+ {
+ "x": 332.74302257387404,
+ "y": -259.76034029088504,
+ "z": 0.0
+ },
+ {
+ "x": 332.7424112809498,
+ "y": -260.7723961810374,
+ "z": 0.0
+ },
+ {
+ "x": 332.7417999880255,
+ "y": -261.7844520711899,
+ "z": 0.0
+ },
+ {
+ "x": 332.7411886951012,
+ "y": -262.7965079613427,
+ "z": 0.0
+ },
+ {
+ "x": 332.74057740217694,
+ "y": -263.80856385149497,
+ "z": 0.0
+ },
+ {
+ "x": 332.73996610925263,
+ "y": -264.82061974164776,
+ "z": 0.0
+ },
+ {
+ "x": 332.7393548163284,
+ "y": -265.83267563180004,
+ "z": 0.0
+ },
+ {
+ "x": 332.7387435234041,
+ "y": -266.84473152195284,
+ "z": 0.0
+ },
+ {
+ "x": 332.73813223047983,
+ "y": -267.8567874121051,
+ "z": 0.0
+ },
+ {
+ "x": 332.73752093755553,
+ "y": -268.8688433022579,
+ "z": 0.0
+ },
+ {
+ "x": 332.7369096446313,
+ "y": -269.8808991924102,
+ "z": 0.0
+ },
+ {
+ "x": 332.736298351707,
+ "y": -270.89295508256276,
+ "z": 0.0
+ },
+ {
+ "x": 332.7356870587827,
+ "y": -271.9050109727155,
+ "z": 0.0
+ },
+ {
+ "x": 332.7350757658584,
+ "y": -272.91706686286784,
+ "z": 0.0
+ },
+ {
+ "x": 332.7344644729341,
+ "y": -273.9291227530206,
+ "z": 0.0
+ },
+ {
+ "x": 332.7338531800099,
+ "y": -274.9411786431729,
+ "z": 0.0
+ },
+ {
+ "x": 332.73324188708557,
+ "y": -275.95323453332566,
+ "z": 0.0
+ },
+ {
+ "x": 332.7326305941613,
+ "y": -276.96529042347794,
+ "z": 0.0
+ },
+ {
+ "x": 332.732019301237,
+ "y": -277.9773463136305,
+ "z": 0.0
+ },
+ {
+ "x": 332.7314080083127,
+ "y": -278.98940220378324,
+ "z": 0.0
+ },
+ {
+ "x": 332.73079671538846,
+ "y": -280.0014580939355,
+ "z": 0.0
+ },
+ {
+ "x": 332.73018542246416,
+ "y": -281.0135139840883,
+ "z": 0.0
+ },
+ {
+ "x": 332.7295741295399,
+ "y": -282.0255698742406,
+ "z": 0.0
+ },
+ {
+ "x": 332.7289628366156,
+ "y": -283.0376257643934,
+ "z": 0.0
+ },
+ {
+ "x": 332.72835154369136,
+ "y": -284.0496816545457,
+ "z": 0.0
+ },
+ {
+ "x": 332.72774025076706,
+ "y": -285.0617375446984,
+ "z": 0.0
+ },
+ {
+ "x": 332.7271289578428,
+ "y": -286.07379343485076,
+ "z": 0.0
+ },
+ {
+ "x": 332.7265176649185,
+ "y": -287.08584932500327,
+ "z": 0.0
+ },
+ {
+ "x": 332.7259063719942,
+ "y": -288.09790521515606,
+ "z": 0.0
+ },
+ {
+ "x": 332.72529507906995,
+ "y": -289.10996110530834,
+ "z": 0.0
+ },
+ {
+ "x": 332.72468378614565,
+ "y": -290.1220169954611,
+ "z": 0.0
+ },
+ {
+ "x": 332.7240724932214,
+ "y": -291.1340728856134,
+ "z": 0.0
+ },
+ {
+ "x": 332.7234612002971,
+ "y": -292.14612877576616,
+ "z": 0.0
+ },
+ {
+ "x": 332.72284990737285,
+ "y": -293.15818466591844,
+ "z": 0.0
+ },
+ {
+ "x": 332.72223861444854,
+ "y": -294.17024055607124,
+ "z": 0.0
+ },
+ {
+ "x": 332.7216273215243,
+ "y": -295.1822964462235,
+ "z": 0.0
+ },
+ {
+ "x": 332.7210160286,
+ "y": -296.1943523363761,
+ "z": 0.0
+ },
+ {
+ "x": 332.7204047356757,
+ "y": -297.2064082265288,
+ "z": 0.0
+ },
+ {
+ "x": 332.71979344275144,
+ "y": -298.2184641166811,
+ "z": 0.0
+ },
+ {
+ "x": 332.71918214982713,
+ "y": -299.2305200068339,
+ "z": 0.0
+ },
+ {
+ "x": 332.7185708569029,
+ "y": -300.2425758969862,
+ "z": 0.0
+ },
+ {
+ "x": 332.7179595639786,
+ "y": -301.254631787139,
+ "z": 0.0
+ },
+ {
+ "x": 332.71734827105433,
+ "y": -302.26668767729126,
+ "z": 0.0
+ },
+ {
+ "x": 332.71673697813003,
+ "y": -303.278743567444,
+ "z": 0.0
+ },
+ {
+ "x": 332.7161256852058,
+ "y": -304.29079945759634,
+ "z": 0.0
+ },
+ {
+ "x": 332.7155143922815,
+ "y": -305.30285534774885,
+ "z": 0.0
+ },
+ {
+ "x": 332.7149030993572,
+ "y": -306.31491123790164,
+ "z": 0.0
+ },
+ {
+ "x": 332.7142918064329,
+ "y": -307.3269671280539,
+ "z": 0.0
+ },
+ {
+ "x": 332.7136805135086,
+ "y": -308.33902301820666,
+ "z": 0.0
+ },
+ {
+ "x": 332.7130692205844,
+ "y": -309.351078908359,
+ "z": 0.0
+ },
+ {
+ "x": 332.71245792766007,
+ "y": -310.36313479851174,
+ "z": 0.0
+ },
+ {
+ "x": 332.7118466347358,
+ "y": -311.3751906886641,
+ "z": 0.0
+ },
+ {
+ "x": 332.7112353418115,
+ "y": -312.3872465788168,
+ "z": 0.0
+ },
+ {
+ "x": 332.71062404888727,
+ "y": -313.3993024689691,
+ "z": 0.0
+ },
+ {
+ "x": 332.71001275596296,
+ "y": -314.41135835912166,
+ "z": 0.0
+ },
+ {
+ "x": 332.70940146303866,
+ "y": -315.4234142492744,
+ "z": 0.0
+ },
+ {
+ "x": 332.7087901701144,
+ "y": -316.43547013942674,
+ "z": 0.0
+ },
+ {
+ "x": 332.7081788771901,
+ "y": -317.44752602957925,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 97,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 336.7735864904296,
+ "y": -209.1599618269517,
+ "z": 0.0
+ },
+ {
+ "x": 336.7729751975053,
+ "y": -210.17201771710424,
+ "z": 0.0
+ },
+ {
+ "x": 336.772363904581,
+ "y": -211.18407360725678,
+ "z": 0.0
+ },
+ {
+ "x": 336.7717526116567,
+ "y": -212.19612949740932,
+ "z": 0.0
+ },
+ {
+ "x": 336.7711413187325,
+ "y": -213.20818538756185,
+ "z": 0.0
+ },
+ {
+ "x": 336.77053002580817,
+ "y": -214.2202412777144,
+ "z": 0.0
+ },
+ {
+ "x": 336.7699187328839,
+ "y": -215.23229716786693,
+ "z": 0.0
+ },
+ {
+ "x": 336.7693074399596,
+ "y": -216.24435305801947,
+ "z": 0.0
+ },
+ {
+ "x": 336.76869614703537,
+ "y": -217.256408948172,
+ "z": 0.0
+ },
+ {
+ "x": 336.76808485411107,
+ "y": -218.26846483832455,
+ "z": 0.0
+ },
+ {
+ "x": 336.76747356118676,
+ "y": -219.2805207284771,
+ "z": 0.0
+ },
+ {
+ "x": 336.7668622682625,
+ "y": -220.29257661862962,
+ "z": 0.0
+ },
+ {
+ "x": 336.7662509753382,
+ "y": -221.30463250878216,
+ "z": 0.0
+ },
+ {
+ "x": 336.76563968241396,
+ "y": -222.3166883989347,
+ "z": 0.0
+ },
+ {
+ "x": 336.76502838948966,
+ "y": -223.32874428908724,
+ "z": 0.0
+ },
+ {
+ "x": 336.7644170965654,
+ "y": -224.34080017923978,
+ "z": 0.0
+ },
+ {
+ "x": 336.7638058036411,
+ "y": -225.35285606939232,
+ "z": 0.0
+ },
+ {
+ "x": 336.76319451071686,
+ "y": -226.36491195954486,
+ "z": 0.0
+ },
+ {
+ "x": 336.76258321779255,
+ "y": -227.3769678496974,
+ "z": 0.0
+ },
+ {
+ "x": 336.76197192486825,
+ "y": -228.38902373984993,
+ "z": 0.0
+ },
+ {
+ "x": 336.761360631944,
+ "y": -229.40107963000247,
+ "z": 0.0
+ },
+ {
+ "x": 336.7607493390197,
+ "y": -230.413135520155,
+ "z": 0.0
+ },
+ {
+ "x": 336.76013804609545,
+ "y": -231.42519141030755,
+ "z": 0.0
+ },
+ {
+ "x": 336.75952675317114,
+ "y": -232.4372473004601,
+ "z": 0.0
+ },
+ {
+ "x": 336.7589154602469,
+ "y": -233.44930319061262,
+ "z": 0.0
+ },
+ {
+ "x": 336.7583041673226,
+ "y": -234.46135908076516,
+ "z": 0.0
+ },
+ {
+ "x": 336.7576928743983,
+ "y": -235.4734149709177,
+ "z": 0.0
+ },
+ {
+ "x": 336.75708158147404,
+ "y": -236.48547086107024,
+ "z": 0.0
+ },
+ {
+ "x": 336.75647028854974,
+ "y": -237.49752675122278,
+ "z": 0.0
+ },
+ {
+ "x": 336.7558589956255,
+ "y": -238.50958264137532,
+ "z": 0.0
+ },
+ {
+ "x": 336.7552477027012,
+ "y": -239.52163853152786,
+ "z": 0.0
+ },
+ {
+ "x": 336.75463640977694,
+ "y": -240.5336944216804,
+ "z": 0.0
+ },
+ {
+ "x": 336.75402511685263,
+ "y": -241.54575031183293,
+ "z": 0.0
+ },
+ {
+ "x": 336.7534138239284,
+ "y": -242.55780620198547,
+ "z": 0.0
+ },
+ {
+ "x": 336.7528025310041,
+ "y": -243.569862092138,
+ "z": 0.0
+ },
+ {
+ "x": 336.7521912380798,
+ "y": -244.58191798229055,
+ "z": 0.0
+ },
+ {
+ "x": 336.7515799451555,
+ "y": -245.5939738724431,
+ "z": 0.0
+ },
+ {
+ "x": 336.7509686522312,
+ "y": -246.60602976259563,
+ "z": 0.0
+ },
+ {
+ "x": 336.750357359307,
+ "y": -247.61808565274816,
+ "z": 0.0
+ },
+ {
+ "x": 336.74974606638267,
+ "y": -248.6301415429007,
+ "z": 0.0
+ },
+ {
+ "x": 336.7491347734584,
+ "y": -249.64219743305324,
+ "z": 0.0
+ },
+ {
+ "x": 336.7485234805341,
+ "y": -250.65425332320578,
+ "z": 0.0
+ },
+ {
+ "x": 336.74791218760987,
+ "y": -251.66630921335832,
+ "z": 0.0
+ },
+ {
+ "x": 336.74730089468557,
+ "y": -252.67836510351086,
+ "z": 0.0
+ },
+ {
+ "x": 336.74668960176126,
+ "y": -253.6904209936634,
+ "z": 0.0
+ },
+ {
+ "x": 336.746078308837,
+ "y": -254.70247688381593,
+ "z": 0.0
+ },
+ {
+ "x": 336.7454670159127,
+ "y": -255.71453277396847,
+ "z": 0.0
+ },
+ {
+ "x": 336.74485572298846,
+ "y": -256.72658866412104,
+ "z": 0.0
+ },
+ {
+ "x": 336.74424443006416,
+ "y": -257.73864455427355,
+ "z": 0.0
+ },
+ {
+ "x": 336.7436331371399,
+ "y": -258.7507004444261,
+ "z": 0.0
+ },
+ {
+ "x": 336.7430218442156,
+ "y": -259.7627563345786,
+ "z": 0.0
+ },
+ {
+ "x": 336.74241055129136,
+ "y": -260.7748122247312,
+ "z": 0.0
+ },
+ {
+ "x": 336.74179925836705,
+ "y": -261.7868681148837,
+ "z": 0.0
+ },
+ {
+ "x": 336.74118796544275,
+ "y": -262.79892400503627,
+ "z": 0.0
+ },
+ {
+ "x": 336.7405766725185,
+ "y": -263.8109798951888,
+ "z": 0.0
+ },
+ {
+ "x": 336.7399653795942,
+ "y": -264.82303578534135,
+ "z": 0.0
+ },
+ {
+ "x": 336.73935408666995,
+ "y": -265.83509167549386,
+ "z": 0.0
+ },
+ {
+ "x": 336.73874279374564,
+ "y": -266.8471475656464,
+ "z": 0.0
+ },
+ {
+ "x": 336.7381315008214,
+ "y": -267.85920345579893,
+ "z": 0.0
+ },
+ {
+ "x": 336.7375202078971,
+ "y": -268.8712593459515,
+ "z": 0.0
+ },
+ {
+ "x": 336.73690891497284,
+ "y": -269.883315236104,
+ "z": 0.0
+ },
+ {
+ "x": 336.73629762204854,
+ "y": -270.8953711262566,
+ "z": 0.0
+ },
+ {
+ "x": 336.73568632912423,
+ "y": -271.9074270164091,
+ "z": 0.0
+ },
+ {
+ "x": 336.7350750362,
+ "y": -272.91948290656165,
+ "z": 0.0
+ },
+ {
+ "x": 336.7344637432757,
+ "y": -273.93153879671416,
+ "z": 0.0
+ },
+ {
+ "x": 336.73385245035143,
+ "y": -274.94359468686673,
+ "z": 0.0
+ },
+ {
+ "x": 336.73324115742713,
+ "y": -275.95565057701924,
+ "z": 0.0
+ },
+ {
+ "x": 336.7326298645029,
+ "y": -276.96770646717175,
+ "z": 0.0
+ },
+ {
+ "x": 336.7320185715786,
+ "y": -277.9797623573243,
+ "z": 0.0
+ },
+ {
+ "x": 336.7314072786543,
+ "y": -278.99181824747683,
+ "z": 0.0
+ },
+ {
+ "x": 336.73079598573,
+ "y": -280.00387413762934,
+ "z": 0.0
+ },
+ {
+ "x": 336.7301846928057,
+ "y": -281.0159300277819,
+ "z": 0.0
+ },
+ {
+ "x": 336.7295733998815,
+ "y": -282.0279859179344,
+ "z": 0.0
+ },
+ {
+ "x": 336.72896210695717,
+ "y": -283.040041808087,
+ "z": 0.0
+ },
+ {
+ "x": 336.7283508140329,
+ "y": -284.0520976982395,
+ "z": 0.0
+ },
+ {
+ "x": 336.7277395211086,
+ "y": -285.064153588392,
+ "z": 0.0
+ },
+ {
+ "x": 336.72712822818437,
+ "y": -286.07620947854457,
+ "z": 0.0
+ },
+ {
+ "x": 336.72651693526007,
+ "y": -287.0882653686971,
+ "z": 0.0
+ },
+ {
+ "x": 336.72590564233576,
+ "y": -288.10032125884965,
+ "z": 0.0
+ },
+ {
+ "x": 336.7252943494115,
+ "y": -289.11237714900216,
+ "z": 0.0
+ },
+ {
+ "x": 336.7246830564872,
+ "y": -290.12443303915467,
+ "z": 0.0
+ },
+ {
+ "x": 336.72407176356296,
+ "y": -291.13648892930723,
+ "z": 0.0
+ },
+ {
+ "x": 336.72346047063866,
+ "y": -292.14854481945974,
+ "z": 0.0
+ },
+ {
+ "x": 336.7228491777144,
+ "y": -293.16060070961225,
+ "z": 0.0
+ },
+ {
+ "x": 336.7222378847901,
+ "y": -294.1726565997648,
+ "z": 0.0
+ },
+ {
+ "x": 336.72162659186586,
+ "y": -295.18471248991733,
+ "z": 0.0
+ },
+ {
+ "x": 336.72101529894155,
+ "y": -296.1967683800699,
+ "z": 0.0
+ },
+ {
+ "x": 336.72040400601725,
+ "y": -297.2088242702224,
+ "z": 0.0
+ },
+ {
+ "x": 336.719792713093,
+ "y": -298.2208801603749,
+ "z": 0.0
+ },
+ {
+ "x": 336.7191814201687,
+ "y": -299.2329360505275,
+ "z": 0.0
+ },
+ {
+ "x": 336.71857012724445,
+ "y": -300.24499194068,
+ "z": 0.0
+ },
+ {
+ "x": 336.71795883432014,
+ "y": -301.25704783083256,
+ "z": 0.0
+ },
+ {
+ "x": 336.7173475413959,
+ "y": -302.2691037209851,
+ "z": 0.0
+ },
+ {
+ "x": 336.7167362484716,
+ "y": -303.2811596111376,
+ "z": 0.0
+ },
+ {
+ "x": 336.71612495554734,
+ "y": -304.29321550129015,
+ "z": 0.0
+ },
+ {
+ "x": 336.71551366262304,
+ "y": -305.30527139144266,
+ "z": 0.0
+ },
+ {
+ "x": 336.71490236969873,
+ "y": -306.3173272815952,
+ "z": 0.0
+ },
+ {
+ "x": 336.7142910767745,
+ "y": -307.32938317174774,
+ "z": 0.0
+ },
+ {
+ "x": 336.7136797838502,
+ "y": -308.34143906190025,
+ "z": 0.0
+ },
+ {
+ "x": 336.71306849092593,
+ "y": -309.3534949520528,
+ "z": 0.0
+ },
+ {
+ "x": 336.71245719800163,
+ "y": -310.3655508422053,
+ "z": 0.0
+ },
+ {
+ "x": 336.7118459050774,
+ "y": -311.3776067323579,
+ "z": 0.0
+ },
+ {
+ "x": 336.7112346121531,
+ "y": -312.3896626225104,
+ "z": 0.0
+ },
+ {
+ "x": 336.71062331922883,
+ "y": -313.4017185126629,
+ "z": 0.0
+ },
+ {
+ "x": 336.7100120263045,
+ "y": -314.4137744028155,
+ "z": 0.0
+ },
+ {
+ "x": 336.7094007333802,
+ "y": -315.425830292968,
+ "z": 0.0
+ },
+ {
+ "x": 336.708789440456,
+ "y": -316.43788618312055,
+ "z": 0.0
+ },
+ {
+ "x": 336.70817814753167,
+ "y": -317.44994207327306,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 98,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 338.7081777827025,
+ "y": -317.45115009511994,
+ "z": 0.0
+ },
+ {
+ "x": 338.7087890756268,
+ "y": -316.43909420496743,
+ "z": 0.0
+ },
+ {
+ "x": 338.709400368551,
+ "y": -315.4270383148148,
+ "z": 0.0
+ },
+ {
+ "x": 338.7100116614753,
+ "y": -314.4149824246624,
+ "z": 0.0
+ },
+ {
+ "x": 338.7106229543996,
+ "y": -313.4029265345098,
+ "z": 0.0
+ },
+ {
+ "x": 338.7112342473239,
+ "y": -312.39087064435716,
+ "z": 0.0
+ },
+ {
+ "x": 338.7118455402482,
+ "y": -311.37881475420477,
+ "z": 0.0
+ },
+ {
+ "x": 338.7124568331724,
+ "y": -310.36675886405214,
+ "z": 0.0
+ },
+ {
+ "x": 338.7130681260967,
+ "y": -309.35470297389975,
+ "z": 0.0
+ },
+ {
+ "x": 338.713679419021,
+ "y": -308.342647083747,
+ "z": 0.0
+ },
+ {
+ "x": 338.7142907119453,
+ "y": -307.3305911935946,
+ "z": 0.0
+ },
+ {
+ "x": 338.7149020048695,
+ "y": -306.318535303442,
+ "z": 0.0
+ },
+ {
+ "x": 338.7155132977938,
+ "y": -305.3064794132896,
+ "z": 0.0
+ },
+ {
+ "x": 338.7161245907181,
+ "y": -304.2944235231371,
+ "z": 0.0
+ },
+ {
+ "x": 338.7167358836424,
+ "y": -303.28236763298435,
+ "z": 0.0
+ },
+ {
+ "x": 338.7173471765667,
+ "y": -302.27031174283195,
+ "z": 0.0
+ },
+ {
+ "x": 338.7179584694909,
+ "y": -301.2582558526793,
+ "z": 0.0
+ },
+ {
+ "x": 338.7185697624152,
+ "y": -300.24619996252693,
+ "z": 0.0
+ },
+ {
+ "x": 338.7191810553395,
+ "y": -299.2341440723743,
+ "z": 0.0
+ },
+ {
+ "x": 338.7197923482638,
+ "y": -298.2220881822218,
+ "z": 0.0
+ },
+ {
+ "x": 338.720403641188,
+ "y": -297.2100322920692,
+ "z": 0.0
+ },
+ {
+ "x": 338.7210149341123,
+ "y": -296.1979764019168,
+ "z": 0.0
+ },
+ {
+ "x": 338.7216262270366,
+ "y": -295.18592051176427,
+ "z": 0.0
+ },
+ {
+ "x": 338.7222375199609,
+ "y": -294.17386462161164,
+ "z": 0.0
+ },
+ {
+ "x": 338.7228488128852,
+ "y": -293.16180873145913,
+ "z": 0.0
+ },
+ {
+ "x": 338.7234601058094,
+ "y": -292.1497528413065,
+ "z": 0.0
+ },
+ {
+ "x": 338.7240713987337,
+ "y": -291.1376969511541,
+ "z": 0.0
+ },
+ {
+ "x": 338.724682691658,
+ "y": -290.1256410610015,
+ "z": 0.0
+ },
+ {
+ "x": 338.7252939845823,
+ "y": -289.1135851708491,
+ "z": 0.0
+ },
+ {
+ "x": 338.7259052775065,
+ "y": -288.10152928069647,
+ "z": 0.0
+ },
+ {
+ "x": 338.7265165704308,
+ "y": -287.08947339054396,
+ "z": 0.0
+ },
+ {
+ "x": 338.7271278633551,
+ "y": -286.07741750039145,
+ "z": 0.0
+ },
+ {
+ "x": 338.7277391562794,
+ "y": -285.0653616102388,
+ "z": 0.0
+ },
+ {
+ "x": 338.72835044920373,
+ "y": -284.0533057200864,
+ "z": 0.0
+ },
+ {
+ "x": 338.7289617421279,
+ "y": -283.0412498299338,
+ "z": 0.0
+ },
+ {
+ "x": 338.7295730350522,
+ "y": -282.0291939397813,
+ "z": 0.0
+ },
+ {
+ "x": 338.73018432797653,
+ "y": -281.01713804962867,
+ "z": 0.0
+ },
+ {
+ "x": 338.73079562090084,
+ "y": -280.0050821594763,
+ "z": 0.0
+ },
+ {
+ "x": 338.731406913825,
+ "y": -278.99302626932365,
+ "z": 0.0
+ },
+ {
+ "x": 338.73201820674933,
+ "y": -277.98097037917125,
+ "z": 0.0
+ },
+ {
+ "x": 338.73262949967364,
+ "y": -276.96891448901863,
+ "z": 0.0
+ },
+ {
+ "x": 338.73324079259794,
+ "y": -275.956858598866,
+ "z": 0.0
+ },
+ {
+ "x": 338.73385208552224,
+ "y": -274.9448027087136,
+ "z": 0.0
+ },
+ {
+ "x": 338.73446337844643,
+ "y": -273.932746818561,
+ "z": 0.0
+ },
+ {
+ "x": 338.73507467137074,
+ "y": -272.9206909284086,
+ "z": 0.0
+ },
+ {
+ "x": 338.73568596429504,
+ "y": -271.90863503825585,
+ "z": 0.0
+ },
+ {
+ "x": 338.73629725721935,
+ "y": -270.89657914810346,
+ "z": 0.0
+ },
+ {
+ "x": 338.73690855014365,
+ "y": -269.88452325795095,
+ "z": 0.0
+ },
+ {
+ "x": 338.73751984306784,
+ "y": -268.8724673677983,
+ "z": 0.0
+ },
+ {
+ "x": 338.73813113599215,
+ "y": -267.8604114776458,
+ "z": 0.0
+ },
+ {
+ "x": 338.73874242891645,
+ "y": -266.8483555874932,
+ "z": 0.0
+ },
+ {
+ "x": 338.73935372184076,
+ "y": -265.8362996973408,
+ "z": 0.0
+ },
+ {
+ "x": 338.73996501476495,
+ "y": -264.82424380718817,
+ "z": 0.0
+ },
+ {
+ "x": 338.74057630768925,
+ "y": -263.81218791703566,
+ "z": 0.0
+ },
+ {
+ "x": 338.74118760061356,
+ "y": -262.80013202688303,
+ "z": 0.0
+ },
+ {
+ "x": 338.74179889353786,
+ "y": -261.78807613673064,
+ "z": 0.0
+ },
+ {
+ "x": 338.74241018646217,
+ "y": -260.7760202465781,
+ "z": 0.0
+ },
+ {
+ "x": 338.74302147938636,
+ "y": -259.7639643564254,
+ "z": 0.0
+ },
+ {
+ "x": 338.74363277231066,
+ "y": -258.751908466273,
+ "z": 0.0
+ },
+ {
+ "x": 338.74424406523497,
+ "y": -257.73985257612037,
+ "z": 0.0
+ },
+ {
+ "x": 338.74485535815927,
+ "y": -256.727796685968,
+ "z": 0.0
+ },
+ {
+ "x": 338.74546665108346,
+ "y": -255.71574079581526,
+ "z": 0.0
+ },
+ {
+ "x": 338.74607794400777,
+ "y": -254.70368490566284,
+ "z": 0.0
+ },
+ {
+ "x": 338.74668923693207,
+ "y": -253.6916290155102,
+ "z": 0.0
+ },
+ {
+ "x": 338.7473005298564,
+ "y": -252.67957312535776,
+ "z": 0.0
+ },
+ {
+ "x": 338.7479118227807,
+ "y": -251.66751723520522,
+ "z": 0.0
+ },
+ {
+ "x": 338.74852311570487,
+ "y": -250.65546134505257,
+ "z": 0.0
+ },
+ {
+ "x": 338.7491344086292,
+ "y": -249.64340545490015,
+ "z": 0.0
+ },
+ {
+ "x": 338.7497457015535,
+ "y": -248.6313495647475,
+ "z": 0.0
+ },
+ {
+ "x": 338.7503569944778,
+ "y": -247.61929367459507,
+ "z": 0.0
+ },
+ {
+ "x": 338.750968287402,
+ "y": -246.60723778444242,
+ "z": 0.0
+ },
+ {
+ "x": 338.7515795803263,
+ "y": -245.59518189429,
+ "z": 0.0
+ },
+ {
+ "x": 338.7521908732506,
+ "y": -244.58312600413734,
+ "z": 0.0
+ },
+ {
+ "x": 338.7528021661749,
+ "y": -243.57107011398492,
+ "z": 0.0
+ },
+ {
+ "x": 338.7534134590992,
+ "y": -242.55901422383238,
+ "z": 0.0
+ },
+ {
+ "x": 338.7540247520234,
+ "y": -241.54695833367973,
+ "z": 0.0
+ },
+ {
+ "x": 338.7546360449477,
+ "y": -240.5349024435273,
+ "z": 0.0
+ },
+ {
+ "x": 338.755247337872,
+ "y": -239.52284655337465,
+ "z": 0.0
+ },
+ {
+ "x": 338.7558586307963,
+ "y": -238.51079066322222,
+ "z": 0.0
+ },
+ {
+ "x": 338.7564699237205,
+ "y": -237.49873477306957,
+ "z": 0.0
+ },
+ {
+ "x": 338.7570812166448,
+ "y": -236.48667888291715,
+ "z": 0.0
+ },
+ {
+ "x": 338.7576925095691,
+ "y": -235.4746229927645,
+ "z": 0.0
+ },
+ {
+ "x": 338.7583038024934,
+ "y": -234.46256710261207,
+ "z": 0.0
+ },
+ {
+ "x": 338.7589150954177,
+ "y": -233.45051121245953,
+ "z": 0.0
+ },
+ {
+ "x": 338.7595263883419,
+ "y": -232.43845532230688,
+ "z": 0.0
+ },
+ {
+ "x": 338.7601376812662,
+ "y": -231.42639943215445,
+ "z": 0.0
+ },
+ {
+ "x": 338.7607489741905,
+ "y": -230.4143435420018,
+ "z": 0.0
+ },
+ {
+ "x": 338.7613602671148,
+ "y": -229.40228765184938,
+ "z": 0.0
+ },
+ {
+ "x": 338.761971560039,
+ "y": -228.39023176169673,
+ "z": 0.0
+ },
+ {
+ "x": 338.7625828529633,
+ "y": -227.3781758715443,
+ "z": 0.0
+ },
+ {
+ "x": 338.7631941458876,
+ "y": -226.36611998139176,
+ "z": 0.0
+ },
+ {
+ "x": 338.7638054388119,
+ "y": -225.3540640912391,
+ "z": 0.0
+ },
+ {
+ "x": 338.7644167317362,
+ "y": -224.34200820108668,
+ "z": 0.0
+ },
+ {
+ "x": 338.7650280246604,
+ "y": -223.32995231093403,
+ "z": 0.0
+ },
+ {
+ "x": 338.7656393175847,
+ "y": -222.3178964207816,
+ "z": 0.0
+ },
+ {
+ "x": 338.766250610509,
+ "y": -221.30584053062896,
+ "z": 0.0
+ },
+ {
+ "x": 338.7668619034333,
+ "y": -220.29378464047653,
+ "z": 0.0
+ },
+ {
+ "x": 338.7674731963575,
+ "y": -219.28172875032388,
+ "z": 0.0
+ },
+ {
+ "x": 338.7680844892818,
+ "y": -218.26967286017145,
+ "z": 0.0
+ },
+ {
+ "x": 338.7686957822061,
+ "y": -217.25761697001892,
+ "z": 0.0
+ },
+ {
+ "x": 338.7693070751304,
+ "y": -216.24556107986626,
+ "z": 0.0
+ },
+ {
+ "x": 338.76991836805473,
+ "y": -215.23350518971384,
+ "z": 0.0
+ },
+ {
+ "x": 338.7705296609789,
+ "y": -214.2214492995612,
+ "z": 0.0
+ },
+ {
+ "x": 338.7711409539032,
+ "y": -213.20939340940876,
+ "z": 0.0
+ },
+ {
+ "x": 338.77175224682753,
+ "y": -212.1973375192561,
+ "z": 0.0
+ },
+ {
+ "x": 338.77236353975184,
+ "y": -211.18528162910368,
+ "z": 0.0
+ },
+ {
+ "x": 338.772974832676,
+ "y": -210.17322573895103,
+ "z": 0.0
+ },
+ {
+ "x": 338.77358612560033,
+ "y": -209.1611698487986,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 99,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 334.7735868552588,
+ "y": -209.1587538051048,
+ "z": 0.0
+ },
+ {
+ "x": 334.7729755623345,
+ "y": -210.17080969525745,
+ "z": 0.0
+ },
+ {
+ "x": 334.7723642694102,
+ "y": -211.18286558540987,
+ "z": 0.0
+ },
+ {
+ "x": 334.7717529764859,
+ "y": -212.19492147556252,
+ "z": 0.0
+ },
+ {
+ "x": 334.7711416835617,
+ "y": -213.20697736571495,
+ "z": 0.0
+ },
+ {
+ "x": 334.7705303906374,
+ "y": -214.2190332558676,
+ "z": 0.0
+ },
+ {
+ "x": 334.7699190977131,
+ "y": -215.23108914602003,
+ "z": 0.0
+ },
+ {
+ "x": 334.7693078047888,
+ "y": -216.24314503617268,
+ "z": 0.0
+ },
+ {
+ "x": 334.7686965118646,
+ "y": -217.2552009263251,
+ "z": 0.0
+ },
+ {
+ "x": 334.7680852189403,
+ "y": -218.26725681647764,
+ "z": 0.0
+ },
+ {
+ "x": 334.767473926016,
+ "y": -219.2793127066303,
+ "z": 0.0
+ },
+ {
+ "x": 334.7668626330917,
+ "y": -220.29136859678272,
+ "z": 0.0
+ },
+ {
+ "x": 334.7662513401674,
+ "y": -221.30342448693537,
+ "z": 0.0
+ },
+ {
+ "x": 334.7656400472432,
+ "y": -222.3154803770878,
+ "z": 0.0
+ },
+ {
+ "x": 334.7650287543189,
+ "y": -223.32753626724045,
+ "z": 0.0
+ },
+ {
+ "x": 334.7644174613946,
+ "y": -224.33959215739287,
+ "z": 0.0
+ },
+ {
+ "x": 334.7638061684703,
+ "y": -225.35164804754552,
+ "z": 0.0
+ },
+ {
+ "x": 334.7631948755461,
+ "y": -226.36370393769795,
+ "z": 0.0
+ },
+ {
+ "x": 334.7625835826218,
+ "y": -227.3757598278505,
+ "z": 0.0
+ },
+ {
+ "x": 334.7619722896975,
+ "y": -228.38781571800314,
+ "z": 0.0
+ },
+ {
+ "x": 334.7613609967732,
+ "y": -229.39987160815556,
+ "z": 0.0
+ },
+ {
+ "x": 334.7607497038489,
+ "y": -230.41192749830822,
+ "z": 0.0
+ },
+ {
+ "x": 334.7601384109247,
+ "y": -231.42398338846064,
+ "z": 0.0
+ },
+ {
+ "x": 334.7595271180004,
+ "y": -232.4360392786133,
+ "z": 0.0
+ },
+ {
+ "x": 334.7589158250761,
+ "y": -233.44809516876572,
+ "z": 0.0
+ },
+ {
+ "x": 334.7583045321518,
+ "y": -234.46015105891826,
+ "z": 0.0
+ },
+ {
+ "x": 334.7576932392275,
+ "y": -235.4722069490709,
+ "z": 0.0
+ },
+ {
+ "x": 334.7570819463033,
+ "y": -236.48426283922333,
+ "z": 0.0
+ },
+ {
+ "x": 334.756470653379,
+ "y": -237.496318729376,
+ "z": 0.0
+ },
+ {
+ "x": 334.7558593604547,
+ "y": -238.5083746195284,
+ "z": 0.0
+ },
+ {
+ "x": 334.7552480675304,
+ "y": -239.52043050968106,
+ "z": 0.0
+ },
+ {
+ "x": 334.7546367746062,
+ "y": -240.5324863998335,
+ "z": 0.0
+ },
+ {
+ "x": 334.7540254816819,
+ "y": -241.54454228998614,
+ "z": 0.0
+ },
+ {
+ "x": 334.7534141887576,
+ "y": -242.55659818013856,
+ "z": 0.0
+ },
+ {
+ "x": 334.75280289583327,
+ "y": -243.5686540702911,
+ "z": 0.0
+ },
+ {
+ "x": 334.75219160290897,
+ "y": -244.58070996044376,
+ "z": 0.0
+ },
+ {
+ "x": 334.7515803099848,
+ "y": -245.59276585059618,
+ "z": 0.0
+ },
+ {
+ "x": 334.75096901706047,
+ "y": -246.60482174074883,
+ "z": 0.0
+ },
+ {
+ "x": 334.75035772413617,
+ "y": -247.61687763090126,
+ "z": 0.0
+ },
+ {
+ "x": 334.74974643121186,
+ "y": -248.6289335210539,
+ "z": 0.0
+ },
+ {
+ "x": 334.74913513828767,
+ "y": -249.64098941120633,
+ "z": 0.0
+ },
+ {
+ "x": 334.74852384536337,
+ "y": -250.653045301359,
+ "z": 0.0
+ },
+ {
+ "x": 334.74791255243906,
+ "y": -251.6651011915114,
+ "z": 0.0
+ },
+ {
+ "x": 334.74730125951476,
+ "y": -252.67715708166395,
+ "z": 0.0
+ },
+ {
+ "x": 334.74668996659045,
+ "y": -253.6892129718166,
+ "z": 0.0
+ },
+ {
+ "x": 334.74607867366626,
+ "y": -254.70126886196903,
+ "z": 0.0
+ },
+ {
+ "x": 334.74546738074196,
+ "y": -255.71332475212168,
+ "z": 0.0
+ },
+ {
+ "x": 334.74485608781765,
+ "y": -256.7253806422741,
+ "z": 0.0
+ },
+ {
+ "x": 334.74424479489335,
+ "y": -257.7374365324267,
+ "z": 0.0
+ },
+ {
+ "x": 334.74363350196916,
+ "y": -258.74949242257924,
+ "z": 0.0
+ },
+ {
+ "x": 334.74302220904485,
+ "y": -259.76154831273186,
+ "z": 0.0
+ },
+ {
+ "x": 334.74241091612055,
+ "y": -260.77360420288426,
+ "z": 0.0
+ },
+ {
+ "x": 334.74179962319624,
+ "y": -261.78566009303677,
+ "z": 0.0
+ },
+ {
+ "x": 334.74118833027194,
+ "y": -262.7977159831895,
+ "z": 0.0
+ },
+ {
+ "x": 334.74057703734775,
+ "y": -263.8097718733419,
+ "z": 0.0
+ },
+ {
+ "x": 334.73996574442344,
+ "y": -264.8218277634945,
+ "z": 0.0
+ },
+ {
+ "x": 334.73935445149914,
+ "y": -265.8338836536469,
+ "z": 0.0
+ },
+ {
+ "x": 334.73874315857483,
+ "y": -266.84593954379966,
+ "z": 0.0
+ },
+ {
+ "x": 334.73813186565064,
+ "y": -267.85799543395206,
+ "z": 0.0
+ },
+ {
+ "x": 334.73752057272634,
+ "y": -268.8700513241047,
+ "z": 0.0
+ },
+ {
+ "x": 334.73690927980203,
+ "y": -269.8821072142571,
+ "z": 0.0
+ },
+ {
+ "x": 334.73629798687773,
+ "y": -270.8941631044097,
+ "z": 0.0
+ },
+ {
+ "x": 334.7356866939534,
+ "y": -271.9062189945623,
+ "z": 0.0
+ },
+ {
+ "x": 334.73507540102923,
+ "y": -272.9182748847147,
+ "z": 0.0
+ },
+ {
+ "x": 334.73446410810493,
+ "y": -273.93033077486734,
+ "z": 0.0
+ },
+ {
+ "x": 334.7338528151806,
+ "y": -274.94238666501985,
+ "z": 0.0
+ },
+ {
+ "x": 334.7332415222563,
+ "y": -275.9544425551725,
+ "z": 0.0
+ },
+ {
+ "x": 334.73263022933213,
+ "y": -276.9664984453249,
+ "z": 0.0
+ },
+ {
+ "x": 334.7320189364078,
+ "y": -277.9785543354774,
+ "z": 0.0
+ },
+ {
+ "x": 334.7314076434835,
+ "y": -278.99061022563,
+ "z": 0.0
+ },
+ {
+ "x": 334.7307963505592,
+ "y": -280.0026661157824,
+ "z": 0.0
+ },
+ {
+ "x": 334.7301850576349,
+ "y": -281.01472200593514,
+ "z": 0.0
+ },
+ {
+ "x": 334.7295737647107,
+ "y": -282.02677789608754,
+ "z": 0.0
+ },
+ {
+ "x": 334.7289624717864,
+ "y": -283.03883378624016,
+ "z": 0.0
+ },
+ {
+ "x": 334.7283511788621,
+ "y": -284.05088967639256,
+ "z": 0.0
+ },
+ {
+ "x": 334.7277398859378,
+ "y": -285.0629455665452,
+ "z": 0.0
+ },
+ {
+ "x": 334.7271285930136,
+ "y": -286.0750014566977,
+ "z": 0.0
+ },
+ {
+ "x": 334.7265173000893,
+ "y": -287.0870573468502,
+ "z": 0.0
+ },
+ {
+ "x": 334.725906007165,
+ "y": -288.0991132370028,
+ "z": 0.0
+ },
+ {
+ "x": 334.7252947142407,
+ "y": -289.1111691271552,
+ "z": 0.0
+ },
+ {
+ "x": 334.7246834213164,
+ "y": -290.12322501730785,
+ "z": 0.0
+ },
+ {
+ "x": 334.7240721283922,
+ "y": -291.13528090746036,
+ "z": 0.0
+ },
+ {
+ "x": 334.7234608354679,
+ "y": -292.147336797613,
+ "z": 0.0
+ },
+ {
+ "x": 334.7228495425436,
+ "y": -293.1593926877654,
+ "z": 0.0
+ },
+ {
+ "x": 334.7222382496193,
+ "y": -294.171448577918,
+ "z": 0.0
+ },
+ {
+ "x": 334.7216269566951,
+ "y": -295.1835044680704,
+ "z": 0.0
+ },
+ {
+ "x": 334.7210156637708,
+ "y": -296.195560358223,
+ "z": 0.0
+ },
+ {
+ "x": 334.7204043708465,
+ "y": -297.20761624837564,
+ "z": 0.0
+ },
+ {
+ "x": 334.7197930779222,
+ "y": -298.21967213852804,
+ "z": 0.0
+ },
+ {
+ "x": 334.7191817849979,
+ "y": -299.23172802868066,
+ "z": 0.0
+ },
+ {
+ "x": 334.7185704920737,
+ "y": -300.24378391883306,
+ "z": 0.0
+ },
+ {
+ "x": 334.7179591991494,
+ "y": -301.2558398089858,
+ "z": 0.0
+ },
+ {
+ "x": 334.7173479062251,
+ "y": -302.2678956991382,
+ "z": 0.0
+ },
+ {
+ "x": 334.7167366133008,
+ "y": -303.2799515892908,
+ "z": 0.0
+ },
+ {
+ "x": 334.7161253203766,
+ "y": -304.2920074794432,
+ "z": 0.0
+ },
+ {
+ "x": 334.7155140274523,
+ "y": -305.3040633695957,
+ "z": 0.0
+ },
+ {
+ "x": 334.714902734528,
+ "y": -306.31611925974846,
+ "z": 0.0
+ },
+ {
+ "x": 334.7142914416037,
+ "y": -307.32817514990086,
+ "z": 0.0
+ },
+ {
+ "x": 334.7136801486794,
+ "y": -308.3402310400535,
+ "z": 0.0
+ },
+ {
+ "x": 334.7130688557552,
+ "y": -309.3522869302059,
+ "z": 0.0
+ },
+ {
+ "x": 334.7124575628309,
+ "y": -310.3643428203585,
+ "z": 0.0
+ },
+ {
+ "x": 334.7118462699066,
+ "y": -311.376398710511,
+ "z": 0.0
+ },
+ {
+ "x": 334.71123497698227,
+ "y": -312.38845460066364,
+ "z": 0.0
+ },
+ {
+ "x": 334.7106236840581,
+ "y": -313.40051049081603,
+ "z": 0.0
+ },
+ {
+ "x": 334.7100123911338,
+ "y": -314.41256638096854,
+ "z": 0.0
+ },
+ {
+ "x": 334.70940109820947,
+ "y": -315.42462227112117,
+ "z": 0.0
+ },
+ {
+ "x": 334.70878980528516,
+ "y": -316.4366781612737,
+ "z": 0.0
+ },
+ {
+ "x": 334.70817851236086,
+ "y": -317.4487340514262,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 100,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": -3.987604267005838,
+ "y": -317.73882523260744,
+ "z": 0.0
+ },
+ {
+ "x": -3.9515143703865285,
+ "y": -318.7810983745968,
+ "z": 0.0
+ },
+ {
+ "x": -3.8357237138442493,
+ "y": -320.0628235375496,
+ "z": 0.0
+ },
+ {
+ "x": -3.6035435046796116,
+ "y": -321.42014727038304,
+ "z": 0.0
+ },
+ {
+ "x": -3.2131749323592027,
+ "y": -322.83156756042615,
+ "z": 0.0
+ },
+ {
+ "x": -2.7092233918898647,
+ "y": -324.14949690005676,
+ "z": 0.0
+ },
+ {
+ "x": -2.1098992234032172,
+ "y": -325.3878357724527,
+ "z": 0.0
+ },
+ {
+ "x": -1.409105747859908,
+ "y": -326.5720532697058,
+ "z": 0.0
+ },
+ {
+ "x": -0.6105033054651816,
+ "y": -327.6951555653618,
+ "z": 0.0
+ },
+ {
+ "x": 0.43807983625093394,
+ "y": -328.8516649130274,
+ "z": 0.0
+ },
+ {
+ "x": 1.5705790610352346,
+ "y": -329.83579929197316,
+ "z": 0.0
+ },
+ {
+ "x": 2.80235614833182,
+ "y": -330.68122629595655,
+ "z": 0.0
+ },
+ {
+ "x": 4.122257124910212,
+ "y": -331.3817673703651,
+ "z": 0.0
+ },
+ {
+ "x": 5.514762444971803,
+ "y": -331.9288192605436,
+ "z": 0.0
+ },
+ {
+ "x": 7.049720839454694,
+ "y": -332.31271128481416,
+ "z": 0.0
+ },
+ {
+ "x": 8.585458950714365,
+ "y": -332.4921951397266,
+ "z": 0.0
+ },
+ {
+ "x": 9.896942070360003,
+ "y": -332.53837993970717,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 101,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 10.123058387403669,
+ "y": -324.54157611498033,
+ "z": 0.0
+ },
+ {
+ "x": 9.350105318731895,
+ "y": -324.5288217382166,
+ "z": 0.0
+ },
+ {
+ "x": 8.811596495545004,
+ "y": -324.5091355549019,
+ "z": 0.0
+ },
+ {
+ "x": 8.311184096648525,
+ "y": -324.43348564915357,
+ "z": 0.0
+ },
+ {
+ "x": 7.750386387471255,
+ "y": -324.25178293460726,
+ "z": 0.0
+ },
+ {
+ "x": 7.2149908856266585,
+ "y": -324.00824685081966,
+ "z": 0.0
+ },
+ {
+ "x": 6.710985586909846,
+ "y": -323.7058546960779,
+ "z": 0.0
+ },
+ {
+ "x": 6.247647921620716,
+ "y": -323.3517632174102,
+ "z": 0.0
+ },
+ {
+ "x": 5.861716980926192,
+ "y": -322.9929896214138,
+ "z": 0.0
+ },
+ {
+ "x": 5.4339661146776255,
+ "y": -322.42809773372966,
+ "z": 0.0
+ },
+ {
+ "x": 5.055313250704519,
+ "y": -321.82978431120443,
+ "z": 0.0
+ },
+ {
+ "x": 4.728104996227859,
+ "y": -321.2022699920468,
+ "z": 0.0
+ },
+ {
+ "x": 4.464117028182713,
+ "y": -320.58230364692054,
+ "z": 0.0
+ },
+ {
+ "x": 4.267820431277832,
+ "y": -319.99129115876485,
+ "z": 0.0
+ },
+ {
+ "x": 4.127488182559836,
+ "y": -319.29649704514026,
+ "z": 0.0
+ },
+ {
+ "x": 4.0436940593728075,
+ "y": -318.5042551613782,
+ "z": 0.0
+ },
+ {
+ "x": 4.007604162753498,
+ "y": -317.4619820193888,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 102,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 10.010000228881836,
+ "y": -328.53997802734375,
+ "z": 0.0
+ },
+ {
+ "x": 8.96778213472313,
+ "y": -328.5105084389716,
+ "z": 0.0
+ },
+ {
+ "x": 7.9306586674998485,
+ "y": -328.410923419858,
+ "z": 0.0
+ },
+ {
+ "x": 6.912973270810164,
+ "y": -328.1811524548486,
+ "z": 0.0
+ },
+ {
+ "x": 5.9363217561907335,
+ "y": -327.8167751524862,
+ "z": 0.0
+ },
+ {
+ "x": 5.008673516979239,
+ "y": -327.3447365733881,
+ "z": 0.0
+ },
+ {
+ "x": 4.14078232397254,
+ "y": -326.7708269940255,
+ "z": 0.0
+ },
+ {
+ "x": 3.3428638789358254,
+ "y": -326.1017140652188,
+ "z": 0.0
+ },
+ {
+ "x": 2.6256068377305053,
+ "y": -325.3440725933878,
+ "z": 0.0
+ },
+ {
+ "x": 2.012430183408859,
+ "y": -324.50007550171773,
+ "z": 0.0
+ },
+ {
+ "x": 1.4727070136506513,
+ "y": -323.6088100418286,
+ "z": 0.0
+ },
+ {
+ "x": 1.0094408021689976,
+ "y": -322.6758834460518,
+ "z": 0.0
+ },
+ {
+ "x": 0.6254710479117551,
+ "y": -321.70693560367334,
+ "z": 0.0
+ },
+ {
+ "x": 0.3321384632991102,
+ "y": -320.70571921457395,
+ "z": 0.0
+ },
+ {
+ "x": 0.14588223435779368,
+ "y": -319.67966029134493,
+ "z": 0.0
+ },
+ {
+ "x": 0.04608984449313969,
+ "y": -318.6426767679875,
+ "z": 0.0
+ },
+ {
+ "x": 0.009999947873830324,
+ "y": -317.6004036259981,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 103,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": -1.988802159566004,
+ "y": -317.6696144293028,
+ "z": 0.0
+ },
+ {
+ "x": -1.9527122629466944,
+ "y": -318.71188757129215,
+ "z": 0.0
+ },
+ {
+ "x": -1.8449207397432277,
+ "y": -319.8712419144473,
+ "z": 0.0
+ },
+ {
+ "x": -1.6357025206902507,
+ "y": -321.0629332424785,
+ "z": 0.0
+ },
+ {
+ "x": -1.2938519422237238,
+ "y": -322.2692515820497,
+ "z": 0.0
+ },
+ {
+ "x": -0.8498912948604336,
+ "y": -323.4126901730543,
+ "z": 0.0
+ },
+ {
+ "x": -0.318596104876283,
+ "y": -324.4983229071406,
+ "z": 0.0
+ },
+ {
+ "x": 0.30166221777447544,
+ "y": -325.53606438571177,
+ "z": 0.0
+ },
+ {
+ "x": 1.0075517661326618,
+ "y": -326.51961407937483,
+ "z": 0.0
+ },
+ {
+ "x": 1.8904718575933797,
+ "y": -327.4766894891231,
+ "z": 0.0
+ },
+ {
+ "x": 2.8556806925038876,
+ "y": -328.30331314299934,
+ "z": 0.0
+ },
+ {
+ "x": 3.9055148326555296,
+ "y": -329.0129814346723,
+ "z": 0.0
+ },
+ {
+ "x": 5.029289440550473,
+ "y": -329.59927126142566,
+ "z": 0.0
+ },
+ {
+ "x": 6.213867857890984,
+ "y": -330.0549858576961,
+ "z": 0.0
+ },
+ {
+ "x": 7.490189753477271,
+ "y": -330.36181735233606,
+ "z": 0.0
+ },
+ {
+ "x": 8.776620542718748,
+ "y": -330.5013517893491,
+ "z": 0.0
+ },
+ {
+ "x": 9.95347114962092,
+ "y": -330.53917898352546,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 104,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 10.066529308142751,
+ "y": -326.54077707116204,
+ "z": 0.0
+ },
+ {
+ "x": 9.158943726727513,
+ "y": -326.51966508859414,
+ "z": 0.0
+ },
+ {
+ "x": 8.371127581522426,
+ "y": -326.46002948738,
+ "z": 0.0
+ },
+ {
+ "x": 7.612078683729344,
+ "y": -326.30731905200105,
+ "z": 0.0
+ },
+ {
+ "x": 6.843354071830994,
+ "y": -326.0342790435467,
+ "z": 0.0
+ },
+ {
+ "x": 6.111832201302949,
+ "y": -325.6764917121039,
+ "z": 0.0
+ },
+ {
+ "x": 5.4258839554411935,
+ "y": -325.2383408450517,
+ "z": 0.0
+ },
+ {
+ "x": 4.795255900278271,
+ "y": -324.7267386413145,
+ "z": 0.0
+ },
+ {
+ "x": 4.243661909328349,
+ "y": -324.1685311074008,
+ "z": 0.0
+ },
+ {
+ "x": 3.723198149043242,
+ "y": -323.4640866177237,
+ "z": 0.0
+ },
+ {
+ "x": 3.264010132177585,
+ "y": -322.71929717651653,
+ "z": 0.0
+ },
+ {
+ "x": 2.8687728991984285,
+ "y": -321.9390767190493,
+ "z": 0.0
+ },
+ {
+ "x": 2.5447940380472343,
+ "y": -321.14461962529697,
+ "z": 0.0
+ },
+ {
+ "x": 2.2999794472884707,
+ "y": -320.3485051866694,
+ "z": 0.0
+ },
+ {
+ "x": 2.136685208458815,
+ "y": -319.48807866824257,
+ "z": 0.0
+ },
+ {
+ "x": 2.0448919519329736,
+ "y": -318.57346596468284,
+ "z": 0.0
+ },
+ {
+ "x": 2.0088020553136645,
+ "y": -317.53119282269347,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 105,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 94.37701805715766,
+ "y": -46.14939141843673,
+ "z": 0.0
+ },
+ {
+ "x": 94.37686197589477,
+ "y": -45.122626724417536,
+ "z": 0.0
+ },
+ {
+ "x": 94.37670589463187,
+ "y": -44.0958620303983,
+ "z": 0.0
+ },
+ {
+ "x": 94.37654981336898,
+ "y": -43.069097336379166,
+ "z": 0.0
+ },
+ {
+ "x": 94.3763937321061,
+ "y": -42.04233264235998,
+ "z": 0.0
+ },
+ {
+ "x": 94.3762376508432,
+ "y": -41.01556794834073,
+ "z": 0.0
+ },
+ {
+ "x": 94.37608156958031,
+ "y": -39.9888032543216,
+ "z": 0.0
+ },
+ {
+ "x": 94.37592548831742,
+ "y": -38.96203856030242,
+ "z": 0.0
+ },
+ {
+ "x": 94.37576940705453,
+ "y": -37.93527386628323,
+ "z": 0.0
+ },
+ {
+ "x": 94.37561332579165,
+ "y": -36.90850917226405,
+ "z": 0.0
+ },
+ {
+ "x": 94.37545724452875,
+ "y": -35.8817444782448,
+ "z": 0.0
+ },
+ {
+ "x": 94.37530116326586,
+ "y": -34.85497978422568,
+ "z": 0.0
+ },
+ {
+ "x": 94.37514508200297,
+ "y": -33.82821509020649,
+ "z": 0.0
+ },
+ {
+ "x": 94.37498900074007,
+ "y": -32.80145039618724,
+ "z": 0.0
+ },
+ {
+ "x": 94.37483291947719,
+ "y": -31.774685702168114,
+ "z": 0.0
+ },
+ {
+ "x": 94.3746768382143,
+ "y": -30.74792100814893,
+ "z": 0.0
+ },
+ {
+ "x": 94.3745207569514,
+ "y": -29.721156314129683,
+ "z": 0.0
+ },
+ {
+ "x": 94.37436467568851,
+ "y": -28.694391620110554,
+ "z": 0.0
+ },
+ {
+ "x": 94.37420859442562,
+ "y": -27.667626926091366,
+ "z": 0.0
+ },
+ {
+ "x": 94.37405251316274,
+ "y": -26.64086223207218,
+ "z": 0.0
+ },
+ {
+ "x": 94.37389643189984,
+ "y": -25.614097538052935,
+ "z": 0.0
+ },
+ {
+ "x": 94.37374035063695,
+ "y": -24.587332844033806,
+ "z": 0.0
+ },
+ {
+ "x": 94.37358426937405,
+ "y": -23.56056815001456,
+ "z": 0.0
+ },
+ {
+ "x": 94.37342818811116,
+ "y": -22.533803455995436,
+ "z": 0.0
+ },
+ {
+ "x": 94.37327210684828,
+ "y": -21.507038761976247,
+ "z": 0.0
+ },
+ {
+ "x": 94.37311602558538,
+ "y": -20.480274067957005,
+ "z": 0.0
+ },
+ {
+ "x": 94.3729599443225,
+ "y": -19.453509373937926,
+ "z": 0.0
+ },
+ {
+ "x": 94.3728038630596,
+ "y": -18.42674467991863,
+ "z": 0.0
+ },
+ {
+ "x": 94.37264778179672,
+ "y": -17.3999799858995,
+ "z": 0.0
+ },
+ {
+ "x": 94.37249170053383,
+ "y": -16.373215291880314,
+ "z": 0.0
+ },
+ {
+ "x": 94.37233561927093,
+ "y": -15.346450597861072,
+ "z": 0.0
+ },
+ {
+ "x": 94.37217953800804,
+ "y": -14.31968590384194,
+ "z": 0.0
+ },
+ {
+ "x": 94.37202345674515,
+ "y": -13.292921209822753,
+ "z": 0.0
+ },
+ {
+ "x": 94.37186737548225,
+ "y": -12.26615651580351,
+ "z": 0.0
+ },
+ {
+ "x": 94.37171129421937,
+ "y": -11.239391821784379,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 106,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 86.3717113866508,
+ "y": -11.240607923288396,
+ "z": 0.0
+ },
+ {
+ "x": 86.37186746791369,
+ "y": -12.267372617307638,
+ "z": 0.0
+ },
+ {
+ "x": 86.37202354917659,
+ "y": -13.29413731132677,
+ "z": 0.0
+ },
+ {
+ "x": 86.37217963043948,
+ "y": -14.320902005345957,
+ "z": 0.0
+ },
+ {
+ "x": 86.37233571170236,
+ "y": -15.347666699365199,
+ "z": 0.0
+ },
+ {
+ "x": 86.37249179296526,
+ "y": -16.374431393384327,
+ "z": 0.0
+ },
+ {
+ "x": 86.37264787422815,
+ "y": -17.401196087403513,
+ "z": 0.0
+ },
+ {
+ "x": 86.37280395549104,
+ "y": -18.427960781422758,
+ "z": 0.0
+ },
+ {
+ "x": 86.37296003675394,
+ "y": -19.454725475441833,
+ "z": 0.0
+ },
+ {
+ "x": 86.37311611801681,
+ "y": -20.481490169461132,
+ "z": 0.0
+ },
+ {
+ "x": 86.37327219927971,
+ "y": -21.50825486348026,
+ "z": 0.0
+ },
+ {
+ "x": 86.3734282805426,
+ "y": -22.53501955749945,
+ "z": 0.0
+ },
+ {
+ "x": 86.37358436180548,
+ "y": -23.561784251518688,
+ "z": 0.0
+ },
+ {
+ "x": 86.37374044306839,
+ "y": -24.58854894553782,
+ "z": 0.0
+ },
+ {
+ "x": 86.37389652433127,
+ "y": -25.615313639557062,
+ "z": 0.0
+ },
+ {
+ "x": 86.37405260559417,
+ "y": -26.642078333576194,
+ "z": 0.0
+ },
+ {
+ "x": 86.37420868685706,
+ "y": -27.66884302759538,
+ "z": 0.0
+ },
+ {
+ "x": 86.37436476811995,
+ "y": -28.695607721614568,
+ "z": 0.0
+ },
+ {
+ "x": 86.37452084938283,
+ "y": -29.72237241563381,
+ "z": 0.0
+ },
+ {
+ "x": 86.37467693064573,
+ "y": -30.749137109652942,
+ "z": 0.0
+ },
+ {
+ "x": 86.37483301190862,
+ "y": -31.775901803672127,
+ "z": 0.0
+ },
+ {
+ "x": 86.37498909317151,
+ "y": -32.80266649769137,
+ "z": 0.0
+ },
+ {
+ "x": 86.37514517443441,
+ "y": -33.829431191710505,
+ "z": 0.0
+ },
+ {
+ "x": 86.3753012556973,
+ "y": -34.85619588572969,
+ "z": 0.0
+ },
+ {
+ "x": 86.37545733696018,
+ "y": -35.882960579748925,
+ "z": 0.0
+ },
+ {
+ "x": 86.37561341822308,
+ "y": -36.90972527376806,
+ "z": 0.0
+ },
+ {
+ "x": 86.37576949948597,
+ "y": -37.936489967787246,
+ "z": 0.0
+ },
+ {
+ "x": 86.37592558074886,
+ "y": -38.96325466180643,
+ "z": 0.0
+ },
+ {
+ "x": 86.37608166201174,
+ "y": -39.990019355825616,
+ "z": 0.0
+ },
+ {
+ "x": 86.37623774327463,
+ "y": -41.01678404984486,
+ "z": 0.0
+ },
+ {
+ "x": 86.37639382453753,
+ "y": -42.043548743863994,
+ "z": 0.0
+ },
+ {
+ "x": 86.37654990580042,
+ "y": -43.07031343788318,
+ "z": 0.0
+ },
+ {
+ "x": 86.3767059870633,
+ "y": -44.09707813190243,
+ "z": 0.0
+ },
+ {
+ "x": 86.3768620683262,
+ "y": -45.12384282592155,
+ "z": 0.0
+ },
+ {
+ "x": 86.37701814958909,
+ "y": -46.15060751994074,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 107,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 90.37171134043508,
+ "y": -11.239999872536387,
+ "z": 0.0
+ },
+ {
+ "x": 90.37186742169797,
+ "y": -12.266764566555574,
+ "z": 0.0
+ },
+ {
+ "x": 90.37202350296087,
+ "y": -13.293529260574761,
+ "z": 0.0
+ },
+ {
+ "x": 90.37217958422376,
+ "y": -14.320293954593948,
+ "z": 0.0
+ },
+ {
+ "x": 90.37233566548664,
+ "y": -15.347058648613135,
+ "z": 0.0
+ },
+ {
+ "x": 90.37249174674955,
+ "y": -16.37382334263232,
+ "z": 0.0
+ },
+ {
+ "x": 90.37264782801243,
+ "y": -17.400588036651506,
+ "z": 0.0
+ },
+ {
+ "x": 90.37280390927532,
+ "y": -18.427352730670695,
+ "z": 0.0
+ },
+ {
+ "x": 90.37295999053822,
+ "y": -19.45411742468988,
+ "z": 0.0
+ },
+ {
+ "x": 90.37311607180109,
+ "y": -20.48088211870907,
+ "z": 0.0
+ },
+ {
+ "x": 90.373272153064,
+ "y": -21.507646812728254,
+ "z": 0.0
+ },
+ {
+ "x": 90.37342823432688,
+ "y": -22.534411506747443,
+ "z": 0.0
+ },
+ {
+ "x": 90.37358431558977,
+ "y": -23.561176200766624,
+ "z": 0.0
+ },
+ {
+ "x": 90.37374039685267,
+ "y": -24.587940894785813,
+ "z": 0.0
+ },
+ {
+ "x": 90.37389647811555,
+ "y": -25.614705588805,
+ "z": 0.0
+ },
+ {
+ "x": 90.37405255937846,
+ "y": -26.641470282824187,
+ "z": 0.0
+ },
+ {
+ "x": 90.37420864064134,
+ "y": -27.668234976843372,
+ "z": 0.0
+ },
+ {
+ "x": 90.37436472190423,
+ "y": -28.69499967086256,
+ "z": 0.0
+ },
+ {
+ "x": 90.37452080316712,
+ "y": -29.721764364881746,
+ "z": 0.0
+ },
+ {
+ "x": 90.37467688443002,
+ "y": -30.748529058900935,
+ "z": 0.0
+ },
+ {
+ "x": 90.3748329656929,
+ "y": -31.77529375292012,
+ "z": 0.0
+ },
+ {
+ "x": 90.37498904695579,
+ "y": -32.802058446939306,
+ "z": 0.0
+ },
+ {
+ "x": 90.37514512821869,
+ "y": -33.8288231409585,
+ "z": 0.0
+ },
+ {
+ "x": 90.37530120948158,
+ "y": -34.85558783497768,
+ "z": 0.0
+ },
+ {
+ "x": 90.37545729074446,
+ "y": -35.88235252899686,
+ "z": 0.0
+ },
+ {
+ "x": 90.37561337200736,
+ "y": -36.909117223016054,
+ "z": 0.0
+ },
+ {
+ "x": 90.37576945327025,
+ "y": -37.93588191703524,
+ "z": 0.0
+ },
+ {
+ "x": 90.37592553453314,
+ "y": -38.962646611054424,
+ "z": 0.0
+ },
+ {
+ "x": 90.37608161579602,
+ "y": -39.98941130507361,
+ "z": 0.0
+ },
+ {
+ "x": 90.37623769705891,
+ "y": -41.016175999092795,
+ "z": 0.0
+ },
+ {
+ "x": 90.37639377832181,
+ "y": -42.04294069311199,
+ "z": 0.0
+ },
+ {
+ "x": 90.3765498595847,
+ "y": -43.06970538713117,
+ "z": 0.0
+ },
+ {
+ "x": 90.37670594084759,
+ "y": -44.096470081150365,
+ "z": 0.0
+ },
+ {
+ "x": 90.37686202211049,
+ "y": -45.12323477516954,
+ "z": 0.0
+ },
+ {
+ "x": 90.37701810337337,
+ "y": -46.149999469188735,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 108,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 92.37701808026551,
+ "y": -46.14969544381273,
+ "z": 0.0
+ },
+ {
+ "x": 92.37686199900263,
+ "y": -45.12293074979354,
+ "z": 0.0
+ },
+ {
+ "x": 92.37670591773973,
+ "y": -44.09616605577433,
+ "z": 0.0
+ },
+ {
+ "x": 92.37654983647684,
+ "y": -43.06940136175517,
+ "z": 0.0
+ },
+ {
+ "x": 92.37639375521395,
+ "y": -42.042636667735984,
+ "z": 0.0
+ },
+ {
+ "x": 92.37623767395105,
+ "y": -41.01587197371676,
+ "z": 0.0
+ },
+ {
+ "x": 92.37608159268817,
+ "y": -39.989107279697606,
+ "z": 0.0
+ },
+ {
+ "x": 92.37592551142528,
+ "y": -38.96234258567842,
+ "z": 0.0
+ },
+ {
+ "x": 92.37576943016239,
+ "y": -37.935577891659236,
+ "z": 0.0
+ },
+ {
+ "x": 92.3756133488995,
+ "y": -36.90881319764005,
+ "z": 0.0
+ },
+ {
+ "x": 92.3754572676366,
+ "y": -35.88204850362083,
+ "z": 0.0
+ },
+ {
+ "x": 92.37530118637372,
+ "y": -34.85528380960168,
+ "z": 0.0
+ },
+ {
+ "x": 92.37514510511083,
+ "y": -33.828519115582495,
+ "z": 0.0
+ },
+ {
+ "x": 92.37498902384793,
+ "y": -32.801754421563274,
+ "z": 0.0
+ },
+ {
+ "x": 92.37483294258504,
+ "y": -31.774989727544117,
+ "z": 0.0
+ },
+ {
+ "x": 92.37467686132216,
+ "y": -30.748225033524932,
+ "z": 0.0
+ },
+ {
+ "x": 92.37452078005926,
+ "y": -29.721460339505715,
+ "z": 0.0
+ },
+ {
+ "x": 92.37436469879637,
+ "y": -28.694695645486558,
+ "z": 0.0
+ },
+ {
+ "x": 92.37420861753348,
+ "y": -27.66793095146737,
+ "z": 0.0
+ },
+ {
+ "x": 92.3740525362706,
+ "y": -26.641166257448184,
+ "z": 0.0
+ },
+ {
+ "x": 92.3738964550077,
+ "y": -25.614401563428967,
+ "z": 0.0
+ },
+ {
+ "x": 92.37374037374481,
+ "y": -24.58763686940981,
+ "z": 0.0
+ },
+ {
+ "x": 92.37358429248191,
+ "y": -23.560872175390593,
+ "z": 0.0
+ },
+ {
+ "x": 92.37342821121902,
+ "y": -22.53410748137144,
+ "z": 0.0
+ },
+ {
+ "x": 92.37327212995613,
+ "y": -21.50734278735225,
+ "z": 0.0
+ },
+ {
+ "x": 92.37311604869323,
+ "y": -20.480578093333037,
+ "z": 0.0
+ },
+ {
+ "x": 92.37295996743036,
+ "y": -19.4538133993139,
+ "z": 0.0
+ },
+ {
+ "x": 92.37280388616746,
+ "y": -18.427048705294663,
+ "z": 0.0
+ },
+ {
+ "x": 92.37264780490457,
+ "y": -17.400284011275502,
+ "z": 0.0
+ },
+ {
+ "x": 92.37249172364169,
+ "y": -16.373519317256317,
+ "z": 0.0
+ },
+ {
+ "x": 92.37233564237879,
+ "y": -15.346754623237103,
+ "z": 0.0
+ },
+ {
+ "x": 92.3721795611159,
+ "y": -14.319989929217943,
+ "z": 0.0
+ },
+ {
+ "x": 92.37202347985301,
+ "y": -13.293225235198758,
+ "z": 0.0
+ },
+ {
+ "x": 92.37186739859011,
+ "y": -12.266460541179542,
+ "z": 0.0
+ },
+ {
+ "x": 92.37171131732723,
+ "y": -11.239695847160384,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 109,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 88.37171136354294,
+ "y": -11.24030389791239,
+ "z": 0.0
+ },
+ {
+ "x": 88.37186744480583,
+ "y": -12.267068591931606,
+ "z": 0.0
+ },
+ {
+ "x": 88.37202352606873,
+ "y": -13.293833285950765,
+ "z": 0.0
+ },
+ {
+ "x": 88.37217960733162,
+ "y": -14.320597979969953,
+ "z": 0.0
+ },
+ {
+ "x": 88.3723356885945,
+ "y": -15.347362673989167,
+ "z": 0.0
+ },
+ {
+ "x": 88.3724917698574,
+ "y": -16.374127368008324,
+ "z": 0.0
+ },
+ {
+ "x": 88.37264785112029,
+ "y": -17.40089206202751,
+ "z": 0.0
+ },
+ {
+ "x": 88.37280393238318,
+ "y": -18.427656756046726,
+ "z": 0.0
+ },
+ {
+ "x": 88.37296001364608,
+ "y": -19.45442145006586,
+ "z": 0.0
+ },
+ {
+ "x": 88.37311609490895,
+ "y": -20.4811861440851,
+ "z": 0.0
+ },
+ {
+ "x": 88.37327217617185,
+ "y": -21.507950838104257,
+ "z": 0.0
+ },
+ {
+ "x": 88.37342825743474,
+ "y": -22.534715532123446,
+ "z": 0.0
+ },
+ {
+ "x": 88.37358433869763,
+ "y": -23.561480226142656,
+ "z": 0.0
+ },
+ {
+ "x": 88.37374041996053,
+ "y": -24.588244920161817,
+ "z": 0.0
+ },
+ {
+ "x": 88.37389650122341,
+ "y": -25.61500961418103,
+ "z": 0.0
+ },
+ {
+ "x": 88.37405258248631,
+ "y": -26.64177430820019,
+ "z": 0.0
+ },
+ {
+ "x": 88.3742086637492,
+ "y": -27.668539002219376,
+ "z": 0.0
+ },
+ {
+ "x": 88.37436474501209,
+ "y": -28.695303696238565,
+ "z": 0.0
+ },
+ {
+ "x": 88.37452082627497,
+ "y": -29.72206839025778,
+ "z": 0.0
+ },
+ {
+ "x": 88.37467690753788,
+ "y": -30.74883308427694,
+ "z": 0.0
+ },
+ {
+ "x": 88.37483298880076,
+ "y": -31.775597778296124,
+ "z": 0.0
+ },
+ {
+ "x": 88.37498907006365,
+ "y": -32.80236247231534,
+ "z": 0.0
+ },
+ {
+ "x": 88.37514515132655,
+ "y": -33.8291271663345,
+ "z": 0.0
+ },
+ {
+ "x": 88.37530123258944,
+ "y": -34.85589186035369,
+ "z": 0.0
+ },
+ {
+ "x": 88.37545731385232,
+ "y": -35.88265655437289,
+ "z": 0.0
+ },
+ {
+ "x": 88.37561339511522,
+ "y": -36.90942124839206,
+ "z": 0.0
+ },
+ {
+ "x": 88.37576947637811,
+ "y": -37.93618594241124,
+ "z": 0.0
+ },
+ {
+ "x": 88.375925557641,
+ "y": -38.96295063643043,
+ "z": 0.0
+ },
+ {
+ "x": 88.37608163890388,
+ "y": -39.98971533044961,
+ "z": 0.0
+ },
+ {
+ "x": 88.37623772016677,
+ "y": -41.01648002446883,
+ "z": 0.0
+ },
+ {
+ "x": 88.37639380142967,
+ "y": -42.04324471848799,
+ "z": 0.0
+ },
+ {
+ "x": 88.37654988269256,
+ "y": -43.070009412507176,
+ "z": 0.0
+ },
+ {
+ "x": 88.37670596395544,
+ "y": -44.0967741065264,
+ "z": 0.0
+ },
+ {
+ "x": 88.37686204521835,
+ "y": -45.123538800545546,
+ "z": 0.0
+ },
+ {
+ "x": 88.37701812648123,
+ "y": -46.15030349456474,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 110,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 94.38821987213683,
+ "y": -119.83939056702773,
+ "z": 0.0
+ },
+ {
+ "x": 94.38806580280658,
+ "y": -118.82586116697327,
+ "z": 0.0
+ },
+ {
+ "x": 94.38791173347632,
+ "y": -117.81233176691876,
+ "z": 0.0
+ },
+ {
+ "x": 94.38775766414606,
+ "y": -116.79880236686435,
+ "z": 0.0
+ },
+ {
+ "x": 94.38760359481581,
+ "y": -115.7852729668099,
+ "z": 0.0
+ },
+ {
+ "x": 94.38744952548556,
+ "y": -114.77174356675543,
+ "z": 0.0
+ },
+ {
+ "x": 94.3872954561553,
+ "y": -113.75821416670092,
+ "z": 0.0
+ },
+ {
+ "x": 94.38714138682504,
+ "y": -112.74468476664646,
+ "z": 0.0
+ },
+ {
+ "x": 94.38698731749479,
+ "y": -111.73115536659205,
+ "z": 0.0
+ },
+ {
+ "x": 94.38683324816454,
+ "y": -110.7176259665376,
+ "z": 0.0
+ },
+ {
+ "x": 94.38667917883427,
+ "y": -109.70409656648307,
+ "z": 0.0
+ },
+ {
+ "x": 94.38652510950402,
+ "y": -108.69056716642868,
+ "z": 0.0
+ },
+ {
+ "x": 94.38637104017377,
+ "y": -107.67703776637423,
+ "z": 0.0
+ },
+ {
+ "x": 94.3862169708435,
+ "y": -106.6635083663197,
+ "z": 0.0
+ },
+ {
+ "x": 94.38606290151326,
+ "y": -105.6499789662653,
+ "z": 0.0
+ },
+ {
+ "x": 94.385908832183,
+ "y": -104.63644956621084,
+ "z": 0.0
+ },
+ {
+ "x": 94.38575476285276,
+ "y": -103.62292016615638,
+ "z": 0.0
+ },
+ {
+ "x": 94.38560069352249,
+ "y": -102.60939076610187,
+ "z": 0.0
+ },
+ {
+ "x": 94.38544662419223,
+ "y": -101.5958613660474,
+ "z": 0.0
+ },
+ {
+ "x": 94.38529255486198,
+ "y": -100.582331965993,
+ "z": 0.0
+ },
+ {
+ "x": 94.38513848553173,
+ "y": -99.56880256593854,
+ "z": 0.0
+ },
+ {
+ "x": 94.38498441620146,
+ "y": -98.55527316588402,
+ "z": 0.0
+ },
+ {
+ "x": 94.38483034687121,
+ "y": -97.54174376582962,
+ "z": 0.0
+ },
+ {
+ "x": 94.38467627754096,
+ "y": -96.52821436577517,
+ "z": 0.0
+ },
+ {
+ "x": 94.3845222082107,
+ "y": -95.51468496572065,
+ "z": 0.0
+ },
+ {
+ "x": 94.38436813888045,
+ "y": -94.50115556566624,
+ "z": 0.0
+ },
+ {
+ "x": 94.3842140695502,
+ "y": -93.48762616561179,
+ "z": 0.0
+ },
+ {
+ "x": 94.38406000021993,
+ "y": -92.47409676555726,
+ "z": 0.0
+ },
+ {
+ "x": 94.38390593088967,
+ "y": -91.46056736550281,
+ "z": 0.0
+ },
+ {
+ "x": 94.38375186155942,
+ "y": -90.4470379654484,
+ "z": 0.0
+ },
+ {
+ "x": 94.38359779222917,
+ "y": -89.43350856539395,
+ "z": 0.0
+ },
+ {
+ "x": 94.3834437228989,
+ "y": -88.41997916533943,
+ "z": 0.0
+ },
+ {
+ "x": 94.38328965356865,
+ "y": -87.40644976528503,
+ "z": 0.0
+ },
+ {
+ "x": 94.3831355842384,
+ "y": -86.39292036523057,
+ "z": 0.0
+ },
+ {
+ "x": 94.38298151490815,
+ "y": -85.37939096517611,
+ "z": 0.0
+ },
+ {
+ "x": 94.38282744557789,
+ "y": -84.36586156512159,
+ "z": 0.0
+ },
+ {
+ "x": 94.38267337624764,
+ "y": -83.3523321650672,
+ "z": 0.0
+ },
+ {
+ "x": 94.38251930691737,
+ "y": -82.33880276501267,
+ "z": 0.0
+ },
+ {
+ "x": 94.38236523758712,
+ "y": -81.32527336495828,
+ "z": 0.0
+ },
+ {
+ "x": 94.38221116825686,
+ "y": -80.31174396490375,
+ "z": 0.0
+ },
+ {
+ "x": 94.38205709892661,
+ "y": -79.29821456484936,
+ "z": 0.0
+ },
+ {
+ "x": 94.38190302959636,
+ "y": -78.2846851647949,
+ "z": 0.0
+ },
+ {
+ "x": 94.3817489602661,
+ "y": -77.27115576474037,
+ "z": 0.0
+ },
+ {
+ "x": 94.38159489093584,
+ "y": -76.25762636468598,
+ "z": 0.0
+ },
+ {
+ "x": 94.3814408216056,
+ "y": -75.24409696463151,
+ "z": 0.0
+ },
+ {
+ "x": 94.38128675227534,
+ "y": -74.23056756457706,
+ "z": 0.0
+ },
+ {
+ "x": 94.38113268294508,
+ "y": -73.21703816452253,
+ "z": 0.0
+ },
+ {
+ "x": 94.38097861361481,
+ "y": -72.20350876446808,
+ "z": 0.0
+ },
+ {
+ "x": 94.38082454428456,
+ "y": -71.18997936441367,
+ "z": 0.0
+ },
+ {
+ "x": 94.38067047495431,
+ "y": -70.17644996435922,
+ "z": 0.0
+ },
+ {
+ "x": 94.38051640562405,
+ "y": -69.1629205643047,
+ "z": 0.0
+ },
+ {
+ "x": 94.3803623362938,
+ "y": -68.1493911642503,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 111,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 86.38036242872523,
+ "y": -68.15060726575432,
+ "z": 0.0
+ },
+ {
+ "x": 86.38051649805548,
+ "y": -69.16413666580883,
+ "z": 0.0
+ },
+ {
+ "x": 86.38067056738575,
+ "y": -70.17766606586324,
+ "z": 0.0
+ },
+ {
+ "x": 86.380824636716,
+ "y": -71.19119546591769,
+ "z": 0.0
+ },
+ {
+ "x": 86.38097870604625,
+ "y": -72.20472486597221,
+ "z": 0.0
+ },
+ {
+ "x": 86.38113277537651,
+ "y": -73.21825426602666,
+ "z": 0.0
+ },
+ {
+ "x": 86.38128684470678,
+ "y": -74.23178366608107,
+ "z": 0.0
+ },
+ {
+ "x": 86.38144091403703,
+ "y": -75.24531306613552,
+ "z": 0.0
+ },
+ {
+ "x": 86.38159498336728,
+ "y": -76.25884246618999,
+ "z": 0.0
+ },
+ {
+ "x": 86.38174905269753,
+ "y": -77.2723718662445,
+ "z": 0.0
+ },
+ {
+ "x": 86.3819031220278,
+ "y": -78.28590126629891,
+ "z": 0.0
+ },
+ {
+ "x": 86.38205719135804,
+ "y": -79.29943066635337,
+ "z": 0.0
+ },
+ {
+ "x": 86.3822112606883,
+ "y": -80.31296006640788,
+ "z": 0.0
+ },
+ {
+ "x": 86.38236533001856,
+ "y": -81.32648946646229,
+ "z": 0.0
+ },
+ {
+ "x": 86.38251939934881,
+ "y": -82.3400188665168,
+ "z": 0.0
+ },
+ {
+ "x": 86.38267346867907,
+ "y": -83.35354826657121,
+ "z": 0.0
+ },
+ {
+ "x": 86.38282753800932,
+ "y": -84.36707766662572,
+ "z": 0.0
+ },
+ {
+ "x": 86.38298160733959,
+ "y": -85.38060706668013,
+ "z": 0.0
+ },
+ {
+ "x": 86.38313567666984,
+ "y": -86.39413646673458,
+ "z": 0.0
+ },
+ {
+ "x": 86.38328974600009,
+ "y": -87.40766586678905,
+ "z": 0.0
+ },
+ {
+ "x": 86.38344381533034,
+ "y": -88.42119526684355,
+ "z": 0.0
+ },
+ {
+ "x": 86.3835978846606,
+ "y": -89.43472466689796,
+ "z": 0.0
+ },
+ {
+ "x": 86.38375195399085,
+ "y": -90.44825406695242,
+ "z": 0.0
+ },
+ {
+ "x": 86.3839060233211,
+ "y": -91.46178346700694,
+ "z": 0.0
+ },
+ {
+ "x": 86.38406009265137,
+ "y": -92.47531286706139,
+ "z": 0.0
+ },
+ {
+ "x": 86.38421416198163,
+ "y": -93.4888422671158,
+ "z": 0.0
+ },
+ {
+ "x": 86.38436823131188,
+ "y": -94.50237166717025,
+ "z": 0.0
+ },
+ {
+ "x": 86.38452230064213,
+ "y": -95.51590106722477,
+ "z": 0.0
+ },
+ {
+ "x": 86.3846763699724,
+ "y": -96.52943046727918,
+ "z": 0.0
+ },
+ {
+ "x": 86.38483043930265,
+ "y": -97.54295986733364,
+ "z": 0.0
+ },
+ {
+ "x": 86.3849845086329,
+ "y": -98.55648926738814,
+ "z": 0.0
+ },
+ {
+ "x": 86.38513857796316,
+ "y": -99.57001866744255,
+ "z": 0.0
+ },
+ {
+ "x": 86.38529264729341,
+ "y": -100.58354806749702,
+ "z": 0.0
+ },
+ {
+ "x": 86.38544671662366,
+ "y": -101.59707746755153,
+ "z": 0.0
+ },
+ {
+ "x": 86.38560078595393,
+ "y": -102.610606867606,
+ "z": 0.0
+ },
+ {
+ "x": 86.38575485528419,
+ "y": -103.62413626766039,
+ "z": 0.0
+ },
+ {
+ "x": 86.38590892461444,
+ "y": -104.63766566771486,
+ "z": 0.0
+ },
+ {
+ "x": 86.38606299394469,
+ "y": -105.65119506776931,
+ "z": 0.0
+ },
+ {
+ "x": 86.38621706327494,
+ "y": -106.66472446782383,
+ "z": 0.0
+ },
+ {
+ "x": 86.3863711326052,
+ "y": -107.67825386787824,
+ "z": 0.0
+ },
+ {
+ "x": 86.38652520193546,
+ "y": -108.69178326793269,
+ "z": 0.0
+ },
+ {
+ "x": 86.3866792712657,
+ "y": -109.7053126679872,
+ "z": 0.0
+ },
+ {
+ "x": 86.38683334059597,
+ "y": -110.71884206804161,
+ "z": 0.0
+ },
+ {
+ "x": 86.38698740992622,
+ "y": -111.73237146809606,
+ "z": 0.0
+ },
+ {
+ "x": 86.38714147925647,
+ "y": -112.74590086815058,
+ "z": 0.0
+ },
+ {
+ "x": 86.38729554858674,
+ "y": -113.75943026820505,
+ "z": 0.0
+ },
+ {
+ "x": 86.387449617917,
+ "y": -114.77295966825945,
+ "z": 0.0
+ },
+ {
+ "x": 86.38760368724725,
+ "y": -115.78648906831391,
+ "z": 0.0
+ },
+ {
+ "x": 86.3877577565775,
+ "y": -116.80001846836836,
+ "z": 0.0
+ },
+ {
+ "x": 86.38791182590775,
+ "y": -117.81354786842289,
+ "z": 0.0
+ },
+ {
+ "x": 86.38806589523801,
+ "y": -118.82707726847728,
+ "z": 0.0
+ },
+ {
+ "x": 86.38821996456826,
+ "y": -119.84060666853175,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 112,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 90.38036238250952,
+ "y": -68.14999921500231,
+ "z": 0.0
+ },
+ {
+ "x": 90.38051645183977,
+ "y": -69.16352861505676,
+ "z": 0.0
+ },
+ {
+ "x": 90.38067052117003,
+ "y": -70.17705801511123,
+ "z": 0.0
+ },
+ {
+ "x": 90.38082459050028,
+ "y": -71.19058741516568,
+ "z": 0.0
+ },
+ {
+ "x": 90.38097865983053,
+ "y": -72.20411681522015,
+ "z": 0.0
+ },
+ {
+ "x": 90.3811327291608,
+ "y": -73.2176462152746,
+ "z": 0.0
+ },
+ {
+ "x": 90.38128679849106,
+ "y": -74.23117561532906,
+ "z": 0.0
+ },
+ {
+ "x": 90.38144086782131,
+ "y": -75.24470501538352,
+ "z": 0.0
+ },
+ {
+ "x": 90.38159493715156,
+ "y": -76.25823441543798,
+ "z": 0.0
+ },
+ {
+ "x": 90.38174900648181,
+ "y": -77.27176381549243,
+ "z": 0.0
+ },
+ {
+ "x": 90.38190307581208,
+ "y": -78.2852932155469,
+ "z": 0.0
+ },
+ {
+ "x": 90.38205714514233,
+ "y": -79.29882261560137,
+ "z": 0.0
+ },
+ {
+ "x": 90.38221121447258,
+ "y": -80.31235201565582,
+ "z": 0.0
+ },
+ {
+ "x": 90.38236528380284,
+ "y": -81.32588141571028,
+ "z": 0.0
+ },
+ {
+ "x": 90.38251935313309,
+ "y": -82.33941081576474,
+ "z": 0.0
+ },
+ {
+ "x": 90.38267342246336,
+ "y": -83.3529402158192,
+ "z": 0.0
+ },
+ {
+ "x": 90.3828274917936,
+ "y": -84.36646961587365,
+ "z": 0.0
+ },
+ {
+ "x": 90.38298156112387,
+ "y": -85.37999901592812,
+ "z": 0.0
+ },
+ {
+ "x": 90.38313563045412,
+ "y": -86.39352841598257,
+ "z": 0.0
+ },
+ {
+ "x": 90.38328969978437,
+ "y": -87.40705781603704,
+ "z": 0.0
+ },
+ {
+ "x": 90.38344376911462,
+ "y": -88.42058721609149,
+ "z": 0.0
+ },
+ {
+ "x": 90.38359783844489,
+ "y": -89.43411661614596,
+ "z": 0.0
+ },
+ {
+ "x": 90.38375190777514,
+ "y": -90.44764601620041,
+ "z": 0.0
+ },
+ {
+ "x": 90.38390597710539,
+ "y": -91.46117541625487,
+ "z": 0.0
+ },
+ {
+ "x": 90.38406004643565,
+ "y": -92.47470481630933,
+ "z": 0.0
+ },
+ {
+ "x": 90.38421411576591,
+ "y": -93.4882342163638,
+ "z": 0.0
+ },
+ {
+ "x": 90.38436818509616,
+ "y": -94.50176361641824,
+ "z": 0.0
+ },
+ {
+ "x": 90.38452225442641,
+ "y": -95.51529301647271,
+ "z": 0.0
+ },
+ {
+ "x": 90.38467632375668,
+ "y": -96.52882241652718,
+ "z": 0.0
+ },
+ {
+ "x": 90.38483039308693,
+ "y": -97.54235181658163,
+ "z": 0.0
+ },
+ {
+ "x": 90.38498446241718,
+ "y": -98.55588121663608,
+ "z": 0.0
+ },
+ {
+ "x": 90.38513853174744,
+ "y": -99.56941061669055,
+ "z": 0.0
+ },
+ {
+ "x": 90.3852926010777,
+ "y": -100.58294001674501,
+ "z": 0.0
+ },
+ {
+ "x": 90.38544667040794,
+ "y": -101.59646941679947,
+ "z": 0.0
+ },
+ {
+ "x": 90.38560073973821,
+ "y": -102.60999881685393,
+ "z": 0.0
+ },
+ {
+ "x": 90.38575480906847,
+ "y": -103.62352821690838,
+ "z": 0.0
+ },
+ {
+ "x": 90.38590887839872,
+ "y": -104.63705761696285,
+ "z": 0.0
+ },
+ {
+ "x": 90.38606294772897,
+ "y": -105.6505870170173,
+ "z": 0.0
+ },
+ {
+ "x": 90.38621701705922,
+ "y": -106.66411641707177,
+ "z": 0.0
+ },
+ {
+ "x": 90.38637108638949,
+ "y": -107.67764581712623,
+ "z": 0.0
+ },
+ {
+ "x": 90.38652515571974,
+ "y": -108.69117521718069,
+ "z": 0.0
+ },
+ {
+ "x": 90.38667922504999,
+ "y": -109.70470461723514,
+ "z": 0.0
+ },
+ {
+ "x": 90.38683329438025,
+ "y": -110.7182340172896,
+ "z": 0.0
+ },
+ {
+ "x": 90.3869873637105,
+ "y": -111.73176341734406,
+ "z": 0.0
+ },
+ {
+ "x": 90.38714143304075,
+ "y": -112.74529281739852,
+ "z": 0.0
+ },
+ {
+ "x": 90.38729550237102,
+ "y": -113.75882221745299,
+ "z": 0.0
+ },
+ {
+ "x": 90.38744957170128,
+ "y": -114.77235161750744,
+ "z": 0.0
+ },
+ {
+ "x": 90.38760364103153,
+ "y": -115.7858810175619,
+ "z": 0.0
+ },
+ {
+ "x": 90.38775771036178,
+ "y": -116.79941041761636,
+ "z": 0.0
+ },
+ {
+ "x": 90.38791177969203,
+ "y": -117.81293981767082,
+ "z": 0.0
+ },
+ {
+ "x": 90.3880658490223,
+ "y": -118.82646921772528,
+ "z": 0.0
+ },
+ {
+ "x": 90.38821991835255,
+ "y": -119.83999861777974,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 113,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 92.38821989524469,
+ "y": -119.83969459240373,
+ "z": 0.0
+ },
+ {
+ "x": 92.38806582591444,
+ "y": -118.82616519234926,
+ "z": 0.0
+ },
+ {
+ "x": 92.38791175658417,
+ "y": -117.8126357922948,
+ "z": 0.0
+ },
+ {
+ "x": 92.38775768725392,
+ "y": -116.79910639224036,
+ "z": 0.0
+ },
+ {
+ "x": 92.38760361792367,
+ "y": -115.7855769921859,
+ "z": 0.0
+ },
+ {
+ "x": 92.38744954859342,
+ "y": -114.77204759213143,
+ "z": 0.0
+ },
+ {
+ "x": 92.38729547926316,
+ "y": -113.75851819207696,
+ "z": 0.0
+ },
+ {
+ "x": 92.3871414099329,
+ "y": -112.7449887920225,
+ "z": 0.0
+ },
+ {
+ "x": 92.38698734060264,
+ "y": -111.73145939196806,
+ "z": 0.0
+ },
+ {
+ "x": 92.3868332712724,
+ "y": -110.71792999191359,
+ "z": 0.0
+ },
+ {
+ "x": 92.38667920194213,
+ "y": -109.7044005918591,
+ "z": 0.0
+ },
+ {
+ "x": 92.38652513261188,
+ "y": -108.69087119180469,
+ "z": 0.0
+ },
+ {
+ "x": 92.38637106328163,
+ "y": -107.67734179175022,
+ "z": 0.0
+ },
+ {
+ "x": 92.38621699395136,
+ "y": -106.66381239169573,
+ "z": 0.0
+ },
+ {
+ "x": 92.38606292462111,
+ "y": -105.65028299164129,
+ "z": 0.0
+ },
+ {
+ "x": 92.38590885529086,
+ "y": -104.63675359158685,
+ "z": 0.0
+ },
+ {
+ "x": 92.38575478596061,
+ "y": -103.62322419153239,
+ "z": 0.0
+ },
+ {
+ "x": 92.38560071663035,
+ "y": -102.60969479147789,
+ "z": 0.0
+ },
+ {
+ "x": 92.38544664730009,
+ "y": -101.59616539142343,
+ "z": 0.0
+ },
+ {
+ "x": 92.38529257796984,
+ "y": -100.58263599136902,
+ "z": 0.0
+ },
+ {
+ "x": 92.38513850863959,
+ "y": -99.56910659131455,
+ "z": 0.0
+ },
+ {
+ "x": 92.38498443930932,
+ "y": -98.55557719126006,
+ "z": 0.0
+ },
+ {
+ "x": 92.38483036997907,
+ "y": -97.54204779120562,
+ "z": 0.0
+ },
+ {
+ "x": 92.38467630064882,
+ "y": -96.52851839115118,
+ "z": 0.0
+ },
+ {
+ "x": 92.38452223131856,
+ "y": -95.51498899109669,
+ "z": 0.0
+ },
+ {
+ "x": 92.3843681619883,
+ "y": -94.50145959104225,
+ "z": 0.0
+ },
+ {
+ "x": 92.38421409265806,
+ "y": -93.48793019098778,
+ "z": 0.0
+ },
+ {
+ "x": 92.38406002332779,
+ "y": -92.47440079093329,
+ "z": 0.0
+ },
+ {
+ "x": 92.38390595399753,
+ "y": -91.46087139087885,
+ "z": 0.0
+ },
+ {
+ "x": 92.38375188466728,
+ "y": -90.44734199082441,
+ "z": 0.0
+ },
+ {
+ "x": 92.38359781533703,
+ "y": -89.43381259076995,
+ "z": 0.0
+ },
+ {
+ "x": 92.38344374600676,
+ "y": -88.42028319071545,
+ "z": 0.0
+ },
+ {
+ "x": 92.38328967667651,
+ "y": -87.40675379066104,
+ "z": 0.0
+ },
+ {
+ "x": 92.38313560734626,
+ "y": -86.39322439060658,
+ "z": 0.0
+ },
+ {
+ "x": 92.38298153801601,
+ "y": -85.37969499055211,
+ "z": 0.0
+ },
+ {
+ "x": 92.38282746868575,
+ "y": -84.36616559049762,
+ "z": 0.0
+ },
+ {
+ "x": 92.3826733993555,
+ "y": -83.3526361904432,
+ "z": 0.0
+ },
+ {
+ "x": 92.38251933002523,
+ "y": -82.33910679038871,
+ "z": 0.0
+ },
+ {
+ "x": 92.38236526069498,
+ "y": -81.32557739033427,
+ "z": 0.0
+ },
+ {
+ "x": 92.38221119136472,
+ "y": -80.31204799027978,
+ "z": 0.0
+ },
+ {
+ "x": 92.38205712203447,
+ "y": -79.29851859022537,
+ "z": 0.0
+ },
+ {
+ "x": 92.38190305270422,
+ "y": -78.2849891901709,
+ "z": 0.0
+ },
+ {
+ "x": 92.38174898337395,
+ "y": -77.27145979011641,
+ "z": 0.0
+ },
+ {
+ "x": 92.3815949140437,
+ "y": -76.25793039006197,
+ "z": 0.0
+ },
+ {
+ "x": 92.38144084471345,
+ "y": -75.2444009900075,
+ "z": 0.0
+ },
+ {
+ "x": 92.3812867753832,
+ "y": -74.23087158995307,
+ "z": 0.0
+ },
+ {
+ "x": 92.38113270605294,
+ "y": -73.21734218989857,
+ "z": 0.0
+ },
+ {
+ "x": 92.38097863672267,
+ "y": -72.20381278984411,
+ "z": 0.0
+ },
+ {
+ "x": 92.38082456739242,
+ "y": -71.19028338978967,
+ "z": 0.0
+ },
+ {
+ "x": 92.38067049806217,
+ "y": -70.17675398973523,
+ "z": 0.0
+ },
+ {
+ "x": 92.38051642873191,
+ "y": -69.16322458968074,
+ "z": 0.0
+ },
+ {
+ "x": 92.38036235940166,
+ "y": -68.1496951896263,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 114,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 88.38036240561738,
+ "y": -68.15030324037832,
+ "z": 0.0
+ },
+ {
+ "x": 88.38051647494763,
+ "y": -69.16383264043279,
+ "z": 0.0
+ },
+ {
+ "x": 88.38067054427789,
+ "y": -70.17736204048722,
+ "z": 0.0
+ },
+ {
+ "x": 88.38082461360814,
+ "y": -71.19089144054169,
+ "z": 0.0
+ },
+ {
+ "x": 88.38097868293839,
+ "y": -72.20442084059619,
+ "z": 0.0
+ },
+ {
+ "x": 88.38113275226866,
+ "y": -73.21795024065062,
+ "z": 0.0
+ },
+ {
+ "x": 88.38128682159892,
+ "y": -74.23147964070506,
+ "z": 0.0
+ },
+ {
+ "x": 88.38144089092917,
+ "y": -75.24500904075953,
+ "z": 0.0
+ },
+ {
+ "x": 88.38159496025942,
+ "y": -76.258538440814,
+ "z": 0.0
+ },
+ {
+ "x": 88.38174902958967,
+ "y": -77.27206784086846,
+ "z": 0.0
+ },
+ {
+ "x": 88.38190309891993,
+ "y": -78.2855972409229,
+ "z": 0.0
+ },
+ {
+ "x": 88.38205716825018,
+ "y": -79.29912664097736,
+ "z": 0.0
+ },
+ {
+ "x": 88.38221123758044,
+ "y": -80.31265604103186,
+ "z": 0.0
+ },
+ {
+ "x": 88.3823653069107,
+ "y": -81.3261854410863,
+ "z": 0.0
+ },
+ {
+ "x": 88.38251937624095,
+ "y": -82.33971484114076,
+ "z": 0.0
+ },
+ {
+ "x": 88.38267344557121,
+ "y": -83.3532442411952,
+ "z": 0.0
+ },
+ {
+ "x": 88.38282751490146,
+ "y": -84.3667736412497,
+ "z": 0.0
+ },
+ {
+ "x": 88.38298158423173,
+ "y": -85.38030304130413,
+ "z": 0.0
+ },
+ {
+ "x": 88.38313565356198,
+ "y": -86.39383244135857,
+ "z": 0.0
+ },
+ {
+ "x": 88.38328972289223,
+ "y": -87.40736184141304,
+ "z": 0.0
+ },
+ {
+ "x": 88.38344379222248,
+ "y": -88.42089124146753,
+ "z": 0.0
+ },
+ {
+ "x": 88.38359786155274,
+ "y": -89.43442064152197,
+ "z": 0.0
+ },
+ {
+ "x": 88.383751930883,
+ "y": -90.4479500415764,
+ "z": 0.0
+ },
+ {
+ "x": 88.38390600021324,
+ "y": -91.4614794416309,
+ "z": 0.0
+ },
+ {
+ "x": 88.38406006954351,
+ "y": -92.47500884168537,
+ "z": 0.0
+ },
+ {
+ "x": 88.38421413887377,
+ "y": -93.4885382417398,
+ "z": 0.0
+ },
+ {
+ "x": 88.38436820820402,
+ "y": -94.50206764179424,
+ "z": 0.0
+ },
+ {
+ "x": 88.38452227753427,
+ "y": -95.51559704184874,
+ "z": 0.0
+ },
+ {
+ "x": 88.38467634686454,
+ "y": -96.52912644190317,
+ "z": 0.0
+ },
+ {
+ "x": 88.38483041619479,
+ "y": -97.54265584195764,
+ "z": 0.0
+ },
+ {
+ "x": 88.38498448552504,
+ "y": -98.5561852420121,
+ "z": 0.0
+ },
+ {
+ "x": 88.3851385548553,
+ "y": -99.56971464206654,
+ "z": 0.0
+ },
+ {
+ "x": 88.38529262418555,
+ "y": -100.58324404212101,
+ "z": 0.0
+ },
+ {
+ "x": 88.3854466935158,
+ "y": -101.5967734421755,
+ "z": 0.0
+ },
+ {
+ "x": 88.38560076284607,
+ "y": -102.61030284222997,
+ "z": 0.0
+ },
+ {
+ "x": 88.38575483217633,
+ "y": -103.62383224228438,
+ "z": 0.0
+ },
+ {
+ "x": 88.38590890150658,
+ "y": -104.63736164233885,
+ "z": 0.0
+ },
+ {
+ "x": 88.38606297083683,
+ "y": -105.65089104239331,
+ "z": 0.0
+ },
+ {
+ "x": 88.38621704016708,
+ "y": -106.6644204424478,
+ "z": 0.0
+ },
+ {
+ "x": 88.38637110949735,
+ "y": -107.67794984250224,
+ "z": 0.0
+ },
+ {
+ "x": 88.3865251788276,
+ "y": -108.69147924255668,
+ "z": 0.0
+ },
+ {
+ "x": 88.38667924815785,
+ "y": -109.70500864261118,
+ "z": 0.0
+ },
+ {
+ "x": 88.38683331748811,
+ "y": -110.71853804266561,
+ "z": 0.0
+ },
+ {
+ "x": 88.38698738681836,
+ "y": -111.73206744272005,
+ "z": 0.0
+ },
+ {
+ "x": 88.38714145614861,
+ "y": -112.74559684277455,
+ "z": 0.0
+ },
+ {
+ "x": 88.38729552547888,
+ "y": -113.75912624282901,
+ "z": 0.0
+ },
+ {
+ "x": 88.38744959480914,
+ "y": -114.77265564288345,
+ "z": 0.0
+ },
+ {
+ "x": 88.38760366413939,
+ "y": -115.78618504293792,
+ "z": 0.0
+ },
+ {
+ "x": 88.38775773346964,
+ "y": -116.79971444299235,
+ "z": 0.0
+ },
+ {
+ "x": 88.38791180279989,
+ "y": -117.81324384304685,
+ "z": 0.0
+ },
+ {
+ "x": 88.38806587213016,
+ "y": -118.82677324310129,
+ "z": 0.0
+ },
+ {
+ "x": 88.3882199414604,
+ "y": -119.84030264315575,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 115,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 94.39832719576235,
+ "y": -186.329389798807,
+ "z": 0.0
+ },
+ {
+ "x": 94.39816991565795,
+ "y": -185.29473864797058,
+ "z": 0.0
+ },
+ {
+ "x": 94.39801263555354,
+ "y": -184.26008749713418,
+ "z": 0.0
+ },
+ {
+ "x": 94.39785535544914,
+ "y": -183.22543634629776,
+ "z": 0.0
+ },
+ {
+ "x": 94.39769807534474,
+ "y": -182.19078519546136,
+ "z": 0.0
+ },
+ {
+ "x": 94.39754079524033,
+ "y": -181.15613404462493,
+ "z": 0.0
+ },
+ {
+ "x": 94.39738351513593,
+ "y": -180.12148289378854,
+ "z": 0.0
+ },
+ {
+ "x": 94.39722623503152,
+ "y": -179.0868317429521,
+ "z": 0.0
+ },
+ {
+ "x": 94.39706895492711,
+ "y": -178.05218059211563,
+ "z": 0.0
+ },
+ {
+ "x": 94.3969116748227,
+ "y": -177.0175294412793,
+ "z": 0.0
+ },
+ {
+ "x": 94.3967543947183,
+ "y": -175.98287829044287,
+ "z": 0.0
+ },
+ {
+ "x": 94.3965971146139,
+ "y": -174.94822713960644,
+ "z": 0.0
+ },
+ {
+ "x": 94.3964398345095,
+ "y": -173.91357598877005,
+ "z": 0.0
+ },
+ {
+ "x": 94.39628255440509,
+ "y": -172.87892483793362,
+ "z": 0.0
+ },
+ {
+ "x": 94.39612527430069,
+ "y": -171.84427368709723,
+ "z": 0.0
+ },
+ {
+ "x": 94.39596799419628,
+ "y": -170.8096225362608,
+ "z": 0.0
+ },
+ {
+ "x": 94.39581071409188,
+ "y": -169.7749713854244,
+ "z": 0.0
+ },
+ {
+ "x": 94.39565343398748,
+ "y": -168.74032023458798,
+ "z": 0.0
+ },
+ {
+ "x": 94.39549615388307,
+ "y": -167.70566908375156,
+ "z": 0.0
+ },
+ {
+ "x": 94.39533887377867,
+ "y": -166.67101793291516,
+ "z": 0.0
+ },
+ {
+ "x": 94.39518159367427,
+ "y": -165.63636678207874,
+ "z": 0.0
+ },
+ {
+ "x": 94.39502431356986,
+ "y": -164.6017156312423,
+ "z": 0.0
+ },
+ {
+ "x": 94.39486703346545,
+ "y": -163.56706448040586,
+ "z": 0.0
+ },
+ {
+ "x": 94.39470975336104,
+ "y": -162.5324133295695,
+ "z": 0.0
+ },
+ {
+ "x": 94.39455247325664,
+ "y": -161.4977621787331,
+ "z": 0.0
+ },
+ {
+ "x": 94.39439519315223,
+ "y": -160.46311102789667,
+ "z": 0.0
+ },
+ {
+ "x": 94.39423791304783,
+ "y": -159.42845987706028,
+ "z": 0.0
+ },
+ {
+ "x": 94.39408063294343,
+ "y": -158.39380872622385,
+ "z": 0.0
+ },
+ {
+ "x": 94.39392335283902,
+ "y": -157.35915757538743,
+ "z": 0.0
+ },
+ {
+ "x": 94.39376607273462,
+ "y": -156.32450642455103,
+ "z": 0.0
+ },
+ {
+ "x": 94.39360879263022,
+ "y": -155.2898552737146,
+ "z": 0.0
+ },
+ {
+ "x": 94.39345151252581,
+ "y": -154.2552041228782,
+ "z": 0.0
+ },
+ {
+ "x": 94.39329423242141,
+ "y": -153.2205529720418,
+ "z": 0.0
+ },
+ {
+ "x": 94.39313695231701,
+ "y": -152.1859018212054,
+ "z": 0.0
+ },
+ {
+ "x": 94.3929796722126,
+ "y": -151.15125067036897,
+ "z": 0.0
+ },
+ {
+ "x": 94.3928223921082,
+ "y": -150.11659951953254,
+ "z": 0.0
+ },
+ {
+ "x": 94.39266511200378,
+ "y": -149.0819483686961,
+ "z": 0.0
+ },
+ {
+ "x": 94.39250783189938,
+ "y": -148.04729721785972,
+ "z": 0.0
+ },
+ {
+ "x": 94.39235055179498,
+ "y": -147.01264606702333,
+ "z": 0.0
+ },
+ {
+ "x": 94.39219327169057,
+ "y": -145.9779949161869,
+ "z": 0.0
+ },
+ {
+ "x": 94.39203599158617,
+ "y": -144.9433437653505,
+ "z": 0.0
+ },
+ {
+ "x": 94.39187871148177,
+ "y": -143.90869261451408,
+ "z": 0.0
+ },
+ {
+ "x": 94.39172143137736,
+ "y": -142.87404146367768,
+ "z": 0.0
+ },
+ {
+ "x": 94.39156415127296,
+ "y": -141.83939031284126,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 116,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 86.3915642437044,
+ "y": -141.8406064143453,
+ "z": 0.0
+ },
+ {
+ "x": 86.3917215238088,
+ "y": -142.87525756518173,
+ "z": 0.0
+ },
+ {
+ "x": 86.3918788039132,
+ "y": -143.90990871601812,
+ "z": 0.0
+ },
+ {
+ "x": 86.3920360840176,
+ "y": -144.94455986685455,
+ "z": 0.0
+ },
+ {
+ "x": 86.39219336412201,
+ "y": -145.97921101769094,
+ "z": 0.0
+ },
+ {
+ "x": 86.39235064422641,
+ "y": -147.01386216852737,
+ "z": 0.0
+ },
+ {
+ "x": 86.39250792433081,
+ "y": -148.04851331936376,
+ "z": 0.0
+ },
+ {
+ "x": 86.39266520443522,
+ "y": -149.08316447020024,
+ "z": 0.0
+ },
+ {
+ "x": 86.39282248453964,
+ "y": -150.11781562103658,
+ "z": 0.0
+ },
+ {
+ "x": 86.39297976464404,
+ "y": -151.152466771873,
+ "z": 0.0
+ },
+ {
+ "x": 86.39313704474844,
+ "y": -152.18711792270943,
+ "z": 0.0
+ },
+ {
+ "x": 86.39329432485285,
+ "y": -153.22176907354583,
+ "z": 0.0
+ },
+ {
+ "x": 86.39345160495725,
+ "y": -154.25642022438225,
+ "z": 0.0
+ },
+ {
+ "x": 86.39360888506165,
+ "y": -155.29107137521865,
+ "z": 0.0
+ },
+ {
+ "x": 86.39376616516606,
+ "y": -156.32572252605507,
+ "z": 0.0
+ },
+ {
+ "x": 86.39392344527046,
+ "y": -157.36037367689147,
+ "z": 0.0
+ },
+ {
+ "x": 86.39408072537486,
+ "y": -158.3950248277279,
+ "z": 0.0
+ },
+ {
+ "x": 86.39423800547927,
+ "y": -159.42967597856432,
+ "z": 0.0
+ },
+ {
+ "x": 86.39439528558367,
+ "y": -160.46432712940071,
+ "z": 0.0
+ },
+ {
+ "x": 86.39455256568807,
+ "y": -161.49897828023714,
+ "z": 0.0
+ },
+ {
+ "x": 86.39470984579248,
+ "y": -162.53362943107354,
+ "z": 0.0
+ },
+ {
+ "x": 86.39486712589688,
+ "y": -163.56828058191002,
+ "z": 0.0
+ },
+ {
+ "x": 86.3950244060013,
+ "y": -164.60293173274636,
+ "z": 0.0
+ },
+ {
+ "x": 86.3951816861057,
+ "y": -165.63758288358278,
+ "z": 0.0
+ },
+ {
+ "x": 86.3953389662101,
+ "y": -166.6722340344192,
+ "z": 0.0
+ },
+ {
+ "x": 86.39549624631451,
+ "y": -167.7068851852556,
+ "z": 0.0
+ },
+ {
+ "x": 86.39565352641891,
+ "y": -168.74153633609203,
+ "z": 0.0
+ },
+ {
+ "x": 86.39581080652331,
+ "y": -169.77618748692845,
+ "z": 0.0
+ },
+ {
+ "x": 86.39596808662772,
+ "y": -170.81083863776485,
+ "z": 0.0
+ },
+ {
+ "x": 86.39612536673212,
+ "y": -171.84548978860127,
+ "z": 0.0
+ },
+ {
+ "x": 86.39628264683653,
+ "y": -172.88014093943767,
+ "z": 0.0
+ },
+ {
+ "x": 86.39643992694093,
+ "y": -173.9147920902741,
+ "z": 0.0
+ },
+ {
+ "x": 86.39659720704533,
+ "y": -174.9494432411105,
+ "z": 0.0
+ },
+ {
+ "x": 86.39675448714974,
+ "y": -175.9840943919469,
+ "z": 0.0
+ },
+ {
+ "x": 86.39691176725414,
+ "y": -177.01874554278334,
+ "z": 0.0
+ },
+ {
+ "x": 86.39706904735854,
+ "y": -178.0533966936198,
+ "z": 0.0
+ },
+ {
+ "x": 86.39722632746296,
+ "y": -179.08804784445616,
+ "z": 0.0
+ },
+ {
+ "x": 86.39738360756736,
+ "y": -180.12269899529258,
+ "z": 0.0
+ },
+ {
+ "x": 86.39754088767177,
+ "y": -181.15735014612898,
+ "z": 0.0
+ },
+ {
+ "x": 86.39769816777617,
+ "y": -182.1920012969654,
+ "z": 0.0
+ },
+ {
+ "x": 86.39785544788057,
+ "y": -183.2266524478018,
+ "z": 0.0
+ },
+ {
+ "x": 86.39801272798498,
+ "y": -184.26130359863822,
+ "z": 0.0
+ },
+ {
+ "x": 86.39817000808938,
+ "y": -185.29595474947462,
+ "z": 0.0
+ },
+ {
+ "x": 86.39832728819378,
+ "y": -186.33060590031104,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 117,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 90.39156419748868,
+ "y": -141.83999836359328,
+ "z": 0.0
+ },
+ {
+ "x": 90.39172147759308,
+ "y": -142.8746495144297,
+ "z": 0.0
+ },
+ {
+ "x": 90.39187875769748,
+ "y": -143.9093006652661,
+ "z": 0.0
+ },
+ {
+ "x": 90.39203603780189,
+ "y": -144.94395181610253,
+ "z": 0.0
+ },
+ {
+ "x": 90.39219331790629,
+ "y": -145.97860296693892,
+ "z": 0.0
+ },
+ {
+ "x": 90.3923505980107,
+ "y": -147.01325411777535,
+ "z": 0.0
+ },
+ {
+ "x": 90.3925078781151,
+ "y": -148.04790526861174,
+ "z": 0.0
+ },
+ {
+ "x": 90.3926651582195,
+ "y": -149.08255641944817,
+ "z": 0.0
+ },
+ {
+ "x": 90.39282243832392,
+ "y": -150.11720757028456,
+ "z": 0.0
+ },
+ {
+ "x": 90.39297971842832,
+ "y": -151.151858721121,
+ "z": 0.0
+ },
+ {
+ "x": 90.39313699853273,
+ "y": -152.1865098719574,
+ "z": 0.0
+ },
+ {
+ "x": 90.39329427863713,
+ "y": -153.2211610227938,
+ "z": 0.0
+ },
+ {
+ "x": 90.39345155874153,
+ "y": -154.25581217363023,
+ "z": 0.0
+ },
+ {
+ "x": 90.39360883884594,
+ "y": -155.29046332446663,
+ "z": 0.0
+ },
+ {
+ "x": 90.39376611895034,
+ "y": -156.32511447530305,
+ "z": 0.0
+ },
+ {
+ "x": 90.39392339905474,
+ "y": -157.35976562613945,
+ "z": 0.0
+ },
+ {
+ "x": 90.39408067915915,
+ "y": -158.39441677697587,
+ "z": 0.0
+ },
+ {
+ "x": 90.39423795926355,
+ "y": -159.4290679278123,
+ "z": 0.0
+ },
+ {
+ "x": 90.39439523936795,
+ "y": -160.4637190786487,
+ "z": 0.0
+ },
+ {
+ "x": 90.39455251947236,
+ "y": -161.49837022948512,
+ "z": 0.0
+ },
+ {
+ "x": 90.39470979957676,
+ "y": -162.53302138032151,
+ "z": 0.0
+ },
+ {
+ "x": 90.39486707968116,
+ "y": -163.56767253115794,
+ "z": 0.0
+ },
+ {
+ "x": 90.39502435978558,
+ "y": -164.60232368199433,
+ "z": 0.0
+ },
+ {
+ "x": 90.39518163988998,
+ "y": -165.63697483283076,
+ "z": 0.0
+ },
+ {
+ "x": 90.39533891999439,
+ "y": -166.67162598366718,
+ "z": 0.0
+ },
+ {
+ "x": 90.39549620009879,
+ "y": -167.70627713450358,
+ "z": 0.0
+ },
+ {
+ "x": 90.3956534802032,
+ "y": -168.74092828534,
+ "z": 0.0
+ },
+ {
+ "x": 90.3958107603076,
+ "y": -169.77557943617643,
+ "z": 0.0
+ },
+ {
+ "x": 90.395968040412,
+ "y": -170.81023058701282,
+ "z": 0.0
+ },
+ {
+ "x": 90.3961253205164,
+ "y": -171.84488173784925,
+ "z": 0.0
+ },
+ {
+ "x": 90.39628260062081,
+ "y": -172.87953288868565,
+ "z": 0.0
+ },
+ {
+ "x": 90.39643988072521,
+ "y": -173.91418403952207,
+ "z": 0.0
+ },
+ {
+ "x": 90.39659716082961,
+ "y": -174.94883519035847,
+ "z": 0.0
+ },
+ {
+ "x": 90.39675444093402,
+ "y": -175.9834863411949,
+ "z": 0.0
+ },
+ {
+ "x": 90.39691172103842,
+ "y": -177.01813749203131,
+ "z": 0.0
+ },
+ {
+ "x": 90.39706900114282,
+ "y": -178.0527886428677,
+ "z": 0.0
+ },
+ {
+ "x": 90.39722628124724,
+ "y": -179.08743979370414,
+ "z": 0.0
+ },
+ {
+ "x": 90.39738356135165,
+ "y": -180.12209094454056,
+ "z": 0.0
+ },
+ {
+ "x": 90.39754084145605,
+ "y": -181.15674209537696,
+ "z": 0.0
+ },
+ {
+ "x": 90.39769812156045,
+ "y": -182.19139324621338,
+ "z": 0.0
+ },
+ {
+ "x": 90.39785540166486,
+ "y": -183.22604439704978,
+ "z": 0.0
+ },
+ {
+ "x": 90.39801268176926,
+ "y": -184.2606955478862,
+ "z": 0.0
+ },
+ {
+ "x": 90.39816996187366,
+ "y": -185.2953466987226,
+ "z": 0.0
+ },
+ {
+ "x": 90.39832724197807,
+ "y": -186.32999784955902,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 118,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 92.39832721887021,
+ "y": -186.329693824183,
+ "z": 0.0
+ },
+ {
+ "x": 92.3981699387658,
+ "y": -185.2950426733466,
+ "z": 0.0
+ },
+ {
+ "x": 92.3980126586614,
+ "y": -184.2603915225102,
+ "z": 0.0
+ },
+ {
+ "x": 92.397855378557,
+ "y": -183.22574037167377,
+ "z": 0.0
+ },
+ {
+ "x": 92.3976980984526,
+ "y": -182.19108922083737,
+ "z": 0.0
+ },
+ {
+ "x": 92.39754081834819,
+ "y": -181.15643807000095,
+ "z": 0.0
+ },
+ {
+ "x": 92.39738353824379,
+ "y": -180.12178691916455,
+ "z": 0.0
+ },
+ {
+ "x": 92.39722625813938,
+ "y": -179.08713576832812,
+ "z": 0.0
+ },
+ {
+ "x": 92.39706897803497,
+ "y": -178.05248461749167,
+ "z": 0.0
+ },
+ {
+ "x": 92.39691169793056,
+ "y": -177.0178334666553,
+ "z": 0.0
+ },
+ {
+ "x": 92.39675441782616,
+ "y": -175.98318231581888,
+ "z": 0.0
+ },
+ {
+ "x": 92.39659713772176,
+ "y": -174.94853116498246,
+ "z": 0.0
+ },
+ {
+ "x": 92.39643985761735,
+ "y": -173.91388001414606,
+ "z": 0.0
+ },
+ {
+ "x": 92.39628257751295,
+ "y": -172.87922886330963,
+ "z": 0.0
+ },
+ {
+ "x": 92.39612529740855,
+ "y": -171.84457771247324,
+ "z": 0.0
+ },
+ {
+ "x": 92.39596801730414,
+ "y": -170.80992656163681,
+ "z": 0.0
+ },
+ {
+ "x": 92.39581073719974,
+ "y": -169.77527541080042,
+ "z": 0.0
+ },
+ {
+ "x": 92.39565345709534,
+ "y": -168.740624259964,
+ "z": 0.0
+ },
+ {
+ "x": 92.39549617699093,
+ "y": -167.70597310912757,
+ "z": 0.0
+ },
+ {
+ "x": 92.39533889688653,
+ "y": -166.67132195829117,
+ "z": 0.0
+ },
+ {
+ "x": 92.39518161678212,
+ "y": -165.63667080745475,
+ "z": 0.0
+ },
+ {
+ "x": 92.39502433667772,
+ "y": -164.60201965661832,
+ "z": 0.0
+ },
+ {
+ "x": 92.3948670565733,
+ "y": -163.5673685057819,
+ "z": 0.0
+ },
+ {
+ "x": 92.3947097764689,
+ "y": -162.5327173549455,
+ "z": 0.0
+ },
+ {
+ "x": 92.3945524963645,
+ "y": -161.4980662041091,
+ "z": 0.0
+ },
+ {
+ "x": 92.3943952162601,
+ "y": -160.46341505327268,
+ "z": 0.0
+ },
+ {
+ "x": 92.39423793615569,
+ "y": -159.4287639024363,
+ "z": 0.0
+ },
+ {
+ "x": 92.39408065605129,
+ "y": -158.39411275159986,
+ "z": 0.0
+ },
+ {
+ "x": 92.39392337594688,
+ "y": -157.35946160076344,
+ "z": 0.0
+ },
+ {
+ "x": 92.39376609584248,
+ "y": -156.32481044992704,
+ "z": 0.0
+ },
+ {
+ "x": 92.39360881573808,
+ "y": -155.29015929909062,
+ "z": 0.0
+ },
+ {
+ "x": 92.39345153563367,
+ "y": -154.25550814825422,
+ "z": 0.0
+ },
+ {
+ "x": 92.39329425552927,
+ "y": -153.2208569974178,
+ "z": 0.0
+ },
+ {
+ "x": 92.39313697542487,
+ "y": -152.1862058465814,
+ "z": 0.0
+ },
+ {
+ "x": 92.39297969532046,
+ "y": -151.15155469574498,
+ "z": 0.0
+ },
+ {
+ "x": 92.39282241521606,
+ "y": -150.11690354490855,
+ "z": 0.0
+ },
+ {
+ "x": 92.39266513511164,
+ "y": -149.08225239407213,
+ "z": 0.0
+ },
+ {
+ "x": 92.39250785500724,
+ "y": -148.04760124323573,
+ "z": 0.0
+ },
+ {
+ "x": 92.39235057490284,
+ "y": -147.01295009239934,
+ "z": 0.0
+ },
+ {
+ "x": 92.39219329479843,
+ "y": -145.9782989415629,
+ "z": 0.0
+ },
+ {
+ "x": 92.39203601469403,
+ "y": -144.94364779072652,
+ "z": 0.0
+ },
+ {
+ "x": 92.39187873458962,
+ "y": -143.9089966398901,
+ "z": 0.0
+ },
+ {
+ "x": 92.39172145448522,
+ "y": -142.8743454890537,
+ "z": 0.0
+ },
+ {
+ "x": 92.39156417438082,
+ "y": -141.83969433821727,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 119,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 88.39156422059654,
+ "y": -141.8403023889693,
+ "z": 0.0
+ },
+ {
+ "x": 88.39172150070094,
+ "y": -142.87495353980572,
+ "z": 0.0
+ },
+ {
+ "x": 88.39187878080534,
+ "y": -143.9096046906421,
+ "z": 0.0
+ },
+ {
+ "x": 88.39203606090975,
+ "y": -144.94425584147854,
+ "z": 0.0
+ },
+ {
+ "x": 88.39219334101415,
+ "y": -145.97890699231493,
+ "z": 0.0
+ },
+ {
+ "x": 88.39235062111855,
+ "y": -147.01355814315136,
+ "z": 0.0
+ },
+ {
+ "x": 88.39250790122296,
+ "y": -148.04820929398775,
+ "z": 0.0
+ },
+ {
+ "x": 88.39266518132736,
+ "y": -149.0828604448242,
+ "z": 0.0
+ },
+ {
+ "x": 88.39282246143178,
+ "y": -150.11751159566057,
+ "z": 0.0
+ },
+ {
+ "x": 88.39297974153618,
+ "y": -151.152162746497,
+ "z": 0.0
+ },
+ {
+ "x": 88.39313702164058,
+ "y": -152.18681389733342,
+ "z": 0.0
+ },
+ {
+ "x": 88.39329430174499,
+ "y": -153.22146504816982,
+ "z": 0.0
+ },
+ {
+ "x": 88.39345158184939,
+ "y": -154.25611619900624,
+ "z": 0.0
+ },
+ {
+ "x": 88.3936088619538,
+ "y": -155.29076734984264,
+ "z": 0.0
+ },
+ {
+ "x": 88.3937661420582,
+ "y": -156.32541850067906,
+ "z": 0.0
+ },
+ {
+ "x": 88.3939234221626,
+ "y": -157.36006965151546,
+ "z": 0.0
+ },
+ {
+ "x": 88.394080702267,
+ "y": -158.39472080235188,
+ "z": 0.0
+ },
+ {
+ "x": 88.39423798237141,
+ "y": -159.4293719531883,
+ "z": 0.0
+ },
+ {
+ "x": 88.39439526247581,
+ "y": -160.4640231040247,
+ "z": 0.0
+ },
+ {
+ "x": 88.39455254258021,
+ "y": -161.49867425486113,
+ "z": 0.0
+ },
+ {
+ "x": 88.39470982268462,
+ "y": -162.53332540569752,
+ "z": 0.0
+ },
+ {
+ "x": 88.39486710278902,
+ "y": -163.56797655653398,
+ "z": 0.0
+ },
+ {
+ "x": 88.39502438289344,
+ "y": -164.60262770737035,
+ "z": 0.0
+ },
+ {
+ "x": 88.39518166299784,
+ "y": -165.63727885820677,
+ "z": 0.0
+ },
+ {
+ "x": 88.39533894310225,
+ "y": -166.6719300090432,
+ "z": 0.0
+ },
+ {
+ "x": 88.39549622320665,
+ "y": -167.7065811598796,
+ "z": 0.0
+ },
+ {
+ "x": 88.39565350331105,
+ "y": -168.74123231071601,
+ "z": 0.0
+ },
+ {
+ "x": 88.39581078341546,
+ "y": -169.77588346155244,
+ "z": 0.0
+ },
+ {
+ "x": 88.39596806351986,
+ "y": -170.81053461238884,
+ "z": 0.0
+ },
+ {
+ "x": 88.39612534362426,
+ "y": -171.84518576322526,
+ "z": 0.0
+ },
+ {
+ "x": 88.39628262372867,
+ "y": -172.87983691406166,
+ "z": 0.0
+ },
+ {
+ "x": 88.39643990383307,
+ "y": -173.91448806489808,
+ "z": 0.0
+ },
+ {
+ "x": 88.39659718393747,
+ "y": -174.94913921573448,
+ "z": 0.0
+ },
+ {
+ "x": 88.39675446404188,
+ "y": -175.9837903665709,
+ "z": 0.0
+ },
+ {
+ "x": 88.39691174414628,
+ "y": -177.01844151740733,
+ "z": 0.0
+ },
+ {
+ "x": 88.39706902425068,
+ "y": -178.05309266824375,
+ "z": 0.0
+ },
+ {
+ "x": 88.3972263043551,
+ "y": -179.08774381908015,
+ "z": 0.0
+ },
+ {
+ "x": 88.3973835844595,
+ "y": -180.12239496991657,
+ "z": 0.0
+ },
+ {
+ "x": 88.39754086456391,
+ "y": -181.15704612075297,
+ "z": 0.0
+ },
+ {
+ "x": 88.39769814466831,
+ "y": -182.1916972715894,
+ "z": 0.0
+ },
+ {
+ "x": 88.39785542477271,
+ "y": -183.2263484224258,
+ "z": 0.0
+ },
+ {
+ "x": 88.39801270487712,
+ "y": -184.2609995732622,
+ "z": 0.0
+ },
+ {
+ "x": 88.39816998498152,
+ "y": -185.2956507240986,
+ "z": 0.0
+ },
+ {
+ "x": 88.39832726508592,
+ "y": -186.33030187493503,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 120,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 94.4182362975105,
+ "y": -317.299388285589,
+ "z": 0.0
+ },
+ {
+ "x": 94.41808291952336,
+ "y": -316.2904068157652,
+ "z": 0.0
+ },
+ {
+ "x": 94.4179295415362,
+ "y": -315.28142534594133,
+ "z": 0.0
+ },
+ {
+ "x": 94.41777616354905,
+ "y": -314.2724438761176,
+ "z": 0.0
+ },
+ {
+ "x": 94.4176227855619,
+ "y": -313.26346240629385,
+ "z": 0.0
+ },
+ {
+ "x": 94.41746940757476,
+ "y": -312.25448093647003,
+ "z": 0.0
+ },
+ {
+ "x": 94.41731602958761,
+ "y": -311.24549946664627,
+ "z": 0.0
+ },
+ {
+ "x": 94.41716265160046,
+ "y": -310.2365179968225,
+ "z": 0.0
+ },
+ {
+ "x": 94.41700927361332,
+ "y": -309.2275365269987,
+ "z": 0.0
+ },
+ {
+ "x": 94.41685589562616,
+ "y": -308.21855505717485,
+ "z": 0.0
+ },
+ {
+ "x": 94.41670251763901,
+ "y": -307.2095735873511,
+ "z": 0.0
+ },
+ {
+ "x": 94.41654913965186,
+ "y": -306.2005921175273,
+ "z": 0.0
+ },
+ {
+ "x": 94.41639576166472,
+ "y": -305.19161064770356,
+ "z": 0.0
+ },
+ {
+ "x": 94.41624238367757,
+ "y": -304.18262917787973,
+ "z": 0.0
+ },
+ {
+ "x": 94.41608900569042,
+ "y": -303.17364770805597,
+ "z": 0.0
+ },
+ {
+ "x": 94.41593562770328,
+ "y": -302.1646662382322,
+ "z": 0.0
+ },
+ {
+ "x": 94.41578224971612,
+ "y": -301.1556847684083,
+ "z": 0.0
+ },
+ {
+ "x": 94.41562887172897,
+ "y": -300.1467032985846,
+ "z": 0.0
+ },
+ {
+ "x": 94.41547549374182,
+ "y": -299.13772182876085,
+ "z": 0.0
+ },
+ {
+ "x": 94.41532211575468,
+ "y": -298.128740358937,
+ "z": 0.0
+ },
+ {
+ "x": 94.41516873776753,
+ "y": -297.11975888911326,
+ "z": 0.0
+ },
+ {
+ "x": 94.41501535978038,
+ "y": -296.1107774192895,
+ "z": 0.0
+ },
+ {
+ "x": 94.41486198179324,
+ "y": -295.10179594946567,
+ "z": 0.0
+ },
+ {
+ "x": 94.41470860380609,
+ "y": -294.0928144796419,
+ "z": 0.0
+ },
+ {
+ "x": 94.41455522581893,
+ "y": -293.0838330098181,
+ "z": 0.0
+ },
+ {
+ "x": 94.4144018478318,
+ "y": -292.07485153999437,
+ "z": 0.0
+ },
+ {
+ "x": 94.41424846984464,
+ "y": -291.0658700701705,
+ "z": 0.0
+ },
+ {
+ "x": 94.41409509185749,
+ "y": -290.0568886003467,
+ "z": 0.0
+ },
+ {
+ "x": 94.41394171387034,
+ "y": -289.04790713052296,
+ "z": 0.0
+ },
+ {
+ "x": 94.4137883358832,
+ "y": -288.0389256606992,
+ "z": 0.0
+ },
+ {
+ "x": 94.41363495789605,
+ "y": -287.02994419087537,
+ "z": 0.0
+ },
+ {
+ "x": 94.41348157990889,
+ "y": -286.02096272105155,
+ "z": 0.0
+ },
+ {
+ "x": 94.41332820192176,
+ "y": -285.0119812512279,
+ "z": 0.0
+ },
+ {
+ "x": 94.41317482393461,
+ "y": -284.002999781404,
+ "z": 0.0
+ },
+ {
+ "x": 94.41302144594745,
+ "y": -282.9940183115802,
+ "z": 0.0
+ },
+ {
+ "x": 94.4128680679603,
+ "y": -281.9850368417565,
+ "z": 0.0
+ },
+ {
+ "x": 94.41271468997316,
+ "y": -280.97605537193266,
+ "z": 0.0
+ },
+ {
+ "x": 94.41256131198601,
+ "y": -279.9670739021089,
+ "z": 0.0
+ },
+ {
+ "x": 94.41240793399886,
+ "y": -278.9580924322851,
+ "z": 0.0
+ },
+ {
+ "x": 94.41225455601172,
+ "y": -277.9491109624613,
+ "z": 0.0
+ },
+ {
+ "x": 94.41210117802457,
+ "y": -276.94012949263754,
+ "z": 0.0
+ },
+ {
+ "x": 94.41194780003741,
+ "y": -275.9311480228137,
+ "z": 0.0
+ },
+ {
+ "x": 94.41179442205026,
+ "y": -274.92216655298995,
+ "z": 0.0
+ },
+ {
+ "x": 94.41164104406312,
+ "y": -273.9131850831662,
+ "z": 0.0
+ },
+ {
+ "x": 94.41148766607597,
+ "y": -272.9042036133424,
+ "z": 0.0
+ },
+ {
+ "x": 94.41133428808882,
+ "y": -271.8952221435186,
+ "z": 0.0
+ },
+ {
+ "x": 94.41118091010168,
+ "y": -270.88624067369483,
+ "z": 0.0
+ },
+ {
+ "x": 94.41102753211453,
+ "y": -269.87725920387106,
+ "z": 0.0
+ },
+ {
+ "x": 94.41087415412737,
+ "y": -268.86827773404724,
+ "z": 0.0
+ },
+ {
+ "x": 94.41072077614024,
+ "y": -267.85929626422353,
+ "z": 0.0
+ },
+ {
+ "x": 94.41056739815309,
+ "y": -266.8503147943997,
+ "z": 0.0
+ },
+ {
+ "x": 94.41041402016593,
+ "y": -265.8413333245759,
+ "z": 0.0
+ },
+ {
+ "x": 94.41026064217878,
+ "y": -264.8323518547522,
+ "z": 0.0
+ },
+ {
+ "x": 94.41010726419164,
+ "y": -263.82337038492835,
+ "z": 0.0
+ },
+ {
+ "x": 94.40995388620449,
+ "y": -262.8143889151046,
+ "z": 0.0
+ },
+ {
+ "x": 94.40980050821734,
+ "y": -261.8054074452808,
+ "z": 0.0
+ },
+ {
+ "x": 94.4096471302302,
+ "y": -260.79642597545705,
+ "z": 0.0
+ },
+ {
+ "x": 94.40949375224305,
+ "y": -259.7874445056333,
+ "z": 0.0
+ },
+ {
+ "x": 94.40934037425589,
+ "y": -258.7784630358094,
+ "z": 0.0
+ },
+ {
+ "x": 94.40918699626874,
+ "y": -257.7694815659857,
+ "z": 0.0
+ },
+ {
+ "x": 94.4090336182816,
+ "y": -256.76050009616193,
+ "z": 0.0
+ },
+ {
+ "x": 94.40888024029445,
+ "y": -255.75151862633814,
+ "z": 0.0
+ },
+ {
+ "x": 94.4087268623073,
+ "y": -254.74253715651437,
+ "z": 0.0
+ },
+ {
+ "x": 94.40857348432014,
+ "y": -253.73355568669052,
+ "z": 0.0
+ },
+ {
+ "x": 94.408420106333,
+ "y": -252.7245742168668,
+ "z": 0.0
+ },
+ {
+ "x": 94.40826672834586,
+ "y": -251.71559274704308,
+ "z": 0.0
+ },
+ {
+ "x": 94.4081133503587,
+ "y": -250.7066112772192,
+ "z": 0.0
+ },
+ {
+ "x": 94.40795997237156,
+ "y": -249.6976298073955,
+ "z": 0.0
+ },
+ {
+ "x": 94.40780659438441,
+ "y": -248.6886483375717,
+ "z": 0.0
+ },
+ {
+ "x": 94.40765321639726,
+ "y": -247.67966686774793,
+ "z": 0.0
+ },
+ {
+ "x": 94.4074998384101,
+ "y": -246.67068539792407,
+ "z": 0.0
+ },
+ {
+ "x": 94.40734646042296,
+ "y": -245.66170392810037,
+ "z": 0.0
+ },
+ {
+ "x": 94.40719308243582,
+ "y": -244.65272245827663,
+ "z": 0.0
+ },
+ {
+ "x": 94.40703970444866,
+ "y": -243.64374098845275,
+ "z": 0.0
+ },
+ {
+ "x": 94.40688632646152,
+ "y": -242.634759518629,
+ "z": 0.0
+ },
+ {
+ "x": 94.40673294847437,
+ "y": -241.62577804880524,
+ "z": 0.0
+ },
+ {
+ "x": 94.40657957048722,
+ "y": -240.61679657898145,
+ "z": 0.0
+ },
+ {
+ "x": 94.40642619250008,
+ "y": -239.60781510915768,
+ "z": 0.0
+ },
+ {
+ "x": 94.40627281451292,
+ "y": -238.59883363933383,
+ "z": 0.0
+ },
+ {
+ "x": 94.40611943652578,
+ "y": -237.58985216951018,
+ "z": 0.0
+ },
+ {
+ "x": 94.40596605853862,
+ "y": -236.5808706996863,
+ "z": 0.0
+ },
+ {
+ "x": 94.40581268055148,
+ "y": -235.57188922986256,
+ "z": 0.0
+ },
+ {
+ "x": 94.40565930256435,
+ "y": -234.56290776003885,
+ "z": 0.0
+ },
+ {
+ "x": 94.40550592457718,
+ "y": -233.55392629021495,
+ "z": 0.0
+ },
+ {
+ "x": 94.40535254659004,
+ "y": -232.54494482039124,
+ "z": 0.0
+ },
+ {
+ "x": 94.40519916860289,
+ "y": -231.53596335056744,
+ "z": 0.0
+ },
+ {
+ "x": 94.40504579061574,
+ "y": -230.52698188074368,
+ "z": 0.0
+ },
+ {
+ "x": 94.4048924126286,
+ "y": -229.51800041091988,
+ "z": 0.0
+ },
+ {
+ "x": 94.40473903464144,
+ "y": -228.50901894109606,
+ "z": 0.0
+ },
+ {
+ "x": 94.4045856566543,
+ "y": -227.50003747127238,
+ "z": 0.0
+ },
+ {
+ "x": 94.40443227866714,
+ "y": -226.4910560014485,
+ "z": 0.0
+ },
+ {
+ "x": 94.40427890068,
+ "y": -225.4820745316248,
+ "z": 0.0
+ },
+ {
+ "x": 94.40412552269285,
+ "y": -224.473093061801,
+ "z": 0.0
+ },
+ {
+ "x": 94.4039721447057,
+ "y": -223.46411159197723,
+ "z": 0.0
+ },
+ {
+ "x": 94.40381876671856,
+ "y": -222.45513012215343,
+ "z": 0.0
+ },
+ {
+ "x": 94.4036653887314,
+ "y": -221.4461486523296,
+ "z": 0.0
+ },
+ {
+ "x": 94.40351201074427,
+ "y": -220.43716718250593,
+ "z": 0.0
+ },
+ {
+ "x": 94.4033586327571,
+ "y": -219.42818571268205,
+ "z": 0.0
+ },
+ {
+ "x": 94.40320525476996,
+ "y": -218.4192042428583,
+ "z": 0.0
+ },
+ {
+ "x": 94.40305187678281,
+ "y": -217.41022277303452,
+ "z": 0.0
+ },
+ {
+ "x": 94.40289849879566,
+ "y": -216.40124130321075,
+ "z": 0.0
+ },
+ {
+ "x": 94.40274512080852,
+ "y": -215.39225983338696,
+ "z": 0.0
+ },
+ {
+ "x": 94.40259174282136,
+ "y": -214.38327836356314,
+ "z": 0.0
+ },
+ {
+ "x": 94.40243836483423,
+ "y": -213.37429689373946,
+ "z": 0.0
+ },
+ {
+ "x": 94.40228498684708,
+ "y": -212.36531542391563,
+ "z": 0.0
+ },
+ {
+ "x": 94.40213160885992,
+ "y": -211.35633395409178,
+ "z": 0.0
+ },
+ {
+ "x": 94.40197823087277,
+ "y": -210.34735248426807,
+ "z": 0.0
+ },
+ {
+ "x": 94.40182485288562,
+ "y": -209.33837101444428,
+ "z": 0.0
+ },
+ {
+ "x": 94.40167147489848,
+ "y": -208.3293895446205,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 121,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 86.40167156732991,
+ "y": -208.33060564612455,
+ "z": 0.0
+ },
+ {
+ "x": 86.40182494531706,
+ "y": -209.33958711594832,
+ "z": 0.0
+ },
+ {
+ "x": 86.4019783233042,
+ "y": -210.3485685857721,
+ "z": 0.0
+ },
+ {
+ "x": 86.40213170129135,
+ "y": -211.35755005559594,
+ "z": 0.0
+ },
+ {
+ "x": 86.40228507927851,
+ "y": -212.36653152541967,
+ "z": 0.0
+ },
+ {
+ "x": 86.40243845726566,
+ "y": -213.37551299524338,
+ "z": 0.0
+ },
+ {
+ "x": 86.40259183525279,
+ "y": -214.3844944650673,
+ "z": 0.0
+ },
+ {
+ "x": 86.40274521323995,
+ "y": -215.393475934891,
+ "z": 0.0
+ },
+ {
+ "x": 86.4028985912271,
+ "y": -216.4024574047148,
+ "z": 0.0
+ },
+ {
+ "x": 86.40305196921425,
+ "y": -217.41143887453856,
+ "z": 0.0
+ },
+ {
+ "x": 86.40320534720139,
+ "y": -218.42042034436236,
+ "z": 0.0
+ },
+ {
+ "x": 86.40335872518854,
+ "y": -219.4294018141862,
+ "z": 0.0
+ },
+ {
+ "x": 86.4035121031757,
+ "y": -220.43838328400986,
+ "z": 0.0
+ },
+ {
+ "x": 86.40366548116283,
+ "y": -221.44736475383377,
+ "z": 0.0
+ },
+ {
+ "x": 86.40381885915,
+ "y": -222.45634622365748,
+ "z": 0.0
+ },
+ {
+ "x": 86.40397223713714,
+ "y": -223.46532769348127,
+ "z": 0.0
+ },
+ {
+ "x": 86.40412561512429,
+ "y": -224.47430916330504,
+ "z": 0.0
+ },
+ {
+ "x": 86.40427899311143,
+ "y": -225.48329063312883,
+ "z": 0.0
+ },
+ {
+ "x": 86.40443237109858,
+ "y": -226.49227210295265,
+ "z": 0.0
+ },
+ {
+ "x": 86.40458574908574,
+ "y": -227.5012535727763,
+ "z": 0.0
+ },
+ {
+ "x": 86.40473912707287,
+ "y": -228.51023504260021,
+ "z": 0.0
+ },
+ {
+ "x": 86.40489250506003,
+ "y": -229.51921651242392,
+ "z": 0.0
+ },
+ {
+ "x": 86.40504588304718,
+ "y": -230.52819798224772,
+ "z": 0.0
+ },
+ {
+ "x": 86.40519926103433,
+ "y": -231.53717945207148,
+ "z": 0.0
+ },
+ {
+ "x": 86.40535263902147,
+ "y": -232.54616092189528,
+ "z": 0.0
+ },
+ {
+ "x": 86.40550601700862,
+ "y": -233.5551423917191,
+ "z": 0.0
+ },
+ {
+ "x": 86.40565939499578,
+ "y": -234.56412386154278,
+ "z": 0.0
+ },
+ {
+ "x": 86.40581277298291,
+ "y": -235.5731053313666,
+ "z": 0.0
+ },
+ {
+ "x": 86.40596615097006,
+ "y": -236.58208680119046,
+ "z": 0.0
+ },
+ {
+ "x": 86.40611952895722,
+ "y": -237.5910682710141,
+ "z": 0.0
+ },
+ {
+ "x": 86.40627290694435,
+ "y": -238.600049740838,
+ "z": 0.0
+ },
+ {
+ "x": 86.40642628493151,
+ "y": -239.60903121066173,
+ "z": 0.0
+ },
+ {
+ "x": 86.40657966291866,
+ "y": -240.6180126804855,
+ "z": 0.0
+ },
+ {
+ "x": 86.4067330409058,
+ "y": -241.6269941503093,
+ "z": 0.0
+ },
+ {
+ "x": 86.40688641889295,
+ "y": -242.63597562013305,
+ "z": 0.0
+ },
+ {
+ "x": 86.4070397968801,
+ "y": -243.6449570899569,
+ "z": 0.0
+ },
+ {
+ "x": 86.40719317486726,
+ "y": -244.65393855978056,
+ "z": 0.0
+ },
+ {
+ "x": 86.40734655285439,
+ "y": -245.6629200296044,
+ "z": 0.0
+ },
+ {
+ "x": 86.40749993084154,
+ "y": -246.67190149942823,
+ "z": 0.0
+ },
+ {
+ "x": 86.4076533088287,
+ "y": -247.68088296925197,
+ "z": 0.0
+ },
+ {
+ "x": 86.40780668681585,
+ "y": -248.68986443907573,
+ "z": 0.0
+ },
+ {
+ "x": 86.40796006480299,
+ "y": -249.69884590889953,
+ "z": 0.0
+ },
+ {
+ "x": 86.40811344279014,
+ "y": -250.70782737872335,
+ "z": 0.0
+ },
+ {
+ "x": 86.4082668207773,
+ "y": -251.716808848547,
+ "z": 0.0
+ },
+ {
+ "x": 86.40842019876443,
+ "y": -252.72579031837085,
+ "z": 0.0
+ },
+ {
+ "x": 86.40857357675158,
+ "y": -253.73477178819468,
+ "z": 0.0
+ },
+ {
+ "x": 86.40872695473874,
+ "y": -254.74375325801842,
+ "z": 0.0
+ },
+ {
+ "x": 86.40888033272589,
+ "y": -255.75273472784218,
+ "z": 0.0
+ },
+ {
+ "x": 86.40903371071303,
+ "y": -256.761716197666,
+ "z": 0.0
+ },
+ {
+ "x": 86.40918708870018,
+ "y": -257.77069766748974,
+ "z": 0.0
+ },
+ {
+ "x": 86.40934046668733,
+ "y": -258.77967913731356,
+ "z": 0.0
+ },
+ {
+ "x": 86.40949384467449,
+ "y": -259.78866060713733,
+ "z": 0.0
+ },
+ {
+ "x": 86.40964722266163,
+ "y": -260.7976420769611,
+ "z": 0.0
+ },
+ {
+ "x": 86.40980060064878,
+ "y": -261.80662354678486,
+ "z": 0.0
+ },
+ {
+ "x": 86.40995397863593,
+ "y": -262.81560501660863,
+ "z": 0.0
+ },
+ {
+ "x": 86.41010735662307,
+ "y": -263.8245864864324,
+ "z": 0.0
+ },
+ {
+ "x": 86.41026073461022,
+ "y": -264.8335679562562,
+ "z": 0.0
+ },
+ {
+ "x": 86.41041411259737,
+ "y": -265.84254942608004,
+ "z": 0.0
+ },
+ {
+ "x": 86.41056749058453,
+ "y": -266.85153089590375,
+ "z": 0.0
+ },
+ {
+ "x": 86.41072086857167,
+ "y": -267.86051236572746,
+ "z": 0.0
+ },
+ {
+ "x": 86.4108742465588,
+ "y": -268.8694938355514,
+ "z": 0.0
+ },
+ {
+ "x": 86.41102762454597,
+ "y": -269.8784753053751,
+ "z": 0.0
+ },
+ {
+ "x": 86.41118100253311,
+ "y": -270.88745677519887,
+ "z": 0.0
+ },
+ {
+ "x": 86.41133438052026,
+ "y": -271.89643824502264,
+ "z": 0.0
+ },
+ {
+ "x": 86.4114877585074,
+ "y": -272.90541971484646,
+ "z": 0.0
+ },
+ {
+ "x": 86.41164113649455,
+ "y": -273.9144011846702,
+ "z": 0.0
+ },
+ {
+ "x": 86.4117945144817,
+ "y": -274.923382654494,
+ "z": 0.0
+ },
+ {
+ "x": 86.41194789246885,
+ "y": -275.93236412431787,
+ "z": 0.0
+ },
+ {
+ "x": 86.412101270456,
+ "y": -276.9413455941416,
+ "z": 0.0
+ },
+ {
+ "x": 86.41225464844315,
+ "y": -277.95032706396535,
+ "z": 0.0
+ },
+ {
+ "x": 86.4124080264303,
+ "y": -278.95930853378917,
+ "z": 0.0
+ },
+ {
+ "x": 86.41256140441745,
+ "y": -279.96829000361294,
+ "z": 0.0
+ },
+ {
+ "x": 86.41271478240459,
+ "y": -280.9772714734367,
+ "z": 0.0
+ },
+ {
+ "x": 86.41286816039174,
+ "y": -281.9862529432605,
+ "z": 0.0
+ },
+ {
+ "x": 86.41302153837889,
+ "y": -282.99523441308435,
+ "z": 0.0
+ },
+ {
+ "x": 86.41317491636605,
+ "y": -284.00421588290806,
+ "z": 0.0
+ },
+ {
+ "x": 86.41332829435319,
+ "y": -285.0131973527318,
+ "z": 0.0
+ },
+ {
+ "x": 86.41348167234032,
+ "y": -286.0221788225557,
+ "z": 0.0
+ },
+ {
+ "x": 86.41363505032749,
+ "y": -287.0311602923794,
+ "z": 0.0
+ },
+ {
+ "x": 86.41378842831463,
+ "y": -288.04014176220323,
+ "z": 0.0
+ },
+ {
+ "x": 86.41394180630178,
+ "y": -289.049123232027,
+ "z": 0.0
+ },
+ {
+ "x": 86.41409518428893,
+ "y": -290.05810470185077,
+ "z": 0.0
+ },
+ {
+ "x": 86.41424856227607,
+ "y": -291.06708617167465,
+ "z": 0.0
+ },
+ {
+ "x": 86.41440194026323,
+ "y": -292.0760676414983,
+ "z": 0.0
+ },
+ {
+ "x": 86.41455531825036,
+ "y": -293.08504911132223,
+ "z": 0.0
+ },
+ {
+ "x": 86.41470869623753,
+ "y": -294.09403058114594,
+ "z": 0.0
+ },
+ {
+ "x": 86.41486207422467,
+ "y": -295.1030120509697,
+ "z": 0.0
+ },
+ {
+ "x": 86.41501545221182,
+ "y": -296.11199352079353,
+ "z": 0.0
+ },
+ {
+ "x": 86.41516883019897,
+ "y": -297.1209749906173,
+ "z": 0.0
+ },
+ {
+ "x": 86.41532220818611,
+ "y": -298.12995646044106,
+ "z": 0.0
+ },
+ {
+ "x": 86.41547558617326,
+ "y": -299.1389379302649,
+ "z": 0.0
+ },
+ {
+ "x": 86.4156289641604,
+ "y": -300.14791940008865,
+ "z": 0.0
+ },
+ {
+ "x": 86.41578234214755,
+ "y": -301.1569008699125,
+ "z": 0.0
+ },
+ {
+ "x": 86.41593572013471,
+ "y": -302.16588233973624,
+ "z": 0.0
+ },
+ {
+ "x": 86.41608909812186,
+ "y": -303.17486380956,
+ "z": 0.0
+ },
+ {
+ "x": 86.416242476109,
+ "y": -304.1838452793838,
+ "z": 0.0
+ },
+ {
+ "x": 86.41639585409615,
+ "y": -305.1928267492076,
+ "z": 0.0
+ },
+ {
+ "x": 86.4165492320833,
+ "y": -306.20180821903136,
+ "z": 0.0
+ },
+ {
+ "x": 86.41670261007044,
+ "y": -307.21078968885513,
+ "z": 0.0
+ },
+ {
+ "x": 86.41685598805759,
+ "y": -308.219771158679,
+ "z": 0.0
+ },
+ {
+ "x": 86.41700936604475,
+ "y": -309.2287526285027,
+ "z": 0.0
+ },
+ {
+ "x": 86.4171627440319,
+ "y": -310.23773409832654,
+ "z": 0.0
+ },
+ {
+ "x": 86.41731612201905,
+ "y": -311.2467155681503,
+ "z": 0.0
+ },
+ {
+ "x": 86.41746950000619,
+ "y": -312.2556970379741,
+ "z": 0.0
+ },
+ {
+ "x": 86.41762287799334,
+ "y": -313.2646785077979,
+ "z": 0.0
+ },
+ {
+ "x": 86.41777625598048,
+ "y": -314.27365997762166,
+ "z": 0.0
+ },
+ {
+ "x": 86.41792963396763,
+ "y": -315.2826414474455,
+ "z": 0.0
+ },
+ {
+ "x": 86.41808301195479,
+ "y": -316.29162291726925,
+ "z": 0.0
+ },
+ {
+ "x": 86.41823638994194,
+ "y": -317.300604387093,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 122,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 90.4016715211142,
+ "y": -208.32999759537253,
+ "z": 0.0
+ },
+ {
+ "x": 90.40182489910134,
+ "y": -209.3389790651963,
+ "z": 0.0
+ },
+ {
+ "x": 90.40197827708849,
+ "y": -210.3479605350201,
+ "z": 0.0
+ },
+ {
+ "x": 90.40213165507564,
+ "y": -211.35694200484386,
+ "z": 0.0
+ },
+ {
+ "x": 90.4022850330628,
+ "y": -212.36592347466765,
+ "z": 0.0
+ },
+ {
+ "x": 90.40243841104994,
+ "y": -213.37490494449142,
+ "z": 0.0
+ },
+ {
+ "x": 90.40259178903707,
+ "y": -214.3838864143152,
+ "z": 0.0
+ },
+ {
+ "x": 90.40274516702424,
+ "y": -215.39286788413898,
+ "z": 0.0
+ },
+ {
+ "x": 90.40289854501138,
+ "y": -216.40184935396277,
+ "z": 0.0
+ },
+ {
+ "x": 90.40305192299853,
+ "y": -217.41083082378654,
+ "z": 0.0
+ },
+ {
+ "x": 90.40320530098568,
+ "y": -218.41981229361033,
+ "z": 0.0
+ },
+ {
+ "x": 90.40335867897282,
+ "y": -219.42879376343413,
+ "z": 0.0
+ },
+ {
+ "x": 90.40351205695998,
+ "y": -220.4377752332579,
+ "z": 0.0
+ },
+ {
+ "x": 90.40366543494711,
+ "y": -221.4467567030817,
+ "z": 0.0
+ },
+ {
+ "x": 90.40381881293428,
+ "y": -222.45573817290546,
+ "z": 0.0
+ },
+ {
+ "x": 90.40397219092142,
+ "y": -223.46471964272925,
+ "z": 0.0
+ },
+ {
+ "x": 90.40412556890857,
+ "y": -224.47370111255302,
+ "z": 0.0
+ },
+ {
+ "x": 90.40427894689572,
+ "y": -225.4826825823768,
+ "z": 0.0
+ },
+ {
+ "x": 90.40443232488286,
+ "y": -226.49166405220058,
+ "z": 0.0
+ },
+ {
+ "x": 90.40458570287002,
+ "y": -227.50064552202434,
+ "z": 0.0
+ },
+ {
+ "x": 90.40473908085715,
+ "y": -228.50962699184814,
+ "z": 0.0
+ },
+ {
+ "x": 90.40489245884432,
+ "y": -229.5186084616719,
+ "z": 0.0
+ },
+ {
+ "x": 90.40504583683146,
+ "y": -230.5275899314957,
+ "z": 0.0
+ },
+ {
+ "x": 90.40519921481861,
+ "y": -231.53657140131946,
+ "z": 0.0
+ },
+ {
+ "x": 90.40535259280576,
+ "y": -232.54555287114326,
+ "z": 0.0
+ },
+ {
+ "x": 90.4055059707929,
+ "y": -233.55453434096702,
+ "z": 0.0
+ },
+ {
+ "x": 90.40565934878006,
+ "y": -234.56351581079082,
+ "z": 0.0
+ },
+ {
+ "x": 90.4058127267672,
+ "y": -235.57249728061458,
+ "z": 0.0
+ },
+ {
+ "x": 90.40596610475434,
+ "y": -236.58147875043838,
+ "z": 0.0
+ },
+ {
+ "x": 90.4061194827415,
+ "y": -237.59046022026214,
+ "z": 0.0
+ },
+ {
+ "x": 90.40627286072863,
+ "y": -238.5994416900859,
+ "z": 0.0
+ },
+ {
+ "x": 90.4064262387158,
+ "y": -239.6084231599097,
+ "z": 0.0
+ },
+ {
+ "x": 90.40657961670294,
+ "y": -240.61740462973347,
+ "z": 0.0
+ },
+ {
+ "x": 90.40673299469009,
+ "y": -241.62638609955727,
+ "z": 0.0
+ },
+ {
+ "x": 90.40688637267723,
+ "y": -242.63536756938103,
+ "z": 0.0
+ },
+ {
+ "x": 90.40703975066438,
+ "y": -243.64434903920483,
+ "z": 0.0
+ },
+ {
+ "x": 90.40719312865154,
+ "y": -244.6533305090286,
+ "z": 0.0
+ },
+ {
+ "x": 90.40734650663867,
+ "y": -245.6623119788524,
+ "z": 0.0
+ },
+ {
+ "x": 90.40749988462582,
+ "y": -246.67129344867615,
+ "z": 0.0
+ },
+ {
+ "x": 90.40765326261298,
+ "y": -247.68027491849995,
+ "z": 0.0
+ },
+ {
+ "x": 90.40780664060013,
+ "y": -248.6892563883237,
+ "z": 0.0
+ },
+ {
+ "x": 90.40796001858727,
+ "y": -249.6982378581475,
+ "z": 0.0
+ },
+ {
+ "x": 90.40811339657442,
+ "y": -250.70721932797127,
+ "z": 0.0
+ },
+ {
+ "x": 90.40826677456158,
+ "y": -251.71620079779504,
+ "z": 0.0
+ },
+ {
+ "x": 90.40842015254871,
+ "y": -252.72518226761883,
+ "z": 0.0
+ },
+ {
+ "x": 90.40857353053586,
+ "y": -253.7341637374426,
+ "z": 0.0
+ },
+ {
+ "x": 90.40872690852302,
+ "y": -254.7431452072664,
+ "z": 0.0
+ },
+ {
+ "x": 90.40888028651017,
+ "y": -255.75212667709016,
+ "z": 0.0
+ },
+ {
+ "x": 90.40903366449731,
+ "y": -256.76110814691395,
+ "z": 0.0
+ },
+ {
+ "x": 90.40918704248446,
+ "y": -257.7700896167377,
+ "z": 0.0
+ },
+ {
+ "x": 90.40934042047161,
+ "y": -258.7790710865615,
+ "z": 0.0
+ },
+ {
+ "x": 90.40949379845877,
+ "y": -259.7880525563853,
+ "z": 0.0
+ },
+ {
+ "x": 90.40964717644592,
+ "y": -260.7970340262091,
+ "z": 0.0
+ },
+ {
+ "x": 90.40980055443306,
+ "y": -261.80601549603284,
+ "z": 0.0
+ },
+ {
+ "x": 90.40995393242021,
+ "y": -262.8149969658566,
+ "z": 0.0
+ },
+ {
+ "x": 90.41010731040735,
+ "y": -263.8239784356804,
+ "z": 0.0
+ },
+ {
+ "x": 90.4102606883945,
+ "y": -264.8329599055042,
+ "z": 0.0
+ },
+ {
+ "x": 90.41041406638165,
+ "y": -265.84194137532796,
+ "z": 0.0
+ },
+ {
+ "x": 90.41056744436881,
+ "y": -266.85092284515173,
+ "z": 0.0
+ },
+ {
+ "x": 90.41072082235596,
+ "y": -267.8599043149755,
+ "z": 0.0
+ },
+ {
+ "x": 90.41087420034309,
+ "y": -268.8688857847993,
+ "z": 0.0
+ },
+ {
+ "x": 90.41102757833025,
+ "y": -269.8778672546231,
+ "z": 0.0
+ },
+ {
+ "x": 90.4111809563174,
+ "y": -270.88684872444685,
+ "z": 0.0
+ },
+ {
+ "x": 90.41133433430454,
+ "y": -271.8958301942706,
+ "z": 0.0
+ },
+ {
+ "x": 90.41148771229169,
+ "y": -272.90481166409444,
+ "z": 0.0
+ },
+ {
+ "x": 90.41164109027883,
+ "y": -273.9137931339182,
+ "z": 0.0
+ },
+ {
+ "x": 90.41179446826598,
+ "y": -274.92277460374197,
+ "z": 0.0
+ },
+ {
+ "x": 90.41194784625313,
+ "y": -275.9317560735658,
+ "z": 0.0
+ },
+ {
+ "x": 90.41210122424029,
+ "y": -276.94073754338956,
+ "z": 0.0
+ },
+ {
+ "x": 90.41225460222743,
+ "y": -277.9497190132133,
+ "z": 0.0
+ },
+ {
+ "x": 90.41240798021458,
+ "y": -278.95870048303715,
+ "z": 0.0
+ },
+ {
+ "x": 90.41256135820173,
+ "y": -279.9676819528609,
+ "z": 0.0
+ },
+ {
+ "x": 90.41271473618887,
+ "y": -280.9766634226847,
+ "z": 0.0
+ },
+ {
+ "x": 90.41286811417602,
+ "y": -281.9856448925085,
+ "z": 0.0
+ },
+ {
+ "x": 90.41302149216317,
+ "y": -282.99462636233227,
+ "z": 0.0
+ },
+ {
+ "x": 90.41317487015033,
+ "y": -284.00360783215604,
+ "z": 0.0
+ },
+ {
+ "x": 90.41332824813747,
+ "y": -285.01258930197986,
+ "z": 0.0
+ },
+ {
+ "x": 90.41348162612461,
+ "y": -286.0215707718036,
+ "z": 0.0
+ },
+ {
+ "x": 90.41363500411177,
+ "y": -287.0305522416274,
+ "z": 0.0
+ },
+ {
+ "x": 90.41378838209891,
+ "y": -288.0395337114512,
+ "z": 0.0
+ },
+ {
+ "x": 90.41394176008606,
+ "y": -289.048515181275,
+ "z": 0.0
+ },
+ {
+ "x": 90.41409513807321,
+ "y": -290.05749665109875,
+ "z": 0.0
+ },
+ {
+ "x": 90.41424851606035,
+ "y": -291.06647812092257,
+ "z": 0.0
+ },
+ {
+ "x": 90.41440189404751,
+ "y": -292.07545959074633,
+ "z": 0.0
+ },
+ {
+ "x": 90.41455527203465,
+ "y": -293.08444106057016,
+ "z": 0.0
+ },
+ {
+ "x": 90.41470865002181,
+ "y": -294.0934225303939,
+ "z": 0.0
+ },
+ {
+ "x": 90.41486202800895,
+ "y": -295.1024040002177,
+ "z": 0.0
+ },
+ {
+ "x": 90.4150154059961,
+ "y": -296.1113854700415,
+ "z": 0.0
+ },
+ {
+ "x": 90.41516878398325,
+ "y": -297.1203669398653,
+ "z": 0.0
+ },
+ {
+ "x": 90.4153221619704,
+ "y": -298.12934840968904,
+ "z": 0.0
+ },
+ {
+ "x": 90.41547553995754,
+ "y": -299.13832987951287,
+ "z": 0.0
+ },
+ {
+ "x": 90.41562891794469,
+ "y": -300.14731134933663,
+ "z": 0.0
+ },
+ {
+ "x": 90.41578229593183,
+ "y": -301.1562928191604,
+ "z": 0.0
+ },
+ {
+ "x": 90.415935673919,
+ "y": -302.1652742889842,
+ "z": 0.0
+ },
+ {
+ "x": 90.41608905190614,
+ "y": -303.174255758808,
+ "z": 0.0
+ },
+ {
+ "x": 90.41624242989329,
+ "y": -304.18323722863175,
+ "z": 0.0
+ },
+ {
+ "x": 90.41639580788043,
+ "y": -305.1922186984556,
+ "z": 0.0
+ },
+ {
+ "x": 90.41654918586758,
+ "y": -306.20120016827934,
+ "z": 0.0
+ },
+ {
+ "x": 90.41670256385473,
+ "y": -307.2101816381031,
+ "z": 0.0
+ },
+ {
+ "x": 90.41685594184187,
+ "y": -308.21916310792693,
+ "z": 0.0
+ },
+ {
+ "x": 90.41700931982903,
+ "y": -309.2281445777507,
+ "z": 0.0
+ },
+ {
+ "x": 90.41716269781618,
+ "y": -310.2371260475745,
+ "z": 0.0
+ },
+ {
+ "x": 90.41731607580333,
+ "y": -311.2461075173983,
+ "z": 0.0
+ },
+ {
+ "x": 90.41746945379047,
+ "y": -312.25508898722205,
+ "z": 0.0
+ },
+ {
+ "x": 90.41762283177762,
+ "y": -313.2640704570459,
+ "z": 0.0
+ },
+ {
+ "x": 90.41777620976477,
+ "y": -314.27305192686964,
+ "z": 0.0
+ },
+ {
+ "x": 90.41792958775191,
+ "y": -315.2820333966934,
+ "z": 0.0
+ },
+ {
+ "x": 90.41808296573907,
+ "y": -316.29101486651723,
+ "z": 0.0
+ },
+ {
+ "x": 90.41823634372622,
+ "y": -317.299996336341,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 123,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 92.41823632061836,
+ "y": -317.299692310965,
+ "z": 0.0
+ },
+ {
+ "x": 92.41808294263122,
+ "y": -316.2907108411412,
+ "z": 0.0
+ },
+ {
+ "x": 92.41792956464406,
+ "y": -315.2817293713174,
+ "z": 0.0
+ },
+ {
+ "x": 92.41777618665691,
+ "y": -314.27274790149363,
+ "z": 0.0
+ },
+ {
+ "x": 92.41762280866976,
+ "y": -313.26376643166986,
+ "z": 0.0
+ },
+ {
+ "x": 92.41746943068262,
+ "y": -312.25478496184604,
+ "z": 0.0
+ },
+ {
+ "x": 92.41731605269547,
+ "y": -311.2458034920223,
+ "z": 0.0
+ },
+ {
+ "x": 92.41716267470832,
+ "y": -310.2368220221985,
+ "z": 0.0
+ },
+ {
+ "x": 92.41700929672118,
+ "y": -309.2278405523747,
+ "z": 0.0
+ },
+ {
+ "x": 92.41685591873402,
+ "y": -308.2188590825509,
+ "z": 0.0
+ },
+ {
+ "x": 92.41670254074687,
+ "y": -307.2098776127271,
+ "z": 0.0
+ },
+ {
+ "x": 92.41654916275972,
+ "y": -306.20089614290333,
+ "z": 0.0
+ },
+ {
+ "x": 92.41639578477258,
+ "y": -305.19191467307957,
+ "z": 0.0
+ },
+ {
+ "x": 92.41624240678543,
+ "y": -304.18293320325574,
+ "z": 0.0
+ },
+ {
+ "x": 92.41608902879828,
+ "y": -303.173951733432,
+ "z": 0.0
+ },
+ {
+ "x": 92.41593565081114,
+ "y": -302.1649702636082,
+ "z": 0.0
+ },
+ {
+ "x": 92.41578227282398,
+ "y": -301.15598879378433,
+ "z": 0.0
+ },
+ {
+ "x": 92.41562889483683,
+ "y": -300.1470073239606,
+ "z": 0.0
+ },
+ {
+ "x": 92.41547551684968,
+ "y": -299.13802585413686,
+ "z": 0.0
+ },
+ {
+ "x": 92.41532213886254,
+ "y": -298.12904438431303,
+ "z": 0.0
+ },
+ {
+ "x": 92.41516876087539,
+ "y": -297.12006291448927,
+ "z": 0.0
+ },
+ {
+ "x": 92.41501538288824,
+ "y": -296.1110814446655,
+ "z": 0.0
+ },
+ {
+ "x": 92.4148620049011,
+ "y": -295.1020999748417,
+ "z": 0.0
+ },
+ {
+ "x": 92.41470862691395,
+ "y": -294.0931185050179,
+ "z": 0.0
+ },
+ {
+ "x": 92.41455524892679,
+ "y": -293.0841370351941,
+ "z": 0.0
+ },
+ {
+ "x": 92.41440187093966,
+ "y": -292.0751555653703,
+ "z": 0.0
+ },
+ {
+ "x": 92.4142484929525,
+ "y": -291.06617409554656,
+ "z": 0.0
+ },
+ {
+ "x": 92.41409511496535,
+ "y": -290.05719262572273,
+ "z": 0.0
+ },
+ {
+ "x": 92.4139417369782,
+ "y": -289.04821115589897,
+ "z": 0.0
+ },
+ {
+ "x": 92.41378835899106,
+ "y": -288.0392296860752,
+ "z": 0.0
+ },
+ {
+ "x": 92.41363498100391,
+ "y": -287.0302482162514,
+ "z": 0.0
+ },
+ {
+ "x": 92.41348160301675,
+ "y": -286.0212667464276,
+ "z": 0.0
+ },
+ {
+ "x": 92.41332822502962,
+ "y": -285.01228527660385,
+ "z": 0.0
+ },
+ {
+ "x": 92.41317484704247,
+ "y": -284.00330380678,
+ "z": 0.0
+ },
+ {
+ "x": 92.41302146905531,
+ "y": -282.9943223369562,
+ "z": 0.0
+ },
+ {
+ "x": 92.41286809106816,
+ "y": -281.9853408671325,
+ "z": 0.0
+ },
+ {
+ "x": 92.41271471308102,
+ "y": -280.97635939730867,
+ "z": 0.0
+ },
+ {
+ "x": 92.41256133509387,
+ "y": -279.9673779274849,
+ "z": 0.0
+ },
+ {
+ "x": 92.41240795710672,
+ "y": -278.95839645766114,
+ "z": 0.0
+ },
+ {
+ "x": 92.41225457911958,
+ "y": -277.9494149878373,
+ "z": 0.0
+ },
+ {
+ "x": 92.41210120113243,
+ "y": -276.94043351801355,
+ "z": 0.0
+ },
+ {
+ "x": 92.41194782314527,
+ "y": -275.9314520481897,
+ "z": 0.0
+ },
+ {
+ "x": 92.41179444515812,
+ "y": -274.92247057836596,
+ "z": 0.0
+ },
+ {
+ "x": 92.41164106717098,
+ "y": -273.9134891085422,
+ "z": 0.0
+ },
+ {
+ "x": 92.41148768918383,
+ "y": -272.9045076387184,
+ "z": 0.0
+ },
+ {
+ "x": 92.41133431119668,
+ "y": -271.8955261688946,
+ "z": 0.0
+ },
+ {
+ "x": 92.41118093320954,
+ "y": -270.88654469907084,
+ "z": 0.0
+ },
+ {
+ "x": 92.41102755522239,
+ "y": -269.8775632292471,
+ "z": 0.0
+ },
+ {
+ "x": 92.41087417723523,
+ "y": -268.86858175942325,
+ "z": 0.0
+ },
+ {
+ "x": 92.4107207992481,
+ "y": -267.8596002895995,
+ "z": 0.0
+ },
+ {
+ "x": 92.41056742126095,
+ "y": -266.8506188197757,
+ "z": 0.0
+ },
+ {
+ "x": 92.41041404327379,
+ "y": -265.84163734995195,
+ "z": 0.0
+ },
+ {
+ "x": 92.41026066528664,
+ "y": -264.8326558801282,
+ "z": 0.0
+ },
+ {
+ "x": 92.4101072872995,
+ "y": -263.82367441030436,
+ "z": 0.0
+ },
+ {
+ "x": 92.40995390931235,
+ "y": -262.8146929404806,
+ "z": 0.0
+ },
+ {
+ "x": 92.4098005313252,
+ "y": -261.80571147065683,
+ "z": 0.0
+ },
+ {
+ "x": 92.40964715333806,
+ "y": -260.79673000083307,
+ "z": 0.0
+ },
+ {
+ "x": 92.40949377535091,
+ "y": -259.7877485310093,
+ "z": 0.0
+ },
+ {
+ "x": 92.40934039736375,
+ "y": -258.7787670611855,
+ "z": 0.0
+ },
+ {
+ "x": 92.4091870193766,
+ "y": -257.7697855913617,
+ "z": 0.0
+ },
+ {
+ "x": 92.40903364138946,
+ "y": -256.76080412153794,
+ "z": 0.0
+ },
+ {
+ "x": 92.40888026340231,
+ "y": -255.75182265171415,
+ "z": 0.0
+ },
+ {
+ "x": 92.40872688541516,
+ "y": -254.74284118189038,
+ "z": 0.0
+ },
+ {
+ "x": 92.408573507428,
+ "y": -253.73385971206656,
+ "z": 0.0
+ },
+ {
+ "x": 92.40842012944086,
+ "y": -252.72487824224282,
+ "z": 0.0
+ },
+ {
+ "x": 92.40826675145372,
+ "y": -251.71589677241906,
+ "z": 0.0
+ },
+ {
+ "x": 92.40811337346656,
+ "y": -250.70691530259523,
+ "z": 0.0
+ },
+ {
+ "x": 92.40795999547942,
+ "y": -249.6979338327715,
+ "z": 0.0
+ },
+ {
+ "x": 92.40780661749227,
+ "y": -248.6889523629477,
+ "z": 0.0
+ },
+ {
+ "x": 92.40765323950512,
+ "y": -247.67997089312394,
+ "z": 0.0
+ },
+ {
+ "x": 92.40749986151796,
+ "y": -246.6709894233001,
+ "z": 0.0
+ },
+ {
+ "x": 92.40734648353082,
+ "y": -245.66200795347638,
+ "z": 0.0
+ },
+ {
+ "x": 92.40719310554368,
+ "y": -244.6530264836526,
+ "z": 0.0
+ },
+ {
+ "x": 92.40703972755652,
+ "y": -243.6440450138288,
+ "z": 0.0
+ },
+ {
+ "x": 92.40688634956938,
+ "y": -242.63506354400502,
+ "z": 0.0
+ },
+ {
+ "x": 92.40673297158223,
+ "y": -241.62608207418126,
+ "z": 0.0
+ },
+ {
+ "x": 92.40657959359508,
+ "y": -240.61710060435746,
+ "z": 0.0
+ },
+ {
+ "x": 92.40642621560794,
+ "y": -239.6081191345337,
+ "z": 0.0
+ },
+ {
+ "x": 92.40627283762078,
+ "y": -238.59913766470987,
+ "z": 0.0
+ },
+ {
+ "x": 92.40611945963364,
+ "y": -237.59015619488616,
+ "z": 0.0
+ },
+ {
+ "x": 92.40596608164648,
+ "y": -236.58117472506234,
+ "z": 0.0
+ },
+ {
+ "x": 92.40581270365934,
+ "y": -235.57219325523857,
+ "z": 0.0
+ },
+ {
+ "x": 92.4056593256722,
+ "y": -234.56321178541484,
+ "z": 0.0
+ },
+ {
+ "x": 92.40550594768504,
+ "y": -233.55423031559098,
+ "z": 0.0
+ },
+ {
+ "x": 92.4053525696979,
+ "y": -232.54524884576725,
+ "z": 0.0
+ },
+ {
+ "x": 92.40519919171075,
+ "y": -231.53626737594345,
+ "z": 0.0
+ },
+ {
+ "x": 92.4050458137236,
+ "y": -230.5272859061197,
+ "z": 0.0
+ },
+ {
+ "x": 92.40489243573646,
+ "y": -229.5183044362959,
+ "z": 0.0
+ },
+ {
+ "x": 92.4047390577493,
+ "y": -228.5093229664721,
+ "z": 0.0
+ },
+ {
+ "x": 92.40458567976216,
+ "y": -227.50034149664836,
+ "z": 0.0
+ },
+ {
+ "x": 92.404432301775,
+ "y": -226.49136002682454,
+ "z": 0.0
+ },
+ {
+ "x": 92.40427892378786,
+ "y": -225.4823785570008,
+ "z": 0.0
+ },
+ {
+ "x": 92.40412554580071,
+ "y": -224.473397087177,
+ "z": 0.0
+ },
+ {
+ "x": 92.40397216781356,
+ "y": -223.46441561735324,
+ "z": 0.0
+ },
+ {
+ "x": 92.40381878982642,
+ "y": -222.45543414752944,
+ "z": 0.0
+ },
+ {
+ "x": 92.40366541183926,
+ "y": -221.44645267770565,
+ "z": 0.0
+ },
+ {
+ "x": 92.40351203385212,
+ "y": -220.4374712078819,
+ "z": 0.0
+ },
+ {
+ "x": 92.40335865586496,
+ "y": -219.4284897380581,
+ "z": 0.0
+ },
+ {
+ "x": 92.40320527787782,
+ "y": -218.41950826823432,
+ "z": 0.0
+ },
+ {
+ "x": 92.40305189989067,
+ "y": -217.41052679841053,
+ "z": 0.0
+ },
+ {
+ "x": 92.40289852190352,
+ "y": -216.40154532858676,
+ "z": 0.0
+ },
+ {
+ "x": 92.40274514391638,
+ "y": -215.39256385876297,
+ "z": 0.0
+ },
+ {
+ "x": 92.40259176592922,
+ "y": -214.38358238893917,
+ "z": 0.0
+ },
+ {
+ "x": 92.40243838794208,
+ "y": -213.37460091911544,
+ "z": 0.0
+ },
+ {
+ "x": 92.40228500995494,
+ "y": -212.36561944929164,
+ "z": 0.0
+ },
+ {
+ "x": 92.40213163196778,
+ "y": -211.35663797946782,
+ "z": 0.0
+ },
+ {
+ "x": 92.40197825398063,
+ "y": -210.34765650964408,
+ "z": 0.0
+ },
+ {
+ "x": 92.40182487599348,
+ "y": -209.3386750398203,
+ "z": 0.0
+ },
+ {
+ "x": 92.40167149800634,
+ "y": -208.32969356999652,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 124,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 88.40167154422205,
+ "y": -208.33030162074854,
+ "z": 0.0
+ },
+ {
+ "x": 88.4018249222092,
+ "y": -209.3392830905723,
+ "z": 0.0
+ },
+ {
+ "x": 88.40197830019635,
+ "y": -210.3482645603961,
+ "z": 0.0
+ },
+ {
+ "x": 88.4021316781835,
+ "y": -211.3572460302199,
+ "z": 0.0
+ },
+ {
+ "x": 88.40228505617065,
+ "y": -212.36622750004366,
+ "z": 0.0
+ },
+ {
+ "x": 88.4024384341578,
+ "y": -213.3752089698674,
+ "z": 0.0
+ },
+ {
+ "x": 88.40259181214493,
+ "y": -214.38419043969125,
+ "z": 0.0
+ },
+ {
+ "x": 88.4027451901321,
+ "y": -215.393171909515,
+ "z": 0.0
+ },
+ {
+ "x": 88.40289856811924,
+ "y": -216.40215337933878,
+ "z": 0.0
+ },
+ {
+ "x": 88.40305194610639,
+ "y": -217.41113484916255,
+ "z": 0.0
+ },
+ {
+ "x": 88.40320532409353,
+ "y": -218.42011631898635,
+ "z": 0.0
+ },
+ {
+ "x": 88.40335870208068,
+ "y": -219.42909778881017,
+ "z": 0.0
+ },
+ {
+ "x": 88.40351208006784,
+ "y": -220.43807925863388,
+ "z": 0.0
+ },
+ {
+ "x": 88.40366545805497,
+ "y": -221.44706072845773,
+ "z": 0.0
+ },
+ {
+ "x": 88.40381883604213,
+ "y": -222.45604219828147,
+ "z": 0.0
+ },
+ {
+ "x": 88.40397221402928,
+ "y": -223.46502366810526,
+ "z": 0.0
+ },
+ {
+ "x": 88.40412559201643,
+ "y": -224.47400513792903,
+ "z": 0.0
+ },
+ {
+ "x": 88.40427897000357,
+ "y": -225.48298660775282,
+ "z": 0.0
+ },
+ {
+ "x": 88.40443234799072,
+ "y": -226.49196807757662,
+ "z": 0.0
+ },
+ {
+ "x": 88.40458572597788,
+ "y": -227.50094954740032,
+ "z": 0.0
+ },
+ {
+ "x": 88.40473910396501,
+ "y": -228.50993101722418,
+ "z": 0.0
+ },
+ {
+ "x": 88.40489248195217,
+ "y": -229.5189124870479,
+ "z": 0.0
+ },
+ {
+ "x": 88.40504585993932,
+ "y": -230.5278939568717,
+ "z": 0.0
+ },
+ {
+ "x": 88.40519923792647,
+ "y": -231.53687542669547,
+ "z": 0.0
+ },
+ {
+ "x": 88.40535261591361,
+ "y": -232.54585689651927,
+ "z": 0.0
+ },
+ {
+ "x": 88.40550599390076,
+ "y": -233.55483836634306,
+ "z": 0.0
+ },
+ {
+ "x": 88.40565937188792,
+ "y": -234.5638198361668,
+ "z": 0.0
+ },
+ {
+ "x": 88.40581274987505,
+ "y": -235.5728013059906,
+ "z": 0.0
+ },
+ {
+ "x": 88.4059661278622,
+ "y": -236.58178277581442,
+ "z": 0.0
+ },
+ {
+ "x": 88.40611950584936,
+ "y": -237.59076424563813,
+ "z": 0.0
+ },
+ {
+ "x": 88.4062728838365,
+ "y": -238.59974571546195,
+ "z": 0.0
+ },
+ {
+ "x": 88.40642626182365,
+ "y": -239.60872718528572,
+ "z": 0.0
+ },
+ {
+ "x": 88.4065796398108,
+ "y": -240.61770865510948,
+ "z": 0.0
+ },
+ {
+ "x": 88.40673301779795,
+ "y": -241.62669012493328,
+ "z": 0.0
+ },
+ {
+ "x": 88.4068863957851,
+ "y": -242.63567159475704,
+ "z": 0.0
+ },
+ {
+ "x": 88.40703977377224,
+ "y": -243.64465306458087,
+ "z": 0.0
+ },
+ {
+ "x": 88.4071931517594,
+ "y": -244.65363453440457,
+ "z": 0.0
+ },
+ {
+ "x": 88.40734652974653,
+ "y": -245.6626160042284,
+ "z": 0.0
+ },
+ {
+ "x": 88.40749990773368,
+ "y": -246.6715974740522,
+ "z": 0.0
+ },
+ {
+ "x": 88.40765328572084,
+ "y": -247.68057894387596,
+ "z": 0.0
+ },
+ {
+ "x": 88.40780666370799,
+ "y": -248.68956041369972,
+ "z": 0.0
+ },
+ {
+ "x": 88.40796004169513,
+ "y": -249.69854188352352,
+ "z": 0.0
+ },
+ {
+ "x": 88.40811341968228,
+ "y": -250.7075233533473,
+ "z": 0.0
+ },
+ {
+ "x": 88.40826679766944,
+ "y": -251.71650482317102,
+ "z": 0.0
+ },
+ {
+ "x": 88.40842017565657,
+ "y": -252.72548629299484,
+ "z": 0.0
+ },
+ {
+ "x": 88.40857355364372,
+ "y": -253.73446776281864,
+ "z": 0.0
+ },
+ {
+ "x": 88.40872693163088,
+ "y": -254.7434492326424,
+ "z": 0.0
+ },
+ {
+ "x": 88.40888030961803,
+ "y": -255.75243070246617,
+ "z": 0.0
+ },
+ {
+ "x": 88.40903368760517,
+ "y": -256.76141217228997,
+ "z": 0.0
+ },
+ {
+ "x": 88.40918706559232,
+ "y": -257.77039364211373,
+ "z": 0.0
+ },
+ {
+ "x": 88.40934044357947,
+ "y": -258.7793751119375,
+ "z": 0.0
+ },
+ {
+ "x": 88.40949382156663,
+ "y": -259.7883565817613,
+ "z": 0.0
+ },
+ {
+ "x": 88.40964719955377,
+ "y": -260.7973380515851,
+ "z": 0.0
+ },
+ {
+ "x": 88.40980057754092,
+ "y": -261.80631952140885,
+ "z": 0.0
+ },
+ {
+ "x": 88.40995395552807,
+ "y": -262.8153009912326,
+ "z": 0.0
+ },
+ {
+ "x": 88.41010733351521,
+ "y": -263.8242824610564,
+ "z": 0.0
+ },
+ {
+ "x": 88.41026071150236,
+ "y": -264.8332639308802,
+ "z": 0.0
+ },
+ {
+ "x": 88.4104140894895,
+ "y": -265.842245400704,
+ "z": 0.0
+ },
+ {
+ "x": 88.41056746747667,
+ "y": -266.85122687052774,
+ "z": 0.0
+ },
+ {
+ "x": 88.41072084546381,
+ "y": -267.8602083403515,
+ "z": 0.0
+ },
+ {
+ "x": 88.41087422345095,
+ "y": -268.8691898101754,
+ "z": 0.0
+ },
+ {
+ "x": 88.41102760143811,
+ "y": -269.8781712799991,
+ "z": 0.0
+ },
+ {
+ "x": 88.41118097942525,
+ "y": -270.88715274982286,
+ "z": 0.0
+ },
+ {
+ "x": 88.4113343574124,
+ "y": -271.8961342196466,
+ "z": 0.0
+ },
+ {
+ "x": 88.41148773539955,
+ "y": -272.90511568947045,
+ "z": 0.0
+ },
+ {
+ "x": 88.4116411133867,
+ "y": -273.9140971592942,
+ "z": 0.0
+ },
+ {
+ "x": 88.41179449137384,
+ "y": -274.923078629118,
+ "z": 0.0
+ },
+ {
+ "x": 88.41194786936099,
+ "y": -275.93206009894186,
+ "z": 0.0
+ },
+ {
+ "x": 88.41210124734815,
+ "y": -276.94104156876557,
+ "z": 0.0
+ },
+ {
+ "x": 88.4122546253353,
+ "y": -277.95002303858934,
+ "z": 0.0
+ },
+ {
+ "x": 88.41240800332244,
+ "y": -278.95900450841316,
+ "z": 0.0
+ },
+ {
+ "x": 88.41256138130959,
+ "y": -279.9679859782369,
+ "z": 0.0
+ },
+ {
+ "x": 88.41271475929673,
+ "y": -280.9769674480607,
+ "z": 0.0
+ },
+ {
+ "x": 88.41286813728388,
+ "y": -281.9859489178845,
+ "z": 0.0
+ },
+ {
+ "x": 88.41302151527103,
+ "y": -282.99493038770834,
+ "z": 0.0
+ },
+ {
+ "x": 88.41317489325819,
+ "y": -284.00391185753205,
+ "z": 0.0
+ },
+ {
+ "x": 88.41332827124533,
+ "y": -285.01289332735587,
+ "z": 0.0
+ },
+ {
+ "x": 88.41348164923247,
+ "y": -286.02187479717963,
+ "z": 0.0
+ },
+ {
+ "x": 88.41363502721963,
+ "y": -287.0308562670034,
+ "z": 0.0
+ },
+ {
+ "x": 88.41378840520677,
+ "y": -288.0398377368272,
+ "z": 0.0
+ },
+ {
+ "x": 88.41394178319392,
+ "y": -289.048819206651,
+ "z": 0.0
+ },
+ {
+ "x": 88.41409516118107,
+ "y": -290.05780067647476,
+ "z": 0.0
+ },
+ {
+ "x": 88.41424853916821,
+ "y": -291.0667821462986,
+ "z": 0.0
+ },
+ {
+ "x": 88.41440191715537,
+ "y": -292.07576361612234,
+ "z": 0.0
+ },
+ {
+ "x": 88.4145552951425,
+ "y": -293.0847450859462,
+ "z": 0.0
+ },
+ {
+ "x": 88.41470867312967,
+ "y": -294.09372655576993,
+ "z": 0.0
+ },
+ {
+ "x": 88.41486205111681,
+ "y": -295.1027080255937,
+ "z": 0.0
+ },
+ {
+ "x": 88.41501542910396,
+ "y": -296.1116894954175,
+ "z": 0.0
+ },
+ {
+ "x": 88.4151688070911,
+ "y": -297.1206709652413,
+ "z": 0.0
+ },
+ {
+ "x": 88.41532218507825,
+ "y": -298.12965243506505,
+ "z": 0.0
+ },
+ {
+ "x": 88.4154755630654,
+ "y": -299.1386339048889,
+ "z": 0.0
+ },
+ {
+ "x": 88.41562894105255,
+ "y": -300.14761537471264,
+ "z": 0.0
+ },
+ {
+ "x": 88.41578231903969,
+ "y": -301.15659684453647,
+ "z": 0.0
+ },
+ {
+ "x": 88.41593569702685,
+ "y": -302.16557831436023,
+ "z": 0.0
+ },
+ {
+ "x": 88.416089075014,
+ "y": -303.174559784184,
+ "z": 0.0
+ },
+ {
+ "x": 88.41624245300115,
+ "y": -304.18354125400776,
+ "z": 0.0
+ },
+ {
+ "x": 88.4163958309883,
+ "y": -305.1925227238316,
+ "z": 0.0
+ },
+ {
+ "x": 88.41654920897544,
+ "y": -306.20150419365535,
+ "z": 0.0
+ },
+ {
+ "x": 88.41670258696259,
+ "y": -307.2104856634791,
+ "z": 0.0
+ },
+ {
+ "x": 88.41685596494973,
+ "y": -308.21946713330294,
+ "z": 0.0
+ },
+ {
+ "x": 88.4170093429369,
+ "y": -309.2284486031267,
+ "z": 0.0
+ },
+ {
+ "x": 88.41716272092404,
+ "y": -310.23743007295053,
+ "z": 0.0
+ },
+ {
+ "x": 88.41731609891119,
+ "y": -311.2464115427743,
+ "z": 0.0
+ },
+ {
+ "x": 88.41746947689833,
+ "y": -312.25539301259806,
+ "z": 0.0
+ },
+ {
+ "x": 88.41762285488548,
+ "y": -313.2643744824219,
+ "z": 0.0
+ },
+ {
+ "x": 88.41777623287263,
+ "y": -314.27335595224565,
+ "z": 0.0
+ },
+ {
+ "x": 88.41792961085977,
+ "y": -315.2823374220694,
+ "z": 0.0
+ },
+ {
+ "x": 88.41808298884693,
+ "y": -316.29131889189324,
+ "z": 0.0
+ },
+ {
+ "x": 88.41823636683408,
+ "y": -317.300300361717,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 125,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 160.02380355703423,
+ "y": -46.204824954497035,
+ "z": 0.0
+ },
+ {
+ "x": 160.02506048809644,
+ "y": -45.17011983558629,
+ "z": 0.0
+ },
+ {
+ "x": 160.02631741915866,
+ "y": -44.135414716675555,
+ "z": 0.0
+ },
+ {
+ "x": 160.02757435022087,
+ "y": -43.10070959776482,
+ "z": 0.0
+ },
+ {
+ "x": 160.02883128128312,
+ "y": -42.06600447885419,
+ "z": 0.0
+ },
+ {
+ "x": 160.03008821234533,
+ "y": -41.03129935994334,
+ "z": 0.0
+ },
+ {
+ "x": 160.03134514340755,
+ "y": -39.996594241032604,
+ "z": 0.0
+ },
+ {
+ "x": 160.03260207446976,
+ "y": -38.96188912212187,
+ "z": 0.0
+ },
+ {
+ "x": 160.03385900553198,
+ "y": -37.927184003211124,
+ "z": 0.0
+ },
+ {
+ "x": 160.0351159365942,
+ "y": -36.89247888430038,
+ "z": 0.0
+ },
+ {
+ "x": 160.0363728676564,
+ "y": -35.857773765389645,
+ "z": 0.0
+ },
+ {
+ "x": 160.03762979871863,
+ "y": -34.82306864647891,
+ "z": 0.0
+ },
+ {
+ "x": 160.03888672978084,
+ "y": -33.78836352756817,
+ "z": 0.0
+ },
+ {
+ "x": 160.04014366084309,
+ "y": -32.75365840865754,
+ "z": 0.0
+ },
+ {
+ "x": 160.0414005919053,
+ "y": -31.7189532897467,
+ "z": 0.0
+ },
+ {
+ "x": 160.04265752296752,
+ "y": -30.68424817083596,
+ "z": 0.0
+ },
+ {
+ "x": 160.04391445402973,
+ "y": -29.649543051925225,
+ "z": 0.0
+ },
+ {
+ "x": 160.04517138509195,
+ "y": -28.61483793301449,
+ "z": 0.0
+ },
+ {
+ "x": 160.04642831615416,
+ "y": -27.580132814103752,
+ "z": 0.0
+ },
+ {
+ "x": 160.04768524721638,
+ "y": -26.545427695193016,
+ "z": 0.0
+ },
+ {
+ "x": 160.0489421782786,
+ "y": -25.51072257628228,
+ "z": 0.0
+ },
+ {
+ "x": 160.05019910934084,
+ "y": -24.476017457371654,
+ "z": 0.0
+ },
+ {
+ "x": 160.05145604040305,
+ "y": -23.441312338460804,
+ "z": 0.0
+ },
+ {
+ "x": 160.05271297146527,
+ "y": -22.406607219550068,
+ "z": 0.0
+ },
+ {
+ "x": 160.05396990252748,
+ "y": -21.371902100639332,
+ "z": 0.0
+ },
+ {
+ "x": 160.0552268335897,
+ "y": -20.337196981728592,
+ "z": 0.0
+ },
+ {
+ "x": 160.05648376465192,
+ "y": -19.302491862817856,
+ "z": 0.0
+ },
+ {
+ "x": 160.05774069571413,
+ "y": -18.26778674390712,
+ "z": 0.0
+ },
+ {
+ "x": 160.05899762677635,
+ "y": -17.233081624996384,
+ "z": 0.0
+ },
+ {
+ "x": 160.06025455783856,
+ "y": -16.198376506085648,
+ "z": 0.0
+ },
+ {
+ "x": 160.0615114889008,
+ "y": -15.16367138717502,
+ "z": 0.0
+ },
+ {
+ "x": 160.06276841996302,
+ "y": -14.128966268264172,
+ "z": 0.0
+ },
+ {
+ "x": 160.06402535102524,
+ "y": -13.094261149353436,
+ "z": 0.0
+ },
+ {
+ "x": 160.06528228208745,
+ "y": -12.059556030442698,
+ "z": 0.0
+ },
+ {
+ "x": 160.06653921314967,
+ "y": -11.024850911531962,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 126,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 152.06654511582957,
+ "y": -11.015132740726886,
+ "z": 0.0
+ },
+ {
+ "x": 152.06528818476735,
+ "y": -12.049837859637622,
+ "z": 0.0
+ },
+ {
+ "x": 152.06403125370514,
+ "y": -13.08454297854836,
+ "z": 0.0
+ },
+ {
+ "x": 152.06277432264292,
+ "y": -14.119248097459096,
+ "z": 0.0
+ },
+ {
+ "x": 152.0615173915807,
+ "y": -15.153953216369723,
+ "z": 0.0
+ },
+ {
+ "x": 152.06026046051846,
+ "y": -16.188658335280568,
+ "z": 0.0
+ },
+ {
+ "x": 152.05900352945625,
+ "y": -17.223363454191304,
+ "z": 0.0
+ },
+ {
+ "x": 152.05774659839403,
+ "y": -18.25806857310204,
+ "z": 0.0
+ },
+ {
+ "x": 152.05648966733182,
+ "y": -19.292773692012776,
+ "z": 0.0
+ },
+ {
+ "x": 152.0552327362696,
+ "y": -20.327478810923512,
+ "z": 0.0
+ },
+ {
+ "x": 152.0539758052074,
+ "y": -21.362183929834252,
+ "z": 0.0
+ },
+ {
+ "x": 152.05271887414517,
+ "y": -22.39688904874499,
+ "z": 0.0
+ },
+ {
+ "x": 152.05146194308296,
+ "y": -23.431594167655724,
+ "z": 0.0
+ },
+ {
+ "x": 152.05020501202074,
+ "y": -24.466299286566354,
+ "z": 0.0
+ },
+ {
+ "x": 152.0489480809585,
+ "y": -25.5010044054772,
+ "z": 0.0
+ },
+ {
+ "x": 152.04769114989628,
+ "y": -26.535709524387936,
+ "z": 0.0
+ },
+ {
+ "x": 152.04643421883407,
+ "y": -27.570414643298673,
+ "z": 0.0
+ },
+ {
+ "x": 152.04517728777185,
+ "y": -28.60511976220941,
+ "z": 0.0
+ },
+ {
+ "x": 152.04392035670963,
+ "y": -29.639824881120145,
+ "z": 0.0
+ },
+ {
+ "x": 152.04266342564742,
+ "y": -30.67453000003088,
+ "z": 0.0
+ },
+ {
+ "x": 152.0414064945852,
+ "y": -31.70923511894162,
+ "z": 0.0
+ },
+ {
+ "x": 152.040149563523,
+ "y": -32.74394023785224,
+ "z": 0.0
+ },
+ {
+ "x": 152.03889263246074,
+ "y": -33.7786453567631,
+ "z": 0.0
+ },
+ {
+ "x": 152.03763570139853,
+ "y": -34.813350475673836,
+ "z": 0.0
+ },
+ {
+ "x": 152.0363787703363,
+ "y": -35.84805559458457,
+ "z": 0.0
+ },
+ {
+ "x": 152.0351218392741,
+ "y": -36.88276071349531,
+ "z": 0.0
+ },
+ {
+ "x": 152.03386490821188,
+ "y": -37.91746583240605,
+ "z": 0.0
+ },
+ {
+ "x": 152.03260797714967,
+ "y": -38.952170951316795,
+ "z": 0.0
+ },
+ {
+ "x": 152.03135104608745,
+ "y": -39.98687607022753,
+ "z": 0.0
+ },
+ {
+ "x": 152.03009411502524,
+ "y": -41.02158118913827,
+ "z": 0.0
+ },
+ {
+ "x": 152.02883718396302,
+ "y": -42.05628630804889,
+ "z": 0.0
+ },
+ {
+ "x": 152.02758025290078,
+ "y": -43.09099142695975,
+ "z": 0.0
+ },
+ {
+ "x": 152.02632332183856,
+ "y": -44.12569654587048,
+ "z": 0.0
+ },
+ {
+ "x": 152.02506639077635,
+ "y": -45.16040166478122,
+ "z": 0.0
+ },
+ {
+ "x": 152.02380945971413,
+ "y": -46.19510678369196,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 127,
+ "map_element_id": 6,
+ "type": "road_line",
+ "geometry": [
+ {
+ "x": 156.06654216448962,
+ "y": -11.019991826129424,
+ "z": 0.0
+ },
+ {
+ "x": 156.0652852334274,
+ "y": -12.05469694504016,
+ "z": 0.0
+ },
+ {
+ "x": 156.0640283023652,
+ "y": -13.089402063950898,
+ "z": 0.0
+ },
+ {
+ "x": 156.06277137130297,
+ "y": -14.124107182861634,
+ "z": 0.0
+ },
+ {
+ "x": 156.06151444024076,
+ "y": -15.158812301772372,
+ "z": 0.0
+ },
+ {
+ "x": 156.0602575091785,
+ "y": -16.193517420683108,
+ "z": 0.0
+ },
+ {
+ "x": 156.0590005781163,
+ "y": -17.228222539593844,
+ "z": 0.0
+ },
+ {
+ "x": 156.05774364705408,
+ "y": -18.26292765850458,
+ "z": 0.0
+ },
+ {
+ "x": 156.05648671599187,
+ "y": -19.297632777415316,
+ "z": 0.0
+ },
+ {
+ "x": 156.05522978492965,
+ "y": -20.332337896326052,
+ "z": 0.0
+ },
+ {
+ "x": 156.05397285386744,
+ "y": -21.367043015236792,
+ "z": 0.0
+ },
+ {
+ "x": 156.05271592280522,
+ "y": -22.401748134147528,
+ "z": 0.0
+ },
+ {
+ "x": 156.051458991743,
+ "y": -23.436453253058264,
+ "z": 0.0
+ },
+ {
+ "x": 156.0502020606808,
+ "y": -24.471158371969004,
+ "z": 0.0
+ },
+ {
+ "x": 156.04894512961855,
+ "y": -25.50586349087974,
+ "z": 0.0
+ },
+ {
+ "x": 156.04768819855633,
+ "y": -26.540568609790476,
+ "z": 0.0
+ },
+ {
+ "x": 156.0464312674941,
+ "y": -27.575273728701212,
+ "z": 0.0
+ },
+ {
+ "x": 156.0451743364319,
+ "y": -28.60997884761195,
+ "z": 0.0
+ },
+ {
+ "x": 156.04391740536968,
+ "y": -29.644683966522685,
+ "z": 0.0
+ },
+ {
+ "x": 156.04266047430747,
+ "y": -30.67938908543342,
+ "z": 0.0
+ },
+ {
+ "x": 156.04140354324525,
+ "y": -31.71409420434416,
+ "z": 0.0
+ },
+ {
+ "x": 156.04014661218304,
+ "y": -32.74879932325489,
+ "z": 0.0
+ },
+ {
+ "x": 156.0388896811208,
+ "y": -33.783504442165636,
+ "z": 0.0
+ },
+ {
+ "x": 156.03763275005858,
+ "y": -34.81820956107637,
+ "z": 0.0
+ },
+ {
+ "x": 156.03637581899636,
+ "y": -35.85291467998711,
+ "z": 0.0
+ },
+ {
+ "x": 156.03511888793415,
+ "y": -36.887619798897845,
+ "z": 0.0
+ },
+ {
+ "x": 156.03386195687193,
+ "y": -37.92232491780859,
+ "z": 0.0
+ },
+ {
+ "x": 156.03260502580972,
+ "y": -38.95703003671933,
+ "z": 0.0
+ },
+ {
+ "x": 156.0313480947475,
+ "y": -39.99173515563007,
+ "z": 0.0
+ },
+ {
+ "x": 156.03009116368528,
+ "y": -41.0264402745408,
+ "z": 0.0
+ },
+ {
+ "x": 156.02883423262307,
+ "y": -42.06114539345154,
+ "z": 0.0
+ },
+ {
+ "x": 156.02757730156083,
+ "y": -43.09585051236228,
+ "z": 0.0
+ },
+ {
+ "x": 156.0263203704986,
+ "y": -44.13055563127302,
+ "z": 0.0
+ },
+ {
+ "x": 156.0250634394364,
+ "y": -45.165260750183755,
+ "z": 0.0
+ },
+ {
+ "x": 156.02380650837418,
+ "y": -46.1999658690945,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 128,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 158.02380503270422,
+ "y": -46.20239541179576,
+ "z": 0.0
+ },
+ {
+ "x": 158.0250619637664,
+ "y": -45.16769029288503,
+ "z": 0.0
+ },
+ {
+ "x": 158.02631889482865,
+ "y": -44.13298517397429,
+ "z": 0.0
+ },
+ {
+ "x": 158.02757582589084,
+ "y": -43.098280055063555,
+ "z": 0.0
+ },
+ {
+ "x": 158.02883275695308,
+ "y": -42.06357493615286,
+ "z": 0.0
+ },
+ {
+ "x": 158.03008968801532,
+ "y": -41.02886981724207,
+ "z": 0.0
+ },
+ {
+ "x": 158.0313466190775,
+ "y": -39.99416469833133,
+ "z": 0.0
+ },
+ {
+ "x": 158.03260355013975,
+ "y": -38.959459579420596,
+ "z": 0.0
+ },
+ {
+ "x": 158.03386048120194,
+ "y": -37.92475446050986,
+ "z": 0.0
+ },
+ {
+ "x": 158.03511741226419,
+ "y": -36.89004934159911,
+ "z": 0.0
+ },
+ {
+ "x": 158.03637434332637,
+ "y": -35.85534422268837,
+ "z": 0.0
+ },
+ {
+ "x": 158.03763127438862,
+ "y": -34.82063910377764,
+ "z": 0.0
+ },
+ {
+ "x": 158.0388882054508,
+ "y": -33.7859339848669,
+ "z": 0.0
+ },
+ {
+ "x": 158.04014513651305,
+ "y": -32.75122886595622,
+ "z": 0.0
+ },
+ {
+ "x": 158.0414020675753,
+ "y": -31.71652374704543,
+ "z": 0.0
+ },
+ {
+ "x": 158.04265899863748,
+ "y": -30.681818628134693,
+ "z": 0.0
+ },
+ {
+ "x": 158.04391592969972,
+ "y": -29.647113509223956,
+ "z": 0.0
+ },
+ {
+ "x": 158.0451728607619,
+ "y": -28.61240839031322,
+ "z": 0.0
+ },
+ {
+ "x": 158.04642979182415,
+ "y": -27.577703271402484,
+ "z": 0.0
+ },
+ {
+ "x": 158.04768672288634,
+ "y": -26.542998152491748,
+ "z": 0.0
+ },
+ {
+ "x": 158.04894365394858,
+ "y": -25.508293033581012,
+ "z": 0.0
+ },
+ {
+ "x": 158.05020058501083,
+ "y": -24.47358791467033,
+ "z": 0.0
+ },
+ {
+ "x": 158.05145751607301,
+ "y": -23.438882795759532,
+ "z": 0.0
+ },
+ {
+ "x": 158.05271444713526,
+ "y": -22.404177676848796,
+ "z": 0.0
+ },
+ {
+ "x": 158.05397137819745,
+ "y": -21.36947255793806,
+ "z": 0.0
+ },
+ {
+ "x": 158.0552283092597,
+ "y": -20.334767439027324,
+ "z": 0.0
+ },
+ {
+ "x": 158.05648524032188,
+ "y": -19.300062320116588,
+ "z": 0.0
+ },
+ {
+ "x": 158.05774217138412,
+ "y": -18.265357201205852,
+ "z": 0.0
+ },
+ {
+ "x": 158.0589991024463,
+ "y": -17.230652082295116,
+ "z": 0.0
+ },
+ {
+ "x": 158.06025603350855,
+ "y": -16.19594696338438,
+ "z": 0.0
+ },
+ {
+ "x": 158.0615129645708,
+ "y": -15.161241844473697,
+ "z": 0.0
+ },
+ {
+ "x": 158.06276989563298,
+ "y": -14.126536725562904,
+ "z": 0.0
+ },
+ {
+ "x": 158.06402682669523,
+ "y": -13.091831606652168,
+ "z": 0.0
+ },
+ {
+ "x": 158.0652837577574,
+ "y": -12.057126487741428,
+ "z": 0.0
+ },
+ {
+ "x": 158.06654068881966,
+ "y": -11.022421368830692,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 129,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 154.06654364015958,
+ "y": -11.017562283428155,
+ "z": 0.0
+ },
+ {
+ "x": 154.0652867090974,
+ "y": -12.052267402338892,
+ "z": 0.0
+ },
+ {
+ "x": 154.06402977803515,
+ "y": -13.086972521249628,
+ "z": 0.0
+ },
+ {
+ "x": 154.06277284697296,
+ "y": -14.121677640160364,
+ "z": 0.0
+ },
+ {
+ "x": 154.06151591591072,
+ "y": -15.156382759071047,
+ "z": 0.0
+ },
+ {
+ "x": 154.06025898484847,
+ "y": -16.191087877981836,
+ "z": 0.0
+ },
+ {
+ "x": 154.0590020537863,
+ "y": -17.225792996892572,
+ "z": 0.0
+ },
+ {
+ "x": 154.05774512272404,
+ "y": -18.26049811580331,
+ "z": 0.0
+ },
+ {
+ "x": 154.05648819166186,
+ "y": -19.295203234714045,
+ "z": 0.0
+ },
+ {
+ "x": 154.0552312605996,
+ "y": -20.32990835362478,
+ "z": 0.0
+ },
+ {
+ "x": 154.05397432953743,
+ "y": -21.364613472535524,
+ "z": 0.0
+ },
+ {
+ "x": 154.05271739847518,
+ "y": -22.39931859144626,
+ "z": 0.0
+ },
+ {
+ "x": 154.051460467413,
+ "y": -23.434023710356996,
+ "z": 0.0
+ },
+ {
+ "x": 154.05020353635075,
+ "y": -24.46872882926768,
+ "z": 0.0
+ },
+ {
+ "x": 154.0489466052885,
+ "y": -25.50343394817847,
+ "z": 0.0
+ },
+ {
+ "x": 154.04768967422632,
+ "y": -26.538139067089205,
+ "z": 0.0
+ },
+ {
+ "x": 154.04643274316408,
+ "y": -27.57284418599994,
+ "z": 0.0
+ },
+ {
+ "x": 154.0451758121019,
+ "y": -28.607549304910677,
+ "z": 0.0
+ },
+ {
+ "x": 154.04391888103964,
+ "y": -29.642254423821413,
+ "z": 0.0
+ },
+ {
+ "x": 154.04266194997746,
+ "y": -30.67695954273215,
+ "z": 0.0
+ },
+ {
+ "x": 154.0414050189152,
+ "y": -31.711664661642892,
+ "z": 0.0
+ },
+ {
+ "x": 154.04014808785303,
+ "y": -32.746369780553565,
+ "z": 0.0
+ },
+ {
+ "x": 154.03889115679078,
+ "y": -33.78107489946437,
+ "z": 0.0
+ },
+ {
+ "x": 154.03763422572854,
+ "y": -34.81578001837511,
+ "z": 0.0
+ },
+ {
+ "x": 154.03637729466635,
+ "y": -35.850485137285844,
+ "z": 0.0
+ },
+ {
+ "x": 154.0351203636041,
+ "y": -36.88519025619658,
+ "z": 0.0
+ },
+ {
+ "x": 154.03386343254192,
+ "y": -37.919895375107316,
+ "z": 0.0
+ },
+ {
+ "x": 154.03260650147968,
+ "y": -38.95460049401807,
+ "z": 0.0
+ },
+ {
+ "x": 154.0313495704175,
+ "y": -39.9893056129288,
+ "z": 0.0
+ },
+ {
+ "x": 154.03009263935525,
+ "y": -41.02401073183954,
+ "z": 0.0
+ },
+ {
+ "x": 154.02883570829306,
+ "y": -42.05871585075022,
+ "z": 0.0
+ },
+ {
+ "x": 154.02757877723081,
+ "y": -43.09342096966101,
+ "z": 0.0
+ },
+ {
+ "x": 154.02632184616857,
+ "y": -44.12812608857175,
+ "z": 0.0
+ },
+ {
+ "x": 154.02506491510638,
+ "y": -45.16283120748248,
+ "z": 0.0
+ },
+ {
+ "x": 154.02380798404414,
+ "y": -46.197536326393234,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 132,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 325.6289421841928,
+ "y": -1.9886780038783365,
+ "z": 0.0
+ },
+ {
+ "x": 326.6656086716041,
+ "y": -1.9892287191981524,
+ "z": 0.0
+ },
+ {
+ "x": 327.7022751590154,
+ "y": -1.9897794345179682,
+ "z": 0.0
+ },
+ {
+ "x": 328.7389416464267,
+ "y": -1.9903301498377841,
+ "z": 0.0
+ },
+ {
+ "x": 329.6481209673265,
+ "y": -2.051642925567623,
+ "z": 0.0
+ },
+ {
+ "x": 330.4498985439327,
+ "y": -2.203155677126415,
+ "z": 0.0
+ },
+ {
+ "x": 331.1978530249937,
+ "y": -2.4472767584409145,
+ "z": 0.0
+ },
+ {
+ "x": 331.91071142888325,
+ "y": -2.782292263691531,
+ "z": 0.0
+ },
+ {
+ "x": 332.5781554916712,
+ "y": -3.2037777983596696,
+ "z": 0.0
+ },
+ {
+ "x": 333.1259408932245,
+ "y": -3.691726022653432,
+ "z": 0.0
+ },
+ {
+ "x": 333.6427405093016,
+ "y": -4.274703225647427,
+ "z": 0.0
+ },
+ {
+ "x": 334.0803469879803,
+ "y": -4.918202194072655,
+ "z": 0.0
+ },
+ {
+ "x": 334.43130677011334,
+ "y": -5.611689089596034,
+ "z": 0.0
+ },
+ {
+ "x": 334.6907444176936,
+ "y": -6.345222294572525,
+ "z": 0.0
+ },
+ {
+ "x": 334.85430406670866,
+ "y": -7.107636665231244,
+ "z": 0.0
+ },
+ {
+ "x": 334.8887622144692,
+ "y": -7.838413889011973,
+ "z": 0.0
+ },
+ {
+ "x": 334.89479441876426,
+ "y": -8.739828728813038,
+ "z": 0.0
+ },
+ {
+ "x": 334.8940308483802,
+ "y": -9.751811845644003,
+ "z": 0.0
+ },
+ {
+ "x": 334.8934046904095,
+ "y": -10.788478290232261,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 135,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 338.8934037724806,
+ "y": -10.791206034385668,
+ "z": 0.0
+ },
+ {
+ "x": 338.89405960289776,
+ "y": -9.705413920194768,
+ "z": 0.0
+ },
+ {
+ "x": 338.8947154333149,
+ "y": -8.619621806003762,
+ "z": 0.0
+ },
+ {
+ "x": 338.85649157978924,
+ "y": -7.465933222116847,
+ "z": 0.0
+ },
+ {
+ "x": 338.71233106740794,
+ "y": -6.217633808411568,
+ "z": 0.0
+ },
+ {
+ "x": 338.3765877565555,
+ "y": -4.891298316001286,
+ "z": 0.0
+ },
+ {
+ "x": 337.798941246716,
+ "y": -3.5812481318554616,
+ "z": 0.0
+ },
+ {
+ "x": 337.0732723618795,
+ "y": -2.428622935502248,
+ "z": 0.0
+ },
+ {
+ "x": 336.19506370583065,
+ "y": -1.3895071817883942,
+ "z": 0.0
+ },
+ {
+ "x": 335.1955535115176,
+ "y": -0.4858140473350383,
+ "z": 0.0
+ },
+ {
+ "x": 334.1183015498897,
+ "y": 0.27518596346270763,
+ "z": 0.0
+ },
+ {
+ "x": 332.9558134017866,
+ "y": 0.9052869162020982,
+ "z": 0.0
+ },
+ {
+ "x": 331.70985610521825,
+ "y": 1.390851007829021,
+ "z": 0.0
+ },
+ {
+ "x": 330.4587621046933,
+ "y": 1.7266710094051807,
+ "z": 0.0
+ },
+ {
+ "x": 329.17953238403936,
+ "y": 1.928092642384523,
+ "z": 0.0
+ },
+ {
+ "x": 327.9131502261558,
+ "y": 2.007072758973851,
+ "z": 0.0
+ },
+ {
+ "x": 326.71719543516656,
+ "y": 2.0107444404429113,
+ "z": 0.0
+ },
+ {
+ "x": 325.6314032761233,
+ "y": 2.0113212531241174,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 136,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 348.23212641515147,
+ "y": 3.9993152009727924,
+ "z": 0.0
+ },
+ {
+ "x": 347.2048538328333,
+ "y": 3.9998609259051396,
+ "z": 0.0
+ },
+ {
+ "x": 346.1775812505151,
+ "y": 4.000406650837487,
+ "z": 0.0
+ },
+ {
+ "x": 345.15030866819694,
+ "y": 4.0009523757698355,
+ "z": 0.0
+ },
+ {
+ "x": 344.12303608587877,
+ "y": 4.001498100702182,
+ "z": 0.0
+ },
+ {
+ "x": 343.0957635035606,
+ "y": 4.002043825634529,
+ "z": 0.0
+ },
+ {
+ "x": 342.0684909212424,
+ "y": 4.002589550566876,
+ "z": 0.0
+ },
+ {
+ "x": 341.04121833892424,
+ "y": 4.003135275499223,
+ "z": 0.0
+ },
+ {
+ "x": 340.01394575660606,
+ "y": 4.00368100043157,
+ "z": 0.0
+ },
+ {
+ "x": 338.9866731742879,
+ "y": 4.0042267253639166,
+ "z": 0.0
+ },
+ {
+ "x": 337.9594005919697,
+ "y": 4.004772450296263,
+ "z": 0.0
+ },
+ {
+ "x": 336.9321280096516,
+ "y": 4.005318175228612,
+ "z": 0.0
+ },
+ {
+ "x": 335.9048554273334,
+ "y": 4.005863900160959,
+ "z": 0.0
+ },
+ {
+ "x": 334.87758284501524,
+ "y": 4.006409625093306,
+ "z": 0.0
+ },
+ {
+ "x": 333.85031026269706,
+ "y": 4.0069553500256525,
+ "z": 0.0
+ },
+ {
+ "x": 332.8230376803789,
+ "y": 4.007501074957999,
+ "z": 0.0
+ },
+ {
+ "x": 331.7957650980607,
+ "y": 4.008046799890346,
+ "z": 0.0
+ },
+ {
+ "x": 330.76849251574254,
+ "y": 4.008592524822693,
+ "z": 0.0
+ },
+ {
+ "x": 329.74121993342436,
+ "y": 4.00913824975504,
+ "z": 0.0
+ },
+ {
+ "x": 328.7139473511062,
+ "y": 4.009683974687387,
+ "z": 0.0
+ },
+ {
+ "x": 327.686674768788,
+ "y": 4.010229699619733,
+ "z": 0.0
+ },
+ {
+ "x": 326.65940218646983,
+ "y": 4.0107754245520795,
+ "z": 0.0
+ },
+ {
+ "x": 325.63212960415166,
+ "y": 4.011321149484425,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 138,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 348.23106394183185,
+ "y": 1.9993154831852011,
+ "z": 0.0
+ },
+ {
+ "x": 347.2037913595137,
+ "y": 1.9998612081175484,
+ "z": 0.0
+ },
+ {
+ "x": 346.1765187771955,
+ "y": 2.0004069330498955,
+ "z": 0.0
+ },
+ {
+ "x": 345.1492461948773,
+ "y": 2.0009526579822445,
+ "z": 0.0
+ },
+ {
+ "x": 344.12197361255915,
+ "y": 2.0014983829145914,
+ "z": 0.0
+ },
+ {
+ "x": 343.09470103024097,
+ "y": 2.002044107846938,
+ "z": 0.0
+ },
+ {
+ "x": 342.0674284479228,
+ "y": 2.002589832779285,
+ "z": 0.0
+ },
+ {
+ "x": 341.0401558656046,
+ "y": 2.003135557711632,
+ "z": 0.0
+ },
+ {
+ "x": 340.01288328328644,
+ "y": 2.0036812826439783,
+ "z": 0.0
+ },
+ {
+ "x": 338.98561070096827,
+ "y": 2.004227007576325,
+ "z": 0.0
+ },
+ {
+ "x": 337.9583381186501,
+ "y": 2.004772732508672,
+ "z": 0.0
+ },
+ {
+ "x": 336.93106553633197,
+ "y": 2.005318457441021,
+ "z": 0.0
+ },
+ {
+ "x": 335.9037929540138,
+ "y": 2.0058641823733674,
+ "z": 0.0
+ },
+ {
+ "x": 334.8765203716956,
+ "y": 2.0064099073057142,
+ "z": 0.0
+ },
+ {
+ "x": 333.84924778937744,
+ "y": 2.006955632238061,
+ "z": 0.0
+ },
+ {
+ "x": 332.82197520705927,
+ "y": 2.007501357170408,
+ "z": 0.0
+ },
+ {
+ "x": 331.7947026247411,
+ "y": 2.0080470821027547,
+ "z": 0.0
+ },
+ {
+ "x": 330.7674300424229,
+ "y": 2.0085928070351016,
+ "z": 0.0
+ },
+ {
+ "x": 329.74015746010474,
+ "y": 2.0091385319674484,
+ "z": 0.0
+ },
+ {
+ "x": 328.71288487778656,
+ "y": 2.0096842568997952,
+ "z": 0.0
+ },
+ {
+ "x": 327.6856122954684,
+ "y": 2.0102299818321416,
+ "z": 0.0
+ },
+ {
+ "x": 326.6583397131502,
+ "y": 2.010775706764488,
+ "z": 0.0
+ },
+ {
+ "x": 325.63106713083204,
+ "y": 2.0113214316968344,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 141,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 325.6289421841928,
+ "y": -1.9886780038783478,
+ "z": 0.0
+ },
+ {
+ "x": 326.65621476651097,
+ "y": -1.9892237288106946,
+ "z": 0.0
+ },
+ {
+ "x": 327.68348734882915,
+ "y": -1.9897694537430406,
+ "z": 0.0
+ },
+ {
+ "x": 328.7107599311473,
+ "y": -1.9903151786753874,
+ "z": 0.0
+ },
+ {
+ "x": 329.7380325134655,
+ "y": -1.9908609036077343,
+ "z": 0.0
+ },
+ {
+ "x": 330.7653050957837,
+ "y": -1.991406628540081,
+ "z": 0.0
+ },
+ {
+ "x": 331.79257767810185,
+ "y": -1.991952353472428,
+ "z": 0.0
+ },
+ {
+ "x": 332.81985026042,
+ "y": -1.9924980784047743,
+ "z": 0.0
+ },
+ {
+ "x": 333.8471228427382,
+ "y": -1.9930438033371212,
+ "z": 0.0
+ },
+ {
+ "x": 334.8743954250564,
+ "y": -1.993589528269468,
+ "z": 0.0
+ },
+ {
+ "x": 335.90166800737455,
+ "y": -1.9941352532018148,
+ "z": 0.0
+ },
+ {
+ "x": 336.92894058969273,
+ "y": -1.9946809781341617,
+ "z": 0.0
+ },
+ {
+ "x": 337.95621317201085,
+ "y": -1.9952267030665103,
+ "z": 0.0
+ },
+ {
+ "x": 338.983485754329,
+ "y": -1.9957724279988571,
+ "z": 0.0
+ },
+ {
+ "x": 340.0107583366472,
+ "y": -1.996318152931204,
+ "z": 0.0
+ },
+ {
+ "x": 341.0380309189654,
+ "y": -1.9968638778635508,
+ "z": 0.0
+ },
+ {
+ "x": 342.06530350128355,
+ "y": -1.9974096027958976,
+ "z": 0.0
+ },
+ {
+ "x": 343.0925760836017,
+ "y": -1.9979553277282445,
+ "z": 0.0
+ },
+ {
+ "x": 344.1198486659199,
+ "y": -1.9985010526605913,
+ "z": 0.0
+ },
+ {
+ "x": 345.1471212482381,
+ "y": -1.9990467775929377,
+ "z": 0.0
+ },
+ {
+ "x": 346.17439383055626,
+ "y": -1.9995925025252872,
+ "z": 0.0
+ },
+ {
+ "x": 347.20166641287443,
+ "y": -2.000138227457634,
+ "z": 0.0
+ },
+ {
+ "x": 348.2289389951926,
+ "y": -2.000683952389981,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 144,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 348.23106394183185,
+ "y": 1.9993154831852011,
+ "z": 0.0
+ },
+ {
+ "x": 347.1918410730398,
+ "y": 1.9998675565487212,
+ "z": 0.0
+ },
+ {
+ "x": 346.15261820424786,
+ "y": 2.000419629912234,
+ "z": 0.0
+ },
+ {
+ "x": 344.98014390717617,
+ "y": 1.9965987241811827,
+ "z": 0.0
+ },
+ {
+ "x": 343.7230281627808,
+ "y": 1.9009683922471656,
+ "z": 0.0
+ },
+ {
+ "x": 342.47012348855634,
+ "y": 1.6620026224745803,
+ "z": 0.0
+ },
+ {
+ "x": 341.2550498957666,
+ "y": 1.2752840500252611,
+ "z": 0.0
+ },
+ {
+ "x": 340.09415370705904,
+ "y": 0.7459549510153185,
+ "z": 0.0
+ },
+ {
+ "x": 338.97008553424934,
+ "y": 0.0547038951790324,
+ "z": 0.0
+ },
+ {
+ "x": 337.9618192359494,
+ "y": -0.7794300190888428,
+ "z": 0.0
+ },
+ {
+ "x": 337.0809376728373,
+ "y": -1.7338534646852155,
+ "z": 0.0
+ },
+ {
+ "x": 336.3322477308536,
+ "y": -2.7953125992055945,
+ "z": 0.0
+ },
+ {
+ "x": 335.729628727284,
+ "y": -3.9456065362702066,
+ "z": 0.0
+ },
+ {
+ "x": 335.2830505480407,
+ "y": -5.165868569711307,
+ "z": 0.0
+ },
+ {
+ "x": 334.9969996904255,
+ "y": -6.47215966779638,
+ "z": 0.0
+ },
+ {
+ "x": 334.9048119411275,
+ "y": -7.653043324408491,
+ "z": 0.0
+ },
+ {
+ "x": 334.89466009567434,
+ "y": -8.710030720693538,
+ "z": 0.0
+ },
+ {
+ "x": 334.89403239362105,
+ "y": -9.749253546557007,
+ "z": 0.0
+ },
+ {
+ "x": 334.89340469156787,
+ "y": -10.788476372420362,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 147,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 338.8934037724806,
+ "y": -10.791206034385581,
+ "z": 0.0
+ },
+ {
+ "x": 338.8940361484256,
+ "y": -9.7442451184274,
+ "z": 0.0
+ },
+ {
+ "x": 338.89466852437056,
+ "y": -8.697284202469334,
+ "z": 0.0
+ },
+ {
+ "x": 338.89530090031553,
+ "y": -7.650323286511048,
+ "z": 0.0
+ },
+ {
+ "x": 338.9559455676802,
+ "y": -6.729071264869208,
+ "z": 0.0
+ },
+ {
+ "x": 339.0867936424396,
+ "y": -5.853662244728881,
+ "z": 0.0
+ },
+ {
+ "x": 339.34005866146424,
+ "y": -5.243106847878202,
+ "z": 0.0
+ },
+ {
+ "x": 339.70660160297115,
+ "y": -4.618405976128673,
+ "z": 0.0
+ },
+ {
+ "x": 340.17828589458026,
+ "y": -3.994347784720262,
+ "z": 0.0
+ },
+ {
+ "x": 340.7131255868176,
+ "y": -3.4921935668140875,
+ "z": 0.0
+ },
+ {
+ "x": 341.31833084755374,
+ "y": -3.081911018620925,
+ "z": 0.0
+ },
+ {
+ "x": 342.03155256917285,
+ "y": -2.6966663594310103,
+ "z": 0.0
+ },
+ {
+ "x": 342.7922949514217,
+ "y": -2.3886302465492624,
+ "z": 0.0
+ },
+ {
+ "x": 343.58289861139315,
+ "y": -2.167658509517684,
+ "z": 0.0
+ },
+ {
+ "x": 344.39393511088724,
+ "y": -2.036496984348239,
+ "z": 0.0
+ },
+ {
+ "x": 345.2195099685739,
+ "y": -1.9947606781298046,
+ "z": 0.0
+ },
+ {
+ "x": 346.13501707677966,
+ "y": -1.9995715841471782,
+ "z": 0.0
+ },
+ {
+ "x": 347.1819780359861,
+ "y": -2.000127768268577,
+ "z": 0.0
+ },
+ {
+ "x": 348.2289389951926,
+ "y": -2.000683952389981,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 150,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 144.95979698585384,
+ "y": -1.9544698149348096,
+ "z": 0.0
+ },
+ {
+ "x": 146.01070607077742,
+ "y": -1.9545819776888724,
+ "z": 0.0
+ },
+ {
+ "x": 147.061615155701,
+ "y": -1.9546941404429357,
+ "z": 0.0
+ },
+ {
+ "x": 148.11252424062454,
+ "y": -1.9548063031969989,
+ "z": 0.0
+ },
+ {
+ "x": 149.1634333255481,
+ "y": -1.9549184659510621,
+ "z": 0.0
+ },
+ {
+ "x": 150.2143424104717,
+ "y": -1.9550306287051253,
+ "z": 0.0
+ },
+ {
+ "x": 151.26525149539526,
+ "y": -1.9551427914591881,
+ "z": 0.0
+ },
+ {
+ "x": 152.3161605803188,
+ "y": -1.9552549542132514,
+ "z": 0.0
+ },
+ {
+ "x": 153.36706966524238,
+ "y": -1.9553671169673146,
+ "z": 0.0
+ },
+ {
+ "x": 154.41797875016596,
+ "y": -1.9554792797213778,
+ "z": 0.0
+ },
+ {
+ "x": 155.46888783508953,
+ "y": -1.955591442475441,
+ "z": 0.0
+ },
+ {
+ "x": 156.5197969200131,
+ "y": -1.9557036052295038,
+ "z": 0.0
+ },
+ {
+ "x": 157.57070600493665,
+ "y": -1.955815767983567,
+ "z": 0.0
+ },
+ {
+ "x": 158.62161508986023,
+ "y": -1.9559279307376303,
+ "z": 0.0
+ },
+ {
+ "x": 159.6725241747838,
+ "y": -1.9560400934916935,
+ "z": 0.0
+ },
+ {
+ "x": 160.72343325970738,
+ "y": -1.9561522562457565,
+ "z": 0.0
+ },
+ {
+ "x": 161.77434234463095,
+ "y": -1.9562644189998195,
+ "z": 0.0
+ },
+ {
+ "x": 162.8252514295545,
+ "y": -1.9563765817538827,
+ "z": 0.0
+ },
+ {
+ "x": 163.87616051447807,
+ "y": -1.956488744507946,
+ "z": 0.0
+ },
+ {
+ "x": 164.92706959940165,
+ "y": -1.9566009072620092,
+ "z": 0.0
+ },
+ {
+ "x": 165.9779786843252,
+ "y": -1.956713070016072,
+ "z": 0.0
+ },
+ {
+ "x": 167.02888776924877,
+ "y": -1.9568252327701352,
+ "z": 0.0
+ },
+ {
+ "x": 168.07979685417234,
+ "y": -1.9569373955241984,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 151,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 168.08043722975782,
+ "y": 4.043062570302394,
+ "z": 0.0
+ },
+ {
+ "x": 167.02952814483425,
+ "y": 4.043174733056457,
+ "z": 0.0
+ },
+ {
+ "x": 165.97861905991067,
+ "y": 4.04328689581052,
+ "z": 0.0
+ },
+ {
+ "x": 164.92770997498712,
+ "y": 4.043399058564583,
+ "z": 0.0
+ },
+ {
+ "x": 163.87680089006355,
+ "y": 4.043511221318647,
+ "z": 0.0
+ },
+ {
+ "x": 162.82589180513997,
+ "y": 4.04362338407271,
+ "z": 0.0
+ },
+ {
+ "x": 161.77498272021643,
+ "y": 4.043735546826773,
+ "z": 0.0
+ },
+ {
+ "x": 160.72407363529285,
+ "y": 4.043847709580836,
+ "z": 0.0
+ },
+ {
+ "x": 159.67316455036928,
+ "y": 4.0439598723348995,
+ "z": 0.0
+ },
+ {
+ "x": 158.6222554654457,
+ "y": 4.044072035088963,
+ "z": 0.0
+ },
+ {
+ "x": 157.57134638052213,
+ "y": 4.044184197843025,
+ "z": 0.0
+ },
+ {
+ "x": 156.52043729559858,
+ "y": 4.044296360597088,
+ "z": 0.0
+ },
+ {
+ "x": 155.469528210675,
+ "y": 4.0444085233511515,
+ "z": 0.0
+ },
+ {
+ "x": 154.41861912575143,
+ "y": 4.044520686105215,
+ "z": 0.0
+ },
+ {
+ "x": 153.36771004082786,
+ "y": 4.044632848859278,
+ "z": 0.0
+ },
+ {
+ "x": 152.31680095590428,
+ "y": 4.044745011613341,
+ "z": 0.0
+ },
+ {
+ "x": 151.26589187098074,
+ "y": 4.044857174367404,
+ "z": 0.0
+ },
+ {
+ "x": 150.21498278605716,
+ "y": 4.044969337121468,
+ "z": 0.0
+ },
+ {
+ "x": 149.1640737011336,
+ "y": 4.045081499875531,
+ "z": 0.0
+ },
+ {
+ "x": 148.11316461621,
+ "y": 4.045193662629594,
+ "z": 0.0
+ },
+ {
+ "x": 147.06225553128647,
+ "y": 4.0453058253836565,
+ "z": 0.0
+ },
+ {
+ "x": 146.0113464463629,
+ "y": 4.04541798813772,
+ "z": 0.0
+ },
+ {
+ "x": 144.96043736143932,
+ "y": 4.045530150891783,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 153,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 168.08022377122933,
+ "y": 2.0430625816935297,
+ "z": 0.0
+ },
+ {
+ "x": 167.02931468630575,
+ "y": 2.043174744447593,
+ "z": 0.0
+ },
+ {
+ "x": 165.97840560138218,
+ "y": 2.043286907201656,
+ "z": 0.0
+ },
+ {
+ "x": 164.92749651645863,
+ "y": 2.0433990699557194,
+ "z": 0.0
+ },
+ {
+ "x": 163.87658743153506,
+ "y": 2.0435112327097826,
+ "z": 0.0
+ },
+ {
+ "x": 162.82567834661148,
+ "y": 2.0436233954638454,
+ "z": 0.0
+ },
+ {
+ "x": 161.77476926168794,
+ "y": 2.0437355582179086,
+ "z": 0.0
+ },
+ {
+ "x": 160.72386017676436,
+ "y": 2.043847720971972,
+ "z": 0.0
+ },
+ {
+ "x": 159.6729510918408,
+ "y": 2.043959883726035,
+ "z": 0.0
+ },
+ {
+ "x": 158.6220420069172,
+ "y": 2.0440720464800983,
+ "z": 0.0
+ },
+ {
+ "x": 157.57113292199364,
+ "y": 2.044184209234161,
+ "z": 0.0
+ },
+ {
+ "x": 156.5202238370701,
+ "y": 2.0442963719882243,
+ "z": 0.0
+ },
+ {
+ "x": 155.46931475214652,
+ "y": 2.0444085347422876,
+ "z": 0.0
+ },
+ {
+ "x": 154.41840566722294,
+ "y": 2.044520697496351,
+ "z": 0.0
+ },
+ {
+ "x": 153.36749658229937,
+ "y": 2.044632860250414,
+ "z": 0.0
+ },
+ {
+ "x": 152.3165874973758,
+ "y": 2.044745023004477,
+ "z": 0.0
+ },
+ {
+ "x": 151.26567841245225,
+ "y": 2.04485718575854,
+ "z": 0.0
+ },
+ {
+ "x": 150.21476932752867,
+ "y": 2.0449693485126033,
+ "z": 0.0
+ },
+ {
+ "x": 149.1638602426051,
+ "y": 2.0450815112666665,
+ "z": 0.0
+ },
+ {
+ "x": 148.11295115768152,
+ "y": 2.0451936740207297,
+ "z": 0.0
+ },
+ {
+ "x": 147.06204207275798,
+ "y": 2.0453058367747925,
+ "z": 0.0
+ },
+ {
+ "x": 146.0111329878344,
+ "y": 2.0454179995288557,
+ "z": 0.0
+ },
+ {
+ "x": 144.96022390291083,
+ "y": 2.045530162282919,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 156,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 168.08022377122933,
+ "y": 2.0430625816935297,
+ "z": 0.0
+ },
+ {
+ "x": 167.03215555648666,
+ "y": 2.043174441243607,
+ "z": 0.0
+ },
+ {
+ "x": 165.98408734174396,
+ "y": 2.0432863007936906,
+ "z": 0.0
+ },
+ {
+ "x": 164.93601912700126,
+ "y": 2.043398160343768,
+ "z": 0.0
+ },
+ {
+ "x": 163.8132961915106,
+ "y": 2.0421241757558866,
+ "z": 0.0
+ },
+ {
+ "x": 162.63554538749878,
+ "y": 1.9938964723664097,
+ "z": 0.0
+ },
+ {
+ "x": 161.18924212443812,
+ "y": 1.8012417543674824,
+ "z": 0.0
+ },
+ {
+ "x": 159.94561456457726,
+ "y": 1.3847026814330234,
+ "z": 0.0
+ },
+ {
+ "x": 158.77286559370378,
+ "y": 0.8105879617646823,
+ "z": 0.0
+ },
+ {
+ "x": 157.65797728841068,
+ "y": 0.0634867955019085,
+ "z": 0.0
+ },
+ {
+ "x": 156.6259186782699,
+ "y": -0.8908683303096292,
+ "z": 0.0
+ },
+ {
+ "x": 155.84478339365012,
+ "y": -1.903125565677636,
+ "z": 0.0
+ },
+ {
+ "x": 155.18869595419164,
+ "y": -2.9949613928402687,
+ "z": 0.0
+ },
+ {
+ "x": 154.63742025976387,
+ "y": -4.235427124345479,
+ "z": 0.0
+ },
+ {
+ "x": 154.28840923354022,
+ "y": -5.5261527234395516,
+ "z": 0.0
+ },
+ {
+ "x": 154.13300640008842,
+ "y": -6.7169851437406916,
+ "z": 0.0
+ },
+ {
+ "x": 154.07036312990368,
+ "y": -7.8733599411963,
+ "z": 0.0
+ },
+ {
+ "x": 154.06908996665567,
+ "y": -8.921427388606872,
+ "z": 0.0
+ },
+ {
+ "x": 154.06781680340765,
+ "y": -9.9694948360175,
+ "z": 0.0
+ },
+ {
+ "x": 154.06654364015958,
+ "y": -11.017562283428129,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 159,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 158.06654068881966,
+ "y": -11.022421368830695,
+ "z": 0.0
+ },
+ {
+ "x": 158.0678149424262,
+ "y": -9.973456338759608,
+ "z": 0.0
+ },
+ {
+ "x": 158.06908919603273,
+ "y": -8.924491308688518,
+ "z": 0.0
+ },
+ {
+ "x": 158.07036344963927,
+ "y": -7.87552627861743,
+ "z": 0.0
+ },
+ {
+ "x": 158.12809867190316,
+ "y": -6.943618912423863,
+ "z": 0.0
+ },
+ {
+ "x": 158.25659403393146,
+ "y": -6.067036922589827,
+ "z": 0.0
+ },
+ {
+ "x": 158.48513964793386,
+ "y": -5.323581087143358,
+ "z": 0.0
+ },
+ {
+ "x": 158.8149636244475,
+ "y": -4.673993089845661,
+ "z": 0.0
+ },
+ {
+ "x": 159.2522144804559,
+ "y": -3.9833813152728115,
+ "z": 0.0
+ },
+ {
+ "x": 159.76566167994648,
+ "y": -3.3493286804224094,
+ "z": 0.0
+ },
+ {
+ "x": 160.31090892520865,
+ "y": -2.8948529552645708,
+ "z": 0.0
+ },
+ {
+ "x": 160.9297561931375,
+ "y": -2.5283305588664016,
+ "z": 0.0
+ },
+ {
+ "x": 161.63741261604633,
+ "y": -2.2190824547515597,
+ "z": 0.0
+ },
+ {
+ "x": 162.38408928138767,
+ "y": -2.0077331023102722,
+ "z": 0.0
+ },
+ {
+ "x": 163.04644832238787,
+ "y": -1.9759052621068007,
+ "z": 0.0
+ },
+ {
+ "x": 163.94224135337973,
+ "y": -1.9556456724994467,
+ "z": 0.0
+ },
+ {
+ "x": 164.93289945999143,
+ "y": -1.956601529478737,
+ "z": 0.0
+ },
+ {
+ "x": 165.98186525805173,
+ "y": -1.956713484827222,
+ "z": 0.0
+ },
+ {
+ "x": 167.03083105611205,
+ "y": -1.9568254401757135,
+ "z": 0.0
+ },
+ {
+ "x": 168.07979685417234,
+ "y": -1.9569373955241982,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 162,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 144.95979698426007,
+ "y": -1.9544698149346282,
+ "z": 0.0
+ },
+ {
+ "x": 146.0214304459259,
+ "y": -1.9545831222935375,
+ "z": 0.0
+ },
+ {
+ "x": 147.08306390759168,
+ "y": -1.9546964296524467,
+ "z": 0.0
+ },
+ {
+ "x": 148.1446973692575,
+ "y": -1.9548097370113564,
+ "z": 0.0
+ },
+ {
+ "x": 149.13221486047848,
+ "y": -1.9919571126258255,
+ "z": 0.0
+ },
+ {
+ "x": 150.0485746823283,
+ "y": -2.0938982287508408,
+ "z": 0.0
+ },
+ {
+ "x": 150.72698021097798,
+ "y": -2.3205231525512633,
+ "z": 0.0
+ },
+ {
+ "x": 151.4330047742707,
+ "y": -2.655849370064583,
+ "z": 0.0
+ },
+ {
+ "x": 152.11319400930614,
+ "y": -3.086961486560563,
+ "z": 0.0
+ },
+ {
+ "x": 152.7333467146321,
+ "y": -3.601554210063868,
+ "z": 0.0
+ },
+ {
+ "x": 153.17817257834116,
+ "y": -4.154904237046136,
+ "z": 0.0
+ },
+ {
+ "x": 153.54286408029446,
+ "y": -4.790277305034675,
+ "z": 0.0
+ },
+ {
+ "x": 153.83492186558323,
+ "y": -5.5043381450725715,
+ "z": 0.0
+ },
+ {
+ "x": 154.02291814670855,
+ "y": -6.254922652969147,
+ "z": 0.0
+ },
+ {
+ "x": 154.0679879528459,
+ "y": -6.977786630399157,
+ "z": 0.0
+ },
+ {
+ "x": 154.07055697560375,
+ "y": -7.8592499339717055,
+ "z": 0.0
+ },
+ {
+ "x": 154.0691229240025,
+ "y": -8.894296914623997,
+ "z": 0.0
+ },
+ {
+ "x": 154.06783328208104,
+ "y": -9.95592959902604,
+ "z": 0.0
+ },
+ {
+ "x": 154.06654364015958,
+ "y": -11.017562283428138,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 165,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 158.06654068881966,
+ "y": -11.022421368830686,
+ "z": 0.0
+ },
+ {
+ "x": 158.06781259403397,
+ "y": -9.975389534245748,
+ "z": 0.0
+ },
+ {
+ "x": 158.06908449924828,
+ "y": -8.928357699660815,
+ "z": 0.0
+ },
+ {
+ "x": 158.0703564044626,
+ "y": -7.88132586507588,
+ "z": 0.0
+ },
+ {
+ "x": 158.0176154167112,
+ "y": -6.737594738473985,
+ "z": 0.0
+ },
+ {
+ "x": 157.83319850763831,
+ "y": -5.492078756666,
+ "z": 0.0
+ },
+ {
+ "x": 157.4608111181561,
+ "y": -4.216004162987613,
+ "z": 0.0
+ },
+ {
+ "x": 156.909643893399,
+ "y": -3.004761201228715,
+ "z": 0.0
+ },
+ {
+ "x": 156.18182551246588,
+ "y": -1.8783912339856603,
+ "z": 0.0
+ },
+ {
+ "x": 155.26022549620535,
+ "y": -0.8584486238655522,
+ "z": 0.0
+ },
+ {
+ "x": 154.2540718633539,
+ "y": -0.017169875023373082,
+ "z": 0.0
+ },
+ {
+ "x": 153.17022787065991,
+ "y": 0.6805135933196025,
+ "z": 0.0
+ },
+ {
+ "x": 152.0142007369439,
+ "y": 1.2406282699886293,
+ "z": 0.0
+ },
+ {
+ "x": 150.79886301081518,
+ "y": 1.657965068421548,
+ "z": 0.0
+ },
+ {
+ "x": 149.54106696154486,
+ "y": 1.926489243790637,
+ "z": 0.0
+ },
+ {
+ "x": 148.24689406538863,
+ "y": 2.0368968292090828,
+ "z": 0.0
+ },
+ {
+ "x": 147.06031264460555,
+ "y": 2.0452978532285533,
+ "z": 0.0
+ },
+ {
+ "x": 146.007564063204,
+ "y": 2.045418380437568,
+ "z": 0.0
+ },
+ {
+ "x": 144.96053146204522,
+ "y": 2.0455301294573687,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 168,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 101.62105848392994,
+ "y": -326.5890537873581,
+ "z": 0.0
+ },
+ {
+ "x": 100.57439196744656,
+ "y": -326.5884930880701,
+ "z": 0.0
+ },
+ {
+ "x": 99.52772545096343,
+ "y": -326.58793238878195,
+ "z": 0.0
+ },
+ {
+ "x": 98.48105893447985,
+ "y": -326.5873716894939,
+ "z": 0.0
+ },
+ {
+ "x": 97.43439241799669,
+ "y": -326.5868109902058,
+ "z": 0.0
+ },
+ {
+ "x": 96.38772590151311,
+ "y": -326.58625029091775,
+ "z": 0.0
+ },
+ {
+ "x": 95.34105938502998,
+ "y": -326.5856895916296,
+ "z": 0.0
+ },
+ {
+ "x": 94.2943928685465,
+ "y": -326.5851288923415,
+ "z": 0.0
+ },
+ {
+ "x": 93.24772635206314,
+ "y": -326.5845681930534,
+ "z": 0.0
+ },
+ {
+ "x": 92.20105983557977,
+ "y": -326.58400749376534,
+ "z": 0.0
+ },
+ {
+ "x": 91.15439331909641,
+ "y": -326.58344679447725,
+ "z": 0.0
+ },
+ {
+ "x": 90.10772680261304,
+ "y": -326.58288609518917,
+ "z": 0.0
+ },
+ {
+ "x": 89.06106028612967,
+ "y": -326.5823253959011,
+ "z": 0.0
+ },
+ {
+ "x": 88.01439376964632,
+ "y": -326.581764696613,
+ "z": 0.0
+ },
+ {
+ "x": 86.96772725316295,
+ "y": -326.5812039973249,
+ "z": 0.0
+ },
+ {
+ "x": 85.92106073667959,
+ "y": -326.5806432980368,
+ "z": 0.0
+ },
+ {
+ "x": 84.87439422019622,
+ "y": -326.58008259874873,
+ "z": 0.0
+ },
+ {
+ "x": 83.82772770371285,
+ "y": -326.57952189946064,
+ "z": 0.0
+ },
+ {
+ "x": 82.7810611872295,
+ "y": -326.57896120017256,
+ "z": 0.0
+ },
+ {
+ "x": 81.73439467074613,
+ "y": -326.57840050088447,
+ "z": 0.0
+ },
+ {
+ "x": 80.68772815426277,
+ "y": -326.5778398015964,
+ "z": 0.0
+ },
+ {
+ "x": 79.6410616377794,
+ "y": -326.5772791023083,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 169,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 79.63784743803878,
+ "y": -332.57727824138493,
+ "z": 0.0
+ },
+ {
+ "x": 80.68451395452215,
+ "y": -332.577838940673,
+ "z": 0.0
+ },
+ {
+ "x": 81.7311804710055,
+ "y": -332.5783996399611,
+ "z": 0.0
+ },
+ {
+ "x": 82.77784698748887,
+ "y": -332.5789603392492,
+ "z": 0.0
+ },
+ {
+ "x": 83.82451350397223,
+ "y": -332.5795210385373,
+ "z": 0.0
+ },
+ {
+ "x": 84.8711800204556,
+ "y": -332.58008173782537,
+ "z": 0.0
+ },
+ {
+ "x": 85.91784653693897,
+ "y": -332.58064243711345,
+ "z": 0.0
+ },
+ {
+ "x": 86.96451305342232,
+ "y": -332.58120313640154,
+ "z": 0.0
+ },
+ {
+ "x": 88.01117956990569,
+ "y": -332.5817638356896,
+ "z": 0.0
+ },
+ {
+ "x": 89.05784608638905,
+ "y": -332.5823245349777,
+ "z": 0.0
+ },
+ {
+ "x": 90.10451260287242,
+ "y": -332.5828852342658,
+ "z": 0.0
+ },
+ {
+ "x": 91.15117911935579,
+ "y": -332.5834459335539,
+ "z": 0.0
+ },
+ {
+ "x": 92.19784563583914,
+ "y": -332.584006632842,
+ "z": 0.0
+ },
+ {
+ "x": 93.24451215232251,
+ "y": -332.58456733213006,
+ "z": 0.0
+ },
+ {
+ "x": 94.29117866880587,
+ "y": -332.58512803141815,
+ "z": 0.0
+ },
+ {
+ "x": 95.33784518528903,
+ "y": -332.58568873070624,
+ "z": 0.0
+ },
+ {
+ "x": 96.38451170177281,
+ "y": -332.5862494299944,
+ "z": 0.0
+ },
+ {
+ "x": 97.43117821825575,
+ "y": -332.5868101292824,
+ "z": 0.0
+ },
+ {
+ "x": 98.47784473473953,
+ "y": -332.58737082857056,
+ "z": 0.0
+ },
+ {
+ "x": 99.52451125122248,
+ "y": -332.5879315278586,
+ "z": 0.0
+ },
+ {
+ "x": 100.57117776770626,
+ "y": -332.58849222714673,
+ "z": 0.0
+ },
+ {
+ "x": 101.61784428418963,
+ "y": -332.58905292643476,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 171,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 79.63891883795232,
+ "y": -330.5772785283594,
+ "z": 0.0
+ },
+ {
+ "x": 80.68558535443569,
+ "y": -330.5778392276475,
+ "z": 0.0
+ },
+ {
+ "x": 81.73225187091904,
+ "y": -330.57839992693556,
+ "z": 0.0
+ },
+ {
+ "x": 82.77891838740241,
+ "y": -330.57896062622365,
+ "z": 0.0
+ },
+ {
+ "x": 83.82558490388577,
+ "y": -330.57952132551173,
+ "z": 0.0
+ },
+ {
+ "x": 84.87225142036914,
+ "y": -330.5800820247998,
+ "z": 0.0
+ },
+ {
+ "x": 85.91891793685251,
+ "y": -330.5806427240879,
+ "z": 0.0
+ },
+ {
+ "x": 86.96558445333586,
+ "y": -330.581203423376,
+ "z": 0.0
+ },
+ {
+ "x": 88.01225096981923,
+ "y": -330.5817641226641,
+ "z": 0.0
+ },
+ {
+ "x": 89.05891748630259,
+ "y": -330.58232482195217,
+ "z": 0.0
+ },
+ {
+ "x": 90.10558400278596,
+ "y": -330.58288552124026,
+ "z": 0.0
+ },
+ {
+ "x": 91.15225051926933,
+ "y": -330.58344622052834,
+ "z": 0.0
+ },
+ {
+ "x": 92.19891703575269,
+ "y": -330.58400691981643,
+ "z": 0.0
+ },
+ {
+ "x": 93.24558355223606,
+ "y": -330.5845676191045,
+ "z": 0.0
+ },
+ {
+ "x": 94.29225006871941,
+ "y": -330.5851283183926,
+ "z": 0.0
+ },
+ {
+ "x": 95.33891658520267,
+ "y": -330.5856890176807,
+ "z": 0.0
+ },
+ {
+ "x": 96.38558310168625,
+ "y": -330.58624971696884,
+ "z": 0.0
+ },
+ {
+ "x": 97.43224961816941,
+ "y": -330.58681041625687,
+ "z": 0.0
+ },
+ {
+ "x": 98.47891613465296,
+ "y": -330.587371115545,
+ "z": 0.0
+ },
+ {
+ "x": 99.52558265113612,
+ "y": -330.58793181483304,
+ "z": 0.0
+ },
+ {
+ "x": 100.5722491676197,
+ "y": -330.5884925141212,
+ "z": 0.0
+ },
+ {
+ "x": 101.61891568410306,
+ "y": -330.5890532134092,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 174,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 79.73656143631914,
+ "y": -330.57494595568255,
+ "z": 0.0
+ },
+ {
+ "x": 81.01078991817974,
+ "y": -330.5043945565061,
+ "z": 0.0
+ },
+ {
+ "x": 82.29098389026342,
+ "y": -330.30913395288894,
+ "z": 0.0
+ },
+ {
+ "x": 83.54349472443971,
+ "y": -329.9812404475023,
+ "z": 0.0
+ },
+ {
+ "x": 84.75481203058489,
+ "y": -329.52429641276865,
+ "z": 0.0
+ },
+ {
+ "x": 85.91185841679498,
+ "y": -328.9432312187754,
+ "z": 0.0
+ },
+ {
+ "x": 87.0021200663951,
+ "y": -328.24427205410035,
+ "z": 0.0
+ },
+ {
+ "x": 88.01341728803806,
+ "y": -327.435227246739,
+ "z": 0.0
+ },
+ {
+ "x": 88.93900969128816,
+ "y": -326.5202515246551,
+ "z": 0.0
+ },
+ {
+ "x": 89.75107560959849,
+ "y": -325.5266666688634,
+ "z": 0.0
+ },
+ {
+ "x": 90.45728298426096,
+ "y": -324.46701305568627,
+ "z": 0.0
+ },
+ {
+ "x": 91.06141501298855,
+ "y": -323.34667243019805,
+ "z": 0.0
+ },
+ {
+ "x": 91.5584014223586,
+ "y": -322.1752631134002,
+ "z": 0.0
+ },
+ {
+ "x": 91.94405223561498,
+ "y": -320.96281181528263,
+ "z": 0.0
+ },
+ {
+ "x": 92.21508908431153,
+ "y": -319.7196762819973,
+ "z": 0.0
+ },
+ {
+ "x": 92.3684513758152,
+ "y": -318.47466801576627,
+ "z": 0.0
+ },
+ {
+ "x": 92.41629889872712,
+ "y": -317.38843814933017,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 177,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 88.42017200487301,
+ "y": -317.2120253308748,
+ "z": 0.0
+ },
+ {
+ "x": 88.38681659765516,
+ "y": -318.1305891502018,
+ "z": 0.0
+ },
+ {
+ "x": 88.28041774537446,
+ "y": -319.0242218600872,
+ "z": 0.0
+ },
+ {
+ "x": 88.09128024053727,
+ "y": -319.90385005448945,
+ "z": 0.0
+ },
+ {
+ "x": 87.82103436358267,
+ "y": -320.7620070632413,
+ "z": 0.0
+ },
+ {
+ "x": 87.47196227942555,
+ "y": -321.5913992565817,
+ "z": 0.0
+ },
+ {
+ "x": 87.04698127144358,
+ "y": -322.3849604018104,
+ "z": 0.0
+ },
+ {
+ "x": 86.55563133951622,
+ "y": -323.1286292338267,
+ "z": 0.0
+ },
+ {
+ "x": 86.00674941604638,
+ "y": -323.8080489871936,
+ "z": 0.0
+ },
+ {
+ "x": 85.38404558626888,
+ "y": -324.4280697582773,
+ "z": 0.0
+ },
+ {
+ "x": 84.70104078243725,
+ "y": -324.97909432431106,
+ "z": 0.0
+ },
+ {
+ "x": 83.96458694724586,
+ "y": -325.4554743391213,
+ "z": 0.0
+ },
+ {
+ "x": 83.18264360482415,
+ "y": -325.8521635843414,
+ "z": 0.0
+ },
+ {
+ "x": 82.36363121688173,
+ "y": -326.16493986710304,
+ "z": 0.0
+ },
+ {
+ "x": 81.51634906459863,
+ "y": -326.3904453991263,
+ "z": 0.0
+ },
+ {
+ "x": 80.62976620677989,
+ "y": -326.5270911532118,
+ "z": 0.0
+ },
+ {
+ "x": 79.54380142545668,
+ "y": -326.57961414999033,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 180,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 101.71306615229395,
+ "y": -326.59122060270465,
+ "z": 0.0
+ },
+ {
+ "x": 100.67112994207008,
+ "y": -326.54267677716007,
+ "z": 0.0
+ },
+ {
+ "x": 99.80014390413483,
+ "y": -326.4238790735774,
+ "z": 0.0
+ },
+ {
+ "x": 98.96460511255336,
+ "y": -326.22842132801753,
+ "z": 0.0
+ },
+ {
+ "x": 98.15019178427023,
+ "y": -325.95695891031085,
+ "z": 0.0
+ },
+ {
+ "x": 97.3634224837516,
+ "y": -325.61153041774634,
+ "z": 0.0
+ },
+ {
+ "x": 96.64176504893888,
+ "y": -325.1957672182933,
+ "z": 0.0
+ },
+ {
+ "x": 95.955335319999,
+ "y": -324.70501710099404,
+ "z": 0.0
+ },
+ {
+ "x": 95.30486246131848,
+ "y": -324.14508005625663,
+ "z": 0.0
+ },
+ {
+ "x": 94.70767658356107,
+ "y": -323.5275983878604,
+ "z": 0.0
+ },
+ {
+ "x": 94.16755299214661,
+ "y": -322.857239798076,
+ "z": 0.0
+ },
+ {
+ "x": 93.68910215437192,
+ "y": -322.13971373665186,
+ "z": 0.0
+ },
+ {
+ "x": 93.28929316726665,
+ "y": -321.38958509793605,
+ "z": 0.0
+ },
+ {
+ "x": 92.97766384421965,
+ "y": -320.61591701150184,
+ "z": 0.0
+ },
+ {
+ "x": 92.72595349426187,
+ "y": -319.7915731229868,
+ "z": 0.0
+ },
+ {
+ "x": 92.549602496984,
+ "y": -318.9482323186387,
+ "z": 0.0
+ },
+ {
+ "x": 92.44993108110532,
+ "y": -318.0923460328693,
+ "z": 0.0
+ },
+ {
+ "x": 92.41617104017382,
+ "y": -317.2095624415087,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 183,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 88.42029960539836,
+ "y": -317.390819183904,
+ "z": 0.0
+ },
+ {
+ "x": 88.48128925622473,
+ "y": -318.5919860417332,
+ "z": 0.0
+ },
+ {
+ "x": 88.64210023950311,
+ "y": -319.8033681384539,
+ "z": 0.0
+ },
+ {
+ "x": 88.91137574924393,
+ "y": -320.9952761314796,
+ "z": 0.0
+ },
+ {
+ "x": 89.28707508064065,
+ "y": -322.1584901807639,
+ "z": 0.0
+ },
+ {
+ "x": 89.78011362258745,
+ "y": -323.3093921488408,
+ "z": 0.0
+ },
+ {
+ "x": 90.38193707085415,
+ "y": -324.38967433746575,
+ "z": 0.0
+ },
+ {
+ "x": 91.07657134093074,
+ "y": -325.3960522968648,
+ "z": 0.0
+ },
+ {
+ "x": 91.8592434071351,
+ "y": -326.3358427502742,
+ "z": 0.0
+ },
+ {
+ "x": 92.72486614969797,
+ "y": -327.20179380010893,
+ "z": 0.0
+ },
+ {
+ "x": 93.66694103194341,
+ "y": -327.98574947899647,
+ "z": 0.0
+ },
+ {
+ "x": 94.69099899029271,
+ "y": -328.68783136059267,
+ "z": 0.0
+ },
+ {
+ "x": 95.79103375491582,
+ "y": -329.2894683383839,
+ "z": 0.0
+ },
+ {
+ "x": 96.92223094720762,
+ "y": -329.763771091042,
+ "z": 0.0
+ },
+ {
+ "x": 98.09135668384951,
+ "y": -330.1319091695889,
+ "z": 0.0
+ },
+ {
+ "x": 99.28896330206895,
+ "y": -330.39106296260303,
+ "z": 0.0
+ },
+ {
+ "x": 100.48449007762834,
+ "y": -330.5383155470995,
+ "z": 0.0
+ },
+ {
+ "x": 101.52642557922788,
+ "y": -330.58688396887624,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 186,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 79.38066375782434,
+ "y": -1.9577239538036761,
+ "z": 0.0
+ },
+ {
+ "x": 80.44020915609882,
+ "y": -1.9573786375497457,
+ "z": 0.0
+ },
+ {
+ "x": 81.4997545543733,
+ "y": -1.9570333212958153,
+ "z": 0.0
+ },
+ {
+ "x": 82.55929995264778,
+ "y": -1.956688005041885,
+ "z": 0.0
+ },
+ {
+ "x": 83.61884535092224,
+ "y": -1.9563426887879551,
+ "z": 0.0
+ },
+ {
+ "x": 84.67839074919672,
+ "y": -1.9559973725340245,
+ "z": 0.0
+ },
+ {
+ "x": 85.7379361474712,
+ "y": -1.955652056280094,
+ "z": 0.0
+ },
+ {
+ "x": 86.79748154574567,
+ "y": -1.955306740026164,
+ "z": 0.0
+ },
+ {
+ "x": 87.85702694402015,
+ "y": -1.9549614237722337,
+ "z": 0.0
+ },
+ {
+ "x": 88.91657234229463,
+ "y": -1.9546161075183033,
+ "z": 0.0
+ },
+ {
+ "x": 89.97611774056911,
+ "y": -1.9542707912643729,
+ "z": 0.0
+ },
+ {
+ "x": 91.03566313884357,
+ "y": -1.9539254750104427,
+ "z": 0.0
+ },
+ {
+ "x": 92.09520853711805,
+ "y": -1.9535801587565125,
+ "z": 0.0
+ },
+ {
+ "x": 93.15475393539253,
+ "y": -1.953234842502582,
+ "z": 0.0
+ },
+ {
+ "x": 94.214299333667,
+ "y": -1.9528895262486519,
+ "z": 0.0
+ },
+ {
+ "x": 95.27384473194148,
+ "y": -1.9525442099947212,
+ "z": 0.0
+ },
+ {
+ "x": 96.33339013021596,
+ "y": -1.9521988937407913,
+ "z": 0.0
+ },
+ {
+ "x": 97.39293552849043,
+ "y": -1.951853577486861,
+ "z": 0.0
+ },
+ {
+ "x": 98.4524809267649,
+ "y": -1.9515082612329304,
+ "z": 0.0
+ },
+ {
+ "x": 99.51202632503939,
+ "y": -1.951162944979,
+ "z": 0.0
+ },
+ {
+ "x": 100.57157172331387,
+ "y": -1.95081762872507,
+ "z": 0.0
+ },
+ {
+ "x": 101.63111712158833,
+ "y": -1.9504723124711398,
+ "z": 0.0
+ },
+ {
+ "x": 102.69066251986281,
+ "y": -1.9501269962172092,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 187,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 102.68870706102459,
+ "y": 4.049872685131176,
+ "z": 0.0
+ },
+ {
+ "x": 101.6291616627501,
+ "y": 4.049527368877246,
+ "z": 0.0
+ },
+ {
+ "x": 100.56961626447564,
+ "y": 4.0491820526233155,
+ "z": 0.0
+ },
+ {
+ "x": 99.51007086620116,
+ "y": 4.048836736369386,
+ "z": 0.0
+ },
+ {
+ "x": 98.45052546792668,
+ "y": 4.048491420115455,
+ "z": 0.0
+ },
+ {
+ "x": 97.3909800696522,
+ "y": 4.048146103861526,
+ "z": 0.0
+ },
+ {
+ "x": 96.33143467137774,
+ "y": 4.047800787607595,
+ "z": 0.0
+ },
+ {
+ "x": 95.27188927310326,
+ "y": 4.047455471353664,
+ "z": 0.0
+ },
+ {
+ "x": 94.21234387482878,
+ "y": 4.047110155099734,
+ "z": 0.0
+ },
+ {
+ "x": 93.15279847655431,
+ "y": 4.046764838845804,
+ "z": 0.0
+ },
+ {
+ "x": 92.09325307827983,
+ "y": 4.046419522591873,
+ "z": 0.0
+ },
+ {
+ "x": 91.03370768000535,
+ "y": 4.046074206337943,
+ "z": 0.0
+ },
+ {
+ "x": 89.97416228173088,
+ "y": 4.045728890084012,
+ "z": 0.0
+ },
+ {
+ "x": 88.9146168834564,
+ "y": 4.045383573830082,
+ "z": 0.0
+ },
+ {
+ "x": 87.85507148518192,
+ "y": 4.045038257576152,
+ "z": 0.0
+ },
+ {
+ "x": 86.79552608690744,
+ "y": 4.044692941322222,
+ "z": 0.0
+ },
+ {
+ "x": 85.73598068863298,
+ "y": 4.0443476250682915,
+ "z": 0.0
+ },
+ {
+ "x": 84.6764352903585,
+ "y": 4.0440023088143615,
+ "z": 0.0
+ },
+ {
+ "x": 83.61688989208402,
+ "y": 4.0436569925604315,
+ "z": 0.0
+ },
+ {
+ "x": 82.55734449380955,
+ "y": 4.043311676306501,
+ "z": 0.0
+ },
+ {
+ "x": 81.49779909553507,
+ "y": 4.04296636005257,
+ "z": 0.0
+ },
+ {
+ "x": 80.43825369726059,
+ "y": 4.04262104379864,
+ "z": 0.0
+ },
+ {
+ "x": 79.37870829898611,
+ "y": 4.04227572754471,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 189,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 102.68935888063733,
+ "y": 2.049872791348381,
+ "z": 0.0
+ },
+ {
+ "x": 101.62981348236285,
+ "y": 2.049527475094451,
+ "z": 0.0
+ },
+ {
+ "x": 100.57026808408838,
+ "y": 2.0491821588405204,
+ "z": 0.0
+ },
+ {
+ "x": 99.5107226858139,
+ "y": 2.0488368425865904,
+ "z": 0.0
+ },
+ {
+ "x": 98.45117728753942,
+ "y": 2.0484915263326595,
+ "z": 0.0
+ },
+ {
+ "x": 97.39163188926494,
+ "y": 2.04814621007873,
+ "z": 0.0
+ },
+ {
+ "x": 96.33208649099048,
+ "y": 2.0478008938247996,
+ "z": 0.0
+ },
+ {
+ "x": 95.272541092716,
+ "y": 2.0474555775708687,
+ "z": 0.0
+ },
+ {
+ "x": 94.21299569444152,
+ "y": 2.0471102613169387,
+ "z": 0.0
+ },
+ {
+ "x": 93.15345029616705,
+ "y": 2.0467649450630088,
+ "z": 0.0
+ },
+ {
+ "x": 92.09390489789257,
+ "y": 2.046419628809078,
+ "z": 0.0
+ },
+ {
+ "x": 91.03435949961809,
+ "y": 2.046074312555148,
+ "z": 0.0
+ },
+ {
+ "x": 89.97481410134363,
+ "y": 2.045728996301217,
+ "z": 0.0
+ },
+ {
+ "x": 88.91526870306915,
+ "y": 2.045383680047287,
+ "z": 0.0
+ },
+ {
+ "x": 87.85572330479467,
+ "y": 2.045038363793357,
+ "z": 0.0
+ },
+ {
+ "x": 86.79617790652019,
+ "y": 2.0446930475394267,
+ "z": 0.0
+ },
+ {
+ "x": 85.73663250824572,
+ "y": 2.0443477312854963,
+ "z": 0.0
+ },
+ {
+ "x": 84.67708710997124,
+ "y": 2.0440024150315663,
+ "z": 0.0
+ },
+ {
+ "x": 83.61754171169676,
+ "y": 2.043657098777636,
+ "z": 0.0
+ },
+ {
+ "x": 82.5579963134223,
+ "y": 2.0433117825237055,
+ "z": 0.0
+ },
+ {
+ "x": 81.49845091514781,
+ "y": 2.0429664662697746,
+ "z": 0.0
+ },
+ {
+ "x": 80.43890551687333,
+ "y": 2.0426211500158447,
+ "z": 0.0
+ },
+ {
+ "x": 79.37936011859885,
+ "y": 2.0422758337619147,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 192,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 102.68935888063733,
+ "y": 2.049872791348381,
+ "z": 0.0
+ },
+ {
+ "x": 101.65832930984283,
+ "y": 2.0495367686827572,
+ "z": 0.0
+ },
+ {
+ "x": 100.62729973904831,
+ "y": 2.0492007460171333,
+ "z": 0.0
+ },
+ {
+ "x": 99.5962701682538,
+ "y": 2.0488647233515085,
+ "z": 0.0
+ },
+ {
+ "x": 98.5652405974593,
+ "y": 2.0485287006858846,
+ "z": 0.0
+ },
+ {
+ "x": 97.38922935584577,
+ "y": 2.0428834586190012,
+ "z": 0.0
+ },
+ {
+ "x": 96.14515386216075,
+ "y": 1.9400805582782434,
+ "z": 0.0
+ },
+ {
+ "x": 94.8730511827662,
+ "y": 1.6869661986496554,
+ "z": 0.0
+ },
+ {
+ "x": 93.5702008365092,
+ "y": 1.22505021256522,
+ "z": 0.0
+ },
+ {
+ "x": 92.40006126093198,
+ "y": 0.5649586460659338,
+ "z": 0.0
+ },
+ {
+ "x": 91.38046677094792,
+ "y": -0.23641945572233425,
+ "z": 0.0
+ },
+ {
+ "x": 90.48038520357372,
+ "y": -1.1647799831877466,
+ "z": 0.0
+ },
+ {
+ "x": 89.68231525354273,
+ "y": -2.2587983061839196,
+ "z": 0.0
+ },
+ {
+ "x": 89.07111740293382,
+ "y": -3.4722343436080396,
+ "z": 0.0
+ },
+ {
+ "x": 88.67845588237262,
+ "y": -4.704909506053416,
+ "z": 0.0
+ },
+ {
+ "x": 88.45581325061647,
+ "y": -5.935592458876994,
+ "z": 0.0
+ },
+ {
+ "x": 88.37108444520378,
+ "y": -7.116185443357953,
+ "z": 0.0
+ },
+ {
+ "x": 88.37124117478857,
+ "y": -8.14721505699659,
+ "z": 0.0
+ },
+ {
+ "x": 88.37139790437337,
+ "y": -9.17824467063517,
+ "z": 0.0
+ },
+ {
+ "x": 88.37155463395816,
+ "y": -10.20927428427378,
+ "z": 0.0
+ },
+ {
+ "x": 88.37171136354294,
+ "y": -11.240303897912387,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 195,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 92.37171131732724,
+ "y": -11.239695847160373,
+ "z": 0.0
+ },
+ {
+ "x": 92.37155114114427,
+ "y": -10.185993138367436,
+ "z": 0.0
+ },
+ {
+ "x": 92.3713909649613,
+ "y": -9.1322904295745,
+ "z": 0.0
+ },
+ {
+ "x": 92.39046094699293,
+ "y": -8.116508097385378,
+ "z": 0.0
+ },
+ {
+ "x": 92.46620178948825,
+ "y": -7.18354460785133,
+ "z": 0.0
+ },
+ {
+ "x": 92.6608232529945,
+ "y": -6.463353461590874,
+ "z": 0.0
+ },
+ {
+ "x": 92.95346991422174,
+ "y": -5.700548846361753,
+ "z": 0.0
+ },
+ {
+ "x": 93.33315107195224,
+ "y": -4.977802134021738,
+ "z": 0.0
+ },
+ {
+ "x": 93.79523274275404,
+ "y": -4.303944248276251,
+ "z": 0.0
+ },
+ {
+ "x": 94.33434349854011,
+ "y": -3.687590563228103,
+ "z": 0.0
+ },
+ {
+ "x": 94.91530511508498,
+ "y": -3.212018734025133,
+ "z": 0.0
+ },
+ {
+ "x": 95.58835243785953,
+ "y": -2.7800965407806846,
+ "z": 0.0
+ },
+ {
+ "x": 96.31607581087863,
+ "y": -2.4276423861668794,
+ "z": 0.0
+ },
+ {
+ "x": 97.08151497626868,
+ "y": -2.1656349088898588,
+ "z": 0.0
+ },
+ {
+ "x": 97.87475166175554,
+ "y": -1.9978261145678717,
+ "z": 0.0
+ },
+ {
+ "x": 98.63542969358136,
+ "y": -1.9584385980081804,
+ "z": 0.0
+ },
+ {
+ "x": 99.55485470219124,
+ "y": -1.950988954958867,
+ "z": 0.0
+ },
+ {
+ "x": 100.58325718984946,
+ "y": -1.950813820316731,
+ "z": 0.0
+ },
+ {
+ "x": 101.63695985485614,
+ "y": -1.9504704082669708,
+ "z": 0.0
+ },
+ {
+ "x": 102.69066251986281,
+ "y": -1.9501269962172094,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 198,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 79.38066375454355,
+ "y": -1.9577239538047368,
+ "z": 0.0
+ },
+ {
+ "x": 80.4388549865507,
+ "y": -1.9573790788868963,
+ "z": 0.0
+ },
+ {
+ "x": 81.49704621855781,
+ "y": -1.9570342039690558,
+ "z": 0.0
+ },
+ {
+ "x": 82.55091250262038,
+ "y": -1.9589222555269905,
+ "z": 0.0
+ },
+ {
+ "x": 83.43200894284189,
+ "y": -2.0445247038874914,
+ "z": 0.0
+ },
+ {
+ "x": 84.24925844510989,
+ "y": -2.220497821692533,
+ "z": 0.0
+ },
+ {
+ "x": 85.05338347029272,
+ "y": -2.4832087265729244,
+ "z": 0.0
+ },
+ {
+ "x": 85.74791954430364,
+ "y": -2.834730304320984,
+ "z": 0.0
+ },
+ {
+ "x": 86.3801868279096,
+ "y": -3.2781724066689217,
+ "z": 0.0
+ },
+ {
+ "x": 87.00721396453173,
+ "y": -3.82053723236728,
+ "z": 0.0
+ },
+ {
+ "x": 87.55047028720435,
+ "y": -4.425529897110538,
+ "z": 0.0
+ },
+ {
+ "x": 87.83924838450032,
+ "y": -4.996065916476047,
+ "z": 0.0
+ },
+ {
+ "x": 88.12498548627755,
+ "y": -5.719537641098558,
+ "z": 0.0
+ },
+ {
+ "x": 88.31493852913333,
+ "y": -6.482889975872659,
+ "z": 0.0
+ },
+ {
+ "x": 88.36973463992086,
+ "y": -7.223142553947042,
+ "z": 0.0
+ },
+ {
+ "x": 88.37138235691452,
+ "y": -8.090212015485726,
+ "z": 0.0
+ },
+ {
+ "x": 88.37138964653866,
+ "y": -9.123921345952521,
+ "z": 0.0
+ },
+ {
+ "x": 88.3715505050408,
+ "y": -10.182112621932458,
+ "z": 0.0
+ },
+ {
+ "x": 88.37171136354294,
+ "y": -11.240303897912394,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 201,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 92.37171131732723,
+ "y": -11.239695847160402,
+ "z": 0.0
+ },
+ {
+ "x": 92.37155054141259,
+ "y": -10.182047864601843,
+ "z": 0.0
+ },
+ {
+ "x": 92.37138976549794,
+ "y": -9.124399882043246,
+ "z": 0.0
+ },
+ {
+ "x": 92.37122898958329,
+ "y": -8.066751899484675,
+ "z": 0.0
+ },
+ {
+ "x": 92.32627910480849,
+ "y": -6.929613012356661,
+ "z": 0.0
+ },
+ {
+ "x": 92.20804645699295,
+ "y": -5.75344116010853,
+ "z": 0.0
+ },
+ {
+ "x": 91.82483457880105,
+ "y": -4.366599844967185,
+ "z": 0.0
+ },
+ {
+ "x": 91.30775741146184,
+ "y": -3.1709171435836234,
+ "z": 0.0
+ },
+ {
+ "x": 90.65535366129677,
+ "y": -2.054612645824859,
+ "z": 0.0
+ },
+ {
+ "x": 89.81302843243145,
+ "y": -0.9956783172598629,
+ "z": 0.0
+ },
+ {
+ "x": 88.78088189318728,
+ "y": -0.06351850988216023,
+ "z": 0.0
+ },
+ {
+ "x": 87.7192830400309,
+ "y": 0.671605878433852,
+ "z": 0.0
+ },
+ {
+ "x": 86.57424660191658,
+ "y": 1.2764731160905984,
+ "z": 0.0
+ },
+ {
+ "x": 85.22679612447331,
+ "y": 1.7184868629338879,
+ "z": 0.0
+ },
+ {
+ "x": 83.92383958195423,
+ "y": 1.9457360202381637,
+ "z": 0.0
+ },
+ {
+ "x": 82.69024866530056,
+ "y": 2.0386125518403038,
+ "z": 0.0
+ },
+ {
+ "x": 81.49495166259359,
+ "y": 2.0429653258289995,
+ "z": 0.0
+ },
+ {
+ "x": 80.43730372398524,
+ "y": 2.042620627975815,
+ "z": 0.0
+ },
+ {
+ "x": 79.37965578537688,
+ "y": 2.0422759301226296,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 204,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 347.7299857691685,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 346.65641965126474,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 345.5941204708103,
+ "y": -326.6040779914478,
+ "z": 0.0
+ },
+ {
+ "x": 344.648505329607,
+ "y": -326.5354346959316,
+ "z": 0.0
+ },
+ {
+ "x": 343.85970768027084,
+ "y": -326.3567253110556,
+ "z": 0.0
+ },
+ {
+ "x": 343.0776092882985,
+ "y": -326.0795876674798,
+ "z": 0.0
+ },
+ {
+ "x": 342.3354907746227,
+ "y": -325.70986091698387,
+ "z": 0.0
+ },
+ {
+ "x": 341.64405761177926,
+ "y": -325.2530356144291,
+ "z": 0.0
+ },
+ {
+ "x": 341.01329565219686,
+ "y": -324.71580515294767,
+ "z": 0.0
+ },
+ {
+ "x": 340.44702812359935,
+ "y": -324.10413828561445,
+ "z": 0.0
+ },
+ {
+ "x": 339.94535168652635,
+ "y": -323.423605878501,
+ "z": 0.0
+ },
+ {
+ "x": 339.51734115447863,
+ "y": -322.6864068001786,
+ "z": 0.0
+ },
+ {
+ "x": 339.1727150952545,
+ "y": -321.9059384428799,
+ "z": 0.0
+ },
+ {
+ "x": 338.9277300987599,
+ "y": -321.1031441814349,
+ "z": 0.0
+ },
+ {
+ "x": 338.7795076133734,
+ "y": -320.27874964250066,
+ "z": 0.0
+ },
+ {
+ "x": 338.71982898421777,
+ "y": -319.42841040751057,
+ "z": 0.0
+ },
+ {
+ "x": 338.70720255662206,
+ "y": -318.48770881866005,
+ "z": 0.0
+ },
+ {
+ "x": 338.70817756430256,
+ "y": -317.45151167767597,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 207,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 334.70817851236086,
+ "y": -317.44873405142624,
+ "z": 0.0
+ },
+ {
+ "x": 334.7075762305461,
+ "y": -318.5436553177717,
+ "z": 0.0
+ },
+ {
+ "x": 334.7195177420323,
+ "y": -319.7406104743982,
+ "z": 0.0
+ },
+ {
+ "x": 334.82049530304073,
+ "y": -321.0539438473358,
+ "z": 0.0
+ },
+ {
+ "x": 335.0761563021257,
+ "y": -322.3434839951809,
+ "z": 0.0
+ },
+ {
+ "x": 335.47768807384915,
+ "y": -323.58519337120737,
+ "z": 0.0
+ },
+ {
+ "x": 336.01658897447584,
+ "y": -324.77308093046884,
+ "z": 0.0
+ },
+ {
+ "x": 336.68589773112495,
+ "y": -325.8921318270369,
+ "z": 0.0
+ },
+ {
+ "x": 337.49447840776554,
+ "y": -326.94649206913607,
+ "z": 0.0
+ },
+ {
+ "x": 338.40328770494233,
+ "y": -327.87004125241145,
+ "z": 0.0
+ },
+ {
+ "x": 339.4213558134485,
+ "y": -328.69749319947175,
+ "z": 0.0
+ },
+ {
+ "x": 340.60990333464713,
+ "y": -329.43703225907564,
+ "z": 0.0
+ },
+ {
+ "x": 341.8285278971893,
+ "y": -329.9562320320991,
+ "z": 0.0
+ },
+ {
+ "x": 343.0891858483319,
+ "y": -330.3197665843113,
+ "z": 0.0
+ },
+ {
+ "x": 344.35589618935245,
+ "y": -330.53065971257524,
+ "z": 0.0
+ },
+ {
+ "x": 345.57053106457437,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 346.650082156251,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 347.7296332479276,
+ "y": -330.6099853515625,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 208,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 325.71998576749917,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 326.7680810055944,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 327.81617624368965,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 328.8642714817849,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 329.91236671988014,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 330.9604619579754,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 332.0085571960706,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 333.05665243416587,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 334.1047476722611,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 335.15284291035636,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 336.2009381484516,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 337.2490333865468,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 338.297128624642,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 339.34522386273727,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 340.3933191008325,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 341.44141433892776,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 342.489509577023,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 343.53760481511824,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 344.5857000532135,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 345.63379529130873,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 346.681890529404,
+ "y": -332.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 347.7299857674992,
+ "y": -332.6099853515625,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 210,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 325.71998576749917,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 326.7680810055944,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 327.81617624368965,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 328.8642714817849,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 329.91236671988014,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 330.9604619579754,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 332.0085571960706,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 333.05665243416587,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 334.1047476722611,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 335.15284291035636,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 336.2009381484516,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 337.2490333865468,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 338.297128624642,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 339.34522386273727,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 340.3933191008325,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 341.44141433892776,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 342.489509577023,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 343.53760481511824,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 344.5857000532135,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 345.63379529130873,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 346.681890529404,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 347.7299857674992,
+ "y": -330.6099853515625,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 213,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 347.7299857674992,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 346.681890529404,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 345.63379529130873,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 344.5857000532135,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 343.53760481511824,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 342.489509577023,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 341.44141433892776,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 340.3933191008325,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 339.34522386273727,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 338.297128624642,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 337.2490333865468,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 336.2009381484516,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 335.15284291035636,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 334.1047476722611,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 333.05665243416587,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 332.0085571960706,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 330.9604619579754,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 329.91236671988014,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 328.8642714817849,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 327.81617624368965,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 326.7680810055944,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 325.71998576749917,
+ "y": -326.6099853515625,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 216,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 325.71998576749917,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 326.75488808239726,
+ "y": -330.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 327.8118675524266,
+ "y": -330.60986349765574,
+ "z": 0.0
+ },
+ {
+ "x": 328.9873159954276,
+ "y": -330.59190530437644,
+ "z": 0.0
+ },
+ {
+ "x": 330.30964508378855,
+ "y": -330.46197316532766,
+ "z": 0.0
+ },
+ {
+ "x": 331.556025593915,
+ "y": -330.15541174962823,
+ "z": 0.0
+ },
+ {
+ "x": 332.7525040323843,
+ "y": -329.69632142549915,
+ "z": 0.0
+ },
+ {
+ "x": 333.88208912167863,
+ "y": -329.0916278346175,
+ "z": 0.0
+ },
+ {
+ "x": 334.9359359378983,
+ "y": -328.34315517349506,
+ "z": 0.0
+ },
+ {
+ "x": 335.913383204102,
+ "y": -327.4289099766568,
+ "z": 0.0
+ },
+ {
+ "x": 336.7008226662732,
+ "y": -326.4421863771143,
+ "z": 0.0
+ },
+ {
+ "x": 337.3694306959815,
+ "y": -325.3743482667254,
+ "z": 0.0
+ },
+ {
+ "x": 337.9121140564023,
+ "y": -324.2379684904723,
+ "z": 0.0
+ },
+ {
+ "x": 338.3230020237536,
+ "y": -323.0439917139242,
+ "z": 0.0
+ },
+ {
+ "x": 338.60091078909,
+ "y": -321.7401436542182,
+ "z": 0.0
+ },
+ {
+ "x": 338.6862609570376,
+ "y": -320.5934350532335,
+ "z": 0.0
+ },
+ {
+ "x": 338.7069274034519,
+ "y": -319.5212766008853,
+ "z": 0.0
+ },
+ {
+ "x": 338.70755249575484,
+ "y": -318.4863744747684,
+ "z": 0.0
+ },
+ {
+ "x": 338.70817758805777,
+ "y": -317.45147234865163,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 219,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 334.70817851236086,
+ "y": -317.44873405142624,
+ "z": 0.0
+ },
+ {
+ "x": 334.70752421679254,
+ "y": -318.53198507169066,
+ "z": 0.0
+ },
+ {
+ "x": 334.7108944649408,
+ "y": -319.48962363322096,
+ "z": 0.0
+ },
+ {
+ "x": 334.6645566804101,
+ "y": -320.3735075264175,
+ "z": 0.0
+ },
+ {
+ "x": 334.53815197133923,
+ "y": -321.22153723351005,
+ "z": 0.0
+ },
+ {
+ "x": 334.31797944922545,
+ "y": -322.0503964585138,
+ "z": 0.0
+ },
+ {
+ "x": 334.0371918614085,
+ "y": -322.7960531500664,
+ "z": 0.0
+ },
+ {
+ "x": 333.62261883383894,
+ "y": -323.5325454764164,
+ "z": 0.0
+ },
+ {
+ "x": 333.11819234412405,
+ "y": -324.21935487342756,
+ "z": 0.0
+ },
+ {
+ "x": 332.54625711396557,
+ "y": -324.83716484905676,
+ "z": 0.0
+ },
+ {
+ "x": 331.9093734688107,
+ "y": -325.3796459158115,
+ "z": 0.0
+ },
+ {
+ "x": 331.2743947648346,
+ "y": -325.81212613380285,
+ "z": 0.0
+ },
+ {
+ "x": 330.51884277883306,
+ "y": -326.1556341844773,
+ "z": 0.0
+ },
+ {
+ "x": 329.7185175964627,
+ "y": -326.4014722846573,
+ "z": 0.0
+ },
+ {
+ "x": 328.849860451563,
+ "y": -326.5499418368728,
+ "z": 0.0
+ },
+ {
+ "x": 327.8864882032299,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 326.8032369853645,
+ "y": -326.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 325.71998576749917,
+ "y": -326.6099853515625,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 220,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 86.37701814958909,
+ "y": -46.15060751994074,
+ "z": 0.0
+ },
+ {
+ "x": 86.37717740097652,
+ "y": -47.19822655545584,
+ "z": 0.0
+ },
+ {
+ "x": 86.377336652364,
+ "y": -48.24584559097058,
+ "z": 0.0
+ },
+ {
+ "x": 86.37749590375142,
+ "y": -49.29346462648557,
+ "z": 0.0
+ },
+ {
+ "x": 86.37765515513887,
+ "y": -50.34108366200046,
+ "z": 0.0
+ },
+ {
+ "x": 86.3778144065263,
+ "y": -51.38870269751539,
+ "z": 0.0
+ },
+ {
+ "x": 86.37797365791373,
+ "y": -52.436321733030326,
+ "z": 0.0
+ },
+ {
+ "x": 86.37813290930116,
+ "y": -53.48394076854531,
+ "z": 0.0
+ },
+ {
+ "x": 86.3782921606886,
+ "y": -54.531559804060194,
+ "z": 0.0
+ },
+ {
+ "x": 86.37845141207603,
+ "y": -55.579178839575135,
+ "z": 0.0
+ },
+ {
+ "x": 86.37861066346346,
+ "y": -56.62679787509001,
+ "z": 0.0
+ },
+ {
+ "x": 86.37876991485088,
+ "y": -57.67441691060498,
+ "z": 0.0
+ },
+ {
+ "x": 86.37892916623831,
+ "y": -58.722035946119966,
+ "z": 0.0
+ },
+ {
+ "x": 86.37908841762575,
+ "y": -59.76965498163485,
+ "z": 0.0
+ },
+ {
+ "x": 86.37924766901318,
+ "y": -60.817274017149835,
+ "z": 0.0
+ },
+ {
+ "x": 86.37940692040063,
+ "y": -61.86489305266472,
+ "z": 0.0
+ },
+ {
+ "x": 86.37956617178806,
+ "y": -62.91251208817966,
+ "z": 0.0
+ },
+ {
+ "x": 86.37972542317549,
+ "y": -63.960131123694644,
+ "z": 0.0
+ },
+ {
+ "x": 86.37988467456293,
+ "y": -65.00775015920952,
+ "z": 0.0
+ },
+ {
+ "x": 86.38004392595036,
+ "y": -66.05536919472452,
+ "z": 0.0
+ },
+ {
+ "x": 86.3802031773378,
+ "y": -67.10298823023938,
+ "z": 0.0
+ },
+ {
+ "x": 86.38036242872523,
+ "y": -68.15060726575432,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 222,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 88.37701812648123,
+ "y": -46.15030349456474,
+ "z": 0.0
+ },
+ {
+ "x": 88.37717737786866,
+ "y": -47.19792253007975,
+ "z": 0.0
+ },
+ {
+ "x": 88.37733662925613,
+ "y": -48.24554156559458,
+ "z": 0.0
+ },
+ {
+ "x": 88.37749588064356,
+ "y": -49.29316060110955,
+ "z": 0.0
+ },
+ {
+ "x": 88.37765513203101,
+ "y": -50.340779636624454,
+ "z": 0.0
+ },
+ {
+ "x": 88.37781438341844,
+ "y": -51.38839867213939,
+ "z": 0.0
+ },
+ {
+ "x": 88.37797363480587,
+ "y": -52.43601770765432,
+ "z": 0.0
+ },
+ {
+ "x": 88.3781328861933,
+ "y": -53.483636743169285,
+ "z": 0.0
+ },
+ {
+ "x": 88.37829213758074,
+ "y": -54.53125577868419,
+ "z": 0.0
+ },
+ {
+ "x": 88.37845138896817,
+ "y": -55.57887481419913,
+ "z": 0.0
+ },
+ {
+ "x": 88.3786106403556,
+ "y": -56.62649384971404,
+ "z": 0.0
+ },
+ {
+ "x": 88.37876989174302,
+ "y": -57.67411288522898,
+ "z": 0.0
+ },
+ {
+ "x": 88.37892914313045,
+ "y": -58.721731920743935,
+ "z": 0.0
+ },
+ {
+ "x": 88.3790883945179,
+ "y": -59.76935095625885,
+ "z": 0.0
+ },
+ {
+ "x": 88.37924764590532,
+ "y": -60.8169699917738,
+ "z": 0.0
+ },
+ {
+ "x": 88.37940689729277,
+ "y": -61.864589027288716,
+ "z": 0.0
+ },
+ {
+ "x": 88.3795661486802,
+ "y": -62.91220806280366,
+ "z": 0.0
+ },
+ {
+ "x": 88.37972540006763,
+ "y": -63.95982709831861,
+ "z": 0.0
+ },
+ {
+ "x": 88.37988465145507,
+ "y": -65.00744613383353,
+ "z": 0.0
+ },
+ {
+ "x": 88.3800439028425,
+ "y": -66.0550651693485,
+ "z": 0.0
+ },
+ {
+ "x": 88.38020315422995,
+ "y": -67.10268420486338,
+ "z": 0.0
+ },
+ {
+ "x": 88.38036240561738,
+ "y": -68.15030324037832,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 225,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 92.38036235940166,
+ "y": -68.1496951896263,
+ "z": 0.0
+ },
+ {
+ "x": 92.38020310801423,
+ "y": -67.10207615411136,
+ "z": 0.0
+ },
+ {
+ "x": 92.38004385662678,
+ "y": -66.05445711859642,
+ "z": 0.0
+ },
+ {
+ "x": 92.37988460523935,
+ "y": -65.0068380830815,
+ "z": 0.0
+ },
+ {
+ "x": 92.37972535385191,
+ "y": -63.95921904756656,
+ "z": 0.0
+ },
+ {
+ "x": 92.37956610246448,
+ "y": -62.91160001205165,
+ "z": 0.0
+ },
+ {
+ "x": 92.37940685107705,
+ "y": -61.86398097653671,
+ "z": 0.0
+ },
+ {
+ "x": 92.3792475996896,
+ "y": -60.81636194102175,
+ "z": 0.0
+ },
+ {
+ "x": 92.37908834830218,
+ "y": -59.76874290550684,
+ "z": 0.0
+ },
+ {
+ "x": 92.37892909691473,
+ "y": -58.721123869991885,
+ "z": 0.0
+ },
+ {
+ "x": 92.3787698455273,
+ "y": -57.67350483447697,
+ "z": 0.0
+ },
+ {
+ "x": 92.37861059413989,
+ "y": -56.62588579896209,
+ "z": 0.0
+ },
+ {
+ "x": 92.37845134275246,
+ "y": -55.578266763447125,
+ "z": 0.0
+ },
+ {
+ "x": 92.37829209136503,
+ "y": -54.530647727932184,
+ "z": 0.0
+ },
+ {
+ "x": 92.37813283997758,
+ "y": -53.48302869241722,
+ "z": 0.0
+ },
+ {
+ "x": 92.37797358859015,
+ "y": -52.435409656902316,
+ "z": 0.0
+ },
+ {
+ "x": 92.37781433720272,
+ "y": -51.38779062138738,
+ "z": 0.0
+ },
+ {
+ "x": 92.37765508581529,
+ "y": -50.34017158587245,
+ "z": 0.0
+ },
+ {
+ "x": 92.37749583442785,
+ "y": -49.292552550357485,
+ "z": 0.0
+ },
+ {
+ "x": 92.37733658304042,
+ "y": -48.24493351484257,
+ "z": 0.0
+ },
+ {
+ "x": 92.37717733165294,
+ "y": -47.19731447932759,
+ "z": 0.0
+ },
+ {
+ "x": 92.37701808026551,
+ "y": -46.14969544381273,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 228,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 92.38036235940167,
+ "y": -68.14969518962627,
+ "z": 0.0
+ },
+ {
+ "x": 92.38020563148586,
+ "y": -67.11867655529974,
+ "z": 0.0
+ },
+ {
+ "x": 92.38004890357007,
+ "y": -66.08765792097321,
+ "z": 0.0
+ },
+ {
+ "x": 92.37989217565426,
+ "y": -65.05663928664663,
+ "z": 0.0
+ },
+ {
+ "x": 92.41679137427337,
+ "y": -64.10235778117132,
+ "z": 0.0
+ },
+ {
+ "x": 92.51763841393722,
+ "y": -63.2185243615093,
+ "z": 0.0
+ },
+ {
+ "x": 92.75249091121461,
+ "y": -62.65696816837448,
+ "z": 0.0
+ },
+ {
+ "x": 93.10227471287547,
+ "y": -61.994795466111924,
+ "z": 0.0
+ },
+ {
+ "x": 93.54091380759029,
+ "y": -61.38592526043152,
+ "z": 0.0
+ },
+ {
+ "x": 94.05085061454383,
+ "y": -60.88220034541138,
+ "z": 0.0
+ },
+ {
+ "x": 94.61177279804552,
+ "y": -60.50871182938417,
+ "z": 0.0
+ },
+ {
+ "x": 95.31745354601713,
+ "y": -60.11314605700607,
+ "z": 0.0
+ },
+ {
+ "x": 96.06655349456925,
+ "y": -59.79291989053375,
+ "z": 0.0
+ },
+ {
+ "x": 96.77291820728992,
+ "y": -59.62570533772009,
+ "z": 0.0
+ },
+ {
+ "x": 97.53533400954645,
+ "y": -59.54021825949611,
+ "z": 0.0
+ },
+ {
+ "x": 98.41138621242084,
+ "y": -59.49574533581123,
+ "z": 0.0
+ },
+ {
+ "x": 99.32791510795805,
+ "y": -59.498913341565384,
+ "z": 0.0
+ },
+ {
+ "x": 100.35893374654256,
+ "y": -59.49878770907209,
+ "z": 0.0
+ },
+ {
+ "x": 101.3899523851271,
+ "y": -59.49866207657878,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 231,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 101.38975224562901,
+ "y": -55.49866207127013,
+ "z": 0.0
+ },
+ {
+ "x": 100.32582394992707,
+ "y": -55.498791713896836,
+ "z": 0.0
+ },
+ {
+ "x": 99.2618956542251,
+ "y": -55.49892135652354,
+ "z": 0.0
+ },
+ {
+ "x": 98.1054862504992,
+ "y": -55.551454169643684,
+ "z": 0.0
+ },
+ {
+ "x": 96.88035293790236,
+ "y": -55.709600800613835,
+ "z": 0.0
+ },
+ {
+ "x": 95.62580516803563,
+ "y": -56.01536736447157,
+ "z": 0.0
+ },
+ {
+ "x": 94.39865342573762,
+ "y": -56.47985266677764,
+ "z": 0.0
+ },
+ {
+ "x": 93.22010770181319,
+ "y": -57.12204012206544,
+ "z": 0.0
+ },
+ {
+ "x": 92.16829161636967,
+ "y": -57.86982439322365,
+ "z": 0.0
+ },
+ {
+ "x": 91.20693933306167,
+ "y": -58.74018071847535,
+ "z": 0.0
+ },
+ {
+ "x": 90.35163011330322,
+ "y": -59.732371836590005,
+ "z": 0.0
+ },
+ {
+ "x": 89.62431031515885,
+ "y": -60.834491340795715,
+ "z": 0.0
+ },
+ {
+ "x": 89.04863263105773,
+ "y": -62.08959445679456,
+ "z": 0.0
+ },
+ {
+ "x": 88.66727497953346,
+ "y": -63.36411188416538,
+ "z": 0.0
+ },
+ {
+ "x": 88.45615541789783,
+ "y": -64.66441986249069,
+ "z": 0.0
+ },
+ {
+ "x": 88.38263386183175,
+ "y": -65.91996545091644,
+ "z": 0.0
+ },
+ {
+ "x": 88.38020062513496,
+ "y": -67.08604681103495,
+ "z": 0.0
+ },
+ {
+ "x": 88.38036235573624,
+ "y": -68.149975102343,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 234,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 88.37701812648125,
+ "y": -46.15030349456475,
+ "z": 0.0
+ },
+ {
+ "x": 88.37717693375423,
+ "y": -47.195000968393984,
+ "z": 0.0
+ },
+ {
+ "x": 88.37777555539165,
+ "y": -48.2813367156901,
+ "z": 0.0
+ },
+ {
+ "x": 88.40536174558581,
+ "y": -49.43975162297693,
+ "z": 0.0
+ },
+ {
+ "x": 88.52949263747234,
+ "y": -50.762481608388775,
+ "z": 0.0
+ },
+ {
+ "x": 88.82128865116036,
+ "y": -52.00236474058616,
+ "z": 0.0
+ },
+ {
+ "x": 89.2484022072504,
+ "y": -53.190350440385586,
+ "z": 0.0
+ },
+ {
+ "x": 89.80299449894832,
+ "y": -54.32344184045015,
+ "z": 0.0
+ },
+ {
+ "x": 90.47934840662556,
+ "y": -55.389785788630775,
+ "z": 0.0
+ },
+ {
+ "x": 91.33162733593136,
+ "y": -56.43659369078458,
+ "z": 0.0
+ },
+ {
+ "x": 92.29930560058293,
+ "y": -57.31710245789597,
+ "z": 0.0
+ },
+ {
+ "x": 93.36514677863966,
+ "y": -58.05707488016186,
+ "z": 0.0
+ },
+ {
+ "x": 94.51557849293877,
+ "y": -58.65445385888668,
+ "z": 0.0
+ },
+ {
+ "x": 95.73336626093186,
+ "y": -59.10041730364373,
+ "z": 0.0
+ },
+ {
+ "x": 97.04842615778028,
+ "y": -59.3924109703997,
+ "z": 0.0
+ },
+ {
+ "x": 98.23211531382547,
+ "y": -59.48624809731275,
+ "z": 0.0
+ },
+ {
+ "x": 99.30051746549375,
+ "y": -59.498916680044445,
+ "z": 0.0
+ },
+ {
+ "x": 100.34521494363746,
+ "y": -59.49878938074643,
+ "z": 0.0
+ },
+ {
+ "x": 101.38991242178116,
+ "y": -59.498662081448416,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 237,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 101.38975224562901,
+ "y": -55.49866207127013,
+ "z": 0.0
+ },
+ {
+ "x": 100.35451945543977,
+ "y": -55.49878821726955,
+ "z": 0.0
+ },
+ {
+ "x": 99.3468932688754,
+ "y": -55.48506343129918,
+ "z": 0.0
+ },
+ {
+ "x": 98.42662430100265,
+ "y": -55.417625466811955,
+ "z": 0.0
+ },
+ {
+ "x": 97.6485517457146,
+ "y": -55.25379666365033,
+ "z": 0.0
+ },
+ {
+ "x": 96.83662282215542,
+ "y": -55.00957602877695,
+ "z": 0.0
+ },
+ {
+ "x": 96.04978126895155,
+ "y": -54.690974948978656,
+ "z": 0.0
+ },
+ {
+ "x": 95.34292935792287,
+ "y": -54.300343147111725,
+ "z": 0.0
+ },
+ {
+ "x": 94.69551164695628,
+ "y": -53.83370293027281,
+ "z": 0.0
+ },
+ {
+ "x": 94.0722995794701,
+ "y": -53.28615869571014,
+ "z": 0.0
+ },
+ {
+ "x": 93.53147317384932,
+ "y": -52.68638943767184,
+ "z": 0.0
+ },
+ {
+ "x": 93.11206255307954,
+ "y": -52.05384596541708,
+ "z": 0.0
+ },
+ {
+ "x": 92.81868923420566,
+ "y": -51.39541274371947,
+ "z": 0.0
+ },
+ {
+ "x": 92.57536532669909,
+ "y": -50.6445173026241,
+ "z": 0.0
+ },
+ {
+ "x": 92.42453828934885,
+ "y": -49.869001139017534,
+ "z": 0.0
+ },
+ {
+ "x": 92.37078360217731,
+ "y": -49.081449119815105,
+ "z": 0.0
+ },
+ {
+ "x": 92.37733179938255,
+ "y": -48.218720127865645,
+ "z": 0.0
+ },
+ {
+ "x": 92.37717550149249,
+ "y": -47.185274954994725,
+ "z": 0.0
+ },
+ {
+ "x": 92.37701813297217,
+ "y": -46.15004216908085,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 240,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 338.77358612560033,
+ "y": -209.16116984879852,
+ "z": 0.0
+ },
+ {
+ "x": 338.77421008887006,
+ "y": -208.12813694877926,
+ "z": 0.0
+ },
+ {
+ "x": 338.7748340521398,
+ "y": -207.09510404876008,
+ "z": 0.0
+ },
+ {
+ "x": 338.7754580154094,
+ "y": -206.0620711487407,
+ "z": 0.0
+ },
+ {
+ "x": 338.77608197867914,
+ "y": -205.0290382487214,
+ "z": 0.0
+ },
+ {
+ "x": 338.69324281461707,
+ "y": -203.84852588242197,
+ "z": 0.0
+ },
+ {
+ "x": 338.4560333486288,
+ "y": -202.5937711387159,
+ "z": 0.0
+ },
+ {
+ "x": 338.04777525570614,
+ "y": -201.36112786701733,
+ "z": 0.0
+ },
+ {
+ "x": 337.47674806992393,
+ "y": -200.19350299029531,
+ "z": 0.0
+ },
+ {
+ "x": 336.7491768192449,
+ "y": -199.10957978959715,
+ "z": 0.0
+ },
+ {
+ "x": 335.80614769553483,
+ "y": -198.10892696995305,
+ "z": 0.0
+ },
+ {
+ "x": 334.8162987013774,
+ "y": -197.30407433766342,
+ "z": 0.0
+ },
+ {
+ "x": 333.7649898013082,
+ "y": -196.62897077714314,
+ "z": 0.0
+ },
+ {
+ "x": 332.6538532577283,
+ "y": -196.07256717159595,
+ "z": 0.0
+ },
+ {
+ "x": 331.4882291636196,
+ "y": -195.63627292305696,
+ "z": 0.0
+ },
+ {
+ "x": 330.21446207409156,
+ "y": -195.34317675727266,
+ "z": 0.0
+ },
+ {
+ "x": 328.97164850065326,
+ "y": -195.20398179351594,
+ "z": 0.0
+ },
+ {
+ "x": 327.8028929609527,
+ "y": -195.16038550288124,
+ "z": 0.0
+ },
+ {
+ "x": 326.7035191941376,
+ "y": -195.15919559105376,
+ "z": 0.0
+ },
+ {
+ "x": 325.67048610908853,
+ "y": -195.15911164734354,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 243,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 325.6698379252599,
+ "y": -199.15911160787866,
+ "z": 0.0
+ },
+ {
+ "x": 326.698705458449,
+ "y": -199.1591952130984,
+ "z": 0.0
+ },
+ {
+ "x": 327.64217907066535,
+ "y": -199.15744801084946,
+ "z": 0.0
+ },
+ {
+ "x": 328.52144543613406,
+ "y": -199.18957761215478,
+ "z": 0.0
+ },
+ {
+ "x": 329.33788028665595,
+ "y": -199.27490103789137,
+ "z": 0.0
+ },
+ {
+ "x": 330.07872304962353,
+ "y": -199.42141425818107,
+ "z": 0.0
+ },
+ {
+ "x": 330.8432506839614,
+ "y": -199.69421323637448,
+ "z": 0.0
+ },
+ {
+ "x": 331.58171654626835,
+ "y": -200.05387914235382,
+ "z": 0.0
+ },
+ {
+ "x": 332.27416847227875,
+ "y": -200.48357346066885,
+ "z": 0.0
+ },
+ {
+ "x": 332.89058912936,
+ "y": -200.95693908574123,
+ "z": 0.0
+ },
+ {
+ "x": 333.400252169316,
+ "y": -201.44391373597452,
+ "z": 0.0
+ },
+ {
+ "x": 333.85486512684065,
+ "y": -202.06898774610787,
+ "z": 0.0
+ },
+ {
+ "x": 334.22487174474423,
+ "y": -202.74504561156255,
+ "z": 0.0
+ },
+ {
+ "x": 334.5053961897313,
+ "y": -203.46220442450982,
+ "z": 0.0
+ },
+ {
+ "x": 334.6904965133175,
+ "y": -204.1895319344917,
+ "z": 0.0
+ },
+ {
+ "x": 334.7707155407038,
+ "y": -205.05396810570983,
+ "z": 0.0
+ },
+ {
+ "x": 334.7754511969514,
+ "y": -206.07215175838857,
+ "z": 0.0
+ },
+ {
+ "x": 334.77482974972054,
+ "y": -207.101019107294,
+ "z": 0.0
+ },
+ {
+ "x": 334.7742083024897,
+ "y": -208.12988645619942,
+ "z": 0.0
+ },
+ {
+ "x": 334.7735868552588,
+ "y": -209.15875380510485,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 246,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 334.78778715206863,
+ "y": -185.6487580936724,
+ "z": 0.0
+ },
+ {
+ "x": 334.787155504427,
+ "y": -186.69451323135144,
+ "z": 0.0
+ },
+ {
+ "x": 334.78754032623203,
+ "y": -187.6777088195608,
+ "z": 0.0
+ },
+ {
+ "x": 334.7615276547244,
+ "y": -188.60365903590986,
+ "z": 0.0
+ },
+ {
+ "x": 334.7144096790263,
+ "y": -189.3547372712996,
+ "z": 0.0
+ },
+ {
+ "x": 334.5374160576254,
+ "y": -190.1438427004075,
+ "z": 0.0
+ },
+ {
+ "x": 334.25838016768733,
+ "y": -190.92490920055405,
+ "z": 0.0
+ },
+ {
+ "x": 333.897785897096,
+ "y": -191.67086593067626,
+ "z": 0.0
+ },
+ {
+ "x": 333.5024894926457,
+ "y": -192.32274605647348,
+ "z": 0.0
+ },
+ {
+ "x": 332.9903625762737,
+ "y": -192.93797550733024,
+ "z": 0.0
+ },
+ {
+ "x": 332.3794707414414,
+ "y": -193.50480830036958,
+ "z": 0.0
+ },
+ {
+ "x": 331.7127141752909,
+ "y": -194.00395343470421,
+ "z": 0.0
+ },
+ {
+ "x": 331.05090017930854,
+ "y": -194.40768723334773,
+ "z": 0.0
+ },
+ {
+ "x": 330.3217752004306,
+ "y": -194.72386373113207,
+ "z": 0.0
+ },
+ {
+ "x": 329.51933956980224,
+ "y": -194.9515978352368,
+ "z": 0.0
+ },
+ {
+ "x": 328.67413547068077,
+ "y": -195.09519055948655,
+ "z": 0.0
+ },
+ {
+ "x": 327.76202119740066,
+ "y": -195.15928160435453,
+ "z": 0.0
+ },
+ {
+ "x": 326.7162658724131,
+ "y": -195.15919662684195,
+ "z": 0.0
+ },
+ {
+ "x": 325.67051054742564,
+ "y": -195.1591116493294,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 249,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 325.6698379252599,
+ "y": -199.15911160787866,
+ "z": 0.0
+ },
+ {
+ "x": 326.71138163818864,
+ "y": -199.1591962431579,
+ "z": 0.0
+ },
+ {
+ "x": 327.8492730069305,
+ "y": -199.15696665098056,
+ "z": 0.0
+ },
+ {
+ "x": 329.0903995103214,
+ "y": -199.08696153947074,
+ "z": 0.0
+ },
+ {
+ "x": 330.35957533320914,
+ "y": -198.88056682846835,
+ "z": 0.0
+ },
+ {
+ "x": 331.5936119652358,
+ "y": -198.5191337594488,
+ "z": 0.0
+ },
+ {
+ "x": 332.7739635436144,
+ "y": -198.00803518202366,
+ "z": 0.0
+ },
+ {
+ "x": 333.8828403175662,
+ "y": -197.35480324247453,
+ "z": 0.0
+ },
+ {
+ "x": 334.91750112386575,
+ "y": -196.5553271582158,
+ "z": 0.0
+ },
+ {
+ "x": 335.82219654976586,
+ "y": -195.64340922047694,
+ "z": 0.0
+ },
+ {
+ "x": 336.58969986776356,
+ "y": -194.65980949230965,
+ "z": 0.0
+ },
+ {
+ "x": 337.2504434774229,
+ "y": -193.60412357405087,
+ "z": 0.0
+ },
+ {
+ "x": 337.79922846031434,
+ "y": -192.48667964832532,
+ "z": 0.0
+ },
+ {
+ "x": 338.23048861397376,
+ "y": -191.31898851495265,
+ "z": 0.0
+ },
+ {
+ "x": 338.53979013659995,
+ "y": -190.11303929208032,
+ "z": 0.0
+ },
+ {
+ "x": 338.72349839333293,
+ "y": -188.8878609136412,
+ "z": 0.0
+ },
+ {
+ "x": 338.78652799858696,
+ "y": -187.7346192289334,
+ "z": 0.0
+ },
+ {
+ "x": 338.78715710236884,
+ "y": -186.69307570255887,
+ "z": 0.0
+ },
+ {
+ "x": 338.7877862061507,
+ "y": -185.65153217618433,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 252,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 334.78778715206863,
+ "y": -185.64875809367237,
+ "z": 0.0
+ },
+ {
+ "x": 334.7871697478595,
+ "y": -186.6709318202565,
+ "z": 0.0
+ },
+ {
+ "x": 334.7865523436503,
+ "y": -187.6931055468404,
+ "z": 0.0
+ },
+ {
+ "x": 334.7859349394412,
+ "y": -188.71527927342453,
+ "z": 0.0
+ },
+ {
+ "x": 334.78531753523214,
+ "y": -189.73745300000843,
+ "z": 0.0
+ },
+ {
+ "x": 334.784700131023,
+ "y": -190.75962672659244,
+ "z": 0.0
+ },
+ {
+ "x": 334.78408272681384,
+ "y": -191.78180045317663,
+ "z": 0.0
+ },
+ {
+ "x": 334.7834653226047,
+ "y": -192.80397417976064,
+ "z": 0.0
+ },
+ {
+ "x": 334.78284791839565,
+ "y": -193.82614790634466,
+ "z": 0.0
+ },
+ {
+ "x": 334.7822305141865,
+ "y": -194.84832163292856,
+ "z": 0.0
+ },
+ {
+ "x": 334.78161310997734,
+ "y": -195.8704953595127,
+ "z": 0.0
+ },
+ {
+ "x": 334.7809957057683,
+ "y": -196.8926690860966,
+ "z": 0.0
+ },
+ {
+ "x": 334.78037830155915,
+ "y": -197.91484281268072,
+ "z": 0.0
+ },
+ {
+ "x": 334.77976089735,
+ "y": -198.93701653926462,
+ "z": 0.0
+ },
+ {
+ "x": 334.77914349314085,
+ "y": -199.95919026584875,
+ "z": 0.0
+ },
+ {
+ "x": 334.7785260889318,
+ "y": -200.98136399243265,
+ "z": 0.0
+ },
+ {
+ "x": 334.77790868472266,
+ "y": -202.00353771901678,
+ "z": 0.0
+ },
+ {
+ "x": 334.7772912805135,
+ "y": -203.0257114456008,
+ "z": 0.0
+ },
+ {
+ "x": 334.77667387630447,
+ "y": -204.0478851721847,
+ "z": 0.0
+ },
+ {
+ "x": 334.7760564720953,
+ "y": -205.07005889876882,
+ "z": 0.0
+ },
+ {
+ "x": 334.77543906788617,
+ "y": -206.09223262535272,
+ "z": 0.0
+ },
+ {
+ "x": 334.774821663677,
+ "y": -207.11440635193674,
+ "z": 0.0
+ },
+ {
+ "x": 334.77420425946787,
+ "y": -208.13658007852086,
+ "z": 0.0
+ },
+ {
+ "x": 334.7735868552588,
+ "y": -209.15875380510488,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 253,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 340.77358576077114,
+ "y": -209.16237787064532,
+ "z": 0.0
+ },
+ {
+ "x": 340.77420316498024,
+ "y": -208.1402041440613,
+ "z": 0.0
+ },
+ {
+ "x": 340.7748205691894,
+ "y": -207.1180304174775,
+ "z": 0.0
+ },
+ {
+ "x": 340.77543797339854,
+ "y": -206.0958566908935,
+ "z": 0.0
+ },
+ {
+ "x": 340.77605537760763,
+ "y": -205.07368296430926,
+ "z": 0.0
+ },
+ {
+ "x": 340.7766727818168,
+ "y": -204.05150923772547,
+ "z": 0.0
+ },
+ {
+ "x": 340.7772901860259,
+ "y": -203.02933551114123,
+ "z": 0.0
+ },
+ {
+ "x": 340.777907590235,
+ "y": -202.00716178455718,
+ "z": 0.0
+ },
+ {
+ "x": 340.7785249944441,
+ "y": -200.9849880579734,
+ "z": 0.0
+ },
+ {
+ "x": 340.7791423986532,
+ "y": -199.96281433138915,
+ "z": 0.0
+ },
+ {
+ "x": 340.7797598028624,
+ "y": -198.94064060480537,
+ "z": 0.0
+ },
+ {
+ "x": 340.78037720707147,
+ "y": -197.91846687822112,
+ "z": 0.0
+ },
+ {
+ "x": 340.7809946112806,
+ "y": -196.89629315163734,
+ "z": 0.0
+ },
+ {
+ "x": 340.7816120154897,
+ "y": -195.8741194250531,
+ "z": 0.0
+ },
+ {
+ "x": 340.78222941969887,
+ "y": -194.8519456984693,
+ "z": 0.0
+ },
+ {
+ "x": 340.78284682390796,
+ "y": -193.82977197188507,
+ "z": 0.0
+ },
+ {
+ "x": 340.78346422811705,
+ "y": -192.80759824530105,
+ "z": 0.0
+ },
+ {
+ "x": 340.78408163232615,
+ "y": -191.78542451871704,
+ "z": 0.0
+ },
+ {
+ "x": 340.7846990365353,
+ "y": -190.76325079213322,
+ "z": 0.0
+ },
+ {
+ "x": 340.78531644074445,
+ "y": -189.7410770655492,
+ "z": 0.0
+ },
+ {
+ "x": 340.78593384495355,
+ "y": -188.71890333896496,
+ "z": 0.0
+ },
+ {
+ "x": 340.7865512491627,
+ "y": -187.69672961238118,
+ "z": 0.0
+ },
+ {
+ "x": 340.7871686533718,
+ "y": -186.67455588579693,
+ "z": 0.0
+ },
+ {
+ "x": 340.78778605758094,
+ "y": -185.65238215921315,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 255,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 338.77358612560033,
+ "y": -209.16116984879852,
+ "z": 0.0
+ },
+ {
+ "x": 338.7742035298095,
+ "y": -208.1389961222145,
+ "z": 0.0
+ },
+ {
+ "x": 338.77482093401863,
+ "y": -207.1168223956306,
+ "z": 0.0
+ },
+ {
+ "x": 338.7754383382278,
+ "y": -206.0946486690466,
+ "z": 0.0
+ },
+ {
+ "x": 338.7760557424368,
+ "y": -205.07247494246246,
+ "z": 0.0
+ },
+ {
+ "x": 338.776673146646,
+ "y": -204.05030121587856,
+ "z": 0.0
+ },
+ {
+ "x": 338.7772905508551,
+ "y": -203.02812748929443,
+ "z": 0.0
+ },
+ {
+ "x": 338.77790795506417,
+ "y": -202.00595376271036,
+ "z": 0.0
+ },
+ {
+ "x": 338.7785253592733,
+ "y": -200.98378003612646,
+ "z": 0.0
+ },
+ {
+ "x": 338.77914276348247,
+ "y": -199.96160630954233,
+ "z": 0.0
+ },
+ {
+ "x": 338.7797601676916,
+ "y": -198.93943258295843,
+ "z": 0.0
+ },
+ {
+ "x": 338.78037757190066,
+ "y": -197.9172588563743,
+ "z": 0.0
+ },
+ {
+ "x": 338.7809949761098,
+ "y": -196.8950851297904,
+ "z": 0.0
+ },
+ {
+ "x": 338.78161238031896,
+ "y": -195.87291140320627,
+ "z": 0.0
+ },
+ {
+ "x": 338.7822297845281,
+ "y": -194.85073767662237,
+ "z": 0.0
+ },
+ {
+ "x": 338.78284718873715,
+ "y": -193.82856395003824,
+ "z": 0.0
+ },
+ {
+ "x": 338.7834645929463,
+ "y": -192.80639022345423,
+ "z": 0.0
+ },
+ {
+ "x": 338.78408199715534,
+ "y": -191.78421649687021,
+ "z": 0.0
+ },
+ {
+ "x": 338.7846994013645,
+ "y": -190.7620427702863,
+ "z": 0.0
+ },
+ {
+ "x": 338.78531680557364,
+ "y": -189.7398690437023,
+ "z": 0.0
+ },
+ {
+ "x": 338.7859342097828,
+ "y": -188.71769531711817,
+ "z": 0.0
+ },
+ {
+ "x": 338.78655161399195,
+ "y": -187.69552159053427,
+ "z": 0.0
+ },
+ {
+ "x": 338.787169018201,
+ "y": -186.67334786395014,
+ "z": 0.0
+ },
+ {
+ "x": 338.78778642241014,
+ "y": -185.65117413736624,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 258,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 325.1602379954887,
+ "y": -59.47139504390145,
+ "z": 0.0
+ },
+ {
+ "x": 326.19698562451595,
+ "y": -59.47126871331473,
+ "z": 0.0
+ },
+ {
+ "x": 327.2337332535433,
+ "y": -59.471142382727976,
+ "z": 0.0
+ },
+ {
+ "x": 328.1307756152667,
+ "y": -59.466147760085974,
+ "z": 0.0
+ },
+ {
+ "x": 328.95765628647047,
+ "y": -59.51302416468887,
+ "z": 0.0
+ },
+ {
+ "x": 329.76671371919963,
+ "y": -59.643665082959686,
+ "z": 0.0
+ },
+ {
+ "x": 330.5566609642443,
+ "y": -59.860369230187196,
+ "z": 0.0
+ },
+ {
+ "x": 331.29314170067073,
+ "y": -60.146422142017485,
+ "z": 0.0
+ },
+ {
+ "x": 331.9768652134147,
+ "y": -60.51140009081671,
+ "z": 0.0
+ },
+ {
+ "x": 332.63035777743755,
+ "y": -60.98553706174534,
+ "z": 0.0
+ },
+ {
+ "x": 333.21354991847267,
+ "y": -61.51730905876411,
+ "z": 0.0
+ },
+ {
+ "x": 333.72272706335207,
+ "y": -62.1093268069832,
+ "z": 0.0
+ },
+ {
+ "x": 334.1393827093261,
+ "y": -62.73036296148267,
+ "z": 0.0
+ },
+ {
+ "x": 334.4598578619131,
+ "y": -63.39449632595675,
+ "z": 0.0
+ },
+ {
+ "x": 334.6829992249576,
+ "y": -64.14494231539462,
+ "z": 0.0
+ },
+ {
+ "x": 334.8114809369437,
+ "y": -64.98371014715602,
+ "z": 0.0
+ },
+ {
+ "x": 334.86010552665084,
+ "y": -65.91853702404615,
+ "z": 0.0
+ },
+ {
+ "x": 334.8594793197534,
+ "y": -66.95528447165245,
+ "z": 0.0
+ },
+ {
+ "x": 334.8588531128561,
+ "y": -67.99203191925852,
+ "z": 0.0
+ },
+ {
+ "x": 334.85822690595865,
+ "y": -69.02877936686474,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 261,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 338.85822617630015,
+ "y": -69.03119541055852,
+ "z": 0.0
+ },
+ {
+ "x": 338.85888005386664,
+ "y": -67.9486364339345,
+ "z": 0.0
+ },
+ {
+ "x": 338.859533931433,
+ "y": -66.86607745731037,
+ "z": 0.0
+ },
+ {
+ "x": 338.8453984688475,
+ "y": -65.75709899297308,
+ "z": 0.0
+ },
+ {
+ "x": 338.74794995835043,
+ "y": -64.5367784122154,
+ "z": 0.0
+ },
+ {
+ "x": 338.4478942489203,
+ "y": -63.1866427882245,
+ "z": 0.0
+ },
+ {
+ "x": 337.99539461249424,
+ "y": -61.93906013241491,
+ "z": 0.0
+ },
+ {
+ "x": 337.3918416838258,
+ "y": -60.757355585741436,
+ "z": 0.0
+ },
+ {
+ "x": 336.64510581466607,
+ "y": -59.65772951311925,
+ "z": 0.0
+ },
+ {
+ "x": 335.7099172537774,
+ "y": -58.63869350658027,
+ "z": 0.0
+ },
+ {
+ "x": 334.67415102685993,
+ "y": -57.77989147387602,
+ "z": 0.0
+ },
+ {
+ "x": 333.5955595287653,
+ "y": -57.070160318935095,
+ "z": 0.0
+ },
+ {
+ "x": 332.451682977315,
+ "y": -56.47803873653796,
+ "z": 0.0
+ },
+ {
+ "x": 331.24690110232734,
+ "y": -56.00756770704959,
+ "z": 0.0
+ },
+ {
+ "x": 329.9146552998319,
+ "y": -55.688996711487064,
+ "z": 0.0
+ },
+ {
+ "x": 328.6363731316137,
+ "y": -55.52987162210784,
+ "z": 0.0
+ },
+ {
+ "x": 327.4090981995594,
+ "y": -55.47289540543303,
+ "z": 0.0
+ },
+ {
+ "x": 326.2423097504109,
+ "y": -55.47126316074751,
+ "z": 0.0
+ },
+ {
+ "x": 325.15975058434924,
+ "y": -55.47139507359766,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 264,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 334.87188359293737,
+ "y": -46.41878349125916,
+ "z": 0.0
+ },
+ {
+ "x": 334.8712628344383,
+ "y": -47.446510576513944,
+ "z": 0.0
+ },
+ {
+ "x": 334.87064207593926,
+ "y": -48.47423766176885,
+ "z": 0.0
+ },
+ {
+ "x": 334.8700213174402,
+ "y": -49.501964747023536,
+ "z": 0.0
+ },
+ {
+ "x": 334.86940055894115,
+ "y": -50.529691832278345,
+ "z": 0.0
+ },
+ {
+ "x": 334.8687798004421,
+ "y": -51.55741891753325,
+ "z": 0.0
+ },
+ {
+ "x": 334.86815904194316,
+ "y": -52.58514600278794,
+ "z": 0.0
+ },
+ {
+ "x": 334.8675382834441,
+ "y": -53.612873088042846,
+ "z": 0.0
+ },
+ {
+ "x": 334.86691752494505,
+ "y": -54.64060017329754,
+ "z": 0.0
+ },
+ {
+ "x": 334.866296766446,
+ "y": -55.66832725855234,
+ "z": 0.0
+ },
+ {
+ "x": 334.86567600794694,
+ "y": -56.69605434380725,
+ "z": 0.0
+ },
+ {
+ "x": 334.865055249448,
+ "y": -57.72378142906193,
+ "z": 0.0
+ },
+ {
+ "x": 334.86443449094895,
+ "y": -58.75150851431674,
+ "z": 0.0
+ },
+ {
+ "x": 334.8638137324499,
+ "y": -59.77923559957164,
+ "z": 0.0
+ },
+ {
+ "x": 334.86319297395085,
+ "y": -60.80696268482633,
+ "z": 0.0
+ },
+ {
+ "x": 334.8625722154518,
+ "y": -61.83468977008113,
+ "z": 0.0
+ },
+ {
+ "x": 334.86195145695274,
+ "y": -62.862416855336036,
+ "z": 0.0
+ },
+ {
+ "x": 334.8613306984538,
+ "y": -63.89014394059084,
+ "z": 0.0
+ },
+ {
+ "x": 334.86070993995475,
+ "y": -64.91787102584553,
+ "z": 0.0
+ },
+ {
+ "x": 334.8600891814557,
+ "y": -65.94559811110031,
+ "z": 0.0
+ },
+ {
+ "x": 334.85946842295664,
+ "y": -66.97332519635523,
+ "z": 0.0
+ },
+ {
+ "x": 334.8588476644577,
+ "y": -68.00105228160993,
+ "z": 0.0
+ },
+ {
+ "x": 334.85822690595865,
+ "y": -69.02877936686471,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 265,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 340.85822581147096,
+ "y": -69.03240343240542,
+ "z": 0.0
+ },
+ {
+ "x": 340.85884656997,
+ "y": -68.00467634715062,
+ "z": 0.0
+ },
+ {
+ "x": 340.859467328469,
+ "y": -66.9769492618956,
+ "z": 0.0
+ },
+ {
+ "x": 340.86008808696806,
+ "y": -65.94922217664102,
+ "z": 0.0
+ },
+ {
+ "x": 340.8607088454671,
+ "y": -64.92149509138622,
+ "z": 0.0
+ },
+ {
+ "x": 340.8613296039661,
+ "y": -63.8937680061312,
+ "z": 0.0
+ },
+ {
+ "x": 340.8619503624651,
+ "y": -62.866040920876394,
+ "z": 0.0
+ },
+ {
+ "x": 340.86257112096416,
+ "y": -61.83831383562182,
+ "z": 0.0
+ },
+ {
+ "x": 340.8631918794632,
+ "y": -60.810586750367015,
+ "z": 0.0
+ },
+ {
+ "x": 340.8638126379622,
+ "y": -59.782859665112,
+ "z": 0.0
+ },
+ {
+ "x": 340.86443339646127,
+ "y": -58.755132579857424,
+ "z": 0.0
+ },
+ {
+ "x": 340.8650541549603,
+ "y": -57.72740549460262,
+ "z": 0.0
+ },
+ {
+ "x": 340.8656749134593,
+ "y": -56.699678409347605,
+ "z": 0.0
+ },
+ {
+ "x": 340.86629567195837,
+ "y": -55.67195132409302,
+ "z": 0.0
+ },
+ {
+ "x": 340.8669164304574,
+ "y": -54.64422423883823,
+ "z": 0.0
+ },
+ {
+ "x": 340.8675371889564,
+ "y": -53.616497153583204,
+ "z": 0.0
+ },
+ {
+ "x": 340.8681579474555,
+ "y": -52.58877006832863,
+ "z": 0.0
+ },
+ {
+ "x": 340.86877870595447,
+ "y": -51.561042983073605,
+ "z": 0.0
+ },
+ {
+ "x": 340.8693994644535,
+ "y": -50.53331589781903,
+ "z": 0.0
+ },
+ {
+ "x": 340.8700202229526,
+ "y": -49.50558881256423,
+ "z": 0.0
+ },
+ {
+ "x": 340.8706409814516,
+ "y": -48.47786172730921,
+ "z": 0.0
+ },
+ {
+ "x": 340.8712617399506,
+ "y": -47.45013464205463,
+ "z": 0.0
+ },
+ {
+ "x": 340.8718824984497,
+ "y": -46.42240755679985,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 267,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 338.85822617630015,
+ "y": -69.03119541055852,
+ "z": 0.0
+ },
+ {
+ "x": 338.8588469347992,
+ "y": -68.00346832530371,
+ "z": 0.0
+ },
+ {
+ "x": 338.85946769329826,
+ "y": -66.97574124004882,
+ "z": 0.0
+ },
+ {
+ "x": 338.8600884517973,
+ "y": -65.94801415479412,
+ "z": 0.0
+ },
+ {
+ "x": 338.86070921029636,
+ "y": -64.92028706953931,
+ "z": 0.0
+ },
+ {
+ "x": 338.8613299687953,
+ "y": -63.89255998428441,
+ "z": 0.0
+ },
+ {
+ "x": 338.86195072729436,
+ "y": -62.86483289902961,
+ "z": 0.0
+ },
+ {
+ "x": 338.8625714857934,
+ "y": -61.837105813774926,
+ "z": 0.0
+ },
+ {
+ "x": 338.86319224429246,
+ "y": -60.809378728520116,
+ "z": 0.0
+ },
+ {
+ "x": 338.8638130027914,
+ "y": -59.781651643265214,
+ "z": 0.0
+ },
+ {
+ "x": 338.86443376129046,
+ "y": -58.753924558010524,
+ "z": 0.0
+ },
+ {
+ "x": 338.8650545197895,
+ "y": -57.72619747275573,
+ "z": 0.0
+ },
+ {
+ "x": 338.86567527828856,
+ "y": -56.69847038750082,
+ "z": 0.0
+ },
+ {
+ "x": 338.8662960367876,
+ "y": -55.67074330224612,
+ "z": 0.0
+ },
+ {
+ "x": 338.86691679528667,
+ "y": -54.64301621699133,
+ "z": 0.0
+ },
+ {
+ "x": 338.8675375537856,
+ "y": -53.61528913173642,
+ "z": 0.0
+ },
+ {
+ "x": 338.86815831228466,
+ "y": -52.587562046481736,
+ "z": 0.0
+ },
+ {
+ "x": 338.8687790707837,
+ "y": -51.55983496122682,
+ "z": 0.0
+ },
+ {
+ "x": 338.86939982928277,
+ "y": -50.53210787597213,
+ "z": 0.0
+ },
+ {
+ "x": 338.8700205877818,
+ "y": -49.504380790717335,
+ "z": 0.0
+ },
+ {
+ "x": 338.87064134628076,
+ "y": -48.476653705462425,
+ "z": 0.0
+ },
+ {
+ "x": 338.8712621047798,
+ "y": -47.44892662020773,
+ "z": 0.0
+ },
+ {
+ "x": 338.87188286327887,
+ "y": -46.42119953495295,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 270,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 325.1602379954888,
+ "y": -59.47139504390147,
+ "z": 0.0
+ },
+ {
+ "x": 326.2277182989171,
+ "y": -59.470929141072,
+ "z": 0.0
+ },
+ {
+ "x": 327.35842293823544,
+ "y": -59.44753903629696,
+ "z": 0.0
+ },
+ {
+ "x": 328.6249307256167,
+ "y": -59.34585779940172,
+ "z": 0.0
+ },
+ {
+ "x": 329.83283393607644,
+ "y": -59.10445994848552,
+ "z": 0.0
+ },
+ {
+ "x": 330.99854190970746,
+ "y": -58.7476302319203,
+ "z": 0.0
+ },
+ {
+ "x": 332.12450630869796,
+ "y": -58.282204730606395,
+ "z": 0.0
+ },
+ {
+ "x": 333.2016302091149,
+ "y": -57.71199354431562,
+ "z": 0.0
+ },
+ {
+ "x": 334.2573023836869,
+ "y": -57.01204403553369,
+ "z": 0.0
+ },
+ {
+ "x": 335.20689490297315,
+ "y": -56.209077266950956,
+ "z": 0.0
+ },
+ {
+ "x": 336.0601484015708,
+ "y": -55.316518481772064,
+ "z": 0.0
+ },
+ {
+ "x": 336.81763920173995,
+ "y": -54.34038408681393,
+ "z": 0.0
+ },
+ {
+ "x": 337.4701625516368,
+ "y": -53.29086134605254,
+ "z": 0.0
+ },
+ {
+ "x": 338.02303709250344,
+ "y": -52.14534488442073,
+ "z": 0.0
+ },
+ {
+ "x": 338.43226232151005,
+ "y": -50.94637169459995,
+ "z": 0.0
+ },
+ {
+ "x": 338.69371665328697,
+ "y": -49.73742888246052,
+ "z": 0.0
+ },
+ {
+ "x": 338.8269504095423,
+ "y": -48.563284388624226,
+ "z": 0.0
+ },
+ {
+ "x": 338.87125999734656,
+ "y": -47.45241568426286,
+ "z": 0.0
+ },
+ {
+ "x": 338.87188263035193,
+ "y": -46.42158516849574,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 273,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 334.87188359293725,
+ "y": -46.41878349125915,
+ "z": 0.0
+ },
+ {
+ "x": 334.8712500900183,
+ "y": -47.46781103382229,
+ "z": 0.0
+ },
+ {
+ "x": 334.87465533163515,
+ "y": -48.3867486297635,
+ "z": 0.0
+ },
+ {
+ "x": 334.8340411563869,
+ "y": -49.20269489318105,
+ "z": 0.0
+ },
+ {
+ "x": 334.6984352919744,
+ "y": -50.00884118128332,
+ "z": 0.0
+ },
+ {
+ "x": 334.4706425605684,
+ "y": -50.79323570818916,
+ "z": 0.0
+ },
+ {
+ "x": 334.1537904682107,
+ "y": -51.545608539108564,
+ "z": 0.0
+ },
+ {
+ "x": 333.75211379318347,
+ "y": -52.25610409194188,
+ "z": 0.0
+ },
+ {
+ "x": 333.27060793851547,
+ "y": -52.9157049023742,
+ "z": 0.0
+ },
+ {
+ "x": 332.71479896932226,
+ "y": -53.51645171938627,
+ "z": 0.0
+ },
+ {
+ "x": 332.0924357454257,
+ "y": -54.05035381817845,
+ "z": 0.0
+ },
+ {
+ "x": 331.427675970019,
+ "y": -54.50254431697783,
+ "z": 0.0
+ },
+ {
+ "x": 330.7094081648772,
+ "y": -54.87085310925545,
+ "z": 0.0
+ },
+ {
+ "x": 329.9383881173603,
+ "y": -55.15215650825121,
+ "z": 0.0
+ },
+ {
+ "x": 329.14101179884665,
+ "y": -55.343337898478175,
+ "z": 0.0
+ },
+ {
+ "x": 328.25269461726884,
+ "y": -55.442782093772266,
+ "z": 0.0
+ },
+ {
+ "x": 327.2591991124581,
+ "y": -55.47113924994592,
+ "z": 0.0
+ },
+ {
+ "x": 326.2094748484037,
+ "y": -55.471267161771806,
+ "z": 0.0
+ },
+ {
+ "x": 325.15975058434924,
+ "y": -55.47139507359766,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 276,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 92.4016714980064,
+ "y": -208.32969356999655,
+ "z": 0.0
+ },
+ {
+ "x": 92.40151480877489,
+ "y": -207.29892941643521,
+ "z": 0.0
+ },
+ {
+ "x": 92.4013581195434,
+ "y": -206.26816526287388,
+ "z": 0.0
+ },
+ {
+ "x": 92.4348956724687,
+ "y": -205.30636743927084,
+ "z": 0.0
+ },
+ {
+ "x": 92.52818843367211,
+ "y": -204.4130756059148,
+ "z": 0.0
+ },
+ {
+ "x": 92.72123588524576,
+ "y": -203.67070398173175,
+ "z": 0.0
+ },
+ {
+ "x": 93.00974965835567,
+ "y": -202.95958489921435,
+ "z": 0.0
+ },
+ {
+ "x": 93.38865416626015,
+ "y": -202.2434998249028,
+ "z": 0.0
+ },
+ {
+ "x": 93.84361125052354,
+ "y": -201.57227382694185,
+ "z": 0.0
+ },
+ {
+ "x": 94.3679482439317,
+ "y": -200.96386620483992,
+ "z": 0.0
+ },
+ {
+ "x": 94.92835006058691,
+ "y": -200.49959300260977,
+ "z": 0.0
+ },
+ {
+ "x": 95.59256725930115,
+ "y": -200.05094130665384,
+ "z": 0.0
+ },
+ {
+ "x": 96.30313513512215,
+ "y": -199.6804342777397,
+ "z": 0.0
+ },
+ {
+ "x": 97.05276059073066,
+ "y": -199.39214154117593,
+ "z": 0.0
+ },
+ {
+ "x": 97.78075795641391,
+ "y": -199.23561854958365,
+ "z": 0.0
+ },
+ {
+ "x": 98.54816831250857,
+ "y": -199.1678728105677,
+ "z": 0.0
+ },
+ {
+ "x": 99.4342641119304,
+ "y": -199.1392723209954,
+ "z": 0.0
+ },
+ {
+ "x": 100.38873984010004,
+ "y": -199.1408053875916,
+ "z": 0.0
+ },
+ {
+ "x": 101.41950400216771,
+ "y": -199.14088914693036,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 279,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 101.4201637034698,
+ "y": -195.14088918733114,
+ "z": 0.0
+ },
+ {
+ "x": 100.34443380692284,
+ "y": -195.14080177410108,
+ "z": 0.0
+ },
+ {
+ "x": 99.22213065499349,
+ "y": -195.16674073057283,
+ "z": 0.0
+ },
+ {
+ "x": 98.00848018727567,
+ "y": -195.27836301508296,
+ "z": 0.0
+ },
+ {
+ "x": 96.7360855044522,
+ "y": -195.53387222132216,
+ "z": 0.0
+ },
+ {
+ "x": 95.49935446175567,
+ "y": -195.9299935677057,
+ "z": 0.0
+ },
+ {
+ "x": 94.30099645201025,
+ "y": -196.47952520287916,
+ "z": 0.0
+ },
+ {
+ "x": 93.18455033163266,
+ "y": -197.1596159343103,
+ "z": 0.0
+ },
+ {
+ "x": 92.15917603136714,
+ "y": -197.95480405569515,
+ "z": 0.0
+ },
+ {
+ "x": 91.22713561220709,
+ "y": -198.86627341871213,
+ "z": 0.0
+ },
+ {
+ "x": 90.40428222001984,
+ "y": -199.88960224606478,
+ "z": 0.0
+ },
+ {
+ "x": 89.70987654025186,
+ "y": -201.00743384361795,
+ "z": 0.0
+ },
+ {
+ "x": 89.15614980628833,
+ "y": -202.20137215494867,
+ "z": 0.0
+ },
+ {
+ "x": 88.7512504331463,
+ "y": -203.45401329200402,
+ "z": 0.0
+ },
+ {
+ "x": 88.50121720547153,
+ "y": -204.74710415228492,
+ "z": 0.0
+ },
+ {
+ "x": 88.40530287705167,
+ "y": -206.05240752625747,
+ "z": 0.0
+ },
+ {
+ "x": 88.40150796490579,
+ "y": -207.25421174575615,
+ "z": 0.0
+ },
+ {
+ "x": 88.40167148949946,
+ "y": -208.3299416334258,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 280,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 86.39832728819378,
+ "y": -186.330605900311,
+ "z": 0.0
+ },
+ {
+ "x": 86.39848653958121,
+ "y": -187.37822493582607,
+ "z": 0.0
+ },
+ {
+ "x": 86.39864579096867,
+ "y": -188.42584397134087,
+ "z": 0.0
+ },
+ {
+ "x": 86.3988050423561,
+ "y": -189.47346300685584,
+ "z": 0.0
+ },
+ {
+ "x": 86.39896429374355,
+ "y": -190.52108204237072,
+ "z": 0.0
+ },
+ {
+ "x": 86.39912354513098,
+ "y": -191.56870107788566,
+ "z": 0.0
+ },
+ {
+ "x": 86.3992827965184,
+ "y": -192.61632011340058,
+ "z": 0.0
+ },
+ {
+ "x": 86.39944204790584,
+ "y": -193.66393914891557,
+ "z": 0.0
+ },
+ {
+ "x": 86.39960129929328,
+ "y": -194.71155818443046,
+ "z": 0.0
+ },
+ {
+ "x": 86.39976055068071,
+ "y": -195.75917721994537,
+ "z": 0.0
+ },
+ {
+ "x": 86.39991980206814,
+ "y": -196.80679625546037,
+ "z": 0.0
+ },
+ {
+ "x": 86.40007905345558,
+ "y": -197.85441529097523,
+ "z": 0.0
+ },
+ {
+ "x": 86.40023830484301,
+ "y": -198.90203432649022,
+ "z": 0.0
+ },
+ {
+ "x": 86.40039755623046,
+ "y": -199.94965336200508,
+ "z": 0.0
+ },
+ {
+ "x": 86.40055680761789,
+ "y": -200.99727239752002,
+ "z": 0.0
+ },
+ {
+ "x": 86.40071605900532,
+ "y": -202.04489143303496,
+ "z": 0.0
+ },
+ {
+ "x": 86.40087531039275,
+ "y": -203.09251046854993,
+ "z": 0.0
+ },
+ {
+ "x": 86.4010345617802,
+ "y": -204.14012950406482,
+ "z": 0.0
+ },
+ {
+ "x": 86.40119381316762,
+ "y": -205.18774853957976,
+ "z": 0.0
+ },
+ {
+ "x": 86.40135306455505,
+ "y": -206.23536757509473,
+ "z": 0.0
+ },
+ {
+ "x": 86.4015123159425,
+ "y": -207.28298661060958,
+ "z": 0.0
+ },
+ {
+ "x": 86.40167156732993,
+ "y": -208.33060564612452,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 282,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 88.39832726508592,
+ "y": -186.330301874935,
+ "z": 0.0
+ },
+ {
+ "x": 88.39848651647335,
+ "y": -187.37792091045003,
+ "z": 0.0
+ },
+ {
+ "x": 88.39864576786081,
+ "y": -188.42553994596489,
+ "z": 0.0
+ },
+ {
+ "x": 88.39880501924824,
+ "y": -189.4731589814798,
+ "z": 0.0
+ },
+ {
+ "x": 88.39896427063569,
+ "y": -190.5207780169947,
+ "z": 0.0
+ },
+ {
+ "x": 88.39912352202312,
+ "y": -191.56839705250968,
+ "z": 0.0
+ },
+ {
+ "x": 88.39928277341055,
+ "y": -192.6160160880246,
+ "z": 0.0
+ },
+ {
+ "x": 88.39944202479798,
+ "y": -193.66363512353956,
+ "z": 0.0
+ },
+ {
+ "x": 88.39960127618542,
+ "y": -194.71125415905448,
+ "z": 0.0
+ },
+ {
+ "x": 88.39976052757285,
+ "y": -195.7588731945694,
+ "z": 0.0
+ },
+ {
+ "x": 88.39991977896028,
+ "y": -196.80649223008436,
+ "z": 0.0
+ },
+ {
+ "x": 88.40007903034773,
+ "y": -197.85411126559922,
+ "z": 0.0
+ },
+ {
+ "x": 88.40023828173516,
+ "y": -198.90173030111418,
+ "z": 0.0
+ },
+ {
+ "x": 88.4003975331226,
+ "y": -199.9493493366291,
+ "z": 0.0
+ },
+ {
+ "x": 88.40055678451003,
+ "y": -200.996968372144,
+ "z": 0.0
+ },
+ {
+ "x": 88.40071603589746,
+ "y": -202.04458740765898,
+ "z": 0.0
+ },
+ {
+ "x": 88.40087528728489,
+ "y": -203.0922064431739,
+ "z": 0.0
+ },
+ {
+ "x": 88.40103453867233,
+ "y": -204.1398254786888,
+ "z": 0.0
+ },
+ {
+ "x": 88.40119379005976,
+ "y": -205.18744451420378,
+ "z": 0.0
+ },
+ {
+ "x": 88.4013530414472,
+ "y": -206.2350635497187,
+ "z": 0.0
+ },
+ {
+ "x": 88.40151229283464,
+ "y": -207.2826825852336,
+ "z": 0.0
+ },
+ {
+ "x": 88.40167154422207,
+ "y": -208.33030162074851,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 285,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 92.40167149800635,
+ "y": -208.32969356999655,
+ "z": 0.0
+ },
+ {
+ "x": 92.40151224661892,
+ "y": -207.28207453448158,
+ "z": 0.0
+ },
+ {
+ "x": 92.40135299523148,
+ "y": -206.23445549896667,
+ "z": 0.0
+ },
+ {
+ "x": 92.40119374384405,
+ "y": -205.18683646345175,
+ "z": 0.0
+ },
+ {
+ "x": 92.40103449245662,
+ "y": -204.13921742793684,
+ "z": 0.0
+ },
+ {
+ "x": 92.40087524106917,
+ "y": -203.09159839242187,
+ "z": 0.0
+ },
+ {
+ "x": 92.40071598968174,
+ "y": -202.04397935690696,
+ "z": 0.0
+ },
+ {
+ "x": 92.40055673829431,
+ "y": -200.99636032139205,
+ "z": 0.0
+ },
+ {
+ "x": 92.40039748690688,
+ "y": -199.94874128587708,
+ "z": 0.0
+ },
+ {
+ "x": 92.40023823551944,
+ "y": -198.90112225036216,
+ "z": 0.0
+ },
+ {
+ "x": 92.40007898413201,
+ "y": -197.85350321484725,
+ "z": 0.0
+ },
+ {
+ "x": 92.39991973274456,
+ "y": -196.80588417933228,
+ "z": 0.0
+ },
+ {
+ "x": 92.39976048135713,
+ "y": -195.75826514381737,
+ "z": 0.0
+ },
+ {
+ "x": 92.3996012299697,
+ "y": -194.71064610830246,
+ "z": 0.0
+ },
+ {
+ "x": 92.39944197858226,
+ "y": -193.6630270727875,
+ "z": 0.0
+ },
+ {
+ "x": 92.39928272719483,
+ "y": -192.61540803727257,
+ "z": 0.0
+ },
+ {
+ "x": 92.3991234758074,
+ "y": -191.56778900175766,
+ "z": 0.0
+ },
+ {
+ "x": 92.39896422441997,
+ "y": -190.52016996624275,
+ "z": 0.0
+ },
+ {
+ "x": 92.39880497303253,
+ "y": -189.47255093072778,
+ "z": 0.0
+ },
+ {
+ "x": 92.3986457216451,
+ "y": -188.42493189521286,
+ "z": 0.0
+ },
+ {
+ "x": 92.39848647025764,
+ "y": -187.3773128596979,
+ "z": 0.0
+ },
+ {
+ "x": 92.39832721887021,
+ "y": -186.32969382418304,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 288,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 101.42016370346977,
+ "y": -195.14088918733114,
+ "z": 0.0
+ },
+ {
+ "x": 100.3390649845846,
+ "y": -195.1408013378335,
+ "z": 0.0
+ },
+ {
+ "x": 99.25796626569947,
+ "y": -195.14071348833582,
+ "z": 0.0
+ },
+ {
+ "x": 98.28458553074684,
+ "y": -195.0862693380189,
+ "z": 0.0
+ },
+ {
+ "x": 97.40383131032577,
+ "y": -194.94725467952273,
+ "z": 0.0
+ },
+ {
+ "x": 96.57117246015427,
+ "y": -194.71855142809554,
+ "z": 0.0
+ },
+ {
+ "x": 95.76729748780213,
+ "y": -194.40123909394055,
+ "z": 0.0
+ },
+ {
+ "x": 95.00103637582578,
+ "y": -193.99850278004064,
+ "z": 0.0
+ },
+ {
+ "x": 94.34149960300874,
+ "y": -193.52119580541665,
+ "z": 0.0
+ },
+ {
+ "x": 93.73697547677894,
+ "y": -192.95750232040297,
+ "z": 0.0
+ },
+ {
+ "x": 93.25279717064232,
+ "y": -192.34030109965005,
+ "z": 0.0
+ },
+ {
+ "x": 92.87293777889991,
+ "y": -191.6641748771362,
+ "z": 0.0
+ },
+ {
+ "x": 92.59918080829013,
+ "y": -190.93805588245885,
+ "z": 0.0
+ },
+ {
+ "x": 92.43778694671191,
+ "y": -190.1777214558072,
+ "z": 0.0
+ },
+ {
+ "x": 92.39097979703983,
+ "y": -189.39669912723474,
+ "z": 0.0
+ },
+ {
+ "x": 92.398655949702,
+ "y": -188.49221612587775,
+ "z": 0.0
+ },
+ {
+ "x": 92.3984916089792,
+ "y": -187.4111174159142,
+ "z": 0.0
+ },
+ {
+ "x": 92.39832726825641,
+ "y": -186.3300187059507,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 291,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 88.39832726508598,
+ "y": -186.33030187493506,
+ "z": 0.0
+ },
+ {
+ "x": 88.3984916284713,
+ "y": -187.41154966795028,
+ "z": 0.0
+ },
+ {
+ "x": 88.3997952677014,
+ "y": -188.55999082671315,
+ "z": 0.0
+ },
+ {
+ "x": 88.44947052786367,
+ "y": -189.81148110381363,
+ "z": 0.0
+ },
+ {
+ "x": 88.62649926441631,
+ "y": -191.13890401186998,
+ "z": 0.0
+ },
+ {
+ "x": 88.98204913025093,
+ "y": -192.4501989944092,
+ "z": 0.0
+ },
+ {
+ "x": 89.52455006209007,
+ "y": -193.71280814792257,
+ "z": 0.0
+ },
+ {
+ "x": 90.22524077583694,
+ "y": -194.85626879619775,
+ "z": 0.0
+ },
+ {
+ "x": 91.06876625472273,
+ "y": -195.89837434016766,
+ "z": 0.0
+ },
+ {
+ "x": 92.04228546886993,
+ "y": -196.8217242502015,
+ "z": 0.0
+ },
+ {
+ "x": 93.12956285485541,
+ "y": -197.60902540519552,
+ "z": 0.0
+ },
+ {
+ "x": 94.31193266701067,
+ "y": -198.2459903012798,
+ "z": 0.0
+ },
+ {
+ "x": 95.57847859315382,
+ "y": -198.72371333585062,
+ "z": 0.0
+ },
+ {
+ "x": 96.9321412796205,
+ "y": -199.02686395609504,
+ "z": 0.0
+ },
+ {
+ "x": 98.14627840384554,
+ "y": -199.12410570010613,
+ "z": 0.0
+ },
+ {
+ "x": 99.25702742289741,
+ "y": -199.14071342525216,
+ "z": 0.0
+ },
+ {
+ "x": 100.33827522483548,
+ "y": -199.14080128686422,
+ "z": 0.0
+ },
+ {
+ "x": 101.41952302677362,
+ "y": -199.1408891484763,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 294,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 334.8270901428559,
+ "y": -120.57876996339137,
+ "z": 0.0
+ },
+ {
+ "x": 334.826438409234,
+ "y": -121.65777942783936,
+ "z": 0.0
+ },
+ {
+ "x": 334.82911918092043,
+ "y": -122.6225829958806,
+ "z": 0.0
+ },
+ {
+ "x": 334.78744991664456,
+ "y": -123.50619030723817,
+ "z": 0.0
+ },
+ {
+ "x": 334.67608453095875,
+ "y": -124.323014465026,
+ "z": 0.0
+ },
+ {
+ "x": 334.48218923292706,
+ "y": -125.07716990733435,
+ "z": 0.0
+ },
+ {
+ "x": 334.17478222813236,
+ "y": -125.79893448616556,
+ "z": 0.0
+ },
+ {
+ "x": 333.736351798824,
+ "y": -126.49931703182511,
+ "z": 0.0
+ },
+ {
+ "x": 333.2075836156737,
+ "y": -127.14427060363033,
+ "z": 0.0
+ },
+ {
+ "x": 332.5869206240877,
+ "y": -127.73394318759833,
+ "z": 0.0
+ },
+ {
+ "x": 331.951783150246,
+ "y": -128.22595479867536,
+ "z": 0.0
+ },
+ {
+ "x": 331.19135709749276,
+ "y": -128.65090699743394,
+ "z": 0.0
+ },
+ {
+ "x": 330.3850127040796,
+ "y": -128.99600822103105,
+ "z": 0.0
+ },
+ {
+ "x": 329.5488060070645,
+ "y": -129.25864203600875,
+ "z": 0.0
+ },
+ {
+ "x": 328.7330851925337,
+ "y": -129.43304937339707,
+ "z": 0.0
+ },
+ {
+ "x": 327.7768843418315,
+ "y": -129.50432910452471,
+ "z": 0.0
+ },
+ {
+ "x": 326.72022650283077,
+ "y": -129.51556751521045,
+ "z": 0.0
+ },
+ {
+ "x": 325.64121694925416,
+ "y": -129.5150854205275,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 297,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 325.63907988605513,
+ "y": -133.51508486495032,
+ "z": 0.0
+ },
+ {
+ "x": 326.72271965974255,
+ "y": -133.5155690283865,
+ "z": 0.0
+ },
+ {
+ "x": 327.88515173096323,
+ "y": -133.51453576338582,
+ "z": 0.0
+ },
+ {
+ "x": 329.12984339921354,
+ "y": -133.45934839617428,
+ "z": 0.0
+ },
+ {
+ "x": 330.44595125527894,
+ "y": -133.28444611390069,
+ "z": 0.0
+ },
+ {
+ "x": 331.8029942989284,
+ "y": -132.91945053130473,
+ "z": 0.0
+ },
+ {
+ "x": 333.0210008030467,
+ "y": -132.3794292227165,
+ "z": 0.0
+ },
+ {
+ "x": 334.15841440892063,
+ "y": -131.6948662890082,
+ "z": 0.0
+ },
+ {
+ "x": 335.19981972688277,
+ "y": -130.8782083731809,
+ "z": 0.0
+ },
+ {
+ "x": 336.1295437018704,
+ "y": -129.9468692721997,
+ "z": 0.0
+ },
+ {
+ "x": 336.9739198883692,
+ "y": -128.86302591188698,
+ "z": 0.0
+ },
+ {
+ "x": 337.63193009535365,
+ "y": -127.715469424601,
+ "z": 0.0
+ },
+ {
+ "x": 338.14372121746567,
+ "y": -126.5108268803566,
+ "z": 0.0
+ },
+ {
+ "x": 338.5150341584568,
+ "y": -125.2568558340516,
+ "z": 0.0
+ },
+ {
+ "x": 338.741154142397,
+ "y": -123.97452122052148,
+ "z": 0.0
+ },
+ {
+ "x": 338.8257801477764,
+ "y": -122.74880439198486,
+ "z": 0.0
+ },
+ {
+ "x": 338.82643467810203,
+ "y": -121.66516470780864,
+ "z": 0.0
+ },
+ {
+ "x": 338.82708920842776,
+ "y": -120.58152502363232,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 298,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 340.8131424361464,
+ "y": -143.67238981697838,
+ "z": 0.0
+ },
+ {
+ "x": 340.81377637306554,
+ "y": -142.62284455388536,
+ "z": 0.0
+ },
+ {
+ "x": 340.81441030998474,
+ "y": -141.57329929079253,
+ "z": 0.0
+ },
+ {
+ "x": 340.8150442469039,
+ "y": -140.5237540276993,
+ "z": 0.0
+ },
+ {
+ "x": 340.8156781838231,
+ "y": -139.4742087646065,
+ "z": 0.0
+ },
+ {
+ "x": 340.8163121207423,
+ "y": -138.42466350151346,
+ "z": 0.0
+ },
+ {
+ "x": 340.8169460576614,
+ "y": -137.37511823842024,
+ "z": 0.0
+ },
+ {
+ "x": 340.8175799945806,
+ "y": -136.32557297532742,
+ "z": 0.0
+ },
+ {
+ "x": 340.81821393149977,
+ "y": -135.2760277122342,
+ "z": 0.0
+ },
+ {
+ "x": 340.81884786841897,
+ "y": -134.22648244914137,
+ "z": 0.0
+ },
+ {
+ "x": 340.81948180533817,
+ "y": -133.17693718604835,
+ "z": 0.0
+ },
+ {
+ "x": 340.8201157422573,
+ "y": -132.12739192295513,
+ "z": 0.0
+ },
+ {
+ "x": 340.8207496791765,
+ "y": -131.07784665986227,
+ "z": 0.0
+ },
+ {
+ "x": 340.82138361609566,
+ "y": -130.02830139676905,
+ "z": 0.0
+ },
+ {
+ "x": 340.82201755301486,
+ "y": -128.97875613367623,
+ "z": 0.0
+ },
+ {
+ "x": 340.82265148993406,
+ "y": -127.92921087058322,
+ "z": 0.0
+ },
+ {
+ "x": 340.8232854268532,
+ "y": -126.87966560748997,
+ "z": 0.0
+ },
+ {
+ "x": 340.8239193637724,
+ "y": -125.83012034439716,
+ "z": 0.0
+ },
+ {
+ "x": 340.8245533006916,
+ "y": -124.78057508130414,
+ "z": 0.0
+ },
+ {
+ "x": 340.82518723761075,
+ "y": -123.7310298182109,
+ "z": 0.0
+ },
+ {
+ "x": 340.82582117452995,
+ "y": -122.68148455511809,
+ "z": 0.0
+ },
+ {
+ "x": 340.8264551114491,
+ "y": -121.63193929202485,
+ "z": 0.0
+ },
+ {
+ "x": 340.8270890483683,
+ "y": -120.58239402893204,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 300,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 338.8131428009756,
+ "y": -143.6711817951316,
+ "z": 0.0
+ },
+ {
+ "x": 338.8137767378947,
+ "y": -142.62163653203856,
+ "z": 0.0
+ },
+ {
+ "x": 338.814410674814,
+ "y": -141.57209126894566,
+ "z": 0.0
+ },
+ {
+ "x": 338.81504461173313,
+ "y": -140.52254600585252,
+ "z": 0.0
+ },
+ {
+ "x": 338.8156785486523,
+ "y": -139.4730007427596,
+ "z": 0.0
+ },
+ {
+ "x": 338.81631248557153,
+ "y": -138.4234554796666,
+ "z": 0.0
+ },
+ {
+ "x": 338.8169464224907,
+ "y": -137.37391021657345,
+ "z": 0.0
+ },
+ {
+ "x": 338.8175803594098,
+ "y": -136.32436495348054,
+ "z": 0.0
+ },
+ {
+ "x": 338.81821429632896,
+ "y": -135.2748196903874,
+ "z": 0.0
+ },
+ {
+ "x": 338.8188482332482,
+ "y": -134.2252744272945,
+ "z": 0.0
+ },
+ {
+ "x": 338.81948217016736,
+ "y": -133.17572916420147,
+ "z": 0.0
+ },
+ {
+ "x": 338.8201161070865,
+ "y": -132.12618390110833,
+ "z": 0.0
+ },
+ {
+ "x": 338.82075004400576,
+ "y": -131.07663863801537,
+ "z": 0.0
+ },
+ {
+ "x": 338.8213839809249,
+ "y": -130.02709337492226,
+ "z": 0.0
+ },
+ {
+ "x": 338.82201791784405,
+ "y": -128.97754811182932,
+ "z": 0.0
+ },
+ {
+ "x": 338.8226518547633,
+ "y": -127.92800284873633,
+ "z": 0.0
+ },
+ {
+ "x": 338.82328579168245,
+ "y": -126.87845758564319,
+ "z": 0.0
+ },
+ {
+ "x": 338.8239197286016,
+ "y": -125.82891232255027,
+ "z": 0.0
+ },
+ {
+ "x": 338.82455366552085,
+ "y": -124.77936705945724,
+ "z": 0.0
+ },
+ {
+ "x": 338.82518760244,
+ "y": -123.72982179636412,
+ "z": 0.0
+ },
+ {
+ "x": 338.82582153935914,
+ "y": -122.6802765332712,
+ "z": 0.0
+ },
+ {
+ "x": 338.8264554762783,
+ "y": -121.63073127017807,
+ "z": 0.0
+ },
+ {
+ "x": 338.82708941319754,
+ "y": -120.58118600708515,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 303,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 334.8270901428559,
+ "y": -120.57876996339137,
+ "z": 0.0
+ },
+ {
+ "x": 334.8264562059368,
+ "y": -121.62831522648449,
+ "z": 0.0
+ },
+ {
+ "x": 334.82582226901764,
+ "y": -122.67786048957741,
+ "z": 0.0
+ },
+ {
+ "x": 334.8251883320984,
+ "y": -123.72740575267053,
+ "z": 0.0
+ },
+ {
+ "x": 334.82455439517923,
+ "y": -124.77695101576346,
+ "z": 0.0
+ },
+ {
+ "x": 334.8239204582601,
+ "y": -125.82649627885648,
+ "z": 0.0
+ },
+ {
+ "x": 334.82328652134083,
+ "y": -126.8760415419496,
+ "z": 0.0
+ },
+ {
+ "x": 334.8226525844217,
+ "y": -127.92558680504254,
+ "z": 0.0
+ },
+ {
+ "x": 334.82201864750255,
+ "y": -128.97513206813557,
+ "z": 0.0
+ },
+ {
+ "x": 334.8213847105833,
+ "y": -130.02467733122867,
+ "z": 0.0
+ },
+ {
+ "x": 334.82075077366414,
+ "y": -131.0742225943216,
+ "z": 0.0
+ },
+ {
+ "x": 334.820116836745,
+ "y": -132.12376785741475,
+ "z": 0.0
+ },
+ {
+ "x": 334.81948289982586,
+ "y": -133.17331312050766,
+ "z": 0.0
+ },
+ {
+ "x": 334.8188489629066,
+ "y": -134.22285838360068,
+ "z": 0.0
+ },
+ {
+ "x": 334.81821502598746,
+ "y": -135.27240364669382,
+ "z": 0.0
+ },
+ {
+ "x": 334.8175810890683,
+ "y": -136.32194890978673,
+ "z": 0.0
+ },
+ {
+ "x": 334.81694715214906,
+ "y": -137.37149417287986,
+ "z": 0.0
+ },
+ {
+ "x": 334.8163132152299,
+ "y": -138.42103943597277,
+ "z": 0.0
+ },
+ {
+ "x": 334.81567927831077,
+ "y": -139.4705846990658,
+ "z": 0.0
+ },
+ {
+ "x": 334.8150453413915,
+ "y": -140.52012996215893,
+ "z": 0.0
+ },
+ {
+ "x": 334.81441140447237,
+ "y": -141.56967522525184,
+ "z": 0.0
+ },
+ {
+ "x": 334.8137774675532,
+ "y": -142.61922048834498,
+ "z": 0.0
+ },
+ {
+ "x": 334.8131435306341,
+ "y": -143.668765751438,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 306,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 325.63907988605513,
+ "y": -133.51508486495032,
+ "z": 0.0
+ },
+ {
+ "x": 326.67019718616996,
+ "y": -133.5155455616756,
+ "z": 0.0
+ },
+ {
+ "x": 327.6267617532583,
+ "y": -133.51458291459252,
+ "z": 0.0
+ },
+ {
+ "x": 328.52292898248186,
+ "y": -133.543939973342,
+ "z": 0.0
+ },
+ {
+ "x": 329.2742202450984,
+ "y": -133.6035686906993,
+ "z": 0.0
+ },
+ {
+ "x": 330.0201302280161,
+ "y": -133.770079203602,
+ "z": 0.0
+ },
+ {
+ "x": 330.77655635636665,
+ "y": -134.05646514360325,
+ "z": 0.0
+ },
+ {
+ "x": 331.49554132796845,
+ "y": -134.42382055127538,
+ "z": 0.0
+ },
+ {
+ "x": 332.1406372704785,
+ "y": -134.84261994710033,
+ "z": 0.0
+ },
+ {
+ "x": 332.71762879810797,
+ "y": -135.33178515700604,
+ "z": 0.0
+ },
+ {
+ "x": 333.2591096594325,
+ "y": -135.95221620441072,
+ "z": 0.0
+ },
+ {
+ "x": 333.733370070378,
+ "y": -136.6249454962728,
+ "z": 0.0
+ },
+ {
+ "x": 334.1250015663861,
+ "y": -137.3152949237132,
+ "z": 0.0
+ },
+ {
+ "x": 334.4237299295962,
+ "y": -138.01139148784793,
+ "z": 0.0
+ },
+ {
+ "x": 334.63255558517926,
+ "y": -138.80940768845167,
+ "z": 0.0
+ },
+ {
+ "x": 334.7599229345734,
+ "y": -139.6608399232524,
+ "z": 0.0
+ },
+ {
+ "x": 334.81501194915836,
+ "y": -140.57541410661145,
+ "z": 0.0
+ },
+ {
+ "x": 334.8143891429836,
+ "y": -141.60653132155363,
+ "z": 0.0
+ },
+ {
+ "x": 334.81376633680884,
+ "y": -142.63764853649582,
+ "z": 0.0
+ },
+ {
+ "x": 334.8131435306341,
+ "y": -143.66876575143795,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 309,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 338.8131428009756,
+ "y": -143.6711817951316,
+ "z": 0.0
+ },
+ {
+ "x": 338.8137965285674,
+ "y": -142.58887111618375,
+ "z": 0.0
+ },
+ {
+ "x": 338.8144502561594,
+ "y": -141.50656043723603,
+ "z": 0.0
+ },
+ {
+ "x": 338.80452378079116,
+ "y": -140.40517317962764,
+ "z": 0.0
+ },
+ {
+ "x": 338.7221956474102,
+ "y": -139.2014638193349,
+ "z": 0.0
+ },
+ {
+ "x": 338.4870991066125,
+ "y": -137.90405253847825,
+ "z": 0.0
+ },
+ {
+ "x": 338.0897824986565,
+ "y": -136.63336212248896,
+ "z": 0.0
+ },
+ {
+ "x": 337.55332253795063,
+ "y": -135.43436195830742,
+ "z": 0.0
+ },
+ {
+ "x": 336.88172244657096,
+ "y": -134.30613350150293,
+ "z": 0.0
+ },
+ {
+ "x": 336.08408380664827,
+ "y": -133.26372464196993,
+ "z": 0.0
+ },
+ {
+ "x": 335.16573655510433,
+ "y": -132.31945660580425,
+ "z": 0.0
+ },
+ {
+ "x": 334.13272510353136,
+ "y": -131.48915637822523,
+ "z": 0.0
+ },
+ {
+ "x": 333.0025310364399,
+ "y": -130.7917272269492,
+ "z": 0.0
+ },
+ {
+ "x": 331.794475882789,
+ "y": -130.2398661749147,
+ "z": 0.0
+ },
+ {
+ "x": 330.527098532855,
+ "y": -129.84208429620077,
+ "z": 0.0
+ },
+ {
+ "x": 329.21984492042554,
+ "y": -129.60456021730624,
+ "z": 0.0
+ },
+ {
+ "x": 327.9164407754452,
+ "y": -129.51916243893834,
+ "z": 0.0
+ },
+ {
+ "x": 326.72353082855994,
+ "y": -129.5155689915624,
+ "z": 0.0
+ },
+ {
+ "x": 325.6412200602107,
+ "y": -129.51508542191746,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 312,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 101.42088944063468,
+ "y": -129.4149051882574,
+ "z": 0.0
+ },
+ {
+ "x": 100.36794814680857,
+ "y": -129.41443474070897,
+ "z": 0.0
+ },
+ {
+ "x": 99.31500685298246,
+ "y": -129.41396429316055,
+ "z": 0.0
+ },
+ {
+ "x": 98.30383981392947,
+ "y": -129.3924442708536,
+ "z": 0.0
+ },
+ {
+ "x": 97.38637308458796,
+ "y": -129.30831693031158,
+ "z": 0.0
+ },
+ {
+ "x": 96.70134847805133,
+ "y": -129.09939945587251,
+ "z": 0.0
+ },
+ {
+ "x": 95.97200630061965,
+ "y": -128.7864127775635,
+ "z": 0.0
+ },
+ {
+ "x": 95.28913333276736,
+ "y": -128.38290542597278,
+ "z": 0.0
+ },
+ {
+ "x": 94.66256411964747,
+ "y": -127.89454957337901,
+ "z": 0.0
+ },
+ {
+ "x": 94.11758375964698,
+ "y": -127.33284893767612,
+ "z": 0.0
+ },
+ {
+ "x": 93.6843654291251,
+ "y": -126.71718361991702,
+ "z": 0.0
+ },
+ {
+ "x": 93.25681560147831,
+ "y": -125.9858391418419,
+ "z": 0.0
+ },
+ {
+ "x": 92.90470702382066,
+ "y": -125.21397935800047,
+ "z": 0.0
+ },
+ {
+ "x": 92.63198694553196,
+ "y": -124.40914583329769,
+ "z": 0.0
+ },
+ {
+ "x": 92.47881422598947,
+ "y": -123.6229887138957,
+ "z": 0.0
+ },
+ {
+ "x": 92.41383599195208,
+ "y": -122.8063733641458,
+ "z": 0.0
+ },
+ {
+ "x": 92.38746542147446,
+ "y": -121.88066414921204,
+ "z": 0.0
+ },
+ {
+ "x": 92.38838000711462,
+ "y": -120.8929742241692,
+ "z": 0.0
+ },
+ {
+ "x": 92.38821994666225,
+ "y": -119.84003283741217,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 315,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 88.38821994146043,
+ "y": -119.84030264315575,
+ "z": 0.0
+ },
+ {
+ "x": 88.38837809887212,
+ "y": -120.8807250706138,
+ "z": 0.0
+ },
+ {
+ "x": 88.39108030715192,
+ "y": -122.02168901593632,
+ "z": 0.0
+ },
+ {
+ "x": 88.46172661639932,
+ "y": -123.24696762096069,
+ "z": 0.0
+ },
+ {
+ "x": 88.65163376427458,
+ "y": -124.47952527394865,
+ "z": 0.0
+ },
+ {
+ "x": 88.96882473851097,
+ "y": -125.68535880665443,
+ "z": 0.0
+ },
+ {
+ "x": 89.40991646639421,
+ "y": -126.85168614146029,
+ "z": 0.0
+ },
+ {
+ "x": 89.97029178657252,
+ "y": -127.96611544907387,
+ "z": 0.0
+ },
+ {
+ "x": 90.65011037520333,
+ "y": -129.02431893537982,
+ "z": 0.0
+ },
+ {
+ "x": 91.46501813655146,
+ "y": -130.0258988673246,
+ "z": 0.0
+ },
+ {
+ "x": 92.39252006977256,
+ "y": -130.91241263730257,
+ "z": 0.0
+ },
+ {
+ "x": 93.42051250911672,
+ "y": -131.67941488778277,
+ "z": 0.0
+ },
+ {
+ "x": 94.53360561789397,
+ "y": -132.3151872514357,
+ "z": 0.0
+ },
+ {
+ "x": 95.71546101136482,
+ "y": -132.8105823365878,
+ "z": 0.0
+ },
+ {
+ "x": 96.94879613644846,
+ "y": -133.15842236729776,
+ "z": 0.0
+ },
+ {
+ "x": 98.18776931068606,
+ "y": -133.3522153716725,
+ "z": 0.0
+ },
+ {
+ "x": 99.33790052318741,
+ "y": -133.41397492115766,
+ "z": 0.0
+ },
+ {
+ "x": 100.37832285881944,
+ "y": -133.41443977531426,
+ "z": 0.0
+ },
+ {
+ "x": 101.41874519445152,
+ "y": -133.4149046294709,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 318,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 101.42088944063467,
+ "y": -129.4149051882574,
+ "z": 0.0
+ },
+ {
+ "x": 100.34918903743696,
+ "y": -129.41442635925688,
+ "z": 0.0
+ },
+ {
+ "x": 99.27748863423932,
+ "y": -129.41394753025634,
+ "z": 0.0
+ },
+ {
+ "x": 98.2057882310415,
+ "y": -129.41346870125585,
+ "z": 0.0
+ },
+ {
+ "x": 96.9790928920085,
+ "y": -129.50438028664234,
+ "z": 0.0
+ },
+ {
+ "x": 95.72699472251898,
+ "y": -129.72334221739763,
+ "z": 0.0
+ },
+ {
+ "x": 94.47718775569217,
+ "y": -130.09316132412522,
+ "z": 0.0
+ },
+ {
+ "x": 93.20291881911453,
+ "y": -130.70787150482607,
+ "z": 0.0
+ },
+ {
+ "x": 92.09516742532853,
+ "y": -131.44996192328514,
+ "z": 0.0
+ },
+ {
+ "x": 91.10692769644493,
+ "y": -132.30271654696537,
+ "z": 0.0
+ },
+ {
+ "x": 90.21746230150107,
+ "y": -133.29915320805418,
+ "z": 0.0
+ },
+ {
+ "x": 89.45902662178946,
+ "y": -134.54870352378,
+ "z": 0.0
+ },
+ {
+ "x": 88.94031665824139,
+ "y": -135.76772659417503,
+ "z": 0.0
+ },
+ {
+ "x": 88.58295337176378,
+ "y": -137.04449451862712,
+ "z": 0.0
+ },
+ {
+ "x": 88.41675272056585,
+ "y": -138.42152323901217,
+ "z": 0.0
+ },
+ {
+ "x": 88.3914370555155,
+ "y": -139.66810737551634,
+ "z": 0.0
+ },
+ {
+ "x": 88.39140126344014,
+ "y": -140.76830532949788,
+ "z": 0.0
+ },
+ {
+ "x": 88.39156417551544,
+ "y": -141.84000582728214,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 321,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 92.39156417438086,
+ "y": -141.83969433821727,
+ "z": 0.0
+ },
+ {
+ "x": 92.39140217513292,
+ "y": -140.7739987822551,
+ "z": 0.0
+ },
+ {
+ "x": 92.391240175885,
+ "y": -139.7083032262929,
+ "z": 0.0
+ },
+ {
+ "x": 92.41837629818835,
+ "y": -138.69631264740704,
+ "z": 0.0
+ },
+ {
+ "x": 92.52586734119478,
+ "y": -137.8119269363075,
+ "z": 0.0
+ },
+ {
+ "x": 92.74283833555268,
+ "y": -137.0624991874285,
+ "z": 0.0
+ },
+ {
+ "x": 93.06753376102517,
+ "y": -136.3852570186857,
+ "z": 0.0
+ },
+ {
+ "x": 93.495580281799,
+ "y": -135.75125720493622,
+ "z": 0.0
+ },
+ {
+ "x": 94.01667929190448,
+ "y": -135.17314606117776,
+ "z": 0.0
+ },
+ {
+ "x": 94.61882399787538,
+ "y": -134.66403625537419,
+ "z": 0.0
+ },
+ {
+ "x": 95.29395983371364,
+ "y": -134.22585973512975,
+ "z": 0.0
+ },
+ {
+ "x": 96.02427251934127,
+ "y": -133.87263924746935,
+ "z": 0.0
+ },
+ {
+ "x": 96.7940290496316,
+ "y": -133.6140008174741,
+ "z": 0.0
+ },
+ {
+ "x": 97.59150682567487,
+ "y": -133.45419602327453,
+ "z": 0.0
+ },
+ {
+ "x": 98.37060357830944,
+ "y": -133.4171244960692,
+ "z": 0.0
+ },
+ {
+ "x": 99.30449982593655,
+ "y": -133.4138869326253,
+ "z": 0.0
+ },
+ {
+ "x": 100.35309976405674,
+ "y": -133.41442850579415,
+ "z": 0.0
+ },
+ {
+ "x": 101.41879522596236,
+ "y": -133.41490465182466,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 324,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 92.39156417438082,
+ "y": -141.83969433821727,
+ "z": 0.0
+ },
+ {
+ "x": 92.39140492299339,
+ "y": -140.79207530270236,
+ "z": 0.0
+ },
+ {
+ "x": 92.39124567160594,
+ "y": -139.7444562671874,
+ "z": 0.0
+ },
+ {
+ "x": 92.39108642021851,
+ "y": -138.69683723167248,
+ "z": 0.0
+ },
+ {
+ "x": 92.39092716883108,
+ "y": -137.64921819615756,
+ "z": 0.0
+ },
+ {
+ "x": 92.39076791744364,
+ "y": -136.6015991606426,
+ "z": 0.0
+ },
+ {
+ "x": 92.39060866605621,
+ "y": -135.55398012512768,
+ "z": 0.0
+ },
+ {
+ "x": 92.39044941466878,
+ "y": -134.50636108961277,
+ "z": 0.0
+ },
+ {
+ "x": 92.39029016328135,
+ "y": -133.45874205409785,
+ "z": 0.0
+ },
+ {
+ "x": 92.3901309118939,
+ "y": -132.41112301858288,
+ "z": 0.0
+ },
+ {
+ "x": 92.38997166050648,
+ "y": -131.36350398306797,
+ "z": 0.0
+ },
+ {
+ "x": 92.38981240911905,
+ "y": -130.31588494755306,
+ "z": 0.0
+ },
+ {
+ "x": 92.3896531577316,
+ "y": -129.2682659120381,
+ "z": 0.0
+ },
+ {
+ "x": 92.38949390634417,
+ "y": -128.22064687652318,
+ "z": 0.0
+ },
+ {
+ "x": 92.38933465495673,
+ "y": -127.17302784100823,
+ "z": 0.0
+ },
+ {
+ "x": 92.3891754035693,
+ "y": -126.12540880549332,
+ "z": 0.0
+ },
+ {
+ "x": 92.38901615218187,
+ "y": -125.07778976997838,
+ "z": 0.0
+ },
+ {
+ "x": 92.38885690079442,
+ "y": -124.03017073446344,
+ "z": 0.0
+ },
+ {
+ "x": 92.38869764940699,
+ "y": -122.98255169894853,
+ "z": 0.0
+ },
+ {
+ "x": 92.38853839801956,
+ "y": -121.93493266343359,
+ "z": 0.0
+ },
+ {
+ "x": 92.38837914663212,
+ "y": -120.88731362791864,
+ "z": 0.0
+ },
+ {
+ "x": 92.38821989524469,
+ "y": -119.83969459240373,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 325,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 86.38821996456826,
+ "y": -119.84060666853175,
+ "z": 0.0
+ },
+ {
+ "x": 86.3883792159557,
+ "y": -120.88822570404673,
+ "z": 0.0
+ },
+ {
+ "x": 86.38853846734314,
+ "y": -121.9358447395616,
+ "z": 0.0
+ },
+ {
+ "x": 86.38869771873057,
+ "y": -122.98346377507654,
+ "z": 0.0
+ },
+ {
+ "x": 86.388856970118,
+ "y": -124.03108281059153,
+ "z": 0.0
+ },
+ {
+ "x": 86.38901622150544,
+ "y": -125.0787018461064,
+ "z": 0.0
+ },
+ {
+ "x": 86.38917547289287,
+ "y": -126.12632088162133,
+ "z": 0.0
+ },
+ {
+ "x": 86.3893347242803,
+ "y": -127.17393991713632,
+ "z": 0.0
+ },
+ {
+ "x": 86.38949397566775,
+ "y": -128.22155895265118,
+ "z": 0.0
+ },
+ {
+ "x": 86.38965322705518,
+ "y": -129.26917798816618,
+ "z": 0.0
+ },
+ {
+ "x": 86.38981247844262,
+ "y": -130.31679702368103,
+ "z": 0.0
+ },
+ {
+ "x": 86.38997172983005,
+ "y": -131.36441605919597,
+ "z": 0.0
+ },
+ {
+ "x": 86.39013098121748,
+ "y": -132.41203509471094,
+ "z": 0.0
+ },
+ {
+ "x": 86.39029023260493,
+ "y": -133.45965413022583,
+ "z": 0.0
+ },
+ {
+ "x": 86.39044948399236,
+ "y": -134.50727316574077,
+ "z": 0.0
+ },
+ {
+ "x": 86.39060873537979,
+ "y": -135.55489220125568,
+ "z": 0.0
+ },
+ {
+ "x": 86.39076798676722,
+ "y": -136.60251123677068,
+ "z": 0.0
+ },
+ {
+ "x": 86.39092723815466,
+ "y": -137.65013027228557,
+ "z": 0.0
+ },
+ {
+ "x": 86.39108648954209,
+ "y": -138.69774930780048,
+ "z": 0.0
+ },
+ {
+ "x": 86.39124574092952,
+ "y": -139.74536834331548,
+ "z": 0.0
+ },
+ {
+ "x": 86.39140499231696,
+ "y": -140.79298737883033,
+ "z": 0.0
+ },
+ {
+ "x": 86.3915642437044,
+ "y": -141.84060641434527,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 327,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 88.3882199414604,
+ "y": -119.84030264315575,
+ "z": 0.0
+ },
+ {
+ "x": 88.38837919284784,
+ "y": -120.8879216786707,
+ "z": 0.0
+ },
+ {
+ "x": 88.38853844423528,
+ "y": -121.9355407141856,
+ "z": 0.0
+ },
+ {
+ "x": 88.38869769562271,
+ "y": -122.98315974970055,
+ "z": 0.0
+ },
+ {
+ "x": 88.38885694701014,
+ "y": -124.03077878521549,
+ "z": 0.0
+ },
+ {
+ "x": 88.38901619839758,
+ "y": -125.0783978207304,
+ "z": 0.0
+ },
+ {
+ "x": 88.38917544978501,
+ "y": -126.12601685624531,
+ "z": 0.0
+ },
+ {
+ "x": 88.38933470117244,
+ "y": -127.17363589176028,
+ "z": 0.0
+ },
+ {
+ "x": 88.38949395255989,
+ "y": -128.2212549272752,
+ "z": 0.0
+ },
+ {
+ "x": 88.38965320394732,
+ "y": -129.26887396279017,
+ "z": 0.0
+ },
+ {
+ "x": 88.38981245533476,
+ "y": -130.31649299830502,
+ "z": 0.0
+ },
+ {
+ "x": 88.38997170672219,
+ "y": -131.36411203382,
+ "z": 0.0
+ },
+ {
+ "x": 88.39013095810962,
+ "y": -132.4117310693349,
+ "z": 0.0
+ },
+ {
+ "x": 88.39029020949707,
+ "y": -133.45935010484982,
+ "z": 0.0
+ },
+ {
+ "x": 88.3904494608845,
+ "y": -134.5069691403648,
+ "z": 0.0
+ },
+ {
+ "x": 88.39060871227193,
+ "y": -135.5545881758797,
+ "z": 0.0
+ },
+ {
+ "x": 88.39076796365936,
+ "y": -136.60220721139467,
+ "z": 0.0
+ },
+ {
+ "x": 88.3909272150468,
+ "y": -137.64982624690958,
+ "z": 0.0
+ },
+ {
+ "x": 88.39108646643423,
+ "y": -138.6974452824245,
+ "z": 0.0
+ },
+ {
+ "x": 88.39124571782166,
+ "y": -139.74506431793947,
+ "z": 0.0
+ },
+ {
+ "x": 88.3914049692091,
+ "y": -140.79268335345432,
+ "z": 0.0
+ },
+ {
+ "x": 88.39156422059654,
+ "y": -141.8403023889693,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 330,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 154.02380798404414,
+ "y": -46.19753632639322,
+ "z": 0.0
+ },
+ {
+ "x": 154.0225405266159,
+ "y": -47.24090674538898,
+ "z": 0.0
+ },
+ {
+ "x": 154.0212957833844,
+ "y": -48.27687009781563,
+ "z": 0.0
+ },
+ {
+ "x": 154.0224864762247,
+ "y": -49.17072627310411,
+ "z": 0.0
+ },
+ {
+ "x": 153.97584197898615,
+ "y": -49.95867202474612,
+ "z": 0.0
+ },
+ {
+ "x": 153.82494572714774,
+ "y": -50.74658892864789,
+ "z": 0.0
+ },
+ {
+ "x": 153.58120716526844,
+ "y": -51.50973756548072,
+ "z": 0.0
+ },
+ {
+ "x": 153.2478967703762,
+ "y": -52.238362120680605,
+ "z": 0.0
+ },
+ {
+ "x": 152.85518620641,
+ "y": -52.89185296315288,
+ "z": 0.0
+ },
+ {
+ "x": 152.36821934903156,
+ "y": -53.49002530084883,
+ "z": 0.0
+ },
+ {
+ "x": 151.77805426447105,
+ "y": -54.03404810038104,
+ "z": 0.0
+ },
+ {
+ "x": 151.12816900523492,
+ "y": -54.502702172032784,
+ "z": 0.0
+ },
+ {
+ "x": 150.42705192181336,
+ "y": -54.890159888561826,
+ "z": 0.0
+ },
+ {
+ "x": 149.70552810564578,
+ "y": -55.18594301814386,
+ "z": 0.0
+ },
+ {
+ "x": 148.97820888894648,
+ "y": -55.38229475154137,
+ "z": 0.0
+ },
+ {
+ "x": 148.07093106567913,
+ "y": -55.468392753747764,
+ "z": 0.0
+ },
+ {
+ "x": 147.0768176160945,
+ "y": -55.49309497508044,
+ "z": 0.0
+ },
+ {
+ "x": 146.033446435009,
+ "y": -55.493222112765466,
+ "z": 0.0
+ },
+ {
+ "x": 144.99007525392352,
+ "y": -55.49334925045048,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 333,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 144.9902393330799,
+ "y": -59.49334926015318,
+ "z": 0.0
+ },
+ {
+ "x": 146.03540288443622,
+ "y": -59.49322190406285,
+ "z": 0.0
+ },
+ {
+ "x": 147.14476546935714,
+ "y": -59.492056076550405,
+ "z": 0.0
+ },
+ {
+ "x": 148.33262517418535,
+ "y": -59.44855439963858,
+ "z": 0.0
+ },
+ {
+ "x": 149.60538379079756,
+ "y": -59.30093427784442,
+ "z": 0.0
+ },
+ {
+ "x": 150.90060319706703,
+ "y": -58.985014243942075,
+ "z": 0.0
+ },
+ {
+ "x": 152.08417688840183,
+ "y": -58.51452779035827,
+ "z": 0.0
+ },
+ {
+ "x": 153.2043480453745,
+ "y": -57.91271930306415,
+ "z": 0.0
+ },
+ {
+ "x": 154.25115479129303,
+ "y": -57.18432584118074,
+ "z": 0.0
+ },
+ {
+ "x": 155.2151905323367,
+ "y": -56.32888544962101,
+ "z": 0.0
+ },
+ {
+ "x": 156.10325086827027,
+ "y": -55.30748534345081,
+ "z": 0.0
+ },
+ {
+ "x": 156.80994358117522,
+ "y": -54.18961306282728,
+ "z": 0.0
+ },
+ {
+ "x": 157.34809131646162,
+ "y": -53.00526040834794,
+ "z": 0.0
+ },
+ {
+ "x": 157.72881984867638,
+ "y": -51.762961636059096,
+ "z": 0.0
+ },
+ {
+ "x": 157.94460164983178,
+ "y": -50.51353312774852,
+ "z": 0.0
+ },
+ {
+ "x": 158.01999573792733,
+ "y": -49.3382052613273,
+ "z": 0.0
+ },
+ {
+ "x": 158.02126537267566,
+ "y": -48.29304247336981,
+ "z": 0.0
+ },
+ {
+ "x": 158.02253500742398,
+ "y": -47.24787968541243,
+ "z": 0.0
+ },
+ {
+ "x": 158.02380464217237,
+ "y": -46.20271689745499,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 336,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 154.02380798404414,
+ "y": -46.19753632639322,
+ "z": 0.0
+ },
+ {
+ "x": 154.02254778720277,
+ "y": -47.234929833323704,
+ "z": 0.0
+ },
+ {
+ "x": 154.0220914396506,
+ "y": -48.33150366522665,
+ "z": 0.0
+ },
+ {
+ "x": 154.05846020639342,
+ "y": -49.48693261271582,
+ "z": 0.0
+ },
+ {
+ "x": 154.20277863371672,
+ "y": -50.83323725619208,
+ "z": 0.0
+ },
+ {
+ "x": 154.5289316112454,
+ "y": -52.066952903777064,
+ "z": 0.0
+ },
+ {
+ "x": 154.99269289011525,
+ "y": -53.23838843678435,
+ "z": 0.0
+ },
+ {
+ "x": 155.585298044496,
+ "y": -54.34977085110656,
+ "z": 0.0
+ },
+ {
+ "x": 156.35177765287185,
+ "y": -55.44682750656724,
+ "z": 0.0
+ },
+ {
+ "x": 157.22845126186928,
+ "y": -56.37736680088315,
+ "z": 0.0
+ },
+ {
+ "x": 158.17629805628042,
+ "y": -57.17180132816905,
+ "z": 0.0
+ },
+ {
+ "x": 159.19562702626834,
+ "y": -57.86450820303658,
+ "z": 0.0
+ },
+ {
+ "x": 160.34457511087447,
+ "y": -58.480341225935305,
+ "z": 0.0
+ },
+ {
+ "x": 161.52777689166018,
+ "y": -58.92780889150592,
+ "z": 0.0
+ },
+ {
+ "x": 162.72257395798567,
+ "y": -59.232723132560764,
+ "z": 0.0
+ },
+ {
+ "x": 163.9265285225684,
+ "y": -59.41699686668909,
+ "z": 0.0
+ },
+ {
+ "x": 165.09545063910528,
+ "y": -59.49089938414677,
+ "z": 0.0
+ },
+ {
+ "x": 166.1328449037599,
+ "y": -59.49077297476566,
+ "z": 0.0
+ },
+ {
+ "x": 167.1702391684145,
+ "y": -59.49064656538455,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 339,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 167.16975175727498,
+ "y": -55.49064659508076,
+ "z": 0.0
+ },
+ {
+ "x": 166.1275959090633,
+ "y": -55.49077358467409,
+ "z": 0.0
+ },
+ {
+ "x": 165.08544006085165,
+ "y": -55.49090057426743,
+ "z": 0.0
+ },
+ {
+ "x": 164.15696033917465,
+ "y": -55.436032284142954,
+ "z": 0.0
+ },
+ {
+ "x": 163.29745779390208,
+ "y": -55.306797258467256,
+ "z": 0.0
+ },
+ {
+ "x": 162.4896909874122,
+ "y": -55.0948741218035,
+ "z": 0.0
+ },
+ {
+ "x": 161.7535005053105,
+ "y": -54.794716920603875,
+ "z": 0.0
+ },
+ {
+ "x": 161.0666842268726,
+ "y": -54.40656115534773,
+ "z": 0.0
+ },
+ {
+ "x": 160.38320540908438,
+ "y": -53.92896674701984,
+ "z": 0.0
+ },
+ {
+ "x": 159.7578042552214,
+ "y": -53.384689518722695,
+ "z": 0.0
+ },
+ {
+ "x": 159.21527538386513,
+ "y": -52.78400531379128,
+ "z": 0.0
+ },
+ {
+ "x": 158.83996895929573,
+ "y": -52.17304058119422,
+ "z": 0.0
+ },
+ {
+ "x": 158.49249840672923,
+ "y": -51.45319407003326,
+ "z": 0.0
+ },
+ {
+ "x": 158.2337868647591,
+ "y": -50.697068790528874,
+ "z": 0.0
+ },
+ {
+ "x": 158.06719322456945,
+ "y": -49.91369373265339,
+ "z": 0.0
+ },
+ {
+ "x": 158.0261760820918,
+ "y": -49.161618091827535,
+ "z": 0.0
+ },
+ {
+ "x": 158.02114821720056,
+ "y": -48.262173506744624,
+ "z": 0.0
+ },
+ {
+ "x": 158.02253863907634,
+ "y": -47.24489011075576,
+ "z": 0.0
+ },
+ {
+ "x": 158.02380462015304,
+ "y": -46.20273502374609,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 342,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 167.16975175727498,
+ "y": -55.49064659508076,
+ "z": 0.0
+ },
+ {
+ "x": 166.11356128892572,
+ "y": -55.490775294831636,
+ "z": 0.0
+ },
+ {
+ "x": 165.0573708205764,
+ "y": -55.490903994582524,
+ "z": 0.0
+ },
+ {
+ "x": 164.00118035222715,
+ "y": -55.49103269433341,
+ "z": 0.0
+ },
+ {
+ "x": 162.9449898838779,
+ "y": -55.4911613940843,
+ "z": 0.0
+ },
+ {
+ "x": 161.88879941552864,
+ "y": -55.49129009383519,
+ "z": 0.0
+ },
+ {
+ "x": 160.83260894717938,
+ "y": -55.49141879358608,
+ "z": 0.0
+ },
+ {
+ "x": 159.77641847883012,
+ "y": -55.49154749333697,
+ "z": 0.0
+ },
+ {
+ "x": 158.72022801048087,
+ "y": -55.491676193087855,
+ "z": 0.0
+ },
+ {
+ "x": 157.66403754213155,
+ "y": -55.49180489283874,
+ "z": 0.0
+ },
+ {
+ "x": 156.60784707378232,
+ "y": -55.49193359258962,
+ "z": 0.0
+ },
+ {
+ "x": 155.55165660543304,
+ "y": -55.492062292340506,
+ "z": 0.0
+ },
+ {
+ "x": 154.49546613708378,
+ "y": -55.492190992091395,
+ "z": 0.0
+ },
+ {
+ "x": 153.43927566873452,
+ "y": -55.49231969184228,
+ "z": 0.0
+ },
+ {
+ "x": 152.38308520038527,
+ "y": -55.49244839159317,
+ "z": 0.0
+ },
+ {
+ "x": 151.326894732036,
+ "y": -55.49257709134406,
+ "z": 0.0
+ },
+ {
+ "x": 150.2707042636867,
+ "y": -55.49270579109495,
+ "z": 0.0
+ },
+ {
+ "x": 149.21451379533744,
+ "y": -55.49283449084584,
+ "z": 0.0
+ },
+ {
+ "x": 148.15832332698818,
+ "y": -55.492963190596726,
+ "z": 0.0
+ },
+ {
+ "x": 147.10213285863895,
+ "y": -55.4930918903476,
+ "z": 0.0
+ },
+ {
+ "x": 146.04594239028967,
+ "y": -55.49322059009849,
+ "z": 0.0
+ },
+ {
+ "x": 144.9897519219404,
+ "y": -55.49334928984938,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 343,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 144.99048303864967,
+ "y": -61.493349245305076,
+ "z": 0.0
+ },
+ {
+ "x": 146.04667350699893,
+ "y": -61.49322054555419,
+ "z": 0.0
+ },
+ {
+ "x": 147.10286397534819,
+ "y": -61.4930918458033,
+ "z": 0.0
+ },
+ {
+ "x": 148.15905444369747,
+ "y": -61.49296314605242,
+ "z": 0.0
+ },
+ {
+ "x": 149.21524491204673,
+ "y": -61.49283444630153,
+ "z": 0.0
+ },
+ {
+ "x": 150.27143538039599,
+ "y": -61.49270574655064,
+ "z": 0.0
+ },
+ {
+ "x": 151.32762584874524,
+ "y": -61.49257704679975,
+ "z": 0.0
+ },
+ {
+ "x": 152.38381631709453,
+ "y": -61.49244834704887,
+ "z": 0.0
+ },
+ {
+ "x": 153.44000678544379,
+ "y": -61.49231964729798,
+ "z": 0.0
+ },
+ {
+ "x": 154.49619725379307,
+ "y": -61.492190947547094,
+ "z": 0.0
+ },
+ {
+ "x": 155.55238772214233,
+ "y": -61.492062247796206,
+ "z": 0.0
+ },
+ {
+ "x": 156.60857819049156,
+ "y": -61.49193354804532,
+ "z": 0.0
+ },
+ {
+ "x": 157.66476865884084,
+ "y": -61.491804848294436,
+ "z": 0.0
+ },
+ {
+ "x": 158.72095912719013,
+ "y": -61.49167614854355,
+ "z": 0.0
+ },
+ {
+ "x": 159.77714959553938,
+ "y": -61.49154744879266,
+ "z": 0.0
+ },
+ {
+ "x": 160.8333400638886,
+ "y": -61.49141874904177,
+ "z": 0.0
+ },
+ {
+ "x": 161.88953053223793,
+ "y": -61.49129004929089,
+ "z": 0.0
+ },
+ {
+ "x": 162.94572100058718,
+ "y": -61.49116134954,
+ "z": 0.0
+ },
+ {
+ "x": 164.00191146893644,
+ "y": -61.49103264978911,
+ "z": 0.0
+ },
+ {
+ "x": 165.0581019372857,
+ "y": -61.49090395003822,
+ "z": 0.0
+ },
+ {
+ "x": 166.11429240563496,
+ "y": -61.490775250287335,
+ "z": 0.0
+ },
+ {
+ "x": 167.1704828739842,
+ "y": -61.490646550536454,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 345,
+ "map_element_id": 2,
+ "type": "lane",
+ "geometry": [
+ {
+ "x": 144.9902393330799,
+ "y": -59.49334926015318,
+ "z": 0.0
+ },
+ {
+ "x": 146.04642980142916,
+ "y": -59.49322056040229,
+ "z": 0.0
+ },
+ {
+ "x": 147.10262026977844,
+ "y": -59.493091860651404,
+ "z": 0.0
+ },
+ {
+ "x": 148.15881073812773,
+ "y": -59.492963160900516,
+ "z": 0.0
+ },
+ {
+ "x": 149.21500120647698,
+ "y": -59.49283446114963,
+ "z": 0.0
+ },
+ {
+ "x": 150.27119167482624,
+ "y": -59.49270576139874,
+ "z": 0.0
+ },
+ {
+ "x": 151.3273821431755,
+ "y": -59.49257706164785,
+ "z": 0.0
+ },
+ {
+ "x": 152.38357261152476,
+ "y": -59.492448361896976,
+ "z": 0.0
+ },
+ {
+ "x": 153.439763079874,
+ "y": -59.49231966214609,
+ "z": 0.0
+ },
+ {
+ "x": 154.49595354822333,
+ "y": -59.4921909623952,
+ "z": 0.0
+ },
+ {
+ "x": 155.55214401657258,
+ "y": -59.49206226264431,
+ "z": 0.0
+ },
+ {
+ "x": 156.6083344849218,
+ "y": -59.49193356289342,
+ "z": 0.0
+ },
+ {
+ "x": 157.6645249532711,
+ "y": -59.491804863142534,
+ "z": 0.0
+ },
+ {
+ "x": 158.72071542162035,
+ "y": -59.491676163391645,
+ "z": 0.0
+ },
+ {
+ "x": 159.7769058899696,
+ "y": -59.49154746364076,
+ "z": 0.0
+ },
+ {
+ "x": 160.83309635831887,
+ "y": -59.49141876388987,
+ "z": 0.0
+ },
+ {
+ "x": 161.88928682666818,
+ "y": -59.491290064138994,
+ "z": 0.0
+ },
+ {
+ "x": 162.94547729501744,
+ "y": -59.491161364388105,
+ "z": 0.0
+ },
+ {
+ "x": 164.0016677633667,
+ "y": -59.49103266463722,
+ "z": 0.0
+ },
+ {
+ "x": 165.05785823171595,
+ "y": -59.49090396488633,
+ "z": 0.0
+ },
+ {
+ "x": 166.1140487000652,
+ "y": -59.49077526513544,
+ "z": 0.0
+ },
+ {
+ "x": 167.17023916841447,
+ "y": -59.49064656538455,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 130,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 325.6278797108732,
+ "y": -3.988677721665928,
+ "z": 0.0
+ },
+ {
+ "x": 326.6645461982845,
+ "y": -3.989228436985744,
+ "z": 0.0
+ },
+ {
+ "x": 327.7012126856958,
+ "y": -3.9897791523055597,
+ "z": 0.0
+ },
+ {
+ "x": 328.7378791731071,
+ "y": -3.9903298676253756,
+ "z": 0.0
+ },
+ {
+ "x": 329.5221086572586,
+ "y": -4.047669202376462,
+ "z": 0.0
+ },
+ {
+ "x": 330.1072270974078,
+ "y": -4.173581082904699,
+ "z": 0.0
+ },
+ {
+ "x": 330.6144262143476,
+ "y": -4.360288299602975,
+ "z": 0.0
+ },
+ {
+ "x": 331.0954172342736,
+ "y": -4.608571370574099,
+ "z": 0.0
+ },
+ {
+ "x": 331.54334222118945,
+ "y": -4.915257127838937,
+ "z": 0.0
+ },
+ {
+ "x": 331.843444119078,
+ "y": -5.226392769639217,
+ "z": 0.0
+ },
+ {
+ "x": 332.1744536934619,
+ "y": -5.632692116040604,
+ "z": 0.0
+ },
+ {
+ "x": 332.45058407826144,
+ "y": -6.077457497319008,
+ "z": 0.0
+ },
+ {
+ "x": 332.66638742822687,
+ "y": -6.552465214205474,
+ "z": 0.0
+ },
+ {
+ "x": 332.81977427548895,
+ "y": -7.051954724123156,
+ "z": 0.0
+ },
+ {
+ "x": 332.9081272804868,
+ "y": -7.568500980156154,
+ "z": 0.0
+ },
+ {
+ "x": 332.895030754424,
+ "y": -7.996637987132772,
+ "z": 0.0
+ },
+ {
+ "x": 332.89493219600683,
+ "y": -8.76330403472345,
+ "z": 0.0
+ },
+ {
+ "x": 332.8940312132095,
+ "y": -9.750603823797125,
+ "z": 0.0
+ },
+ {
+ "x": 332.89340505523876,
+ "y": -10.787270268385383,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 145,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 340.89340340765136,
+ "y": -10.792414056232396,
+ "z": 0.0
+ },
+ {
+ "x": 340.89403578359634,
+ "y": -9.745453140274215,
+ "z": 0.0
+ },
+ {
+ "x": 340.89466815954137,
+ "y": -8.698492224316256,
+ "z": 0.0
+ },
+ {
+ "x": 340.89530053548634,
+ "y": -7.651531308357863,
+ "z": 0.0
+ },
+ {
+ "x": 340.9521407676781,
+ "y": -6.852378699784743,
+ "z": 0.0
+ },
+ {
+ "x": 341.06688111734144,
+ "y": -6.135182389188954,
+ "z": 0.0
+ },
+ {
+ "x": 341.22823435714616,
+ "y": -5.902494853710985,
+ "z": 0.0
+ },
+ {
+ "x": 341.46602833031625,
+ "y": -5.569414699066449,
+ "z": 0.0
+ },
+ {
+ "x": 341.7994848809484,
+ "y": -5.165549665951211,
+ "z": 0.0
+ },
+ {
+ "x": 342.13051965040574,
+ "y": -4.903219459030506,
+ "z": 0.0
+ },
+ {
+ "x": 342.4962616320244,
+ "y": -4.698227530630974,
+ "z": 0.0
+ },
+ {
+ "x": 343.01185668684076,
+ "y": -4.43994024407544,
+ "z": 0.0
+ },
+ {
+ "x": 343.5712427807595,
+ "y": -4.230705239368477,
+ "z": 0.0
+ },
+ {
+ "x": 344.1507044170504,
+ "y": -4.085364578513123,
+ "z": 0.0
+ },
+ {
+ "x": 344.743421203216,
+ "y": -4.005725125338712,
+ "z": 0.0
+ },
+ {
+ "x": 345.34990134625497,
+ "y": -3.9905056740214206,
+ "z": 0.0
+ },
+ {
+ "x": 346.13395460346004,
+ "y": -3.9995713019347696,
+ "z": 0.0
+ },
+ {
+ "x": 347.1809155626665,
+ "y": -4.000127486056169,
+ "z": 0.0
+ },
+ {
+ "x": 348.227876521873,
+ "y": -4.0006836701775725,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 157,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 160.06653921314967,
+ "y": -11.024850911531969,
+ "z": 0.0
+ },
+ {
+ "x": 160.0678134667562,
+ "y": -9.975885881460881,
+ "z": 0.0
+ },
+ {
+ "x": 160.06908772036275,
+ "y": -8.926920851389792,
+ "z": 0.0
+ },
+ {
+ "x": 160.07036197396928,
+ "y": -7.877955821318704,
+ "z": 0.0
+ },
+ {
+ "x": 160.1246918567833,
+ "y": -7.060305047376277,
+ "z": 0.0
+ },
+ {
+ "x": 160.2374873644286,
+ "y": -6.342829622261114,
+ "z": 0.0
+ },
+ {
+ "x": 160.41028615430943,
+ "y": -5.865624377840656,
+ "z": 0.0
+ },
+ {
+ "x": 160.62898947587635,
+ "y": -5.516198652845463,
+ "z": 0.0
+ },
+ {
+ "x": 160.9587560838947,
+ "y": -5.0263174378290145,
+ "z": 0.0
+ },
+ {
+ "x": 161.34037650307783,
+ "y": -4.58232228373524,
+ "z": 0.0
+ },
+ {
+ "x": 161.6532871645665,
+ "y": -4.377425268002961,
+ "z": 0.0
+ },
+ {
+ "x": 162.012325453008,
+ "y": -4.210009421664965,
+ "z": 0.0
+ },
+ {
+ "x": 162.4819073479187,
+ "y": -4.032043747178901,
+ "z": 0.0
+ },
+ {
+ "x": 162.97457927269812,
+ "y": -3.9185762591816546,
+ "z": 0.0
+ },
+ {
+ "x": 163.2561113559408,
+ "y": -3.9648852550583116,
+ "z": 0.0
+ },
+ {
+ "x": 164.00033558629985,
+ "y": -3.954801759477505,
+ "z": 0.0
+ },
+ {
+ "x": 164.93268600146294,
+ "y": -3.956601518087601,
+ "z": 0.0
+ },
+ {
+ "x": 165.98165179952323,
+ "y": -3.956713473436086,
+ "z": 0.0
+ },
+ {
+ "x": 167.03061759758353,
+ "y": -3.9568254287845774,
+ "z": 0.0
+ },
+ {
+ "x": 168.07958339564385,
+ "y": -3.956937384133062,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 160,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 144.95958352573157,
+ "y": -3.9544698035434926,
+ "z": 0.0
+ },
+ {
+ "x": 146.0212169873974,
+ "y": -3.954583110902402,
+ "z": 0.0
+ },
+ {
+ "x": 147.0828504490632,
+ "y": -3.954696418261311,
+ "z": 0.0
+ },
+ {
+ "x": 148.144483910729,
+ "y": -3.954809725620221,
+ "z": 0.0
+ },
+ {
+ "x": 149.05967964890726,
+ "y": -3.990641340582388,
+ "z": 0.0
+ },
+ {
+ "x": 149.83780177823488,
+ "y": -4.082760914533853,
+ "z": 0.0
+ },
+ {
+ "x": 150.1743168945339,
+ "y": -4.242647825577707,
+ "z": 0.0
+ },
+ {
+ "x": 150.61969315594254,
+ "y": -4.4830122559322945,
+ "z": 0.0
+ },
+ {
+ "x": 151.07615455507627,
+ "y": -4.797092817882984,
+ "z": 0.0
+ },
+ {
+ "x": 151.48742320962174,
+ "y": -5.166058802470898,
+ "z": 0.0
+ },
+ {
+ "x": 151.67611237008094,
+ "y": -5.475440162631369,
+ "z": 0.0
+ },
+ {
+ "x": 151.84574867678245,
+ "y": -5.848483006759167,
+ "z": 0.0
+ },
+ {
+ "x": 152.00442107081673,
+ "y": -6.310109105308325,
+ "z": 0.0
+ },
+ {
+ "x": 152.09632190626255,
+ "y": -6.791790352034089,
+ "z": 0.0
+ },
+ {
+ "x": 152.07837964471057,
+ "y": -7.181400923116529,
+ "z": 0.0
+ },
+ {
+ "x": 152.07070286095353,
+ "y": -7.883406095020281,
+ "z": 0.0
+ },
+ {
+ "x": 152.0691243996725,
+ "y": -8.891867371922766,
+ "z": 0.0
+ },
+ {
+ "x": 152.06783475775103,
+ "y": -9.953500056324756,
+ "z": 0.0
+ },
+ {
+ "x": 152.06654511582957,
+ "y": -11.015132740726854,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 175,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 86.42210766601971,
+ "y": -317.12405432540857,
+ "z": 0.0
+ },
+ {
+ "x": 86.40322153115828,
+ "y": -317.8749514922378,
+ "z": 0.0
+ },
+ {
+ "x": 86.3292625154455,
+ "y": -318.58491186848573,
+ "z": 0.0
+ },
+ {
+ "x": 86.18953213327386,
+ "y": -319.2846940672616,
+ "z": 0.0
+ },
+ {
+ "x": 85.98523313042162,
+ "y": -319.9683863526217,
+ "z": 0.0
+ },
+ {
+ "x": 85.71807956869432,
+ "y": -320.6302044599884,
+ "z": 0.0
+ },
+ {
+ "x": 85.39028468437556,
+ "y": -321.2645335106671,
+ "z": 0.0
+ },
+ {
+ "x": 85.01656276535591,
+ "y": -321.85141823949874,
+ "z": 0.0
+ },
+ {
+ "x": 84.61328386764781,
+ "y": -322.3733874363649,
+ "z": 0.0
+ },
+ {
+ "x": 84.14776694319312,
+ "y": -322.855932640633,
+ "z": 0.0
+ },
+ {
+ "x": 83.63582517526206,
+ "y": -323.28636997869825,
+ "z": 0.0
+ },
+ {
+ "x": 83.08208237236526,
+ "y": -323.6607081495259,
+ "z": 0.0
+ },
+ {
+ "x": 82.49250331518978,
+ "y": -323.9750097865338,
+ "z": 0.0
+ },
+ {
+ "x": 81.87341023048599,
+ "y": -324.22594956684435,
+ "z": 0.0
+ },
+ {
+ "x": 81.23142281271754,
+ "y": -324.41084517913515,
+ "z": 0.0
+ },
+ {
+ "x": 80.53314857363705,
+ "y": -324.5294262581491,
+ "z": 0.0
+ },
+ {
+ "x": 79.44718379231384,
+ "y": -324.5819492549276,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 178,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 101.8061452205714,
+ "y": -324.5933877050256,
+ "z": 0.0
+ },
+ {
+ "x": 100.76420901034751,
+ "y": -324.544843879481,
+ "z": 0.0
+ },
+ {
+ "x": 100.05547286081084,
+ "y": -324.4402442473347,
+ "z": 0.0
+ },
+ {
+ "x": 99.40097425397511,
+ "y": -324.2766062823703,
+ "z": 0.0
+ },
+ {
+ "x": 98.76392649992916,
+ "y": -324.05345432697123,
+ "z": 0.0
+ },
+ {
+ "x": 98.14938349604752,
+ "y": -323.77243681296414,
+ "z": 0.0
+ },
+ {
+ "x": 97.61695804856943,
+ "y": -323.4496290183012,
+ "z": 0.0
+ },
+ {
+ "x": 97.09931695655445,
+ "y": -323.0644970568544,
+ "z": 0.0
+ },
+ {
+ "x": 96.59466314544346,
+ "y": -322.6165467084913,
+ "z": 0.0
+ },
+ {
+ "x": 96.13171624236867,
+ "y": -322.1232796739841,
+ "z": 0.0
+ },
+ {
+ "x": 95.71288930249867,
+ "y": -321.58761950526895,
+ "z": 0.0
+ },
+ {
+ "x": 95.34255411729966,
+ "y": -321.0145041533784,
+ "z": 0.0
+ },
+ {
+ "x": 95.04377845391564,
+ "y": -320.42949063438977,
+ "z": 0.0
+ },
+ {
+ "x": 94.82285770290609,
+ "y": -319.84438630967213,
+ "z": 0.0
+ },
+ {
+ "x": 94.63316860976981,
+ "y": -319.18946806306946,
+ "z": 0.0
+ },
+ {
+ "x": 94.50330750802169,
+ "y": -318.5204043978035,
+ "z": 0.0
+ },
+ {
+ "x": 94.43423405405653,
+ "y": -317.8422626237095,
+ "z": 0.0
+ },
+ {
+ "x": 94.41410567044805,
+ "y": -317.1186932324719,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 193,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 94.37171129421938,
+ "y": -11.239391821784363,
+ "z": 0.0
+ },
+ {
+ "x": 94.37155111803641,
+ "y": -10.185689112991424,
+ "z": 0.0
+ },
+ {
+ "x": 94.37139094185343,
+ "y": -9.131986404198488,
+ "z": 0.0
+ },
+ {
+ "x": 94.39012123383223,
+ "y": -8.153369150514646,
+ "z": 0.0
+ },
+ {
+ "x": 94.46022890273653,
+ "y": -7.337998068902732,
+ "z": 0.0
+ },
+ {
+ "x": 94.6072688252939,
+ "y": -6.9230812441710645,
+ "z": 0.0
+ },
+ {
+ "x": 94.83259463557908,
+ "y": -6.385304482763309,
+ "z": 0.0
+ },
+ {
+ "x": 95.11913777981543,
+ "y": -5.877941833921707,
+ "z": 0.0
+ },
+ {
+ "x": 95.46350212363555,
+ "y": -5.407065852095712,
+ "z": 0.0
+ },
+ {
+ "x": 95.86171945887978,
+ "y": -4.978761611453896,
+ "z": 0.0
+ },
+ {
+ "x": 96.22923305880748,
+ "y": -4.719862677775668,
+ "z": 0.0
+ },
+ {
+ "x": 96.70185990677085,
+ "y": -4.441451745629632,
+ "z": 0.0
+ },
+ {
+ "x": 97.22041617308734,
+ "y": -4.211505752369636,
+ "z": 0.0
+ },
+ {
+ "x": 97.76345113210014,
+ "y": -4.0457846580773555,
+ "z": 0.0
+ },
+ {
+ "x": 98.32410668616481,
+ "y": -3.9466924676147257,
+ "z": 0.0
+ },
+ {
+ "x": 98.79512439302592,
+ "y": -3.95205280415974,
+ "z": 0.0
+ },
+ {
+ "x": 99.58080669915239,
+ "y": -3.9508205713340376,
+ "z": 0.0
+ },
+ {
+ "x": 100.5839090094622,
+ "y": -3.9508137140995263,
+ "z": 0.0
+ },
+ {
+ "x": 101.63761167446887,
+ "y": -3.9504703020497662,
+ "z": 0.0
+ },
+ {
+ "x": 102.69131433947555,
+ "y": -3.950126890000005,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 196,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 79.38131557415628,
+ "y": -3.9577238475875323,
+ "z": 0.0
+ },
+ {
+ "x": 80.43950680616342,
+ "y": -3.9573789726696917,
+ "z": 0.0
+ },
+ {
+ "x": 81.49769803817055,
+ "y": -3.957034097751851,
+ "z": 0.0
+ },
+ {
+ "x": 82.54733788811372,
+ "y": -3.958919061057222,
+ "z": 0.0
+ },
+ {
+ "x": 83.25546999072677,
+ "y": -4.0367179671995865,
+ "z": 0.0
+ },
+ {
+ "x": 83.85626624649599,
+ "y": -4.181507034273803,
+ "z": 0.0
+ },
+ {
+ "x": 84.45707638728011,
+ "y": -4.39224457294905,
+ "z": 0.0
+ },
+ {
+ "x": 84.89020730165043,
+ "y": -4.641475916963456,
+ "z": 0.0
+ },
+ {
+ "x": 85.27499915893839,
+ "y": -4.945073788381097,
+ "z": 0.0
+ },
+ {
+ "x": 85.72199976105516,
+ "y": -5.3529289744430795,
+ "z": 0.0
+ },
+ {
+ "x": 86.08734206940625,
+ "y": -5.789075209259341,
+ "z": 0.0
+ },
+ {
+ "x": 86.12224575164548,
+ "y": -6.021688634033307,
+ "z": 0.0
+ },
+ {
+ "x": 86.28329841826393,
+ "y": -6.499402208514818,
+ "z": 0.0
+ },
+ {
+ "x": 86.38562053758875,
+ "y": -7.009892905183665,
+ "z": 0.0
+ },
+ {
+ "x": 86.38134700142467,
+ "y": -7.4383508230156385,
+ "z": 0.0
+ },
+ {
+ "x": 86.37153594890037,
+ "y": -8.114997986374872,
+ "z": 0.0
+ },
+ {
+ "x": 86.37138966964652,
+ "y": -9.124225371328526,
+ "z": 0.0
+ },
+ {
+ "x": 86.37155052814866,
+ "y": -10.182416647308463,
+ "z": 0.0
+ },
+ {
+ "x": 86.3717113866508,
+ "y": -11.2406079232884,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 202,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 347.7299857691685,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 346.65641965126474,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 345.6051845218596,
+ "y": -324.60410859498836,
+ "z": 0.0
+ },
+ {
+ "x": 344.7850166539401,
+ "y": -324.540098970213,
+ "z": 0.0
+ },
+ {
+ "x": 344.25909294341756,
+ "y": -324.39700813462906,
+ "z": 0.0
+ },
+ {
+ "x": 343.71191033205946,
+ "y": -324.1828372395416,
+ "z": 0.0
+ },
+ {
+ "x": 343.19528786244814,
+ "y": -323.904106512928,
+ "z": 0.0
+ },
+ {
+ "x": 342.7166149375832,
+ "y": -323.5649536309744,
+ "z": 0.0
+ },
+ {
+ "x": 342.28274894064253,
+ "y": -323.17033164995433,
+ "z": 0.0
+ },
+ {
+ "x": 341.8913001189622,
+ "y": -322.7206360617598,
+ "z": 0.0
+ },
+ {
+ "x": 341.5369668432233,
+ "y": -322.2125067112267,
+ "z": 0.0
+ },
+ {
+ "x": 341.2324938951551,
+ "y": -321.65769348921674,
+ "z": 0.0
+ },
+ {
+ "x": 340.99061304977715,
+ "y": -321.07212369910155,
+ "z": 0.0
+ },
+ {
+ "x": 340.83080310229485,
+ "y": -320.48807252445783,
+ "z": 0.0
+ },
+ {
+ "x": 340.74178785032285,
+ "y": -319.89215389539834,
+ "z": 0.0
+ },
+ {
+ "x": 340.71272597311315,
+ "y": -319.2600014064103,
+ "z": 0.0
+ },
+ {
+ "x": 340.70687562977463,
+ "y": -318.4515480594214,
+ "z": 0.0
+ },
+ {
+ "x": 340.70817719947337,
+ "y": -317.45271969952285,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 217,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 332.7081788771901,
+ "y": -317.4475260295794,
+ "z": 0.0
+ },
+ {
+ "x": 332.7075245816217,
+ "y": -318.5307770498437,
+ "z": 0.0
+ },
+ {
+ "x": 332.7149193734867,
+ "y": -319.3628031526399,
+ "z": 0.0
+ },
+ {
+ "x": 332.69090557791753,
+ "y": -320.049931684257,
+ "z": 0.0
+ },
+ {
+ "x": 332.6128631715627,
+ "y": -320.679999573273,
+ "z": 0.0
+ },
+ {
+ "x": 332.4651120128465,
+ "y": -321.2974806177943,
+ "z": 0.0
+ },
+ {
+ "x": 332.31111388697144,
+ "y": -321.78577852098607,
+ "z": 0.0
+ },
+ {
+ "x": 332.0291584429973,
+ "y": -322.3238751397163,
+ "z": 0.0
+ },
+ {
+ "x": 331.67371169882904,
+ "y": -322.8360704972532,
+ "z": 0.0
+ },
+ {
+ "x": 331.276763504097,
+ "y": -323.2917244669964,
+ "z": 0.0
+ },
+ {
+ "x": 330.83781253302345,
+ "y": -323.6909312682483,
+ "z": 0.0
+ },
+ {
+ "x": 330.48216088504284,
+ "y": -323.9757259923004,
+ "z": 0.0
+ },
+ {
+ "x": 329.96569825792506,
+ "y": -324.23364793609016,
+ "z": 0.0
+ },
+ {
+ "x": 329.40367289306323,
+ "y": -324.42640954825083,
+ "z": 0.0
+ },
+ {
+ "x": 328.7325685885115,
+ "y": -324.5533841445278,
+ "z": 0.0
+ },
+ {
+ "x": 327.8864882032299,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 326.8032369853645,
+ "y": -324.6099853515625,
+ "z": 0.0
+ },
+ {
+ "x": 325.71998576749917,
+ "y": -324.6099853515625,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 226,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 94.38036233629381,
+ "y": -68.14939116425025,
+ "z": 0.0
+ },
+ {
+ "x": 94.380205608378,
+ "y": -67.1183725299237,
+ "z": 0.0
+ },
+ {
+ "x": 94.38004888046221,
+ "y": -66.08735389559722,
+ "z": 0.0
+ },
+ {
+ "x": 94.3798921525464,
+ "y": -65.0563352612706,
+ "z": 0.0
+ },
+ {
+ "x": 94.41540859131102,
+ "y": -64.17671650467226,
+ "z": 0.0
+ },
+ {
+ "x": 94.50599020801253,
+ "y": -63.43406355283531,
+ "z": 0.0
+ },
+ {
+ "x": 94.65004354411337,
+ "y": -63.28886531615959,
+ "z": 0.0
+ },
+ {
+ "x": 94.89412789099731,
+ "y": -62.88319975924353,
+ "z": 0.0
+ },
+ {
+ "x": 95.19296693797658,
+ "y": -62.51318763201182,
+ "z": 0.0
+ },
+ {
+ "x": 95.50496933112525,
+ "y": -62.25534955729171,
+ "z": 0.0
+ },
+ {
+ "x": 95.79800974776776,
+ "y": -62.11894221635172,
+ "z": 0.0
+ },
+ {
+ "x": 96.32100408123506,
+ "y": -61.84314210418763,
+ "z": 0.0
+ },
+ {
+ "x": 96.87868341854731,
+ "y": -61.62060831764035,
+ "z": 0.0
+ },
+ {
+ "x": 97.29632721050396,
+ "y": -61.55600143297452,
+ "z": 0.0
+ },
+ {
+ "x": 97.80242386355842,
+ "y": -61.52230377982157,
+ "z": 0.0
+ },
+ {
+ "x": 98.5261196610379,
+ "y": -61.49245168271566,
+ "z": 0.0
+ },
+ {
+ "x": 99.3281588135278,
+ "y": -61.498913326717286,
+ "z": 0.0
+ },
+ {
+ "x": 100.3591774521123,
+ "y": -61.498787694223985,
+ "z": 0.0
+ },
+ {
+ "x": 101.39019609069686,
+ "y": -61.49866206173068,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 235,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 101.38950854005927,
+ "y": -53.49866208611823,
+ "z": 0.0
+ },
+ {
+ "x": 100.35427574987001,
+ "y": -53.49878823211765,
+ "z": 0.0
+ },
+ {
+ "x": 99.37376770017384,
+ "y": -53.48524399821469,
+ "z": 0.0
+ },
+ {
+ "x": 98.56594764529008,
+ "y": -53.42248411699823,
+ "z": 0.0
+ },
+ {
+ "x": 98.02529054486976,
+ "y": -53.28960016706168,
+ "z": 0.0
+ },
+ {
+ "x": 97.39333152686908,
+ "y": -53.08861912710111,
+ "z": 0.0
+ },
+ {
+ "x": 96.78166837055359,
+ "y": -52.82970085027407,
+ "z": 0.0
+ },
+ {
+ "x": 96.28198883142825,
+ "y": -52.534509829604154,
+ "z": 0.0
+ },
+ {
+ "x": 95.8363635631698,
+ "y": -52.191004873637944,
+ "z": 0.0
+ },
+ {
+ "x": 95.37363437662033,
+ "y": -51.767432997723176,
+ "z": 0.0
+ },
+ {
+ "x": 94.99551614629756,
+ "y": -51.32382634745366,
+ "z": 0.0
+ },
+ {
+ "x": 94.75043184234941,
+ "y": -50.90678621458571,
+ "z": 0.0
+ },
+ {
+ "x": 94.61657447268031,
+ "y": -50.51927995168681,
+ "z": 0.0
+ },
+ {
+ "x": 94.46613425141832,
+ "y": -49.99260252804384,
+ "z": 0.0
+ },
+ {
+ "x": 94.38030857826998,
+ "y": -49.45071585721417,
+ "z": 0.0
+ },
+ {
+ "x": 94.36315168668953,
+ "y": -48.906894212072416,
+ "z": 0.0
+ },
+ {
+ "x": 94.37733070564443,
+ "y": -48.21662848944666,
+ "z": 0.0
+ },
+ {
+ "x": 94.37717547838463,
+ "y": -47.18497092961871,
+ "z": 0.0
+ },
+ {
+ "x": 94.37701810986431,
+ "y": -46.14973814370483,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 241,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 325.6696754063413,
+ "y": -201.15911160127555,
+ "z": 0.0
+ },
+ {
+ "x": 326.69854293953034,
+ "y": -201.1591952064953,
+ "z": 0.0
+ },
+ {
+ "x": 327.55662263077403,
+ "y": -201.1556171967777,
+ "z": 0.0
+ },
+ {
+ "x": 328.2878604030311,
+ "y": -201.17589028449774,
+ "z": 0.0
+ },
+ {
+ "x": 328.9011683532972,
+ "y": -201.22663941361236,
+ "z": 0.0
+ },
+ {
+ "x": 329.3792074949348,
+ "y": -201.2950945907748,
+ "z": 0.0
+ },
+ {
+ "x": 329.94437832953804,
+ "y": -201.48083812438352,
+ "z": 0.0
+ },
+ {
+ "x": 330.50391400106264,
+ "y": -201.73861700728952,
+ "z": 0.0
+ },
+ {
+ "x": 331.024340149681,
+ "y": -202.0449603967076,
+ "z": 0.0
+ },
+ {
+ "x": 331.4555572397345,
+ "y": -202.35002324535176,
+ "z": 0.0
+ },
+ {
+ "x": 331.7582337858688,
+ "y": -202.58574368321777,
+ "z": 0.0
+ },
+ {
+ "x": 332.0804677406411,
+ "y": -202.99176286272518,
+ "z": 0.0
+ },
+ {
+ "x": 332.347243162328,
+ "y": -203.43389313205873,
+ "z": 0.0
+ },
+ {
+ "x": 332.55520982858246,
+ "y": -203.9057956290992,
+ "z": 0.0
+ },
+ {
+ "x": 332.69773103323286,
+ "y": -204.35948999220938,
+ "z": 0.0
+ },
+ {
+ "x": 332.77073692392213,
+ "y": -205.06321647940158,
+ "z": 0.0
+ },
+ {
+ "x": 332.7754515617806,
+ "y": -206.07094373654172,
+ "z": 0.0
+ },
+ {
+ "x": 332.77483011454973,
+ "y": -207.09981108544716,
+ "z": 0.0
+ },
+ {
+ "x": 332.7742086673189,
+ "y": -208.12867843435257,
+ "z": 0.0
+ },
+ {
+ "x": 332.773587220088,
+ "y": -209.157545783258,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 244,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 332.7877875168978,
+ "y": -185.64755007182552,
+ "z": 0.0
+ },
+ {
+ "x": 332.7871558692562,
+ "y": -186.69330520950456,
+ "z": 0.0
+ },
+ {
+ "x": 332.78855716050793,
+ "y": -187.6139412482442,
+ "z": 0.0
+ },
+ {
+ "x": 332.769849486949,
+ "y": -188.42140076858865,
+ "z": 0.0
+ },
+ {
+ "x": 332.77083182214864,
+ "y": -188.88303279362856,
+ "z": 0.0
+ },
+ {
+ "x": 332.66348831483367,
+ "y": -189.4449902018104,
+ "z": 0.0
+ },
+ {
+ "x": 332.46997372679783,
+ "y": -190.02958668760976,
+ "z": 0.0
+ },
+ {
+ "x": 332.2154937201096,
+ "y": -190.5892499954893,
+ "z": 0.0
+ },
+ {
+ "x": 331.98978605376124,
+ "y": -191.01441570599346,
+ "z": 0.0
+ },
+ {
+ "x": 331.64962893870444,
+ "y": -191.45391576692543,
+ "z": 0.0
+ },
+ {
+ "x": 331.20220308693445,
+ "y": -191.88800872415374,
+ "z": 0.0
+ },
+ {
+ "x": 330.7115349826413,
+ "y": -192.27258396974145,
+ "z": 0.0
+ },
+ {
+ "x": 330.2919359880639,
+ "y": -192.5572890717597,
+ "z": 0.0
+ },
+ {
+ "x": 329.8012178989161,
+ "y": -192.79279664378373,
+ "z": 0.0
+ },
+ {
+ "x": 329.2041630135967,
+ "y": -192.97658802806663,
+ "z": 0.0
+ },
+ {
+ "x": 328.54331794047005,
+ "y": -193.09947345183087,
+ "z": 0.0
+ },
+ {
+ "x": 327.7621837163193,
+ "y": -193.15928161095763,
+ "z": 0.0
+ },
+ {
+ "x": 326.7164283913317,
+ "y": -193.15919663344505,
+ "z": 0.0
+ },
+ {
+ "x": 325.67067306634425,
+ "y": -193.1591116559325,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 256,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 325.1604817010584,
+ "y": -61.471395029053355,
+ "z": 0.0
+ },
+ {
+ "x": 326.19722933008575,
+ "y": -61.47126869846662,
+ "z": 0.0
+ },
+ {
+ "x": 327.233976959113,
+ "y": -61.47114236787987,
+ "z": 0.0
+ },
+ {
+ "x": 327.99131405353273,
+ "y": -61.46127945318263,
+ "z": 0.0
+ },
+ {
+ "x": 328.6109717729404,
+ "y": -61.482747456950605,
+ "z": 0.0
+ },
+ {
+ "x": 329.2103753540747,
+ "y": -61.5647292733214,
+ "z": 0.0
+ },
+ {
+ "x": 329.79705055025045,
+ "y": -61.71050220350344,
+ "z": 0.0
+ },
+ {
+ "x": 330.3123387974076,
+ "y": -61.889415448071965,
+ "z": 0.0
+ },
+ {
+ "x": 330.77626372745664,
+ "y": -62.11094879964533,
+ "z": 0.0
+ },
+ {
+ "x": 331.25491038381944,
+ "y": -62.43748212523404,
+ "z": 0.0
+ },
+ {
+ "x": 331.670805195674,
+ "y": -62.7900771917235,
+ "z": 0.0
+ },
+ {
+ "x": 332.03159138732866,
+ "y": -63.17706278805754,
+ "z": 0.0
+ },
+ {
+ "x": 332.3123598399787,
+ "y": -63.543989064113035,
+ "z": 0.0
+ },
+ {
+ "x": 332.5315476756131,
+ "y": -63.92517497204276,
+ "z": 0.0
+ },
+ {
+ "x": 332.70310131549746,
+ "y": -64.42779257280169,
+ "z": 0.0
+ },
+ {
+ "x": 332.8139116311539,
+ "y": -65.08228432514662,
+ "z": 0.0
+ },
+ {
+ "x": 332.8601058914801,
+ "y": -65.91732900219925,
+ "z": 0.0
+ },
+ {
+ "x": 332.85947968458265,
+ "y": -66.95407644980567,
+ "z": 0.0
+ },
+ {
+ "x": 332.8588534776853,
+ "y": -67.99082389741164,
+ "z": 0.0
+ },
+ {
+ "x": 332.85822727078784,
+ "y": -69.02757134501785,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 271,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 332.8718839577665,
+ "y": -46.417575469412235,
+ "z": 0.0
+ },
+ {
+ "x": 332.8712509968554,
+ "y": -47.46590647417591,
+ "z": 0.0
+ },
+ {
+ "x": 332.87906109993855,
+ "y": -48.254069835605016,
+ "z": 0.0
+ },
+ {
+ "x": 332.8674708247359,
+ "y": -48.83855051155455,
+ "z": 0.0
+ },
+ {
+ "x": 332.78721881227335,
+ "y": -49.41956063034073,
+ "z": 0.0
+ },
+ {
+ "x": 332.6404482078824,
+ "y": -49.986768950414024,
+ "z": 0.0
+ },
+ {
+ "x": 332.42919462016573,
+ "y": -50.532805912282264,
+ "z": 0.0
+ },
+ {
+ "x": 332.15627773256864,
+ "y": -51.050572148092485,
+ "z": 0.0
+ },
+ {
+ "x": 331.82467710757146,
+ "y": -51.533936458630656,
+ "z": 0.0
+ },
+ {
+ "x": 331.4370083989903,
+ "y": -51.977864296335234,
+ "z": 0.0
+ },
+ {
+ "x": 330.99884451709175,
+ "y": -52.37582157742848,
+ "z": 0.0
+ },
+ {
+ "x": 330.54784008475104,
+ "y": -52.70646836786131,
+ "z": 0.0
+ },
+ {
+ "x": 330.05399673340213,
+ "y": -52.98129341041239,
+ "z": 0.0
+ },
+ {
+ "x": 329.503203182546,
+ "y": -53.20007708555586,
+ "z": 0.0
+ },
+ {
+ "x": 328.93171552914595,
+ "y": -53.35431927828143,
+ "z": 0.0
+ },
+ {
+ "x": 328.1971693258425,
+ "y": -53.443553006846,
+ "z": 0.0
+ },
+ {
+ "x": 327.25895540688833,
+ "y": -53.47113926479402,
+ "z": 0.0
+ },
+ {
+ "x": 326.209231142834,
+ "y": -53.471267176619904,
+ "z": 0.0
+ },
+ {
+ "x": 325.15950687877955,
+ "y": -53.47139508844576,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 274,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 94.40167147489854,
+ "y": -208.3293895446205,
+ "z": 0.0
+ },
+ {
+ "x": 94.40151478566703,
+ "y": -207.29862539105918,
+ "z": 0.0
+ },
+ {
+ "x": 94.40135809643554,
+ "y": -206.26786123749787,
+ "z": 0.0
+ },
+ {
+ "x": 94.43376229952128,
+ "y": -205.3736891092996,
+ "z": 0.0
+ },
+ {
+ "x": 94.51834203531422,
+ "y": -204.61128923276965,
+ "z": 0.0
+ },
+ {
+ "x": 94.66783350768677,
+ "y": -204.1297875213049,
+ "z": 0.0
+ },
+ {
+ "x": 94.87944244681093,
+ "y": -203.6696897342904,
+ "z": 0.0
+ },
+ {
+ "x": 95.16995944891461,
+ "y": -203.15286855648935,
+ "z": 0.0
+ },
+ {
+ "x": 95.51540707027908,
+ "y": -202.67004371951856,
+ "z": 0.0
+ },
+ {
+ "x": 95.90389606178833,
+ "y": -202.24482846065445,
+ "z": 0.0
+ },
+ {
+ "x": 96.2525027421791,
+ "y": -201.99846580436187,
+ "z": 0.0
+ },
+ {
+ "x": 96.73848706787206,
+ "y": -201.69010810485491,
+ "z": 0.0
+ },
+ {
+ "x": 97.25615282237987,
+ "y": -201.43877363286256,
+ "z": 0.0
+ },
+ {
+ "x": 97.80048676780363,
+ "y": -201.24710934793697,
+ "z": 0.0
+ },
+ {
+ "x": 98.25513109950654,
+ "y": -201.17854678323314,
+ "z": 0.0
+ },
+ {
+ "x": 98.76739644056705,
+ "y": -201.15582125755216,
+ "z": 0.0
+ },
+ {
+ "x": 99.51039002690968,
+ "y": -201.13782300713487,
+ "z": 0.0
+ },
+ {
+ "x": 100.38857732118137,
+ "y": -201.1408053809885,
+ "z": 0.0
+ },
+ {
+ "x": 101.4193414832491,
+ "y": -201.14088914032726,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 286,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 101.42032622238838,
+ "y": -193.14088919393424,
+ "z": 0.0
+ },
+ {
+ "x": 100.33922750350321,
+ "y": -193.1408013444366,
+ "z": 0.0
+ },
+ {
+ "x": 99.25812878461814,
+ "y": -193.14071349493892,
+ "z": 0.0
+ },
+ {
+ "x": 98.39054133013732,
+ "y": -193.08907796797558,
+ "z": 0.0
+ },
+ {
+ "x": 97.69618927189643,
+ "y": -192.96873836108958,
+ "z": 0.0
+ },
+ {
+ "x": 97.07486869043078,
+ "y": -192.78301788211778,
+ "z": 0.0
+ },
+ {
+ "x": 96.47651183719475,
+ "y": -192.5312083437614,
+ "z": 0.0
+ },
+ {
+ "x": 95.90761962214879,
+ "y": -192.21577823107452,
+ "z": 0.0
+ },
+ {
+ "x": 95.47809790869928,
+ "y": -191.87555176993956,
+ "z": 0.0
+ },
+ {
+ "x": 95.07232590934612,
+ "y": -191.46859694320713,
+ "z": 0.0
+ },
+ {
+ "x": 94.79183893066474,
+ "y": -191.06305779436045,
+ "z": 0.0
+ },
+ {
+ "x": 94.58695946635352,
+ "y": -190.6335781301305,
+ "z": 0.0
+ },
+ {
+ "x": 94.44899671077283,
+ "y": -190.1776736582307,
+ "z": 0.0
+ },
+ {
+ "x": 94.38112600071274,
+ "y": -189.70503411601993,
+ "z": 0.0
+ },
+ {
+ "x": 94.383139280547,
+ "y": -189.21977939325217,
+ "z": 0.0
+ },
+ {
+ "x": 94.39865592659415,
+ "y": -188.4919121005017,
+ "z": 0.0
+ },
+ {
+ "x": 94.39849158587134,
+ "y": -187.41081339053818,
+ "z": 0.0
+ },
+ {
+ "x": 94.39832724514855,
+ "y": -186.32971468057468,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 292,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 332.82709050768517,
+ "y": -120.57756194154449,
+ "z": 0.0
+ },
+ {
+ "x": 332.82643877406326,
+ "y": -121.6565714059926,
+ "z": 0.0
+ },
+ {
+ "x": 332.83245205105794,
+ "y": -122.50716907762718,
+ "z": 0.0
+ },
+ {
+ "x": 332.81132858665546,
+ "y": -123.19805967071827,
+ "z": 0.0
+ },
+ {
+ "x": 332.7542482002542,
+ "y": -123.76934929727207,
+ "z": 0.0
+ },
+ {
+ "x": 332.6646701817641,
+ "y": -124.24252956643309,
+ "z": 0.0
+ },
+ {
+ "x": 332.5001486679359,
+ "y": -124.70549841621741,
+ "z": 0.0
+ },
+ {
+ "x": 332.2121530385942,
+ "y": -125.20439690327898,
+ "z": 0.0
+ },
+ {
+ "x": 331.8507388515651,
+ "y": -125.67492643492409,
+ "z": 0.0
+ },
+ {
+ "x": 331.39999244756945,
+ "y": -126.12422224787402,
+ "z": 0.0
+ },
+ {
+ "x": 330.99793115335666,
+ "y": -126.46806789445478,
+ "z": 0.0
+ },
+ {
+ "x": 330.4254675243916,
+ "y": -126.80336453193688,
+ "z": 0.0
+ },
+ {
+ "x": 329.8075639202306,
+ "y": -127.08118371157036,
+ "z": 0.0
+ },
+ {
+ "x": 329.1656402917356,
+ "y": -127.29568914951442,
+ "z": 0.0
+ },
+ {
+ "x": 328.59192458915544,
+ "y": -127.43803717191713,
+ "z": 0.0
+ },
+ {
+ "x": 327.75584160763026,
+ "y": -127.50443980675412,
+ "z": 0.0
+ },
+ {
+ "x": 326.7211200901641,
+ "y": -127.51556771483503,
+ "z": 0.0
+ },
+ {
+ "x": 325.6421105365875,
+ "y": -127.51508562015208,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 304,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 325.6381862987218,
+ "y": -135.51508466532573,
+ "z": 0.0
+ },
+ {
+ "x": 326.6693035988366,
+ "y": -135.515545362051,
+ "z": 0.0
+ },
+ {
+ "x": 327.55131543289843,
+ "y": -135.5131593711596,
+ "z": 0.0
+ },
+ {
+ "x": 328.3141035849688,
+ "y": -135.5330080851354,
+ "z": 0.0
+ },
+ {
+ "x": 328.7928591328234,
+ "y": -135.54477745834626,
+ "z": 0.0
+ },
+ {
+ "x": 329.2838720270384,
+ "y": -135.62962857414666,
+ "z": 0.0
+ },
+ {
+ "x": 329.8398044272193,
+ "y": -135.82352366647075,
+ "z": 0.0
+ },
+ {
+ "x": 330.3697282088117,
+ "y": -136.07686163386663,
+ "z": 0.0
+ },
+ {
+ "x": 330.8094226454465,
+ "y": -136.3352242557169,
+ "z": 0.0
+ },
+ {
+ "x": 331.19388056147704,
+ "y": -136.62723539200704,
+ "z": 0.0
+ },
+ {
+ "x": 331.6098466658718,
+ "y": -137.08355681539902,
+ "z": 0.0
+ },
+ {
+ "x": 331.9767702484966,
+ "y": -137.58116569359478,
+ "z": 0.0
+ },
+ {
+ "x": 332.26804777178256,
+ "y": -138.05807524433806,
+ "z": 0.0
+ },
+ {
+ "x": 332.48255764058945,
+ "y": -138.49289968548555,
+ "z": 0.0
+ },
+ {
+ "x": 332.65222061387357,
+ "y": -139.0891815282288,
+ "z": 0.0
+ },
+ {
+ "x": 332.76312477510174,
+ "y": -139.7739642368658,
+ "z": 0.0
+ },
+ {
+ "x": 332.81501231398755,
+ "y": -140.57420608476463,
+ "z": 0.0
+ },
+ {
+ "x": 332.8143895078128,
+ "y": -141.6053232997068,
+ "z": 0.0
+ },
+ {
+ "x": 332.81376670163803,
+ "y": -142.63644051464897,
+ "z": 0.0
+ },
+ {
+ "x": 332.81314389546327,
+ "y": -143.66755772959112,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 310,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 101.42178302796803,
+ "y": -127.41490538788197,
+ "z": 0.0
+ },
+ {
+ "x": 100.36884173414194,
+ "y": -127.41443494033355,
+ "z": 0.0
+ },
+ {
+ "x": 99.31590044031583,
+ "y": -127.41396449278513,
+ "z": 0.0
+ },
+ {
+ "x": 98.34557054873348,
+ "y": -127.3928796818061,
+ "z": 0.0
+ },
+ {
+ "x": 97.55962058570432,
+ "y": -127.31583473381473,
+ "z": 0.0
+ },
+ {
+ "x": 97.20790067612784,
+ "y": -127.16461138721388,
+ "z": 0.0
+ },
+ {
+ "x": 96.7223537644397,
+ "y": -126.93250374971481,
+ "z": 0.0
+ },
+ {
+ "x": 96.27063494180855,
+ "y": -126.64030547433455,
+ "z": 0.0
+ },
+ {
+ "x": 95.85910137782332,
+ "y": -126.29195836230957,
+ "z": 0.0
+ },
+ {
+ "x": 95.51989604462473,
+ "y": -125.90683342043921,
+ "z": 0.0
+ },
+ {
+ "x": 95.28468889415034,
+ "y": -125.51761502775999,
+ "z": 0.0
+ },
+ {
+ "x": 94.97091192766963,
+ "y": -124.95536653932524,
+ "z": 0.0
+ },
+ {
+ "x": 94.71416588676566,
+ "y": -124.36200598792965,
+ "z": 0.0
+ },
+ {
+ "x": 94.51831459567889,
+ "y": -123.74448953392844,
+ "z": 0.0
+ },
+ {
+ "x": 94.4338890820918,
+ "y": -123.20146492211585,
+ "z": 0.0
+ },
+ {
+ "x": 94.40464030373457,
+ "y": -122.61480564194734,
+ "z": 0.0
+ },
+ {
+ "x": 94.38639075227408,
+ "y": -121.8151086621219,
+ "z": 0.0
+ },
+ {
+ "x": 94.38837998400676,
+ "y": -120.89267019879318,
+ "z": 0.0
+ },
+ {
+ "x": 94.38821992355439,
+ "y": -119.83972881203614,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 319,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 94.391564151273,
+ "y": -141.83939031284123,
+ "z": 0.0
+ },
+ {
+ "x": 94.39140215202507,
+ "y": -140.77369475687905,
+ "z": 0.0
+ },
+ {
+ "x": 94.39124015277714,
+ "y": -139.7079992009169,
+ "z": 0.0
+ },
+ {
+ "x": 94.41769376377435,
+ "y": -138.74855890854363,
+ "z": 0.0
+ },
+ {
+ "x": 94.51320921265764,
+ "y": -138.03658731539213,
+ "z": 0.0
+ },
+ {
+ "x": 94.67785056645131,
+ "y": -137.5681944180493,
+ "z": 0.0
+ },
+ {
+ "x": 94.89872548747795,
+ "y": -137.18945653433522,
+ "z": 0.0
+ },
+ {
+ "x": 95.1855065404848,
+ "y": -136.82090632507058,
+ "z": 0.0
+ },
+ {
+ "x": 95.53687355774571,
+ "y": -136.47276500306168,
+ "z": 0.0
+ },
+ {
+ "x": 95.94636994374555,
+ "y": -136.15990448540106,
+ "z": 0.0
+ },
+ {
+ "x": 96.41739399178752,
+ "y": -135.88051851943328,
+ "z": 0.0
+ },
+ {
+ "x": 96.93028384483344,
+ "y": -135.65565452448743,
+ "z": 0.0
+ },
+ {
+ "x": 97.46813231162776,
+ "y": -135.49697314657672,
+ "z": 0.0
+ },
+ {
+ "x": 98.02286346439605,
+ "y": -135.40712496469334,
+ "z": 0.0
+ },
+ {
+ "x": 98.51827011133815,
+ "y": -135.41166569519828,
+ "z": 0.0
+ },
+ {
+ "x": 99.32070176238868,
+ "y": -135.4138213058624,
+ "z": 0.0
+ },
+ {
+ "x": 100.35220617672339,
+ "y": -135.41442830616955,
+ "z": 0.0
+ },
+ {
+ "x": 101.41790163862902,
+ "y": -135.41490445220006,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 328,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 152.02380945971413,
+ "y": -46.195106783691955,
+ "z": 0.0
+ },
+ {
+ "x": 152.02254200228586,
+ "y": -47.23847720268771,
+ "z": 0.0
+ },
+ {
+ "x": 152.0213199732512,
+ "y": -48.26703348854526,
+ "z": 0.0
+ },
+ {
+ "x": 152.0288322655578,
+ "y": -49.01153177480047,
+ "z": 0.0
+ },
+ {
+ "x": 152.01859274755594,
+ "y": -49.54736259613325,
+ "z": 0.0
+ },
+ {
+ "x": 151.9309711128801,
+ "y": -50.10404697631353,
+ "z": 0.0
+ },
+ {
+ "x": 151.77769148461007,
+ "y": -50.64525437326739,
+ "z": 0.0
+ },
+ {
+ "x": 151.56081242716232,
+ "y": -51.164236234723724,
+ "z": 0.0
+ },
+ {
+ "x": 151.33509844602395,
+ "y": -51.59210944971475,
+ "z": 0.0
+ },
+ {
+ "x": 151.03922219866305,
+ "y": -51.995446238265515,
+ "z": 0.0
+ },
+ {
+ "x": 150.63750602870874,
+ "y": -52.39113917962509,
+ "z": 0.0
+ },
+ {
+ "x": 150.1923699306697,
+ "y": -52.735138851514144,
+ "z": 0.0
+ },
+ {
+ "x": 149.70952634494085,
+ "y": -53.023302356093474,
+ "z": 0.0
+ },
+ {
+ "x": 149.23875404894363,
+ "y": -53.24117517081868,
+ "z": 0.0
+ },
+ {
+ "x": 148.79867298597753,
+ "y": -53.39036933638519,
+ "z": 0.0
+ },
+ {
+ "x": 148.0224206112521,
+ "y": -53.468981156349344,
+ "z": 0.0
+ },
+ {
+ "x": 147.07657391052473,
+ "y": -53.493094989928544,
+ "z": 0.0
+ },
+ {
+ "x": 146.03320272943924,
+ "y": -53.49322212761356,
+ "z": 0.0
+ },
+ {
+ "x": 144.98983154835375,
+ "y": -53.49334926529858,
+ "z": 0.0
+ }
+ ]
+ },
+ {
+ "id": 337,
+ "map_element_id": 15,
+ "type": "road_edge",
+ "geometry": [
+ {
+ "x": 167.1695080517052,
+ "y": -53.490646609928866,
+ "z": 0.0
+ },
+ {
+ "x": 166.12735220349356,
+ "y": -53.49077359952219,
+ "z": 0.0
+ },
+ {
+ "x": 165.08519635528188,
+ "y": -53.490900589115526,
+ "z": 0.0
+ },
+ {
+ "x": 164.26826123122513,
+ "y": -53.43913165781505,
+ "z": 0.0
+ },
+ {
+ "x": 163.57831205067666,
+ "y": -53.32661522480176,
+ "z": 0.0
+ },
+ {
+ "x": 162.97263741222574,
+ "y": -53.15405915103483,
+ "z": 0.0
+ },
+ {
+ "x": 162.47269917418078,
+ "y": -52.928503300812395,
+ "z": 0.0
+ },
+ {
+ "x": 162.01532313836688,
+ "y": -52.645855553721226,
+ "z": 0.0
+ },
+ {
+ "x": 161.50784418968078,
+ "y": -52.27512648472766,
+ "z": 0.0
+ },
+ {
+ "x": 161.0504105618973,
+ "y": -51.85852801483733,
+ "z": 0.0
+ },
+ {
+ "x": 160.67677545057913,
+ "y": -51.41871503147218,
+ "z": 0.0
+ },
+ {
+ "x": 160.50406612361127,
+ "y": -51.063635052220704,
+ "z": 0.0
+ },
+ {
+ "x": 160.27764479185996,
+ "y": -50.55138900037866,
+ "z": 0.0
+ },
+ {
+ "x": 160.11411017382582,
+ "y": -50.015611342568725,
+ "z": 0.0
+ },
+ {
+ "x": 160.0156401774726,
+ "y": -49.46252361870256,
+ "z": 0.0
+ },
+ {
+ "x": 160.01938909966404,
+ "y": -48.996991646258856,
+ "z": 0.0
+ },
+ {
+ "x": 160.02102230073152,
+ "y": -48.239731358425196,
+ "z": 0.0
+ },
+ {
+ "x": 160.02253716340635,
+ "y": -47.247319653457076,
+ "z": 0.0
+ },
+ {
+ "x": 160.02380314448305,
+ "y": -46.20516456644735,
+ "z": 0.0
+ }
+ ]
+ }
+ ],
+ "tl_states": {},
+ "metadata": {
+ "sdc_track_index": 0,
+ "tracks_to_predict": [],
+ "objects_of_interest": []
+ }
+}
diff --git a/data_utils/carla/carla_data_utils.py b/data_utils/carla/carla_data_utils.py
new file mode 100644
index 000000000..eadf116bd
--- /dev/null
+++ b/data_utils/carla/carla_data_utils.py
@@ -0,0 +1,67 @@
+import os
+import json
+from typing import List
+
+
+def replace_roads_in_json_files(source_dir: str, destination_dir: str, town_names: List[str]):
+ for town_name in town_names:
+ print(f"Replacing roads for town: {town_name}")
+ source_file = os.path.join(source_dir, f"{town_name}.json")
+ if not os.path.isfile(source_file):
+ print(f"Source file for {town_name} not found, skipping.")
+ continue
+ with open(source_file, "r") as sf:
+ source_data = json.load(sf)
+ roads_value = source_data["roads"]
+ if roads_value is None:
+ print(f"No roads data found for {town_name}, skipping.")
+ continue
+
+ for filename in os.listdir(destination_dir):
+ if filename.startswith(town_name) and filename.endswith(".json"):
+ dest_file = os.path.join(destination_dir, filename)
+ with open(dest_file, "r") as df:
+ dest_data = json.load(df)
+ dest_data["roads"] = roads_value
+ with open(dest_file, "w") as df:
+ json.dump(dest_data, df, indent=2)
+
+
+def make_all_non_expert_agent_initial_velocity_zero(towns, destination_directory):
+ for filename in os.listdir(destination_directory):
+ print(f"Processing file: {filename}")
+ for town in towns:
+ if filename.startswith(town):
+ json_file = os.path.join(destination_directory, filename)
+ try:
+ with open(json_file, "r") as f:
+ data = json.load(f)
+ except json.JSONDecodeError:
+ print(f"Error decoding JSON in file: {json_file}, skipping.")
+ continue
+
+ for agent in data.get("agents", []):
+ if agent.get("is_expert", False) == False:
+ agent["initial_velocity"] = 0
+ with open(json_file, "w") as f:
+ json.dump(data, f, indent=2)
+
+ objects = data.get("objects", [])
+
+ # Make initial velocity zero for all non_expert_agents
+ for obj in objects:
+ if obj.get("mark_as_expert", False) == False:
+ obj["velocity"][0] = {"x": 0.0, "y": 0.0}
+
+ data["objects"] = objects
+ # Save changes to the JSON file
+ with open(json_file, "w") as f:
+ json.dump(data, f, indent=2)
+
+
+if __name__ == "__main__":
+ source_directory = "data/processed/carla"
+ destination_directory = "data/processed/carla_data"
+ towns = ["town01", "town02", "town04", "town06", "town10HD"]
+ # replace_roads_in_json_files(source_directory, destination_directory, towns)
+ make_all_non_expert_agent_initial_velocity_zero(towns, destination_directory)
diff --git a/data_utils/carla/process_carla_roads.py b/data_utils/carla/process_carla_roads.py
new file mode 100644
index 000000000..2b3992488
--- /dev/null
+++ b/data_utils/carla/process_carla_roads.py
@@ -0,0 +1,338 @@
+import sys
+import os
+import pyxodr
+import json
+import numpy as np
+from lxml import etree
+from pyxodr.road_objects.road import Road
+from pyxodr.road_objects.lane import Lane, ConnectionPosition, LaneOrientation, TrafficOrientation
+from pyxodr.road_objects.junction import Junction
+from pyxodr.road_objects.lane_section import LaneSection
+from pyxodr.road_objects.network import RoadNetwork
+from shapely.geometry import Polygon
+from enum import IntEnum
+import random
+import string
+
+
+class MapType(IntEnum):
+ LANE_UNDEFINED = 0
+ LANE_FREEWAY = 1
+ LANE_SURFACE_STREET = 2
+ LANE_BIKE_LANE = 3
+ # Original definition skips 4
+ ROAD_LINE_UNKNOWN = 5
+ ROAD_LINE_BROKEN_SINGLE_WHITE = 6
+ ROAD_LINE_SOLID_SINGLE_WHITE = 7
+ ROAD_LINE_SOLID_DOUBLE_WHITE = 8
+ ROAD_LINE_BROKEN_SINGLE_YELLOW = 9
+ ROAD_LINE_BROKEN_DOUBLE_YELLOW = 10
+ ROAD_LINE_SOLID_SINGLE_YELLOW = 11
+ ROAD_LINE_SOLID_DOUBLE_YELLOW = 12
+ ROAD_LINE_PASSING_DOUBLE_YELLOW = 13
+ ROAD_EDGE_UNKNOWN = 14
+ ROAD_EDGE_BOUNDARY = 15
+ ROAD_EDGE_MEDIAN = 16
+ STOP_SIGN = 17
+ CROSSWALK = 18
+ SPEED_BUMP = 19
+ DRIVEWAY = 20 # New womd datatype in v1.2.0: Driveway entrances
+ UNKNOWN = -1
+ NUM_TYPES = 21
+
+
+def save_lane_section_to_json(xodr_json, id, road_edges, road_lines, lanes, sidewalks=[]):
+ roads = xodr_json.get("roads", [])
+ for road_edge in road_edges:
+ # edge_polygon = Polygon(road_edge)
+ edge_data = {
+ "id": id,
+ "map_element_id": int(MapType.ROAD_EDGE_BOUNDARY),
+ "type": "road_edge",
+ "geometry": [{"x": float(pt[0]), "y": float(pt[1]), "z": 0.0} for pt in road_edge],
+ }
+ roads.append(edge_data)
+ id += 1
+ for road_line in road_lines:
+ line_data = {
+ "id": id,
+ "map_element_id": int(MapType.ROAD_LINE_BROKEN_SINGLE_WHITE),
+ "type": "road_line",
+ "geometry": [{"x": float(pt[0]), "y": float(pt[1]), "z": 0.0} for pt in road_line],
+ }
+ roads.append(line_data)
+ id += 1
+ for lane in lanes:
+ lane_data = {
+ "id": id,
+ "map_element_id": int(MapType.LANE_SURFACE_STREET),
+ "type": "lane",
+ "geometry": [{"x": float(pt[0]), "y": float(pt[1]), "z": 0.0} for pt in lane],
+ }
+ roads.append(lane_data)
+ id += 1
+ # for sidewalk in sidewalks:
+ # sidewalk_data = {
+ # "id": id,
+ # "map_element_id": int(MapType.LANE_BIKE_LANE),
+ # "type": "sidewalk",
+ # "geometry": [{"x": float(pt[0]), "y": float(pt[1]), "z": 0.0} for pt in sidewalk]
+ # }
+ # roads.append(sidewalk_data)
+ # id += 1
+ xodr_json["roads"] = roads
+ return id
+
+
+def get_lane_data(lane, type="BOUNDARY", check_dir=True):
+ if type == "BOUNDARY":
+ points = lane.boundary_line
+ # print(f'Number of boundary pts: {len(points)}')
+ elif type == "CENTERLINE":
+ points = lane.centre_line
+ # print(f'Number of centerline pts: {len(points)}')
+ else:
+ raise ValueError(f"Unknown lane data type: {type}")
+
+ if not check_dir:
+ return points
+
+ # Check traffic direction
+ travel_dir = None
+ vector_lane = lane.lane_xml.find(".//userData/vectorLane")
+ if vector_lane is not None:
+ travel_dir = vector_lane.get("travelDir")
+
+ if travel_dir == "backward":
+ # Reverse points for backward travel
+ points = points[::-1]
+
+ return points
+
+
+def sum_pts(road_elts):
+ road_geometries = [len(elt) for elt in road_elts]
+ return sum(road_geometries)
+
+
+def create_empty_json(town_name):
+ def random_string(length=8):
+ return "".join(random.choices(string.ascii_letters + string.digits, k=length))
+
+ json_data = {
+ "name": town_name,
+ "scenario_id": random_string(12),
+ "objects": [],
+ "roads": [],
+ "tl_states": {},
+ "metadata": {"sdc_track_index": 0, "tracks_to_predict": [], "objects_of_interest": []},
+ }
+ return json_data
+
+
+def generate_carla_road(
+ town_name, source_dir, carla_map_dir, resolution, dest_dir, max_samples, print_number_of_sample_truncations
+):
+ src_file_path = os.path.join(source_dir, f"{town_name}.json")
+ dst_file_path = os.path.join(dest_dir, f"{town_name}.json")
+ if not os.path.isfile(src_file_path):
+ print(f"Warning: {src_file_path} does not exist, creating empty file.")
+ empty_json = create_empty_json(town_name)
+ with open(src_file_path, "w") as f:
+ json.dump(empty_json, f, indent=2)
+
+ with open(src_file_path, "r") as f:
+ xodr_json = json.load(f)
+ xodr_json["roads"] = []
+
+ with open(dst_file_path, "w") as f:
+ json.dump(xodr_json, f, indent=2)
+
+ odr_file = os.path.join(carla_map_dir, town_name + ".xodr")
+
+ road_network = RoadNetwork(xodr_file_path=odr_file, resolution=resolution, max_samples=max_samples)
+ roads = road_network.get_roads()
+ print(f"Number of roads in the network: {len(roads)}")
+ # print(f"Type: {type(roads[0])}\nRoads: {roads}")
+ print(f"Number of lanes in the network: {sum([sum([len(ls.lanes) for ls in r.lane_sections]) for r in roads])}")
+ print(
+ f"Road 0 lane 1 boundary_pts: {len(roads[0].lane_sections[0].lanes[1].boundary_line)}"
+ ) # Sanity check to see if resolution is working
+
+ # Go only till last "driving" lane("parking" NTD)
+ # "median" lane means a road edge(add after all of them appear)
+ # Add "sidewalk" lane as well
+
+ id = 0
+ roads_json_cnt = [[], [], []]
+ print(f"Network has {len(roads)} roads.")
+ for road_obj in roads:
+ # print(f"Road ID: {road_obj.id}")
+ lane_sections = road_obj.lane_sections
+ # print(f"Lane Sections: {lane_sections}")
+ for lane_section in lane_sections:
+ # print(f"Lane Section ID: {lane_section.lane_section_ordinal}")
+ # print(f"Number of Left Lanes: {len(lane_section.left_lanes)}")
+ # print(f"Number of Right Lanes: {len(lane_section.right_lanes)}")
+ road_edges = []
+ road_lines = []
+ lanes = []
+ # sidwalks = []
+
+ left_immediate_driveable = False
+ right_immediate_driveable = False
+
+ # Left Lanes
+ add_lane_data = False
+ add_edge_data = False
+ previous_lane = None
+ for i, left_lane in enumerate(lane_section.left_lanes):
+ if left_lane.type == "driving" or left_lane.type == "parking":
+ if i == 0:
+ left_immediate_driveable = True
+
+ if add_lane_data:
+ road_line_data = get_lane_data(previous_lane, "BOUNDARY")
+ road_line_data = road_line_data
+ road_lines.append(road_line_data)
+ lanes.append(get_lane_data(previous_lane, "CENTERLINE"))
+ # Add outer edge as road edge
+ elif add_edge_data:
+ road_edges.append(get_lane_data(previous_lane, "BOUNDARY"))
+ add_lane_data = True
+ add_edge_data = False
+ else:
+ # Add inner lane as road edge
+ if add_lane_data and i != 0:
+ lanes.append(get_lane_data(previous_lane, "CENTERLINE"))
+ road_edges.append(get_lane_data(previous_lane, "BOUNDARY"))
+ add_edge_data = True
+ add_lane_data = False
+ previous_lane = left_lane
+
+ if add_lane_data:
+ lanes.append(get_lane_data(previous_lane, "CENTERLINE"))
+ road_edges.append(get_lane_data(previous_lane, "BOUNDARY"))
+ # elif add_edge_data:
+ # if previous_lane.type == 'sidewalk':
+ # sidwalks.append(get_lane_data(previous_lane, "BOUNDARY"))
+
+ # print("LEFT STATS")
+ # print(f"Number of Road edges: {len(road_edges)}")
+ # print(f"Road lines: {len(road_lines)}")
+ # print(f"Lanes: {len(lanes)}")
+ # print(f"Sidewalks: {len(sidwalks)}")
+
+ # Right Lanes
+ add_lane_data = False
+ add_edge_data = False
+ previous_lane = None
+ for i, right_lane in enumerate(lane_section.right_lanes):
+ if right_lane.type == "driving" or right_lane.type == "parking":
+ if i == 0:
+ right_immediate_driveable = True
+
+ if add_lane_data:
+ road_line_data = get_lane_data(previous_lane, "BOUNDARY")
+ road_line_data = road_line_data
+ road_lines.append(road_line_data)
+ lanes.append(get_lane_data(previous_lane, "CENTERLINE"))
+ # Add outer edge as road edge
+ elif add_edge_data:
+ road_edges.append(get_lane_data(previous_lane, "BOUNDARY"))
+ add_lane_data = True
+ add_edge_data = False
+ else:
+ # Add inner lane as road edge
+ if add_lane_data and i != 0:
+ lanes.append(get_lane_data(previous_lane, "CENTERLINE"))
+ road_edges.append(get_lane_data(previous_lane, "BOUNDARY"))
+ add_edge_data = True
+ add_lane_data = False
+ previous_lane = right_lane
+
+ if add_lane_data:
+ lanes.append(get_lane_data(previous_lane, "CENTERLINE"))
+ road_edges.append(get_lane_data(previous_lane, "BOUNDARY"))
+ # elif add_edge_data:
+ # if previous_lane.type == 'sidewalk':
+ # sidwalks.append(get_lane_data(previous_lane, "BOUNDARY"))
+
+ # print(f"Number of Road edges in {road_obj.id}: {len(road_edges)}")
+ # print(f"Road lines in {road_obj.id}: {len(road_lines)}")
+ # print(f"Lanes in {road_obj.id}: {len(lanes)}")
+ # print(f"Sidewalks in {road_obj.id}: {len(sidwalks)}")
+
+ # If atleast one side has no immediate driveable lane add center as road edge
+ if not left_immediate_driveable or not right_immediate_driveable:
+ road_edges.append(lane_section.lane_section_reference_line)
+ else:
+ road_line_data = get_lane_data(previous_lane, "BOUNDARY")
+ road_lines.append(road_line_data)
+
+ if len(road_lines) == 0 and len(lanes) == 0:
+ road_edges = []
+ id = save_lane_section_to_json(xodr_json, id, road_edges, road_lines, lanes)
+ roads_json_cnt[0].append(len(road_edges))
+ roads_json_cnt[1].append(len(road_lines))
+ roads_json_cnt[2].append(len(lanes))
+ # if len(lanes) == 0 and len(road_lines) != 0:
+ # print(f"Road: {road_obj.id}, Lane Section: {lane_section.lane_section_ordinal}")
+ # print(f"Road edges: {len(road_edges)}, Road lines: {len(road_lines)}, Lanes: {len(lanes)}")
+ # break
+ # break
+ print(f"Total roads JSON count: {sum(roads_json_cnt[0]) + sum(roads_json_cnt[1]) + sum(roads_json_cnt[2])}")
+
+ # Save to file
+ with open(dst_file_path, "w") as f:
+ json.dump(xodr_json, f, indent=2)
+
+ # Print logs
+ if print_number_of_sample_truncations:
+ road_network.print_logs_max_samples_hit()
+
+
+def generate_carla_roads(
+ town_names, source_dir, carla_map_dir, resolution, dest_dir, max_samples, print_number_of_sample_truncations
+):
+ if type(resolution) == float:
+ resolution = [resolution] * len(town_names)
+ elif type(resolution) != list:
+ raise ValueError("Resolution must be a float or a list type")
+ elif len(resolution) != len(town_names):
+ raise ValueError("Resolution must be of the same length as town_names.")
+ for i, town in enumerate(town_names):
+ print(f"Processing town: {town}")
+ generate_carla_road(
+ town,
+ source_dir,
+ carla_map_dir,
+ resolution[i],
+ dest_dir,
+ max_samples,
+ print_number_of_sample_truncations=print_number_of_sample_truncations,
+ )
+
+
+if __name__ == "__main__":
+ town_names = ["Town01", "Town02", "Town03", "Town04", "Town05", "Town06", "Town07", "Town10HD"]
+ source_dir = "data_utils/carla"
+ dest_dir = "data_utils/carla"
+ carla_map_dir = "/scratch/pm3881/Carla-0.10.0-Linux-Shipping/CarlaUnreal/Content/Carla/Maps/OpenDrive"
+ resolution = 1.0 # [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5] # Meters
+ max_samples = int(1e5) # Max points to sample per reference line
+ print_number_of_sample_truncations = True # Enable to see the number of data points lost
+ generate_carla_roads(
+ town_names, source_dir, carla_map_dir, resolution, dest_dir, max_samples, print_number_of_sample_truncations
+ )
+ # resolution = 1.0
+ # town_name = 'town06'
+ # generate_carla_road(
+ # town_name,
+ # source_dir,
+ # carla_map_dir,
+ # resolution,
+ # dest_dir,
+ # max_samples,
+ # print_number_of_sample_truncations
+ # )
diff --git a/data_utils/carla/process_carla_xodr.py b/data_utils/carla/process_carla_xodr.py
new file mode 100644
index 000000000..0c11b8c1b
--- /dev/null
+++ b/data_utils/carla/process_carla_xodr.py
@@ -0,0 +1,897 @@
+import sys
+import os
+import json
+import numpy as np
+import random
+from lxml import etree
+import pyxodr
+from pyxodr.road_objects.road import Road
+from pyxodr.road_objects.lane import Lane, ConnectionPosition, LaneOrientation, TrafficOrientation
+from pyxodr.road_objects.junction import Junction
+from pyxodr.road_objects.lane_section import LaneSection
+from pyxodr.road_objects.network import RoadNetwork
+from shapely.geometry import Polygon
+from enum import IntEnum
+
+
+class MapType(IntEnum):
+ LANE_UNDEFINED = 0
+ LANE_FREEWAY = 1
+ LANE_SURFACE_STREET = 2
+ LANE_BIKE_LANE = 3
+ # Original definition skips 4
+ ROAD_LINE_UNKNOWN = 5
+ ROAD_LINE_BROKEN_SINGLE_WHITE = 6
+ ROAD_LINE_SOLID_SINGLE_WHITE = 7
+ ROAD_LINE_SOLID_DOUBLE_WHITE = 8
+ ROAD_LINE_BROKEN_SINGLE_YELLOW = 9
+ ROAD_LINE_BROKEN_DOUBLE_YELLOW = 10
+ ROAD_LINE_SOLID_SINGLE_YELLOW = 11
+ ROAD_LINE_SOLID_DOUBLE_YELLOW = 12
+ ROAD_LINE_PASSING_DOUBLE_YELLOW = 13
+ ROAD_EDGE_UNKNOWN = 14
+ ROAD_EDGE_BOUNDARY = 15
+ ROAD_EDGE_MEDIAN = 16
+ STOP_SIGN = 17
+ CROSSWALK = 18
+ SPEED_BUMP = 19
+ DRIVEWAY = 20 # New womd datatype in v1.2.0: Driveway entrances
+ UNKNOWN = -1
+ NUM_TYPES = 21
+
+
+def save_lane_section_to_json(xodr_json, id, road_edges, road_lines, lanes, sidewalks=[]):
+ roads = xodr_json.get("roads", [])
+ for road_edge in road_edges:
+ # edge_polygon = Polygon(road_edge)
+ edge_data = {
+ "id": id,
+ "map_element_id": int(MapType.ROAD_EDGE_BOUNDARY),
+ "type": "road_edge",
+ "geometry": [{"x": float(pt[0]), "y": float(pt[1]), "z": 0.0} for pt in road_edge],
+ }
+ roads.append(edge_data)
+ id += 1
+ for road_line in road_lines:
+ line_data = {
+ "id": id,
+ "map_element_id": int(MapType.ROAD_LINE_BROKEN_SINGLE_WHITE),
+ "type": "road_line",
+ "geometry": [{"x": float(pt[0]), "y": float(pt[1]), "z": 0.0} for pt in road_line],
+ }
+ roads.append(line_data)
+ id += 1
+ for lane in lanes:
+ lane_data = {
+ "id": id,
+ "map_element_id": int(MapType.LANE_SURFACE_STREET),
+ "type": "lane",
+ "geometry": [{"x": float(pt[0]), "y": float(pt[1]), "z": 0.0} for pt in lane],
+ }
+ roads.append(lane_data)
+ id += 1
+ # for sidewalk in sidewalks:
+ # sidewalk_data = {
+ # "id": id,
+ # "map_element_id": int(MapType.LANE_BIKE_LANE),
+ # "type": "sidewalk",
+ # "geometry": [{"x": float(pt[0]), "y": float(pt[1]), "z": 0.0} for pt in sidewalk]
+ # }
+ # roads.append(sidewalk_data)
+ # id += 1
+ xodr_json["roads"] = roads
+ return id
+
+
+def get_lane_data(lane, type="BOUNDARY", check_dir=True):
+ if type == "BOUNDARY":
+ points = lane.boundary_line
+ elif type == "CENTERLINE":
+ points = lane.centre_line
+ else:
+ raise ValueError(f"Unknown lane data type: {type}")
+
+ if not check_dir:
+ return points
+
+ # Check traffic direction
+ travel_dir = None
+ vector_lane = lane.lane_xml.find(".//userData/vectorLane")
+ if vector_lane is not None:
+ travel_dir = vector_lane.get("travelDir")
+
+ if travel_dir == "backward":
+ # Reverse points for backward travel
+ points = points[::-1]
+
+ return points
+
+
+class RoadLinkObject:
+ def __init__(self, road_id, pred_lane_section_ids, succ_lane_section_ids):
+ self.road_id = road_id
+ self.pred_lane_section_ids = pred_lane_section_ids
+ self.succ_lane_section_ids = succ_lane_section_ids
+ self.lane_links_map = {} # map from (lane_id, lane_section_index) to LaneLinkObject
+ self.predecessor_roads = []
+ self.successor_roads = []
+
+
+class LaneLinkObject:
+ def __init__(self, lane_id, lane_section_index, road_id, lane, lane_centerpoints, forward_dir, is_junction):
+ self.lane_id = lane_id
+ self.lane_section_index = lane_section_index
+ self.road_id = road_id
+ self.lane = lane
+ self.lane_centerpoints = lane_centerpoints
+ self.forward_dir = forward_dir
+ self.predecessor_lanes = []
+ self.successor_lanes = []
+ self.outgoing_edges = []
+ self.incoming_edges = []
+ self.is_sampled = False
+ self.is_junction = is_junction
+
+
+def get_junction(road_network, junction_id):
+ for junction in road_network.get_junctions():
+ if junction.id == junction_id:
+ return junction
+ return None
+
+
+def get_road(road_network, road_id):
+ for road in road_network.get_roads():
+ if road.id == road_id:
+ return road
+ return None
+
+
+def is_forward_dir(lane):
+ # Check traffic direction
+ travel_dir = None
+ vector_lane = lane.lane_xml.find(".//userData/vectorLane")
+ if vector_lane is not None:
+ travel_dir = vector_lane.get("travelDir")
+
+ if travel_dir == "forward":
+ return True
+ return False
+
+
+def create_lane_link_elements(road_network, roads, road_link_map):
+ roads_json_cnt = [[], [], []]
+ print(f"Network has {len(roads)} roads.")
+ for road_obj in roads:
+ # print(f"Road ID: {road_obj.id}")
+ lane_sections = road_obj.lane_sections
+
+ is_road_junction = False if road_obj.road_xml.attrib["junction"] == "-1" else True
+ pred_lane_section_ids = {}
+ for predecessor_xml in road_obj.road_xml.find("link").findall("predecessor"):
+ if predecessor_xml.attrib["elementType"] == "road":
+ pred_road_id = predecessor_xml.attrib["elementId"]
+ if predecessor_xml.attrib["contactPoint"] == "start":
+ pred_lane_section_ids[pred_road_id] = 0
+ else:
+ pred_road = get_road(road_network, pred_road_id)
+ pred_lane_section_ids[pred_road_id] = len(pred_road.lane_sections) - 1
+
+ succ_lane_section_ids = {}
+ for successor_xml in road_obj.road_xml.find("link").findall("successor"):
+ if successor_xml.attrib["elementType"] == "road":
+ succ_road_id = successor_xml.attrib["elementId"]
+ if successor_xml.attrib["contactPoint"] == "start":
+ succ_lane_section_ids[succ_road_id] = 0
+ else:
+ succ_road = get_road(road_network, succ_road_id)
+ succ_lane_section_ids[succ_road_id] = len(succ_road.lane_sections) - 1
+
+ road_link_object = RoadLinkObject(
+ road_id=road_obj.id,
+ pred_lane_section_ids=pred_lane_section_ids,
+ succ_lane_section_ids=succ_lane_section_ids,
+ )
+
+ for lane_section in lane_sections:
+ # print(f"Lane Section ID: {lane_section.lane_section_ordinal}")
+ # print(f"Number of Left Lanes: {len(lane_section.left_lanes)}")
+ # print(f"Number of Right Lanes: {len(lane_section.right_lanes)}")
+ road_edges = []
+ road_lines = []
+ lanes = []
+ # sidwalks = []
+
+ left_immediate_driveable = False
+ right_immediate_driveable = False
+
+ # Left Lanes
+ add_lane_data = False
+ add_edge_data = False
+ previous_lane = None
+ for i, left_lane in enumerate(lane_section.left_lanes):
+ if left_lane.type == "driving": # We only deal with driving lanes
+ if i == 0:
+ left_immediate_driveable = True
+
+ if add_lane_data:
+ road_line_data = get_lane_data(previous_lane, "BOUNDARY")
+ road_line_data = road_line_data[::40]
+ road_lines.append(road_line_data)
+ waypoints = get_lane_data(previous_lane, "CENTERLINE")
+ lanes.append(waypoints)
+ road_link_object.lane_links_map[(str(previous_lane.id), lane_section.lane_section_ordinal)] = (
+ LaneLinkObject(
+ lane_id=previous_lane.id,
+ lane_section_index=lane_section.lane_section_ordinal,
+ road_id=road_obj.id,
+ lane=previous_lane,
+ lane_centerpoints=waypoints,
+ forward_dir=is_forward_dir(previous_lane),
+ is_junction=is_road_junction,
+ )
+ )
+ # Add outer edge as road edge
+ elif add_edge_data:
+ road_edges.append(get_lane_data(previous_lane, "BOUNDARY"))
+ add_lane_data = True
+ add_edge_data = False
+ else:
+ # Add inner lane as road edge
+ if add_lane_data and i != 0:
+ waypoints = get_lane_data(previous_lane, "CENTERLINE")
+ lanes.append(waypoints)
+ road_link_object.lane_links_map[(str(previous_lane.id), lane_section.lane_section_ordinal)] = (
+ LaneLinkObject(
+ lane_id=previous_lane.id,
+ lane_section_index=lane_section.lane_section_ordinal,
+ road_id=road_obj.id,
+ lane=previous_lane,
+ lane_centerpoints=waypoints,
+ forward_dir=is_forward_dir(previous_lane),
+ is_junction=is_road_junction,
+ )
+ )
+ road_edges.append(get_lane_data(previous_lane, "BOUNDARY"))
+ add_edge_data = True
+ add_lane_data = False
+ previous_lane = left_lane
+
+ if add_lane_data:
+ waypoints = get_lane_data(previous_lane, "CENTERLINE")
+ lanes.append(waypoints)
+ road_link_object.lane_links_map[(str(previous_lane.id), lane_section.lane_section_ordinal)] = (
+ LaneLinkObject(
+ lane_id=previous_lane.id,
+ lane_section_index=lane_section.lane_section_ordinal,
+ road_id=road_obj.id,
+ lane=previous_lane,
+ lane_centerpoints=waypoints,
+ forward_dir=is_forward_dir(previous_lane),
+ is_junction=is_road_junction,
+ )
+ )
+ road_edges.append(get_lane_data(previous_lane, "BOUNDARY"))
+ # elif add_edge_data:
+ # if previous_lane.type == 'sidewalk':
+ # sidwalks.append(get_lane_data(previous_lane, "BOUNDARY"))
+
+ # print("LEFT STATS")
+ # print(f"Number of Road edges: {len(road_edges)}")
+ # print(f"Road lines: {len(road_lines)}")
+ # print(f"Lanes: {len(lanes)}")
+ # print(f"Sidewalks: {len(sidwalks)}")
+
+ # Right Lanes
+ add_lane_data = False
+ add_edge_data = False
+ previous_lane = None
+ for i, right_lane in enumerate(lane_section.right_lanes):
+ if right_lane.type == "driving":
+ if i == 0:
+ right_immediate_driveable = True
+
+ if add_lane_data:
+ road_line_data = get_lane_data(previous_lane, "BOUNDARY")
+ road_line_data = road_line_data[::40]
+ road_lines.append(road_line_data)
+ waypoints = get_lane_data(previous_lane, "CENTERLINE")
+ lanes.append(waypoints)
+ road_link_object.lane_links_map[(str(previous_lane.id), lane_section.lane_section_ordinal)] = (
+ LaneLinkObject(
+ lane_id=previous_lane.id,
+ lane_section_index=lane_section.lane_section_ordinal,
+ road_id=road_obj.id,
+ lane=previous_lane,
+ lane_centerpoints=waypoints,
+ forward_dir=is_forward_dir(previous_lane),
+ is_junction=is_road_junction,
+ )
+ )
+ # Add outer edge as road edge
+ elif add_edge_data:
+ road_edges.append(get_lane_data(previous_lane, "BOUNDARY"))
+ add_lane_data = True
+ add_edge_data = False
+ else:
+ # Add inner lane as road edge
+ if add_lane_data and i != 0:
+ waypoints = get_lane_data(previous_lane, "CENTERLINE")
+ lanes.append(waypoints)
+ road_link_object.lane_links_map[(str(previous_lane.id), lane_section.lane_section_ordinal)] = (
+ LaneLinkObject(
+ lane_id=previous_lane.id,
+ lane_section_index=lane_section.lane_section_ordinal,
+ road_id=road_obj.id,
+ lane=previous_lane,
+ lane_centerpoints=waypoints,
+ forward_dir=is_forward_dir(previous_lane),
+ is_junction=is_road_junction,
+ )
+ )
+ road_edges.append(get_lane_data(previous_lane, "BOUNDARY"))
+ add_edge_data = True
+ add_lane_data = False
+ previous_lane = right_lane
+
+ if add_lane_data:
+ waypoints = get_lane_data(previous_lane, "CENTERLINE")
+ lanes.append(waypoints)
+ road_link_object.lane_links_map[(str(previous_lane.id), lane_section.lane_section_ordinal)] = (
+ LaneLinkObject(
+ lane_id=previous_lane.id,
+ lane_section_index=lane_section.lane_section_ordinal,
+ road_id=road_obj.id,
+ lane=previous_lane,
+ lane_centerpoints=waypoints,
+ forward_dir=is_forward_dir(previous_lane),
+ is_junction=is_road_junction,
+ )
+ )
+ road_edges.append(get_lane_data(previous_lane, "BOUNDARY"))
+ # elif add_edge_data:
+ # if previous_lane.type == 'sidewalk':
+ # sidwalks.append(get_lane_data(previous_lane, "BOUNDARY"))
+
+ road_link_map[road_obj.id] = road_link_object
+
+ roads_json_cnt[0].append(len(road_edges))
+ roads_json_cnt[1].append(len(road_lines))
+ roads_json_cnt[2].append(len(lanes))
+ # if len(lanes) == 0 and len(road_lines) != 0:
+ # print(f"Road: {road_obj.id}, Lane Section: {lane_section.lane_section_ordinal}")
+ # print(f"Road edges: {len(road_edges)}, Road lines: {len(road_lines)}, Lanes: {len(lanes)}")
+ # break
+ # break
+ print(f"Total roads JSON count: {sum(roads_json_cnt[0]) + sum(roads_json_cnt[1]) + sum(roads_json_cnt[2])}")
+ # print(f"Road edges count: {roads_json_cnt[0]}")
+ # print(f"Road lines count: {roads_json_cnt[1]}")
+ print(f"Lanes count: {sum(roads_json_cnt[2])}")
+ total_lane_links = sum(len(obj.lane_links_map) for obj in road_link_map.values())
+ assert sum(roads_json_cnt[2]) == total_lane_links
+
+
+def create_successor_predecessor_elements(road_network, roads, road_link_map):
+ stopping_points = 0
+
+ for road_obj in roads:
+ # print(f"Road ID: {road_obj.id}")
+ road_link_object = road_link_map[road_obj.id]
+ lane_sections = road_obj.lane_sections
+ # print(f"Lane Sections: {lane_sections}")
+
+ for lane_link_obj in road_link_object.lane_links_map.values():
+ lane_link_obj.predecessor_lanes = []
+ lane_link_obj.successor_lanes = []
+
+ lane = lane_link_obj.lane
+
+ link_xml = lane.lane_xml.find("link")
+
+ successor_is_junction = True
+ if link_xml is not None and link_xml.findall("successor") != []:
+ successor_is_junction = False
+ # if link_xml.findall("successor") == []:
+ # print(f"Successor for road: {road_obj.id}, lane_section: {lane_link_obj.lane_section_index}, lane: {lane_link_obj.lane.id}: {link_xml.findall('successor')}")
+ # Process Successor Links
+ for successor in link_xml.findall("successor"):
+ successor_id = successor.get("id")
+
+ if lane_link_obj.lane_section_index + 1 < len(lane_sections):
+ # Lane link in next lane section
+ lane_link_obj.successor_lanes.append(
+ road_link_object.lane_links_map[(successor_id, lane_link_obj.lane_section_index + 1)]
+ )
+ else:
+ # Lane link in successor roads
+ for road_succ in road_obj.road_xml.find("link").findall("successor"):
+ if road_succ.attrib["elementType"] == "road":
+ succ_road_id = road_succ.attrib["elementId"]
+ succ_road = road_link_map[succ_road_id]
+ succ_lane_section_index = road_link_object.succ_lane_section_ids[succ_road_id]
+ # if (lane_link_obj.lane_id, succ_lane_section_index) not in succ_road.lane_links_map:
+ # print(f"Key:{(successor_id, succ_lane_section_index)} not found in lane_links_map - road_id: {succ_road_id}, lane_section_index: {succ_lane_section_index}, lane_id: {successor_id}")
+ lane_link_obj.successor_lanes.append(
+ succ_road.lane_links_map[(successor_id, succ_lane_section_index)]
+ )
+ else:
+ # Junction case
+ successor_is_junction = True
+ elif successor_is_junction:
+ # if road_obj.id == "0" and str(lane.id) == "-1":
+ # print(f"Road: {road_obj.id}, lane: {lane.id}, successor is a junction")
+ # break
+ # Handle junction case
+ for successor in road_obj.road_xml.find("link").findall("successor"):
+ if successor.attrib["elementType"] == "junction":
+ junction_id = successor.attrib["elementId"]
+ # print(f"Road: {road_obj.id}, lane: {lane.id}, successor is a junction: {junction_id}")
+ junction = get_junction(road_network, junction_id)
+ # print(f"Retrieved Junction: {junction.id} from road_network")
+ connected_lanes = junction.get_lane_junction_lanes(str(lane.id), road_id=road_obj.id)
+ if len(connected_lanes) == 0 and lane_link_obj.forward_dir:
+ stopping_points += 1
+ print(
+ f"Non junction road: {road_obj.id}, lane_section: {lane_link_obj.lane_section_index}, lane: {lane_link_obj.lane.id} has no junction or road links, it is an ending lane"
+ )
+ for conn_lane in connected_lanes:
+ succ_road_obj = get_road(road_network, conn_lane["road_id"])
+ succ_road = road_link_map[conn_lane["road_id"]]
+ succ_lane_section_index = conn_lane["lane_section_index"]
+ if succ_lane_section_index == -1:
+ succ_lane_section_index = len(succ_road_obj.lane_sections) - 1
+ succ_lane_id = conn_lane["lane_id"]
+ lane_link_obj.successor_lanes.append(
+ succ_road.lane_links_map[(str(succ_lane_id), succ_lane_section_index)]
+ )
+ else:
+ if lane_link_obj.forward_dir:
+ # Stopping point
+ stopping_points += 1
+ print(
+ f"Non junction road: {road_obj.id}, lane_section: {lane_link_obj.lane_section_index}, lane: {lane_link_obj.lane.id} has no junction or road links, it is an ending lane"
+ )
+
+ predecessor_is_junction = True
+ if link_xml is not None and link_xml.findall("predecessor") != []:
+ predecessor_is_junction = False
+ # Process Predecessor Links
+ for predecessor in link_xml.findall("predecessor"):
+ predecessor_id = predecessor.get("id")
+
+ if lane_link_obj.lane_section_index - 1 >= 0:
+ # Lane link in previous lane section
+ lane_link_obj.predecessor_lanes.append(
+ road_link_object.lane_links_map[(predecessor_id, lane_link_obj.lane_section_index - 1)]
+ )
+ else:
+ # Lane link in predecessor roads
+ for road_pred in road_obj.road_xml.find("link").findall("predecessor"):
+ if road_pred.attrib["elementType"] == "road":
+ pred_id = road_pred.attrib["elementId"]
+ pred_road = road_link_map[pred_id]
+ pred_lane_section_index = road_link_object.pred_lane_section_ids[pred_id]
+ # print(f"Curr lane: {lane_link_obj.lane.id}, section: {lane_link_obj.lane_section_index}, road: {road_obj.id}; Pred lane: {predecessor_id}, section: {road_link_object.pred_lane_section_ids[pred_id]}, road: {pred_id}")
+ lane_link_obj.predecessor_lanes.append(
+ pred_road.lane_links_map[(predecessor_id, pred_lane_section_index)]
+ )
+ else:
+ # Junction case
+ predecessor_is_junction = True
+ elif predecessor_is_junction:
+ # Handle junction case
+ for predecessor in road_obj.road_xml.find("link").findall("predecessor"):
+ if predecessor.attrib["elementType"] == "junction":
+ junction_id = predecessor.attrib["elementId"]
+ junction = get_junction(road_network, junction_id)
+ connected_lanes = junction.get_lane_junction_lanes(lane_id=str(lane.id), road_id=road_obj.id)
+ if len(connected_lanes) == 0 and not lane_link_obj.forward_dir:
+ stopping_points += 1
+ print(
+ f"Non junction road: {road_obj.id}, lane_section: {lane_link_obj.lane_section_index}, lane: {lane_link_obj.lane.id} has no junction or road links, it is a starting lane"
+ )
+ for conn_lane in connected_lanes:
+ pred_road_obj = get_road(road_network, conn_lane["road_id"])
+ pred_road = road_link_map[conn_lane["road_id"]]
+ pred_lane_section_index = conn_lane["lane_section_index"]
+ if pred_lane_section_index == -1:
+ pred_lane_section_index = len(pred_road_obj.lane_sections) - 1
+ pred_lane_id = conn_lane["lane_id"]
+ lane_link_obj.predecessor_lanes.append(
+ pred_road.lane_links_map[(str(pred_lane_id), pred_lane_section_index)]
+ )
+ else:
+ if not lane_link_obj.forward_dir:
+ # Stopping case
+ stopping_points += 1
+ print(
+ f"Non junction road: {road_obj.id}, lane_section: {lane_link_obj.lane_section_index}, lane: {lane_link_obj.lane.id} has no junction or road links, it is a starting lane"
+ )
+
+ print(f"Road network has {stopping_points} stopping points (lanes with no predecessors or successors).")
+
+
+def add_incoming_outgoing_edges(road_network, roads, road_link_map):
+ for road_obj in roads:
+ # print(f"Road ID: {road_obj.id}")
+ road_link_object = road_link_map[road_obj.id]
+ lane_sections = road_obj.lane_sections
+ # print(f"Lane Sections: {lane_sections}")
+
+ for lane_link_obj in road_link_object.lane_links_map.values():
+ lane = lane_link_obj.lane
+ link_xml = lane.lane_xml.find("link")
+
+ if lane_link_obj.forward_dir:
+ # Forward direction, predecessor lanes are incoming edges, successor lanes are outgoing edges
+ lane_link_obj.incoming_edges = lane_link_obj.predecessor_lanes
+ lane_link_obj.outgoing_edges = lane_link_obj.successor_lanes
+ else:
+ # Backward direction, predecessor lanes are outgoing edges, successor lanes are incoming edges
+ lane_link_obj.outgoing_edges = lane_link_obj.predecessor_lanes
+ lane_link_obj.incoming_edges = lane_link_obj.successor_lanes
+
+
+def test_linkage(road_link_map):
+ # Testing linkage
+
+ start_road_id = "0"
+ road_link_object = road_link_map[start_road_id]
+
+ lane_link_keys = list(road_link_object.lane_links_map.keys())
+ random_lane_link_key = None
+ if random_lane_link_key is None:
+ random_lane_link_key = random.choice(lane_link_keys)
+ lane_link_obj = road_link_object.lane_links_map[random_lane_link_key]
+
+ print(f"Starting at road id: {start_road_id}")
+ print(f"Lane link key: {random_lane_link_key}")
+ print(f"Lane id: {lane_link_obj.lane_id}, Lane section index: {lane_link_obj.lane_section_index}")
+
+ # Traverse outgoing edges for 10 steps
+ current = lane_link_obj
+ for step in range(10):
+ print(f"\nStep {step}:")
+ print(
+ f" Road id: {current.road_id}, Lane id: {current.lane_id}, Lane section index: {current.lane_section_index}"
+ )
+ if current.outgoing_edges:
+ current = random.choice(current.outgoing_edges)
+ else:
+ print(" No outgoing edges. Stopping traversal.")
+ print("Debugging")
+ print(
+ f"Outgoing Edges: {[(edge.road_id, str(edge.lane.id), edge.lane_section_index) for edge in current.outgoing_edges]}"
+ )
+ print(
+ f"Incoming Edges: {[(edge.road_id, str(edge.lane.id), edge.lane_section_index) for edge in current.incoming_edges]}"
+ )
+ print(
+ f"Successors: {[(edge.road_id, str(edge.lane.id), edge.lane_section_index) for edge in current.successor_lanes]}"
+ )
+ print(
+ f"Predecessors: {[(edge.road_id, str(edge.lane.id), edge.lane_section_index) for edge in current.predecessor_lanes]}"
+ )
+ break
+
+
+def print_traj_stats(waypoints_list, num_timestamps, episode_length):
+ # Extract positions
+ positions = [wp["position"] for wp in waypoints_list if "position" in wp]
+ positions = np.array(positions)
+
+ # Compute consecutive distances
+ if positions.shape[0] < 2:
+ print("Not enough waypoints to compute statistics.")
+ return
+
+ diffs = positions[1:] - positions[:-1]
+ distances = np.linalg.norm(diffs, axis=1)
+ distance_traversed = np.sum(distances)
+
+ # Compute max speed along trajectory
+ timestamp_dur = episode_length / num_timestamps
+ speeds = distances / timestamp_dur
+ max_speed_traj = np.max(speeds)
+
+ print(f"Distance traversed: {distance_traversed} meters")
+ print(f"Max speed in trajectory: {max_speed_traj} m/s")
+
+
+def check_geometry(point, all_geometries):
+ for pt in all_geometries:
+ dist = np.linalg.norm(np.array(pt) - np.array(point))
+ if dist < 1e-9: # threshold, adjust as needed
+ return False
+ return True
+
+
+def generate_traj_data(
+ road_link_map,
+ num_timestamps=90,
+ resolution=0.1,
+ episode_length=9,
+ max_speed=10,
+ random_sampling_variation=1,
+ resample=True,
+ all_geometries=[],
+):
+ # Calculate average speed (70% of max_speed)
+ avg_speed = 0.7 * max_speed
+ avg_cons_pts_dist = resolution * (1 + np.sqrt(2)) / 2
+ time_step_dur = episode_length / num_timestamps
+ sampling_length = int((avg_speed * time_step_dur) / avg_cons_pts_dist)
+
+ # # Calculate junction speed (20% of max_speed)
+ # junction_speed = 0.2 * max_speed
+
+ # Pick a random lane_link_key
+ while True:
+ road_link_keys = list(road_link_map.keys())
+ start_key = random.choice(road_link_keys)
+ lane_link_keys = list(road_link_map[start_key].lane_links_map.keys())
+ if lane_link_keys != []:
+ if resample:
+ start_lane_key = random.choice(lane_link_keys)
+ lane_link_obj = road_link_map[start_key].lane_links_map[start_lane_key]
+ if not lane_link_obj.is_sampled:
+ # print(f"Starting: RoadLink key: {start_key}\n LaneLink key: {start_lane_key}")
+ break
+ else:
+ start_lane_key = random.choice(lane_link_keys)
+ lane_link_obj = road_link_map[start_key].lane_links_map[start_lane_key]
+
+ waypoints_list = []
+ current_lane_link = lane_link_obj
+ current_lane_link.is_sampled = True
+ idx = random.randint(0, len(current_lane_link.lane_centerpoints) - 1)
+ # if check_geometry(current_lane_link.lane_centerpoints[idx], all_geometries) == False:
+ # print(f"Waypoint {current_lane_link.lane_centerpoints[idx]}, lane: {current_lane_link.lane_id}, Lane_Section: {current_lane_link.lane_section_index} Road: {current_lane_link.road_id} not in all_geometries")
+ waypoints_list.append(
+ {
+ "timestamp": 0,
+ "position": current_lane_link.lane_centerpoints[idx].tolist()
+ if hasattr(current_lane_link.lane_centerpoints[idx], "tolist")
+ else list(current_lane_link.lane_centerpoints[idx]),
+ "lane_id": current_lane_link.lane_id,
+ "lane_section_index": current_lane_link.lane_section_index,
+ "road_id": current_lane_link.road_id,
+ }
+ )
+ change_lane = False
+
+ for t in range(num_timestamps):
+ if change_lane:
+ # Pick a random outgoing edge
+ if current_lane_link.outgoing_edges:
+ if resample:
+ # Filter outgoing_edges with is_sampled == False
+ unsampled_edges = [
+ edge for edge in current_lane_link.outgoing_edges if not getattr(edge, "is_sampled", False)
+ ]
+ if unsampled_edges != []:
+ current_lane_link = random.choice(unsampled_edges)
+ else:
+ current_lane_link = random.choice(current_lane_link.outgoing_edges)
+ current_lane_link.is_sampled = True
+ idx = 0 # Lane connection width is zero so reset at start
+ else:
+ current_lane_link = random.choice(current_lane_link.outgoing_edges)
+ else:
+ # No outgoing edge, stop trajectory
+ print("No outgoing edge, stopping trajectory")
+ while len(waypoints_list) < num_timestamps + 1:
+ waypoints_list.append(
+ {
+ "position": waypoint.tolist() if hasattr(waypoint, "tolist") else list(waypoint),
+ "velocity": {"x": 0.0, "y": 0.0},
+ "heading": 0.0 if len(waypoints_list) == 0 else waypoints_list[-1]["heading"],
+ "lane_id": current_lane_link.lane_id,
+ "lane_section_index": current_lane_link.lane_section_index,
+ "road_id": current_lane_link.road_id,
+ "change_lane": change_lane,
+ }
+ )
+ break
+
+ # Randomize sampling length
+ curr_sampling_length = sampling_length + random.randint(-random_sampling_variation, random_sampling_variation)
+ next_idx = idx + curr_sampling_length
+
+ if next_idx < len(current_lane_link.lane_centerpoints):
+ waypoint = current_lane_link.lane_centerpoints[next_idx]
+ idx = next_idx
+ change_lane = False
+ else:
+ waypoint = current_lane_link.lane_centerpoints[-1]
+ change_lane = True
+
+ # Velocity and heading calculation
+ v_x = (waypoint[0] - waypoints_list[t - 1]["position"][0]) / time_step_dur
+ v_y = (waypoint[1] - waypoints_list[t - 1]["position"][1]) / time_step_dur
+ heading = np.arctan2(v_y, v_x)
+
+ # if check_geometry(waypoint, all_geometries) == False:
+ # print(f"Waypoint {waypoint}, lane: {current_lane_link.lane_id}, Lane_Section: {current_lane_link.lane_section_index} Road: {current_lane_link.road_id} not in all_geometries")
+
+ waypoints_list.append(
+ {
+ "position": waypoint.tolist() if hasattr(waypoint, "tolist") else list(waypoint),
+ "velocity": {"x": v_x, "y": v_y},
+ "heading": heading,
+ "lane_id": current_lane_link.lane_id,
+ "lane_section_index": current_lane_link.lane_section_index,
+ "road_id": current_lane_link.road_id,
+ }
+ )
+
+ # Change first waypoint with average velocity and avg heading keeping everything else same
+ waypoints_list[0] = {
+ "position": waypoints_list[0]["position"],
+ "velocity": {
+ "x": np.mean([wp["velocity"]["x"] for wp in waypoints_list[1:]]),
+ "y": np.mean([wp["velocity"]["y"] for wp in waypoints_list[1:]]),
+ },
+ "heading": np.mean([wp["heading"] for wp in waypoints_list[1:]]),
+ "lane_id": waypoints_list[0]["lane_id"],
+ "lane_section_index": waypoints_list[0]["lane_section_index"],
+ "road_id": waypoints_list[0]["road_id"],
+ }
+
+ return waypoints_list
+
+
+def save_object_to_json(
+ xodr_json,
+ road_link_map,
+ id,
+ resolution=0.1,
+ object_type="vehicle",
+ all_geometries=[],
+ start_with_zero_velocity=True,
+):
+ traj_data = generate_traj_data(road_link_map=road_link_map, resolution=resolution, all_geometries=all_geometries)
+
+ z = 1.0
+ headings = []
+ positions = []
+ velocities = []
+ for i, traj in enumerate(traj_data):
+ x = traj["position"][0]
+ y = traj["position"][1]
+ positions.append({"x": float(x), "y": float(y), "z": float(z)})
+ v_x = 0.0 if start_with_zero_velocity and i == 0 else traj["velocity"]["x"]
+ v_y = 0.0 if start_with_zero_velocity and i == 0 else traj["velocity"]["y"]
+ velocities.append({"x": float(v_x), "y": float(v_y)})
+ headings.append(float(traj["heading"]))
+
+ object_data = {
+ "position": list(positions),
+ "width": 2.0,
+ "length": 4.5,
+ "height": 1.8,
+ "id": id,
+ "heading": list(headings),
+ "velocity": list(velocities),
+ "valid": [True] * len(positions),
+ "goalPosition": {
+ "x": float(positions[-1]["x"]),
+ "y": float(positions[-1]["y"]),
+ "z": float(positions[-1]["z"]),
+ },
+ "type": object_type,
+ "mark_as_expert": False,
+ }
+
+ objects = xodr_json.get("objects", [])
+ objects.append(object_data)
+ xodr_json["objects"] = objects
+ return id + 1
+
+
+def generate_data_each_map(
+ town_names,
+ carla_map_dir,
+ resolution,
+ input_json_base_path,
+ output_json_root_dir,
+ num_data_per_map,
+ num_objects,
+ make_only_first_agent_controllable,
+ start_with_zero_velocity=True,
+):
+ os.makedirs(output_json_root_dir, exist_ok=True)
+ for town_name in town_names:
+ json_file = town_name + ".json"
+ odr_file = os.path.join(carla_map_dir, "T" + town_name[1:] + ".xodr")
+ input_json_path = os.path.join(input_json_base_path, json_file)
+
+ for id in range(num_data_per_map):
+ output_json_path = os.path.join(output_json_root_dir, f"{town_name}_{id}.json")
+
+ road_network = RoadNetwork(xodr_file_path=odr_file, resolution=resolution)
+ roads = road_network.get_roads()
+ print(f"Number of roads in the network: {len(roads)}")
+
+ # Create a dictionary to map road_id to RoadLinkObject
+ road_link_map = {}
+
+ # First create the lane link elements
+ create_lane_link_elements(road_network, roads, road_link_map)
+
+ # Create successor predecessor elements
+ create_successor_predecessor_elements(road_network, roads, road_link_map)
+
+ # Now add outgoing and incoming edges based on driving direction
+ add_incoming_outgoing_edges(road_network, roads, road_link_map)
+
+ # Test linkage
+ test_linkage(road_link_map)
+
+ with open(input_json_path, "r") as f:
+ xodr_json = json.load(f)
+
+ roads = xodr_json["roads"]
+ all_geometries = []
+ for road in roads:
+ geometry = [[pt["x"], pt["y"], pt["z"]] for pt in road["geometry"]]
+ all_geometries.extend(geometry)
+
+ print(f"Total number of geometry points: {len(all_geometries)}")
+ # print(all_geometries[:100])
+
+ xodr_json["objects"] = []
+
+ for i in range(num_objects):
+ id = i + 1
+ save_object_to_json(
+ xodr_json,
+ road_link_map,
+ id,
+ resolution=resolution,
+ all_geometries=all_geometries,
+ start_with_zero_velocity=start_with_zero_velocity,
+ )
+
+ # Make first agent only controllable
+ if make_only_first_agent_controllable:
+ for i, obj in enumerate(xodr_json.get("objects", [])):
+ if i == 0:
+ obj["mark_as_expert"] = False
+ else:
+ obj["mark_as_expert"] = True
+
+ # Save to file
+ with open(output_json_path, "w") as f:
+ json.dump(xodr_json, f, indent=2)
+
+ # Verify number of objects
+ with open(output_json_path, "r") as f:
+ xodr_json = json.load(f)
+ assert len(xodr_json.get("objects", [])) == num_objects
+
+ print(f"Saved {num_objects} objects to {output_json_path}")
+
+
+if __name__ == "__main__":
+ town_names = ["Town01", "Town02", "Town03", "Town04", "Town05", "Town06", "Town07", "Town10HD"]
+ # town_names = ['Town03']
+ input_json_base_path = "data_utils/carla"
+ output_json_root_dir = "data/processed/carla_data"
+ carla_map_dir = "/scratch/pm3881/Carla-0.10.0-Linux-Shipping/CarlaUnreal/Content/Carla/Maps/OpenDrive"
+ resolution = 0.1
+ num_data_per_map = 20
+ num_objects = 32
+ make_only_first_agent_controllable = False
+ start_with_zero_velocity = True
+ generate_data_each_map(
+ town_names,
+ carla_map_dir,
+ resolution,
+ input_json_base_path,
+ output_json_root_dir,
+ num_data_per_map,
+ num_objects=num_objects,
+ make_only_first_agent_controllable=make_only_first_agent_controllable,
+ start_with_zero_velocity=start_with_zero_velocity,
+ )
diff --git a/data_utils/carla/roads_analysis.ipynb b/data_utils/carla/roads_analysis.ipynb
new file mode 100644
index 000000000..7588438e1
--- /dev/null
+++ b/data_utils/carla/roads_analysis.ipynb
@@ -0,0 +1,262 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0b6f726c",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sys\n",
+ "import os\n",
+ "import json\n",
+ "import glob\n",
+ "import numpy as np\n",
+ "from lxml import etree\n",
+ "from pyxodr.road_objects.road import Road\n",
+ "from pyxodr.road_objects.lane import Lane, ConnectionPosition, LaneOrientation, TrafficOrientation\n",
+ "from pyxodr.road_objects.junction import Junction\n",
+ "from pyxodr.road_objects.lane_section import LaneSection\n",
+ "from pyxodr.road_objects.network import RoadNetwork\n",
+ "from shapely.geometry import Polygon\n",
+ "from enum import IntEnum"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "79719698",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "carla_map_dir = \"C:\\\\Carla-0.10.0\\\\CarlaUnreal\\\\Content\\\\Carla\\\\Maps\\\\OpenDrive\"\n",
+ "odr_file = os.path.join(carla_map_dir, \"Town04.xodr\")\n",
+ "\n",
+ "road_network = RoadNetwork(xodr_file_path=odr_file)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6fb6ef11",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "roads = road_network.get_roads()\n",
+ "print(f\"Number of roads in the network: {len(roads)}\")\n",
+ "print(f\"Type: {type(roads[0])}\\nRoads: {roads}\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b75ca96f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "multi_lane_section_roads = []\n",
+ "\n",
+ "for road in roads:\n",
+ " if len(road.lane_sections) > 1:\n",
+ " multi_lane_section_roads.append(road)\n",
+ "\n",
+ "print(f\"Number of roads with multiple lane sections: {len(multi_lane_section_roads)}\")\n",
+ "print(\"Road IDs with multiple lane sections:\")\n",
+ "for road in multi_lane_section_roads:\n",
+ " print(f\" - {road.id}\")\n",
+ "\n",
+ "# Check for no links case in lanes of roads with multiple lane sections\n",
+ "for road in multi_lane_section_roads:\n",
+ " for lane_section in road.lane_sections:\n",
+ " for lane in lane_section.left_lanes:\n",
+ " if lane.lane_xml.attrib[\"type\"] == \"driving\":\n",
+ " link_xml = lane.lane_xml.find(\"link\")\n",
+ " if link_xml is None:\n",
+ " print(\n",
+ " f\" - Road ID: {road.id}, Lane Section ID: {lane_section.lane_section_ordinal}, Lane ID: {lane.id} has no link.\"\n",
+ " )\n",
+ " for lane in lane_section.right_lanes:\n",
+ " if lane.lane_xml.attrib[\"type\"] == \"driving\":\n",
+ " link_xml = lane.lane_xml.find(\"link\")\n",
+ " if link_xml is None:\n",
+ " print(\n",
+ " f\" - Road ID: {road.id}, Lane Section ID: {lane_section.lane_section_ordinal}, Lane ID: {lane.id} has no link.\"\n",
+ " )"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "08461732",
+ "metadata": {},
+ "source": [
+ "Conclusion: There is no driving lane without a link in a road that has multiple lane_sections"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "70cb7fb6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Finding multi-successor/predecessor roads\n",
+ "\n",
+ "multi_successor_roads = []\n",
+ "multi_predecessor_roads = []\n",
+ "\n",
+ "for road in road_network.get_roads():\n",
+ " if len(road.road_xml.find(\"link\").findall(\"successor\")) > 1:\n",
+ " multi_successor_roads.append(road)\n",
+ " if len(road.road_xml.find(\"link\").findall(\"predecessor\")) > 1:\n",
+ " multi_predecessor_roads.append(road)\n",
+ "\n",
+ "print(f\"Multi-successor roads: {[road.id for road in multi_successor_roads]}\")\n",
+ "print(f\"Multi-predecessor roads: {[road.id for road in multi_predecessor_roads]}\")\n",
+ "\n",
+ "# Finding multi-successor/predecessor lanes\n",
+ "\n",
+ "multi_successor_lanes = []\n",
+ "multi_predecessor_lanes = []\n",
+ "\n",
+ "for road in road_network.get_roads():\n",
+ " for lane_section in road.lane_sections:\n",
+ " for lane in lane_section.left_lanes + lane_section.right_lanes:\n",
+ " if lane.lane_xml.find(\"link\") is not None:\n",
+ " if lane.lane_xml.find(\"link\").findall(\"successor\") is not []:\n",
+ " if len(lane.lane_xml.find(\"link\").findall(\"successor\")) > 1:\n",
+ " multi_successor_lanes.append((lane.id, lane_section.lane_section_ordinal, road.id))\n",
+ " if lane.lane_xml.find(\"link\").findall(\"predecessor\") is not []:\n",
+ " if len(lane.lane_xml.find(\"link\").findall(\"predecessor\")) > 1:\n",
+ " multi_predecessor_lanes.append((lane.id, lane_section.lane_section_ordinal, road.id))\n",
+ "\n",
+ "print(f\"Multi-successor lanes: {multi_successor_lanes}\")\n",
+ "print(f\"Multi-predecessor lanes: {multi_predecessor_lanes}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5613bebc",
+ "metadata": {},
+ "source": [
+ "Conclusion: There is no road element or lane that has multiple successor or predecessor links"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ac751a0b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_road(road_network, road_id):\n",
+ " for road in road_network.get_roads():\n",
+ " if road.id == road_id:\n",
+ " return road\n",
+ " return None"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e63af106",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Check if every pred of a road has itself as a succ/pred in the pred_road\n",
+ "for road_obj in road_network.get_roads():\n",
+ " if road_obj.road_xml.attrib[\"junction\"] != \"-1\":\n",
+ " continue\n",
+ " if road_obj.road_xml.find(\"link\") is not None and road_obj.road_xml.find(\"link\").findall(\"predecessor\") is not []:\n",
+ " for pred in road_obj.road_xml.find(\"link\").findall(\"predecessor\"):\n",
+ " found = False\n",
+ " if pred.attrib[\"elementType\"] != \"road\":\n",
+ " continue\n",
+ " pred_road = get_road(road_network, pred.attrib[\"elementId\"])\n",
+ " if pred_road is not None:\n",
+ " if (\n",
+ " pred_road.road_xml.find(\"link\") is not None\n",
+ " and pred_road.road_xml.find(\"link\").findall(\"successor\") is not []\n",
+ " ):\n",
+ " for succ in pred_road.road_xml.find(\"link\").findall(\"successor\"):\n",
+ " if succ.attrib[\"elementType\"] == \"road\" and succ.attrib[\"elementId\"] == road_obj.id:\n",
+ " found = True\n",
+ " break\n",
+ " if (\n",
+ " pred_road.road_xml.find(\"link\") is not None\n",
+ " and pred_road.road_xml.find(\"link\").findall(\"predecessor\") is not []\n",
+ " ):\n",
+ " for pred_pred in pred_road.road_xml.find(\"link\").findall(\"predecessor\"):\n",
+ " if pred_pred.attrib[\"elementType\"] == \"road\" and pred_pred.attrib[\"elementId\"] == road_obj.id:\n",
+ " found = True\n",
+ " break\n",
+ " if not found:\n",
+ " print(\n",
+ " f\"Road {pred_road.id} is a predecessor of {road_obj.id}, but {pred_road.id} does not list {road_obj.id} as a successor/predecessor.\"\n",
+ " )\n",
+ " else:\n",
+ " print(f\"Predecessor road with ID {pred.attrib['elementId']} not found in the network.\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "eba158a3",
+ "metadata": {},
+ "source": [
+ "Conclusion: Every predecessor of a road has itself as a successor/predecessor in the pred_road, and vice-versa for successor"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8a3083c5",
+ "metadata": {},
+ "source": [
+ "Roads Data Analysis in JSON"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4826ec18",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "json_dir = \"../carla\" # replace with your directory path\n",
+ "json_files = glob.glob(os.path.join(json_dir, \"*.json\"))\n",
+ "\n",
+ "for jf in json_files:\n",
+ " with open(jf, \"r\") as f:\n",
+ " print(f\"\\nReading JSON file: {jf}\")\n",
+ " data = json.load(f)\n",
+ " if \"roads\" in data:\n",
+ " num_geometries = [len(road[\"geometry\"]) for road in data[\"roads\"]]\n",
+ " print(f\"Number of roads in the JSON: {len(data['roads'])}\")\n",
+ " print(f\"Max geometries in a road: {max(num_geometries)}\")\n",
+ " print(f\"Min geometries in a road: {min(num_geometries)}\")\n",
+ " print(f\"Total geometries in the JSON: {sum(num_geometries)}\")\n",
+ " print(f\"Average geometries per road: {sum(num_geometries) / len(num_geometries)}\")\n",
+ " else:\n",
+ " print(\"No 'roads' key found in this JSON file.\")"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/gym_env.py b/examples/gym_env.py
index 8d8597893..94e525d93 100644
--- a/examples/gym_env.py
+++ b/examples/gym_env.py
@@ -1,6 +1,7 @@
import gym
import pufferlib.emulation
+
class SampleGymEnv(gym.Env):
def __init__(self):
self.observation_space = gym.spaces.Box(low=-1, high=1, shape=(1,))
@@ -12,7 +13,8 @@ def reset(self):
def step(self, action):
return self.observation_space.sample(), 0.0, False, {}
-if __name__ == '__main__':
+
+if __name__ == "__main__":
gym_env = SampleGymEnv()
gymnasium_env = pufferlib.GymToGymnasium(gym_env)
puffer_env = pufferlib.emulation.GymnasiumPufferEnv(gymnasium_env)
diff --git a/examples/gymnasium_env.py b/examples/gymnasium_env.py
index bb7f00c34..e33ae289e 100644
--- a/examples/gymnasium_env.py
+++ b/examples/gymnasium_env.py
@@ -1,6 +1,7 @@
import gymnasium
import pufferlib.emulation
+
class SampleGymnasiumEnv(gymnasium.Env):
def __init__(self):
self.observation_space = gymnasium.spaces.Box(low=-1, high=1, shape=(1,))
@@ -12,7 +13,8 @@ def reset(self):
def step(self, action):
return self.observation_space.sample(), 0.0, False, False, {}
-if __name__ == '__main__':
+
+if __name__ == "__main__":
gymnasium_env = SampleGymnasiumEnv()
puffer_env = pufferlib.emulation.GymnasiumPufferEnv(gymnasium_env)
observation, info = puffer_env.reset()
diff --git a/examples/pettingzoo_env.py b/examples/pettingzoo_env.py
index 7b1b1abf4..333069229 100644
--- a/examples/pettingzoo_env.py
+++ b/examples/pettingzoo_env.py
@@ -2,10 +2,11 @@
import pettingzoo
import pufferlib.emulation
+
class SamplePettingzooEnv(pettingzoo.ParallelEnv):
def __init__(self):
- self.possible_agents = ['agent_0', 'agent_1']
- self.agents = ['agent_0', 'agent_1']
+ self.possible_agents = ["agent_0", "agent_1"]
+ self.agents = ["agent_0", "agent_1"]
def observation_space(self, agent):
return gymnasium.spaces.Box(low=-1, high=1, shape=(1,))
@@ -25,7 +26,8 @@ def step(self, action):
infos = {agent: {} for agent in self.agents}
return observations, rewards, terminals, truncations, infos
-if __name__ == '__main__':
+
+if __name__ == "__main__":
env = SamplePettingzooEnv()
puffer_env = pufferlib.emulation.PettingZooPufferEnv(env)
observations, infos = puffer_env.reset()
diff --git a/examples/puffer_env.py b/examples/puffer_env.py
index 8e89dc14a..f18bad977 100644
--- a/examples/puffer_env.py
+++ b/examples/puffer_env.py
@@ -1,6 +1,7 @@
import gymnasium
import pufferlib.emulation
+
class SamplePufferEnv(pufferlib.PufferEnv):
def __init__(self, buf=None, seed=0):
self.single_observation_space = gymnasium.spaces.Box(low=-1, high=1, shape=(1,))
@@ -14,16 +15,17 @@ def reset(self, seed=0):
def step(self, action):
self.observations[:] = self.observation_space.sample()
- infos = [{'infos': 'is a list of dictionaries'}]
+ infos = [{"infos": "is a list of dictionaries"}]
return self.observations, self.rewards, self.terminals, self.truncations, infos
-if __name__ == '__main__':
+
+if __name__ == "__main__":
puffer_env = SamplePufferEnv()
observations, infos = puffer_env.reset()
actions = puffer_env.action_space.sample()
observations, rewards, terminals, truncations, infos = puffer_env.step(actions)
- print('Puffer envs use a vector interface and in-place array updates')
- print('Observation:', observations)
- print('Reward:', rewards)
- print('Terminal:', terminals)
- print('Truncation:', truncations)
+ print("Puffer envs use a vector interface and in-place array updates")
+ print("Observation:", observations)
+ print("Reward:", rewards)
+ print("Terminal:", terminals)
+ print("Truncation:", truncations)
diff --git a/examples/pufferl.py b/examples/pufferl.py
index 4294e7063..baa51baaa 100644
--- a/examples/pufferl.py
+++ b/examples/pufferl.py
@@ -6,7 +6,8 @@
# Equivalent to running puffer train puffer_breakout
def cli():
- pufferl.train('puffer_breakout')
+ pufferl.train("puffer_breakout")
+
class Policy(torch.nn.Module):
def __init__(self, env):
@@ -29,17 +30,24 @@ def forward_eval(self, observations, state=None):
def forward(self, observations, state=None):
return self.forward_eval(observations, state)
+
# Managing your own trainer
-if __name__ == '__main__':
- env_name = 'puffer_breakout'
+if __name__ == "__main__":
+ env_name = "puffer_breakout"
env_creator = pufferlib.ocean.env_creator(env_name)
- vecenv = pufferlib.vector.make(env_creator, num_envs=2, num_workers=2, batch_size=1,
- backend=pufferlib.vector.Multiprocessing, env_kwargs={'num_envs': 4096})
+ vecenv = pufferlib.vector.make(
+ env_creator,
+ num_envs=2,
+ num_workers=2,
+ batch_size=1,
+ backend=pufferlib.vector.Multiprocessing,
+ env_kwargs={"num_envs": 4096},
+ )
policy = Policy(vecenv.driver_env).cuda()
- args = pufferl.load_config('default')
- args['train']['env'] = env_name
+ args = pufferl.load_config("default")
+ args["train"]["env"] = env_name
- trainer = pufferl.PuffeRL(args['train'], vecenv, policy)
+ trainer = pufferl.PuffeRL(args["train"], vecenv, policy)
for epoch in range(10):
trainer.evaluate()
diff --git a/examples/render.py b/examples/render.py
index d66f076ec..b3965859f 100644
--- a/examples/render.py
+++ b/examples/render.py
@@ -1,8 +1,7 @@
-
from pufferlib.ocean.breakout import breakout
+
env = breakout.Breakout()
env.reset()
while True:
env.step(env.action_space.sample())
frame = env.render()
-
diff --git a/examples/structured_env.py b/examples/structured_env.py
index 6dc678445..f7af0bee3 100644
--- a/examples/structured_env.py
+++ b/examples/structured_env.py
@@ -1,12 +1,15 @@
import gymnasium
import pufferlib.emulation
+
class SampleGymnasiumEnv(gymnasium.Env):
def __init__(self):
- self.observation_space = gymnasium.spaces.Dict({
- 'foo': gymnasium.spaces.Box(low=-1, high=1, shape=(2,)),
- 'bar': gymnasium.spaces.Box(low=2, high=3, shape=(3,)),
- })
+ self.observation_space = gymnasium.spaces.Dict(
+ {
+ "foo": gymnasium.spaces.Box(low=-1, high=1, shape=(2,)),
+ "bar": gymnasium.spaces.Box(low=2, high=3, shape=(3,)),
+ }
+ )
self.action_space = gymnasium.spaces.MultiDiscrete([2, 5])
def reset(self):
@@ -15,20 +18,22 @@ def reset(self):
def step(self, action):
return self.observation_space.sample(), 0.0, False, False, {}
-if __name__ == '__main__':
+
+if __name__ == "__main__":
gymnasium_env = SampleGymnasiumEnv()
puffer_env = pufferlib.emulation.GymnasiumPufferEnv(gymnasium_env)
flat_observation, info = puffer_env.reset()
flat_action = puffer_env.action_space.sample()
flat_observation, reward, terminal, truncation, info = puffer_env.step(flat_action)
- print(f'PufferLib flattens observations and actions:\n{flat_observation}\n{flat_action}')
+ print(f"PufferLib flattens observations and actions:\n{flat_observation}\n{flat_action}")
observation = flat_observation.view(puffer_env.obs_dtype)
- print(f'You can unflatten observations with numpy:\n{observation}')
+ print(f"You can unflatten observations with numpy:\n{observation}")
import torch
import pufferlib.pytorch
+
flat_torch_observation = torch.from_numpy(flat_observation)
torch_dtype = pufferlib.pytorch.nativize_dtype(puffer_env.emulated)
torch_observation = pufferlib.pytorch.nativize_tensor(flat_torch_observation, torch_dtype)
- print(f'But we suggest unflattening observations with torch in your model forward pass:\n{torch_observation}')
+ print(f"But we suggest unflattening observations with torch in your model forward pass:\n{torch_observation}")
diff --git a/examples/vectorization.py b/examples/vectorization.py
index 4a6ff2ecb..62c999789 100644
--- a/examples/vectorization.py
+++ b/examples/vectorization.py
@@ -2,6 +2,7 @@
import pufferlib.emulation
import pufferlib.vector
+
class SamplePufferEnv(pufferlib.PufferEnv):
def __init__(self, foo=0, bar=1, buf=None, seed=0):
self.single_observation_space = gymnasium.spaces.Box(low=-1, high=1, shape=(1,))
@@ -19,60 +20,63 @@ def reset(self, seed=0):
def step(self, action):
self.observations[:] = self.observation_space.sample()
- infos = [{'infos': 'is a list of dictionaries'}]
+ infos = [{"infos": "is a list of dictionaries"}]
return self.observations, self.rewards, self.terminals, self.truncations, infos
def close(self):
pass
-if __name__ == '__main__':
- serial_vecenv = pufferlib.vector.make(
- SamplePufferEnv, num_envs=2, backend=pufferlib.vector.Serial)
+
+if __name__ == "__main__":
+ serial_vecenv = pufferlib.vector.make(SamplePufferEnv, num_envs=2, backend=pufferlib.vector.Serial)
observations, infos = serial_vecenv.reset()
actions = serial_vecenv.action_space.sample()
o, r, d, t, i = serial_vecenv.step(actions)
- print('Serial VecEnv:')
- print('Observations:', o)
- print('Rewards:', r)
- print('Terminals:', t)
- print('Truncations:', d)
+ print("Serial VecEnv:")
+ print("Observations:", o)
+ print("Rewards:", r)
+ print("Terminals:", t)
+ print("Truncations:", d)
# Pass arguments to all environments like this
serial_vecenv = pufferlib.vector.make(
- SamplePufferEnv, num_envs=2, backend=pufferlib.vector.Serial,
- env_args=[3], env_kwargs={'bar': 4}
+ SamplePufferEnv, num_envs=2, backend=pufferlib.vector.Serial, env_args=[3], env_kwargs={"bar": 4}
)
- print('Foo: ', [env.foo for env in serial_vecenv.envs])
- print('Bar: ', [env.bar for env in serial_vecenv.envs])
+ print("Foo: ", [env.foo for env in serial_vecenv.envs])
+ print("Bar: ", [env.bar for env in serial_vecenv.envs])
# Or to each environment like this
serial_vecenv = pufferlib.vector.make(
- [SamplePufferEnv, SamplePufferEnv], num_envs=2, backend=pufferlib.vector.Serial,
- env_args=[[3], [4]], env_kwargs=[{'bar': 4}, {'bar': 5}]
+ [SamplePufferEnv, SamplePufferEnv],
+ num_envs=2,
+ backend=pufferlib.vector.Serial,
+ env_args=[[3], [4]],
+ env_kwargs=[{"bar": 4}, {"bar": 5}],
)
- print('Foo: ', [env.foo for env in serial_vecenv.envs])
- print('Bar: ', [env.bar for env in serial_vecenv.envs])
+ print("Foo: ", [env.foo for env in serial_vecenv.envs])
+ print("Bar: ", [env.bar for env in serial_vecenv.envs])
- vecenv = pufferlib.vector.make(SamplePufferEnv,
- num_envs=2, num_workers=2, batch_size=1, backend=pufferlib.vector.Multiprocessing)
- vecenv.async_reset() # You can also use the synchronous API with Multiprocessing
+ vecenv = pufferlib.vector.make(
+ SamplePufferEnv, num_envs=2, num_workers=2, batch_size=1, backend=pufferlib.vector.Multiprocessing
+ )
+ vecenv.async_reset() # You can also use the synchronous API with Multiprocessing
o, r, d, t, i, env_ids, masks = vecenv.recv()
actions = vecenv.action_space.sample()
- print('Policy computes actions for all agents in batch_size=1 of the total num_envs=2 environments')
- print('Actions:', actions)
+ print("Policy computes actions for all agents in batch_size=1 of the total num_envs=2 environments")
+ print("Actions:", actions)
vecenv.send(actions)
# New observations are ready while the other envs are running in the background
o, r, d, t, i, env_ids, masks = vecenv.recv()
- print('Observations:', o)
+ print("Observations:", o)
# Make sure to close the vecenv when you're done
vecenv.close()
try:
- vecenv = pufferlib.vector.make(SamplePufferEnv,
- num_envs=1, num_workers=2, batch_size=3, backend=pufferlib.vector.Multiprocessing)
+ vecenv = pufferlib.vector.make(
+ SamplePufferEnv, num_envs=1, num_workers=2, batch_size=3, backend=pufferlib.vector.Multiprocessing
+ )
except pufferlib.APIUsageError:
- #Make sure num_envs divides num_workers, and both num_envs and num_workers should divide batch_size
+ # Make sure num_envs divides num_workers, and both num_envs and num_workers should divide batch_size
pass
-
diff --git a/pufferlib/__init__.py b/pufferlib/__init__.py
index f86643a4e..7fb2007e2 100644
--- a/pufferlib/__init__.py
+++ b/pufferlib/__init__.py
@@ -1,23 +1,26 @@
__version__ = 3.0
import os
+
path = __path__[0]
-link_to = os.path.join(path, 'resources')
+link_to = os.path.join(path, "resources")
try:
- os.symlink(link_to, 'resources')
+ os.symlink(link_to, "resources")
except FileExistsError:
pass
# Silence noisy dependencies
import warnings
+
warnings.filterwarnings("ignore", category=DeprecationWarning)
# Silence noisy packages
import sys
+
original_stdout = sys.stdout
original_stderr = sys.stderr
-sys.stdout = open(os.devnull, 'w')
-sys.stderr = open(os.devnull, 'w')
+sys.stdout = open(os.devnull, "w")
+sys.stderr = open(os.devnull, "w")
try:
import gymnasium
import pygame
@@ -29,4 +32,3 @@
sys.stderr = original_stderr
from pufferlib.pufferlib import *
-from pufferlib import environments
diff --git a/pufferlib/cleanrl_ppo_atari.py b/pufferlib/cleanrl_ppo_atari.py
index 595f62ab2..c086dc88d 100644
--- a/pufferlib/cleanrl_ppo_atari.py
+++ b/pufferlib/cleanrl_ppo_atari.py
@@ -1,5 +1,4 @@
# docs and experiment results can be found at https://docs.cleanrl.dev/rl-algorithms/ppo/#ppo_ataripy
-import os
import random
import time
from dataclasses import dataclass
@@ -21,9 +20,10 @@
NoopResetEnv,
)
+
@dataclass
class Args:
- exp_name: str = 'cleanrl_ppo_atari'
+ exp_name: str = "cleanrl_ppo_atari"
"""the name of this experiment"""
seed: int = 1
"""seed of the experiment"""
@@ -182,6 +182,7 @@ def get_action_and_value(self, x, action=None):
# PufferLib vectorization makes CleanRL ~65% faster!
import pufferlib.vector
import pufferlib.environments.atari
+
envs = pufferlib.vector.make(
pufferlib.environments.atari.env_creator(args.env_id),
env_kwargs=dict(framestack=4),
diff --git a/pufferlib/config/atari.ini b/pufferlib/config/atari.ini
deleted file mode 100644
index 75d1557ab..000000000
--- a/pufferlib/config/atari.ini
+++ /dev/null
@@ -1,49 +0,0 @@
-[base]
-package = atari
-
-env_name = adventure air_raid alien amidar assault asterix asteroids atlantis2 atlantis backgammon bank_heist basic_math battle_zone beam_rider berzerk blackjack bowling boxing breakout carnival casino centipede chopper_command combat crazy_climber crossbow darkchambers defender demon_attack donkey_kong double_dunk earthworld elevator_action enduro entombed et fishing_derby flag_capture freeway frogger frostbite galaxian gopher gravitar hangman haunted_house hero human_cannonball ice_hockey jamesbond journey_escape joust kaboom kangaroo keystone_kapers king_kong klax koolaid krull kung_fu_master laser_gates lost_luggage mario_bros maze_craze miniature_golf montezuma_revenge mr_do ms_pacman name_this_game othello pacman phoenix pitfall2 pitfall pong pooyan private_eye qbert riverraid road_runner robotank seaquest sir_lancelot skiing solaris space_invaders space_war star_gunner superman surround tennis tetris tic_tac_toe_3d time_pilot trondead turmoil tutankham up_n_down venture video_checkers video_chess video_cube video_pinball warlords wizard_of_wor word_zapper yars_revenge zaxxon
-
-policy_name = Policy
-rnn_name = Recurrent
-
-[vec]
-num_envs = 128
-num_workers = 16
-batch_size = 64
-
-[train]
-batch_size = 8192
-minibatch_size = 2048
-update_epochs = 1
-bptt_horizon = 64
-total_timesteps = 10_000_000
-anneal_lr = False
-
-[env]
-frameskip = 1
-repeat_action_probability = 0.0
-
-[sweep.parameters.env.parameters.frameskip]
-distribution = uniform
-min = 1
-max = 10
-
-#[sweep.parameters.env.parameters.repeat_action_probability]
-#distribution = uniform
-#min = 0
-#max = 1
-
-[sweep.parameters.train.parameters.total_timesteps]
-distribution = uniform
-min = 5_000_000
-max = 200_000_000
-
-[sweep.parameters.train.parameters.batch_size]
-distribution = uniform
-min = 16384
-max = 65536
-
-[sweep.parameters.train.parameters.minibatch_size]
-distribution = uniform
-min = 512
-max = 8192
diff --git a/pufferlib/config/box2d.ini b/pufferlib/config/box2d.ini
deleted file mode 100644
index a87ae3627..000000000
--- a/pufferlib/config/box2d.ini
+++ /dev/null
@@ -1,11 +0,0 @@
-[base]
-package = box2d
-env_name = car-racing
-
-[train]
-num_envs = 48
-num_workers = 24
-env_batch_size = 48
-zero_copy = False
-batch_size = 16384
-minibatch_size = 2048
diff --git a/pufferlib/config/bsuite.ini b/pufferlib/config/bsuite.ini
deleted file mode 100644
index bab515466..000000000
--- a/pufferlib/config/bsuite.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[base]
-package = bsuite
-env_name = bandit/0
-
-[train]
-total_timesteps = 1_000_000
-num_envs = 1
diff --git a/pufferlib/config/butterfly.ini b/pufferlib/config/butterfly.ini
deleted file mode 100644
index a616c2917..000000000
--- a/pufferlib/config/butterfly.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[base]
-package = butterfly
-env_name = cooperative_pong_v5
diff --git a/pufferlib/config/classic_control.ini b/pufferlib/config/classic_control.ini
deleted file mode 100644
index 8bc4f44e4..000000000
--- a/pufferlib/config/classic_control.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[base]
-package = classic_control
-env_name = cartpole mountaincar
-
-[train]
-total_timesteps = 500_000
-num_envs = 64
-env_batch_size = 64
diff --git a/pufferlib/config/classic_control_continuous.ini b/pufferlib/config/classic_control_continuous.ini
deleted file mode 100644
index cd0603c2e..000000000
--- a/pufferlib/config/classic_control_continuous.ini
+++ /dev/null
@@ -1,8 +0,0 @@
-[base]
-package = classic_control_continuous
-env_name = mountaincar-continuous
-
-[train]
-total_timesteps = 500_000
-num_envs = 64
-env_batch_size = 64
diff --git a/pufferlib/config/craftax.ini b/pufferlib/config/craftax.ini
deleted file mode 100644
index 2c5b2023f..000000000
--- a/pufferlib/config/craftax.ini
+++ /dev/null
@@ -1,24 +0,0 @@
-[base]
-package = craftax
-env_name = Craftax-Symbolic-v1 Craftax-Classic-Symbolic-v1
-policy_name = Policy
-rnn_name = Recurrent
-
-[env]
-num_envs = 1024
-
-[vec]
-num_envs = 1
-num_workers = 1
-batch_size = 1
-
-[train]
-total_timesteps = 100_000_000
-checkpoint_interval = 200
-update_epochs = 4
-batch_size = 131072
-minibatch_size = 8192
-learning_rate = 0.0002
-gamma = 0.99
-gae_lambda = 0.8
-ent_coef = 0.01
diff --git a/pufferlib/config/crafter.ini b/pufferlib/config/crafter.ini
deleted file mode 100644
index d46260889..000000000
--- a/pufferlib/config/crafter.ini
+++ /dev/null
@@ -1,10 +0,0 @@
-[base]
-package = crafter
-env_name = crafter
-
-[train]
-num_envs = 96
-num_workers = 24
-env_batch_size = 48
-zero_copy = False
-batch_size = 6144
diff --git a/pufferlib/config/default.ini b/pufferlib/config/default.ini
index 0990fdb13..810de828c 100644
--- a/pufferlib/config/default.ini
+++ b/pufferlib/config/default.ini
@@ -18,7 +18,7 @@ seed = 42
[rnn]
[train]
-name = pufferai
+name = pufferai
project = ablations
seed = 42
@@ -61,7 +61,7 @@ prio_alpha = 0.8
prio_beta0 = 0.2
[sweep]
-method = Protein
+method = Protein
metric = score
goal = maximize
downsample = 10
@@ -73,138 +73,138 @@ downsample = 10
#mean = 8
#scale = auto
-# TODO: Elim from base
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 5e7
-max = 1e10
-mean = 1e8
-scale = time
-
-[sweep.train.bptt_horizon]
-distribution = uniform_pow2
-min = 16
-max = 64
-mean = 64
-scale = auto
-
-[sweep.train.minibatch_size]
-distribution = uniform_pow2
-min = 8192
-max = 65536
-mean = 32768
-scale = auto
-
-[sweep.train.learning_rate]
-distribution = log_normal
-min = 0.00001
-mean = 0.01
-max = 0.1
-scale = 0.5
-
-[sweep.train.ent_coef]
-distribution = log_normal
-min = 0.00001
-mean = 0.01
-max = 0.2
-scale = auto
-
-[sweep.train.gamma]
-distribution = logit_normal
-min = 0.8
-mean = 0.98
-max = 0.9999
-scale = auto
-
-[sweep.train.gae_lambda]
-distribution = logit_normal
-min = 0.6
-mean = 0.95
-max = 0.995
-scale = auto
-
-[sweep.train.vtrace_rho_clip]
-distribution = uniform
-min = 0.0
-max = 5.0
-mean = 1.0
-scale = auto
-
-[sweep.train.vtrace_c_clip]
-distribution = uniform
-min = 0.0
-max = 5.0
-mean = 1.0
-scale = auto
-
-#[sweep.train.update_epochs]
-#distribution = int_uniform
-#min = 1
-#max = 8
-#mean = 1
-#scale = 2.0
-
-[sweep.train.clip_coef]
-distribution = uniform
-min = 0.01
-max = 1.0
-mean = 0.2
-scale = auto
-
-# Optimal vf clip can be lower than 0.1,
-# but this results in jank unstable runs
-[sweep.train.vf_clip_coef]
-distribution = uniform
-min = 0.1
-max = 5.0
-mean = 0.2
-scale = auto
-
-[sweep.train.vf_coef]
-distribution = uniform
-min = 0.0
-max = 5.0
-mean = 2.0
-scale = auto
-
-[sweep.train.max_grad_norm]
-distribution = uniform
-min = 0.0
-mean = 1.0
-max = 5.0
-scale = auto
-
-[sweep.train.adam_beta1]
-distribution = logit_normal
-min = 0.5
-mean = 0.9
-max = 0.999
-scale = auto
-
-[sweep.train.adam_beta2]
-distribution = logit_normal
-min = 0.9
-mean = 0.999
-max = 0.99999
-scale = auto
-
-[sweep.train.adam_eps]
-distribution = log_normal
-min = 1e-14
-mean = 1e-8
-max = 1e-4
-scale = auto
-
-[sweep.train.prio_alpha]
-distribution = logit_normal
-min = 0.1
-mean = 0.85
-max = 0.99
-scale = auto
-
-[sweep.train.prio_beta0]
-distribution = logit_normal
-min = 0.1
-mean = 0.85
-max = 0.99
-scale = auto
+; # TODO: Elim from base
+; [sweep.train.total_timesteps]
+; distribution = log_normal
+; min = 5e7
+; max = 1e10
+; mean = 1e8
+; scale = time
+
+; [sweep.train.bptt_horizon]
+; distribution = uniform_pow2
+; min = 16
+; max = 64
+; mean = 64
+; scale = auto
+
+; [sweep.train.minibatch_size]
+; distribution = uniform_pow2
+; min = 8192
+; max = 65536
+; mean = 32768
+; scale = auto
+
+; [sweep.train.learning_rate]
+; distribution = log_normal
+; min = 0.00001
+; mean = 0.01
+; max = 0.1
+; scale = 0.5
+
+; [sweep.train.ent_coef]
+; distribution = log_normal
+; min = 0.00001
+; mean = 0.01
+; max = 0.2
+; scale = auto
+
+; [sweep.train.gamma]
+; distribution = logit_normal
+; min = 0.8
+; mean = 0.98
+; max = 0.9999
+; scale = auto
+
+; [sweep.train.gae_lambda]
+; distribution = logit_normal
+; min = 0.6
+; mean = 0.95
+; max = 0.995
+; scale = auto
+
+; [sweep.train.vtrace_rho_clip]
+; distribution = uniform
+; min = 0.0
+; max = 5.0
+; mean = 1.0
+; scale = auto
+
+; [sweep.train.vtrace_c_clip]
+; distribution = uniform
+; min = 0.0
+; max = 5.0
+; mean = 1.0
+; scale = auto
+
+; #[sweep.train.update_epochs]
+; #distribution = int_uniform
+; #min = 1
+; #max = 8
+; #mean = 1
+; #scale = 2.0
+
+; [sweep.train.clip_coef]
+; distribution = uniform
+; min = 0.01
+; max = 1.0
+; mean = 0.2
+; scale = auto
+
+; # Optimal vf clip can be lower than 0.1,
+; # but this results in jank unstable runs
+; [sweep.train.vf_clip_coef]
+; distribution = uniform
+; min = 0.1
+; max = 5.0
+; mean = 0.2
+; scale = auto
+
+; [sweep.train.vf_coef]
+; distribution = uniform
+; min = 0.0
+; max = 5.0
+; mean = 2.0
+; scale = auto
+
+; [sweep.train.max_grad_norm]
+; distribution = uniform
+; min = 0.0
+; mean = 1.0
+; max = 5.0
+; scale = auto
+
+; [sweep.train.adam_beta1]
+; distribution = logit_normal
+; min = 0.5
+; mean = 0.9
+; max = 0.999
+; scale = auto
+
+; [sweep.train.adam_beta2]
+; distribution = logit_normal
+; min = 0.9
+; mean = 0.999
+; max = 0.99999
+; scale = auto
+
+; [sweep.train.adam_eps]
+; distribution = log_normal
+; min = 1e-14
+; mean = 1e-8
+; max = 1e-4
+; scale = auto
+
+; [sweep.train.prio_alpha]
+; distribution = logit_normal
+; min = 0.1
+; mean = 0.85
+; max = 0.99
+; scale = auto
+
+; [sweep.train.prio_beta0]
+; distribution = logit_normal
+; min = 0.1
+; mean = 0.85
+; max = 0.99
+; scale = auto
diff --git a/pufferlib/config/dm_control.ini b/pufferlib/config/dm_control.ini
deleted file mode 100644
index 8cce146e1..000000000
--- a/pufferlib/config/dm_control.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[base]
-package = dm_control
-env_name = dmc
diff --git a/pufferlib/config/dm_lab.ini b/pufferlib/config/dm_lab.ini
deleted file mode 100644
index 8350696de..000000000
--- a/pufferlib/config/dm_lab.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[base]
-package = dm_lab
-env_name = dml
diff --git a/pufferlib/config/doom.ini b/pufferlib/config/doom.ini
deleted file mode 100644
index 62cf850e7..000000000
--- a/pufferlib/config/doom.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[base]
-package = vizdoom
-env_name = doom
-
-[train]
-num_envs = 144
-num_workers = 24
-env_batch_size = 48
-zero_copy = False
-batch_size = 8192
-minibatch_size = 2048
-update_epochs = 1
diff --git a/pufferlib/config/gpudrive.ini b/pufferlib/config/gpudrive.ini
deleted file mode 100644
index 41052ecfe..000000000
--- a/pufferlib/config/gpudrive.ini
+++ /dev/null
@@ -1,46 +0,0 @@
-[base]
-package = gpudrive
-env_name = gpudrive
-policy_name = Policy
-rnn_name = Recurrent
-
-[env]
-num_worlds = 512
-
-[train]
-total_timesteps = 10_000_000
-num_envs = 1
-num_workers = 1
-env_batch_size = 1
-zero_copy = False
-batch_size = 262_144
-update_epochs = 5
-minibatch_size = 32768
-bptt_horizon = 4
-anneal_lr = False
-gae_lambda = 0.95
-gamma = 0.99
-clip_coef = 0.2
-vf_coef = 0.5
-vf_clip_coef = 0.2
-max_grad_norm = 0.5
-ent_coef = 0.00
-learning_rate = 0.0003
-checkpoint_interval = 1000
-device = cuda
-
-[sweep.metric]
-goal = maximize
-name = environment/goal_achieved
-
-[sweep.parameters.train.parameters.batch_size]
-distribution = uniform
-min = 32768
-max = 524288
-
-[sweep.parameters.train.parameters.minibatch_size]
-distribution = uniform
-min = 2048
-max = 32768
-
-
diff --git a/pufferlib/config/griddly.ini b/pufferlib/config/griddly.ini
deleted file mode 100644
index ab23d7ba8..000000000
--- a/pufferlib/config/griddly.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[base]
-package = griddly
-env_name = spiders
diff --git a/pufferlib/config/gvgai.ini b/pufferlib/config/gvgai.ini
deleted file mode 100644
index 21459bca5..000000000
--- a/pufferlib/config/gvgai.ini
+++ /dev/null
@@ -1,36 +0,0 @@
-[base]
-package = gvgai
-env_name = zelda
-policy_name = Policy
-rnn_name = Recurrent
-
-[train]
-total_timesteps = 1_000_000
-checkpoint_interval = 1000
-learning_rate = 0.00024290984560207393
-num_envs = 96
-num_workers = 24
-env_batch_size = 32
-update_epochs = 1
-zero_copy = False
-bptt_horizon = 16
-batch_size = 4096
-minibatch_size = 1024
-compile = False
-anneal_lr = False
-device = cuda
-
-[sweep.metric]
-goal = maximize
-name = environment/reward
-
-[sweep.parameters.train.parameters.total_timesteps]
-distribution = log_uniform_values
-min = 500_000_000
-max = 10_000_000_000
-
-[sweep.parameters.train.parameters.batch_size]
-values = [4096, 8192, 16384]
-
-[sweep.parameters.train.parameters.minibatch_size]
-values = [512, 1024, 2048, 4096]
diff --git a/pufferlib/config/kinetix.ini b/pufferlib/config/kinetix.ini
deleted file mode 100644
index e9f6e02ac..000000000
--- a/pufferlib/config/kinetix.ini
+++ /dev/null
@@ -1,53 +0,0 @@
-[base]
-package = kinetix
-env_name = kinetix-pixels-discrete kinetix-symbolic-discrete
-policy_name = PixelsPolicy
-rnn_name = Recurrent
-
-[env]
-num_envs = 2048
-
-[train]
-total_timesteps = 100_000_000
-checkpoint_interval = 200
-num_envs = 1
-num_workers = 1
-env_batch_size = 1
-update_epochs = 8
-batch_size = 131072
-minibatch_size = 4096
-learning_rate = 0.0003
-gamma = 0.995
-gae_lambda = 0.9
-ent_coef = 0.01
-
-[sweep]
-method = protein
-name = sweep
-
-[sweep.metric]
-goal = maximize
-name = GoalR
-min = 0
-max = None
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 5e6
-max = 1e9
-mean = 1e7
-scale = auto
-
-[sweep.train.batch_size]
-distribution = uniform_pow2
-min = 32768
-max = 131072
-mean = 65536
-scale = auto
-
-[sweep.train.minibatch_size]
-distribution = uniform_pow2
-min = 1024
-max = 32768
-mean = 8192
-scale = auto
diff --git a/pufferlib/config/magent.ini b/pufferlib/config/magent.ini
deleted file mode 100644
index 0df7336f8..000000000
--- a/pufferlib/config/magent.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[base]
-package = magent
-env_name = battle_v4
diff --git a/pufferlib/config/mani_skill.ini b/pufferlib/config/mani_skill.ini
deleted file mode 100644
index 56e990d41..000000000
--- a/pufferlib/config/mani_skill.ini
+++ /dev/null
@@ -1,69 +0,0 @@
-
-[base]
-package = mani_skill
-env_name = mani_pickcube mani_pushcube mani_stackcube mani_peginsertion
-policy_name = Policy
-rnn_name = Recurrent
-
-[env]
-num_envs = 4096
-sim_steps_per_control = 5
-control_freq = 100
-solver_position_iterations = 15
-
-[vec]
-backend = PufferEnv
-num_envs = 1
-
-[train]
-total_timesteps = 15_000_000
-adam_beta1 = 0.9832254546070032
-adam_beta2 = 0.9996089758513379
-adam_eps = 0.0000024542110227211678
-bptt_horizon = 64
-clip_coef = 0.6609987983481933
-ent_coef = 0.001194131610607018
-gae_lambda = 0.968478898646462
-gamma = 0.8880001899050386
-learning_rate = 0.04729013902338006
-max_grad_norm = 1.9301595176438802
-minibatch_size = 32768
-prio_alpha = 0.9531362058849446
-prio_beta0 = 0.8285186322612919
-vf_clip_coef = 0.2581908677409054
-vf_coef = 2.6102252379894217
-vtrace_c_clip = 2.008516783867587
-vtrace_rho_clip = 0.7482202150166445
-
-[sweep]
-method = Protein
-metric = success_once
-downsample = 0
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 2e7
-max = 5e7
-mean = 4e7
-scale = time
-
-[sweep.env.sim_steps_per_control]
-distribution = int_uniform
-min = 1
-max = 10
-mean = 5
-scale = auto
-
-[sweep.env.control_freq]
-distribution = int_uniform
-min = 10
-max = 100
-mean = 20
-scale = auto
-
-[sweep.env.solver_position_iterations]
-distribution = int_uniform
-min = 4
-max = 30
-mean = 15
-scale = auto
diff --git a/pufferlib/config/metta.ini b/pufferlib/config/metta.ini
deleted file mode 100644
index 355e2b3a2..000000000
--- a/pufferlib/config/metta.ini
+++ /dev/null
@@ -1,67 +0,0 @@
-[base]
-package = metta
-env_name = metta
-policy_name = Policy
-rnn_name = Recurrent
-
-[vec]
-num_envs = 64
-num_workers = 16
-
-[env]
-render_mode = auto
-ore_reward = 0.17088483842567775
-battery_reward = 0.9882859711234822
-heart_reward = 1.0
-
-[train]
-total_timesteps = 300_000_000
-batch_size = auto
-adam_beta1 = 0.8923106632311335
-adam_beta2 = 0.9632470625784862
-adam_eps = 1.3537431449843922e-7
-clip_coef = 0.14919147162017737
-ent_coef = 0.016700174334611493
-gae_lambda = 0.8443676864928215
-gamma = 0.997950174315581
-learning_rate = 0.018470110879570414
-max_grad_norm = 2.572849891206465
-minibatch_size = 32768
-bptt_horizon = 64
-prio_alpha = 0.7918451491719373
-prio_beta0 = 0.5852686803034238
-vf_clip_coef = 0.1569624916309049
-vf_coef = 3.2211333828684454
-vtrace_c_clip = 2.134490283650365
-vtrace_rho_clip = 2.296343917695581
-
-[sweep]
-metric = agent/heart.gained
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 1e8
-max = 5e8
-mean = 3e8
-scale = auto
-
-[sweep.env.ore_reward]
-distribution = uniform
-min = 0.0
-mean = 0.25
-max = 1.0
-scale = auto
-
-[sweep.env.battery_reward]
-distribution = uniform
-min = 0.0
-mean = 0.5
-max = 1.0
-scale = auto
-
-[sweep.env.heart_reward]
-distribution = uniform
-min = 0.0
-mean = 1.0
-max = 1.0
-scale = auto
diff --git a/pufferlib/config/microrts.ini b/pufferlib/config/microrts.ini
deleted file mode 100644
index 3c1da0f24..000000000
--- a/pufferlib/config/microrts.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[base]
-package = microrts
-env_name = GlobalAgentCombinedRewardEnv
diff --git a/pufferlib/config/minerl.ini b/pufferlib/config/minerl.ini
deleted file mode 100644
index 25190f698..000000000
--- a/pufferlib/config/minerl.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[base]
-package = minerl
-env_name = MineRLNavigateDense-v0
diff --git a/pufferlib/config/minigrid.ini b/pufferlib/config/minigrid.ini
deleted file mode 100644
index c44178d9f..000000000
--- a/pufferlib/config/minigrid.ini
+++ /dev/null
@@ -1,19 +0,0 @@
-[base]
-package = minigrid
-env_name = minigrid
-
-[vec]
-num_envs = 48
-num_workers = 6
-batch_size = 48
-
-[train]
-total_timesteps = 1_000_000
-batch_size = 6144
-minibatch_size = 768
-update_epochs = 4
-anneal_lr = False
-gae_lambda = 0.95
-gamma = 0.95
-ent_coef = 0.025
-learning_rate = 2.5e-4
diff --git a/pufferlib/config/minihack.ini b/pufferlib/config/minihack.ini
deleted file mode 100644
index e356a5518..000000000
--- a/pufferlib/config/minihack.ini
+++ /dev/null
@@ -1,15 +0,0 @@
-[base]
-package = minihack
-env_name = minihack
-
-[vec]
-num_envs = 128
-num_workers = 16
-batch_size = 64
-
-[train]
-batch_size = 8192
-minibatch_size = 2048
-update_epochs = 1
-bptt_horizon = 64
-total_timesteps = 10_000_000
diff --git a/pufferlib/config/mujoco.ini b/pufferlib/config/mujoco.ini
deleted file mode 100644
index 9de3495a1..000000000
--- a/pufferlib/config/mujoco.ini
+++ /dev/null
@@ -1,29 +0,0 @@
-[base]
-package = mujoco
-env_name = HalfCheetah-v4 Hopper-v4 Swimmer-v4 Walker2d-v4 Ant-v4 Humanoid-v4 Reacher-v4 InvertedPendulum-v4 InvertedDoublePendulum-v4 Pusher-v4 HumanoidStandup-v4
-policy_name = Policy
-rnn_name = Recurrent
-
-[env]
-render_mode = rgb_array
-
-[vec]
-num_envs = 512
-num_workers = 16
-batch_size = auto
-
-[train]
-total_timesteps = 5_000_000
-learning_rate = 3e-4
-gamma = 0.99
-gae_lambda = 0.95
-update_epochs = 10
-clip_coef = 0.2
-vf_coef = 0.5
-vf_clip_coef = 0.2
-max_grad_norm = 0.5
-ent_coef = 0.0
-checkpoint_interval = 200
-batch_size = 32768
-minibatch_size = 4096
-bptt_horizon = 64
diff --git a/pufferlib/config/nethack.ini b/pufferlib/config/nethack.ini
deleted file mode 100644
index 9e35dbff5..000000000
--- a/pufferlib/config/nethack.ini
+++ /dev/null
@@ -1,16 +0,0 @@
-[base]
-package = nethack
-env_name = nethack
-
-[vec]
-num_envs = 128
-num_workers = 16
-batch_size = 64
-
-[train]
-batch_size = 8192
-minibatch_size = 2048
-update_epochs = 1
-bptt_horizon = 64
-total_timesteps = 10_000_000
-anneal_lr = False
diff --git a/pufferlib/config/nmmo.ini b/pufferlib/config/nmmo.ini
deleted file mode 100644
index 4a4f419ca..000000000
--- a/pufferlib/config/nmmo.ini
+++ /dev/null
@@ -1,10 +0,0 @@
-[base]
-package = nmmo
-env_name = nmmo
-
-[train]
-num_envs = 4
-env_batch_size = 4
-num_workers = 4
-batch_size = 4096
-minibatch_size = 2048
diff --git a/pufferlib/config/ocean/asteroids.ini b/pufferlib/config/ocean/asteroids.ini
deleted file mode 100644
index 754d62418..000000000
--- a/pufferlib/config/ocean/asteroids.ini
+++ /dev/null
@@ -1,37 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_asteroids
-policy_name = Policy
-rnn_name = Recurrent
-
-[vec]
-num_envs = 8
-
-[env]
-num_envs = 1024
-size = 500
-
-[train]
-adam_beta1 = 0.975493290069733
-adam_beta2 = 0.9999436458974764
-adam_eps = 6.915036275112011e-08
-anneal_lr = true
-batch_size = auto
-bptt_horizon = 64
-checkpoint_interval = 200
-clip_coef = 0.18588778503512546
-ent_coef = 0.0016620361911332262
-gae_lambda = 0.8400278040617952
-gamma = 0.9998708818940873
-learning_rate = 0.00502237062536979
-max_grad_norm = 0.7306435358436453
-max_minibatch_size = 32768
-minibatch_size = 8192
-prio_alpha = 0.9165093859993415
-prio_beta0 = 0.8869674411376214
-total_timesteps = 100_000_000
-update_epochs = 1
-vf_clip_coef = 0.1
-vf_coef = 2.960148388519086
-vtrace_c_clip = 1.0767718761515104
-vtrace_rho_clip = 4.132507367126342
diff --git a/pufferlib/config/ocean/battle.ini b/pufferlib/config/ocean/battle.ini
deleted file mode 100644
index dcb4baa0f..000000000
--- a/pufferlib/config/ocean/battle.ini
+++ /dev/null
@@ -1,66 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_battle
-policy_name = Policy
-rnn_name = Recurrent
-
-[policy]
-hidden_size = 512
-
-[rnn]
-input_size = 512
-hidden_size = 512
-
-[vec]
-num_envs = 16
-
-[env]
-num_envs = 4
-num_agents = 128
-num_armies = 2
-size_x = 2
-size_y = 1.0
-size_z = 2
-
-[train]
-total_timesteps = 50_000_000
-
-#adam_beta1 = 0.9672322418397323
-#adam_beta2 = 0.9877607751795193
-#adam_eps = 3.1721115738865995e-12
-#clip_coef = 0.43568934504743784
-#ent_coef = 0.0009836417478975427
-#gae_lambda = 0.9668222538234107
-#gamma = 0.990709789440733
-#learning_rate = 0.006246420318636455
-#max_grad_norm = 1.7919049246329588
-#minibatch_size = 65536
-#prio_alpha = 0.09999999999999998
-#prio_beta0 = 0.7406397128300295
-#vf_clip_coef = 1.6190073090306314
-#vf_coef = 3.4918587292978454
-#vtrace_c_clip = 0.5344573247342275
-#vtrace_rho_clip = 1.2893540729776307
-
-#learning_rate = 0.0015534438005054883
-#gamma = 0.9923382806478448
-#minibatch_size = 32768
-
-#adam_beta1 = 0.5797997352318079
-#adam_beta2 = 0.9001752474216785
-#adam_eps = 6.121819610318236e-8
-#clip_coef = 0.3616904471336408
-#ent_coef = 0.020160134702951138
-#gae_lambda = 0.5999999999999999
-#gamma = 0.9923382806478448
-#learning_rate = 0.0015534438005054883
-#max_grad_norm = 0.5104995231814086
-#minibatch_size = 65536
-#prio_alpha = 0.5594506255128311
-#prio_beta0 = 0.9852161239512259
-#vf_clip_coef = 0.1
-#vf_coef = 1.8024088377114245
-#vtrace_c_clip = 1.7578256946375268
-#vtrace_rho_clip = 1.0041987439042879
-
-
diff --git a/pufferlib/config/ocean/blastar.ini b/pufferlib/config/ocean/blastar.ini
deleted file mode 100644
index ddde00396..000000000
--- a/pufferlib/config/ocean/blastar.ini
+++ /dev/null
@@ -1,23 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_blastar
-policy_name = Policy
-rnn_name = Recurrent
-
-[env]
-num_envs = 4096
-
-[train]
-total_timesteps = 200_000_000
-gamma = 0.95
-learning_rate = 0.05
-minibatch_size = 32768
-
-[sweep]
-metric = environment/enemy_crossed_screen
-goal = minimize
-
-[sweep.parameters.train.parameters.total_timesteps]
-distribution = uniform
-min = 10_000_000
-max = 100_000_000
diff --git a/pufferlib/config/ocean/boids.ini b/pufferlib/config/ocean/boids.ini
deleted file mode 100644
index 2f8412d24..000000000
--- a/pufferlib/config/ocean/boids.ini
+++ /dev/null
@@ -1,72 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_boids
-policy_name = Boids
-rnn_name = Recurrent
-; rnn_name = None
-
-[env]
-num_envs = 64
-num_boids = 64
-; num_envs = 1
-; num_boids = 1
-margin_turn_factor = 0.0
-centering_factor = 0.00
-avoid_factor = 1.00
-matching_factor = 1.00
-
-[vec]
-num_workers = 2
-num_envs = 2
-batch_size = auto
-
-[train]
-total_timesteps = 100_000_000
-gamma = 0.95
-learning_rate = 0.025
-minibatch_size = 16384
-; minibatch_size = 1
-
-; [sweep]
-; method = protein
-; metric = episode_length
-
-; [sweep.train.total_timesteps]
-; distribution = log_normal
-; min = 1e6
-; max = 1e7
-; mean = 5e6
-; scale = 0.5
-
-; [sweep.train.gamma]
-; distribution = log_normal
-; min = 0.9
-; max = 0.999
-; mean = 0.97
-
-; [sweep.train.gae_lambda]
-; distribution = log_normal
-; min = 0.7
-; max = 0.999
-; mean = 0.95
-
-; [sweep.train.learning_rate]
-; distribution = log_normal
-; min = 0.0001
-; max = 0.001
-; mean = 0.00025
-; scale = 0.5
-
-; [sweep.train.batch_size]
-; min = 32768
-; max = 131072
-; mean = 65536
-; scale = 0.5
-
-; [sweep.train.minibatch_size]
-; min = 512
-; max = 2048
-; mean = 1024
-; scale = 0.5
-
-
diff --git a/pufferlib/config/ocean/breakout.ini b/pufferlib/config/ocean/breakout.ini
deleted file mode 100644
index a1cfdbc10..000000000
--- a/pufferlib/config/ocean/breakout.ini
+++ /dev/null
@@ -1,54 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_breakout
-policy_name = Policy
-rnn_name = Recurrent
-
-[vec]
-num_envs = 8
-
-[env]
-num_envs = 1024
-frameskip = 4
-
-[policy]
-hidden_size = 128
-
-[rnn]
-input_size = 128
-hidden_size = 128
-
-[train]
-total_timesteps = 90_000_000
-adam_beta1 = 0.8946507418260217
-adam_beta2 = 0.9
-adam_eps = 0.0001
-batch_size = auto
-bptt_horizon = 64
-clip_coef = 0.19696765958267629
-ent_coef = 0.0005690816545012474
-gae_lambda = 0.747650023961198
-gamma = 0.9997053654668936
-learning_rate = 0.044482546441415506
-max_grad_norm = 2.2356112188495723
-minibatch_size = 32768
-prio_alpha = 0.98967001208896
-prio_beta0 = 0.09999999999999998
-vf_clip_coef = 2.178492167689251
-vf_coef = 1.6832989594296321
-vtrace_c_clip = 2.878171091654008
-vtrace_rho_clip = 0.7876748061547312
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 3e7
-max = 2e8
-mean = 8e7
-scale = auto
-
-[sweep.env.frameskip]
-distribution = int_uniform
-min = 1
-max = 8
-mean = 4
-scale = 2.0
diff --git a/pufferlib/config/ocean/cartpole.ini b/pufferlib/config/ocean/cartpole.ini
deleted file mode 100644
index 6ecfb7db0..000000000
--- a/pufferlib/config/ocean/cartpole.ini
+++ /dev/null
@@ -1,56 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_cartpole
-policy_name = Policy
-rnn_name = Recurrent
-
-[env]
-num_envs = 4096
-
-[train]
-total_timesteps = 20_000_000
-gamma = 0.95
-learning_rate = 0.05
-minibatch_size = 32768
-
-[sweep]
-method = protein
-metric = episode_length
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 1e6
-max = 1e7
-mean = 5e6
-scale = 0.5
-
-[sweep.train.gamma]
-distribution = log_normal
-min = 0.9
-max = 0.999
-mean = 0.97
-
-[sweep.train.gae_lambda]
-distribution = log_normal
-min = 0.7
-max = 0.999
-mean = 0.95
-
-[sweep.train.learning_rate]
-distribution = log_normal
-min = 0.0001
-max = 0.001
-mean = 0.00025
-scale = 0.5
-
-[sweep.train.batch_size]
-min = 32768
-max = 131072
-mean = 65536
-scale = 0.5
-
-[sweep.train.minibatch_size]
-min = 512
-max = 2048
-mean = 1024
-scale = 0.5
diff --git a/pufferlib/config/ocean/checkers.ini b/pufferlib/config/ocean/checkers.ini
deleted file mode 100644
index 91eb417f5..000000000
--- a/pufferlib/config/ocean/checkers.ini
+++ /dev/null
@@ -1,17 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_checkers
-policy_name = Policy
-rnn_name = Recurrent
-
-[env]
-num_envs = 4096
-size = 8
-
-[vec]
-num_envs = 8
-
-[train]
-total_timesteps = 1_000_000_000
-minibatch_size = 65536
-gamma = 0.95
diff --git a/pufferlib/config/ocean/connect4.ini b/pufferlib/config/ocean/connect4.ini
deleted file mode 100644
index 252b79350..000000000
--- a/pufferlib/config/ocean/connect4.ini
+++ /dev/null
@@ -1,37 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_connect4
-policy_name = Policy
-rnn_name = Recurrent
-
-[env]
-num_envs = 1024
-
-[vec]
-num_envs = 8
-
-[train]
-total_timesteps = 22_000_000
-adam_beta1 = 0.7332525176640032
-adam_beta2 = 0.9992588002434659
-adam_eps = 0.0001
-clip_coef = 0.3344358533613167
-ent_coef = 0.00004214003802569246
-gae_lambda = 0.8969790930039623
-gamma = 0.9945932652529774
-learning_rate = 0.1
-max_grad_norm = 1.0219144411399215
-minibatch_size = 32768
-prio_alpha = 0.9057091953725436
-prio_beta0 = 0.6320607520016285
-vf_clip_coef = 1.9948775471721416
-vf_coef = 2.3734839181925462
-vtrace_c_clip = 0.5659747235622431
-vtrace_rho_clip = 1.4499061438546799
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 1e7
-max = 2e8
-mean = 3e7
-scale = 0.5
diff --git a/pufferlib/config/ocean/continuous.ini b/pufferlib/config/ocean/continuous.ini
deleted file mode 100644
index fd35cd485..000000000
--- a/pufferlib/config/ocean/continuous.ini
+++ /dev/null
@@ -1,13 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_continuous
-
-[train]
-total_timesteps = 1_000_000
-anneal_lr = False
-num_envs = 64
-batch_size = 16384
-minibatch_size = 4096
-update_epochs = 1
-gamma = 0.8
-ent_coef = 0.05
diff --git a/pufferlib/config/ocean/convert.ini b/pufferlib/config/ocean/convert.ini
deleted file mode 100644
index 53c91519e..000000000
--- a/pufferlib/config/ocean/convert.ini
+++ /dev/null
@@ -1,22 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_convert
-policy_name = Policy
-rnn_name = Recurrent
-
-[vec]
-num_envs = 16
-
-[env]
-num_envs = 1
-num_agents = 1024
-num_factories = 32
-num_resources = 8
-
-[train]
-total_timesteps = 100_000_000
-gamma = 0.99
-learning_rate = 0.015
-minibatch_size = 32768
-ent_coef = 0.02
-
diff --git a/pufferlib/config/ocean/convert_circle.ini b/pufferlib/config/ocean/convert_circle.ini
deleted file mode 100644
index 60dfd3467..000000000
--- a/pufferlib/config/ocean/convert_circle.ini
+++ /dev/null
@@ -1,24 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_convert_circle
-policy_name = Policy
-rnn_name = Recurrent
-
-[vec]
-num_envs = 16
-
-[env]
-num_envs = 1
-num_agents = 1024
-num_factories = 32
-num_resources = 8
-equidistant = 1
-radius = 400
-
-[train]
-total_timesteps = 100_000_000
-gamma = 0.99
-learning_rate = 0.015
-minibatch_size = 32768
-ent_coef = 0.02
-
diff --git a/pufferlib/config/ocean/cpr.ini b/pufferlib/config/ocean/cpr.ini
deleted file mode 100644
index d64697cd9..000000000
--- a/pufferlib/config/ocean/cpr.ini
+++ /dev/null
@@ -1,51 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_cpr
-rnn_name = Recurrent
-
-[env]
-num_envs = 512
-vision = 3
-num_agents = [8]
-report_interval=1
-reward_food = 0.1
-interactive_food_reward = 0.2
-reward_move = +0.00
-food_base_spawn_rate = 2e-3
-
-[train]
-total_timesteps = 60_000_000
-bptt_horizon = 16
-checkpoint_interval = 200
-learning_rate = 0.0008524
-gamma = 0.9989
-gae_lambda = 0.99
-vf_coef = 1
-ent_coef = 0.01
-adam_beta1 = 0.9
-adam_beta2 = 0.999
-adam_eps = 1e-12
-max_grad_norm = 0.5
-vf_clip_coef = 0.1
-update_epochs = 1
-
-[sweep.env.reward_food]
-distribution = log_normal
-min = 0.0001
-max = 0.01
-mean = 0.001
-scale = auto
-
-[sweep.env.interactive_food_reward]
-distribution = log_normal
-min = 0.0001
-max = 0.02
-mean = 0.002
-scale = auto
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 50e6
-max = 75e6
-mean = 60e6
-scale = time
diff --git a/pufferlib/config/ocean/drive.ini b/pufferlib/config/ocean/drive.ini
index 6e86dbd20..81567f730 100644
--- a/pufferlib/config/ocean/drive.ini
+++ b/pufferlib/config/ocean/drive.ini
@@ -5,10 +5,10 @@ policy_name = Drive
rnn_name = Recurrent
[vec]
-num_workers = 8
-num_envs = 8
+num_workers = 16
+num_envs = 16
batch_size = 2
-#backend = Serial
+; backend = Serial
[policy]
input_size = 64
@@ -20,19 +20,41 @@ hidden_size = 256
[env]
num_agents = 256
+; Options: discrete, continuous
+action_type = discrete
+; Options: classic, jerk
+dynamics_model = classic
reward_vehicle_collision = -0.5
reward_offroad_collision = -0.2
-spawn_immunity_timer = 50
+reward_ade = 0.0
+dt = 0.1
+reward_goal = 1.0
reward_goal_post_respawn = 0.25
-reward_vehicle_collision_post_respawn = -0.5
+; Meters around goal to be considered "reached"
+goal_radius = 2.0
+; What to do when the goal is reached. Options: 0:"respawn", 1:"generate_new_goals", 2:"stop"
+goal_behavior = 0
+; Options: 0 - Ignore, 1 - Stop, 2 - Remove
+collision_behavior = 0
+; Options: 0 - Ignore, 1 - Stop, 2 - Remove
+offroad_behavior = 0
+; Number of steps before reset
+scenario_length = 91
resample_frequency = 910
num_maps = 8
+; Determines which step of the trajectory to initialize the agents at upon reset
+init_steps = 0
+; Options: "control_vehicles", "control_agents", "control_tracks_to_predict", "control_sdc_only"
+control_mode = "control_vehicles"
+; Options: "created_all_valid", "create_only_controlled"
+init_mode = "create_all_valid"
[train]
total_timesteps = 2_000_000_000
-#learning_rate = 0.02
-#gamma = 0.985
+; learning_rate = 0.02
+; gamma = 0.985
anneal_lr = True
+; Needs to be: num_agents * num_workers * BPTT horizon
batch_size = auto
minibatch_size = 11648
max_minibatch_size = 11648
@@ -41,10 +63,10 @@ adam_beta1 = 0.9
adam_beta2 = 0.999
adam_eps = 1e-8
clip_coef = 0.2
-ent_coef = 0.001
+ent_coef = 0.005
gae_lambda = 0.95
gamma = 0.98
-learning_rate = 0.001
+learning_rate = 0.003
max_grad_norm = 1
prio_alpha = 0.8499999999999999
prio_beta0 = 0.8499999999999999
@@ -54,35 +76,67 @@ vf_coef = 2
vtrace_c_clip = 1
vtrace_rho_clip = 1
checkpoint_interval = 1000
+; Rendering options
+render = True
+render_interval = 1000
+; If True, show exactly what the agent sees in agent observation
+obs_only = True
+; Show grid lines
+show_grid = False
+; Draws lines from ego agent observed ORUs and road elements to show detection range
+show_lasers = False
+; Display human xy logs in the background
+show_human_logs = True
+; Options: str to path (e.g., "resources/drive/binaries/map_001.bin"), None
+render_map = none
+[eval]
+eval_interval = 1000
+backend = PufferEnv
+; WOSAC (Waymo Open Sim Agents Challenge) evaluation settings
+; If True, enables evaluation on realism metrics each time we save a checkpoint
+wosac_realism_eval = False
+wosac_num_rollouts = 32 # Number of policy rollouts per scene
+wosac_init_steps = 10 # When to start the simulation
+wosac_num_agents = 256 # Total number of WOSAC agents to evaluate
+wosac_control_mode = "control_tracks_to_predict" # Control the tracks to predict
+wosac_init_mode = "create_all_valid" # Initialize from the tracks to predict
+wosac_goal_behavior = 2 # Stop when reaching the goal
+wosac_goal_radius = 2.0 # Can shrink goal radius for WOSAC evaluation
+wosac_sanity_check = False
+wosac_aggregate_results = True # Only return aggregate results across all scenes
+; If True, enable human replay evaluation (pair policy-controlled agent with human replays)
+human_replay_eval = False
+human_replay_control_mode = "control_sdc_only" # Control only the self-driving car
+human_replay_num_agents = 64 # This equals the number of scenarios, since we control one agent in each
+[sweep.train.learning_rate]
+distribution = log_normal
+min = 0.001
+mean = 0.003
+max = 0.005
+scale = auto
-[sweep.train.total_timesteps]
+[sweep.train.ent_coef]
distribution = log_normal
-min = 1e8
-max = 4e8
-mean = 2e8
-scale = time
-
-[sweep.env.reward_vehicle_collision]
-distribution = uniform
-min = -1.0
-max = 0.0
-mean = -0.2
-scale = auto
-
-[sweep.env.reward_offroad_collision]
+min = 0.001
+mean = 0.005
+max = 0.01
+scale = auto
+
+
+[sweep.env.goal_radius]
distribution = uniform
-min = -1.0
-max = 0.0
-mean = -0.2
+min = 2.0
+max = 20.0
+mean = 10.0
scale = auto
-[sweep.env.spawn_immunity_timer]
+[sweep.env.reward_ade]
distribution = uniform
-min = 1
-max = 91
-mean = 30
+min = -0.1
+max = 0.0
+mean = -0.02
scale = auto
[sweep.env.reward_goal_post_respawn]
@@ -91,10 +145,3 @@ min = 0.0
max = 1.0
mean = 0.5
scale = auto
-
-[sweep.env.reward_vehicle_collision_post_respawn]
-distribution = uniform
-min = -1.0
-max = 0.0
-mean = -0.2
-scale = auto
diff --git a/pufferlib/config/ocean/drone_race.ini b/pufferlib/config/ocean/drone_race.ini
deleted file mode 100644
index cfb9d9772..000000000
--- a/pufferlib/config/ocean/drone_race.ini
+++ /dev/null
@@ -1,37 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_drone_race
-policy_name = Policy
-rnn_name = Recurrent
-
-[vec]
-num_envs = 8
-
-[env]
-num_envs = 1024
-
-[train]
-adam_beta1 = 0.9610890980775877
-adam_beta2 = 0.9999260775286266
-adam_eps = 7.782906079040132e-10
-anneal_lr = true
-batch_size = auto
-bptt_horizon = 64
-checkpoint_interval = 200
-clip_coef = 0.05982655642208556
-ent_coef = 0.002465076521024325
-gae_lambda = 0.9641173414828333
-gamma = 0.997472126425902
-learning_rate = 0.010933756713881205
-max_grad_norm = 1.6317688647793107
-max_minibatch_size = 32768
-minibatch_size = 32768
-prio_alpha = 0.8968873016577552
-prio_beta0 = 0.8672928227817938
-total_timesteps = 100_000_000
-update_epochs = 1
-#use_rnn = false
-vf_clip_coef = 0.5869845581530236
-vf_coef = 2.1319065538539963
-vtrace_c_clip = 2.714930379733876
-vtrace_rho_clip = 3.8183814893708057
diff --git a/pufferlib/config/ocean/drone_swarm.ini b/pufferlib/config/ocean/drone_swarm.ini
deleted file mode 100644
index 59915325a..000000000
--- a/pufferlib/config/ocean/drone_swarm.ini
+++ /dev/null
@@ -1,57 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_drone_swarm
-policy_name = Policy
-rnn_name = Recurrent
-
-[policy]
-hidden_size = 128
-
-[rnn]
-input_size = 128
-hidden_size = 128
-
-[vec]
-num_envs = 8
-
-[env]
-num_envs = 16
-num_drones = 64
-max_rings = 10
-
-[train]
-adam_beta1 = 0.9610890980775877
-adam_beta2 = 0.9999260775286266
-adam_eps = 7.782906079040132e-10
-anneal_lr = true
-batch_size = auto
-bptt_horizon = 64
-checkpoint_interval = 200
-clip_coef = 0.05982655642208556
-ent_coef = 0.002465076521024325
-gae_lambda = 0.9641173414828333
-gamma = 0.997472126425902
-learning_rate = 0.010933756713881205
-#learning_rate = 0.005
-max_grad_norm = 1.6317688647793107
-max_minibatch_size = 32768
-minibatch_size = 32768
-prio_alpha = 0.8968873016577552
-prio_beta0 = 0.8672928227817938
-total_timesteps = 500_000_000
-update_epochs = 1
-#use_rnn = false
-vf_clip_coef = 0.5869845581530236
-vf_coef = 2.1319065538539963
-vtrace_c_clip = 2.714930379733876
-vtrace_rho_clip = 3.8183814893708057
-
-[sweep]
-downsample = 0
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 2e8
-max = 4e8
-mean = 2e8
-scale = time
diff --git a/pufferlib/config/ocean/enduro.ini b/pufferlib/config/ocean/enduro.ini
deleted file mode 100644
index 6586183fb..000000000
--- a/pufferlib/config/ocean/enduro.ini
+++ /dev/null
@@ -1,42 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_enduro
-policy_name = Policy
-rnn_name = Recurrent
-
-[env]
-num_envs = 1024
-
-[vec]
-num_envs = 1
-
-[train]
-total_timesteps = 400_000_000
-adam_beta1 = 0.9602226117399812
-adam_beta2 = 0.999983918771099
-adam_eps = 2.109767652202695e-9
-bptt_horizon = 64
-clip_coef = 0.5716251062832933
-ent_coef = 0.009778379693175061
-gae_lambda = 0.9924829173144767
-gamma = 0.9433427558493771
-learning_rate = 0.014263349414255656
-max_grad_norm = 0.42249653686869115
-max_minibatch_size = 32768
-minibatch_size = 65536
-prio_alpha = 0.22253503344197678
-prio_beta0 = 0.7866639848626998
-vf_clip_coef = 0.01
-vf_coef = 3.2952964839081016
-vtrace_c_clip = 3.060525785199293
-vtrace_rho_clip = 5
-
-[sweep]
-metric = days_completed
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 5e7
-max = 4e8
-mean = 2e8
-scale = auto
diff --git a/pufferlib/config/ocean/freeway.ini b/pufferlib/config/ocean/freeway.ini
deleted file mode 100644
index 2acceb7a0..000000000
--- a/pufferlib/config/ocean/freeway.ini
+++ /dev/null
@@ -1,27 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_freeway
-policy_name = Policy
-rnn_name = Recurrent
-
-[vec]
-num_envs = 8
-
-[env]
-num_envs = 1024
-frameskip = 4
-use_dense_rewards = True
-env_randomization = True
-difficulty = 0
-level = -1
-
-[train]
-total_timesteps = 500_000_000
-minibatch_size = 32768
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 3e8
-max = 4e8
-mean = 3e8
-scale = auto
diff --git a/pufferlib/config/ocean/g2048.ini b/pufferlib/config/ocean/g2048.ini
deleted file mode 100644
index 9cbfb1f62..000000000
--- a/pufferlib/config/ocean/g2048.ini
+++ /dev/null
@@ -1,40 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_g2048
-policy_name = Policy
-rnn_name = Recurrent
-
-[policy]
-hidden_size = 128
-
-[rnn]
-input_size = 128
-hidden_size = 128
-
-[vec]
-num_envs = 4
-
-[env]
-num_envs = 4096
-
-[train]
-total_timesteps = 5_000_000_000
-adam_beta1 = 0.9529488439604378
-adam_beta2 = 0.9993901829477296
-adam_eps = 2.745365927413118e-7
-bptt_horizon = 64
-clip_coef = 0.596573170393339
-ent_coef = 0.02107417730003862
-gae_lambda = 0.9940613415815854
-gamma = 0.9889857974154952
-#learning_rate = 0.0032402460796988127
-learning_rate = 0.001
-max_grad_norm = 1.0752406726589745
-minibatch_size = 16384
-prio_alpha = 0.25297099593586336
-prio_beta0 = 0.940606268942572
-vf_clip_coef = 0.1
-vf_coef = 1.6362878279900643
-vtrace_c_clip = 0
-vtrace_rho_clip = 1.2917509971869054
-anneal_lr = False
diff --git a/pufferlib/config/ocean/go.ini b/pufferlib/config/ocean/go.ini
deleted file mode 100644
index fdf6867d4..000000000
--- a/pufferlib/config/ocean/go.ini
+++ /dev/null
@@ -1,72 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_go
-policy_name = Policy
-rnn_name = Recurrent
-
-[env]
-num_envs = 1024
-reward_move_pass = -0.6026362603175613
-reward_move_valid = 0
-reward_move_invalid = -0.5393516480382454
-reward_opponent_capture = -0.3152783593705354
-reward_player_capture = 0.42122681325442923
-grid_size = 7
-
-[vec]
-num_envs = 8
-
-[train]
-total_timesteps = 100_000_000
-adam_beta1 = 0.5686370767889766
-adam_beta2 = 0.9999454817221638
-adam_eps = 2.007252656207671e-12
-bptt_horizon = 64
-clip_coef = 0.17930104885238807
-ent_coef = 0.0018946598458748304
-gae_lambda = 0.9831319174802507
-gamma = 0.9480351741863737
-learning_rate = 0.031603809039284864
-max_grad_norm = 1.320177349287771
-minibatch_size = 8192
-prio_alpha = 0.6979639079178326
-prio_beta0 = 0.5614257332458639
-vf_clip_coef = 1.1755607092687304
-vf_coef = 1.6195967557187005
-vtrace_c_clip = 0
-vtrace_rho_clip = 4.060318960532289
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 1e8
-max = 5e8
-mean = 2e8
-scale = 0.25
-
-[sweep.env.reward_move_invalid]
-distribution = uniform
-min = -1.0
-max = 0.0
-mean = -0.5
-scale = 0.5
-
-[sweep.env.reward_move_pass]
-distribution = uniform
-min = -1.0
-max = 0.0
-mean = -0.5
-scale = 0.5
-
-[sweep.env.reward_player_capture]
-distribution = uniform
-min = 0.0
-max = 1.0
-mean = 0.5
-scale = 0.5
-
-[sweep.env.reward_opponent_capture]
-distribution = uniform
-min = -1.0
-max = 0.0
-mean = -0.5
-scale = 0.5
diff --git a/pufferlib/config/ocean/grid.ini b/pufferlib/config/ocean/grid.ini
deleted file mode 100644
index 65bd540b6..000000000
--- a/pufferlib/config/ocean/grid.ini
+++ /dev/null
@@ -1,72 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_grid
-policy_name = Policy
-rnn_name = Recurrent
-
-[policy]
-hidden_size = 512
-
-[rnn]
-input_size = 512
-hidden_size = 512
-
-[vec]
-#num_envs = 8
-num_envs = 1
-
-[env]
-max_size = 47
-num_envs = 1024
-#num_envs = 4096
-num_maps = 8192
-
-[train]
-# Best params
-#total_timesteps = 435_000_000
-#adam_beta1 = 0.9801350114303844
-#adam_beta2 = 0.9931056135397744
-#adam_eps = 6.024885743259763e-8
-#clip_coef = 0.283658795325587
-#ent_coef = 0.007885530106105381
-#gae_lambda = 0.9574676436577135
-#gamma = 0.9961782334639131
-#learning_rate = 0.0007890771333884192
-#max_grad_norm = 2.5271346931510053
-#minibatch_size = 8192
-#prio_alpha = 0.8735470630752789
-#prio_beta0 = 0.6533958384978629
-#vf_clip_coef = 1.9338563232919095
-#vf_coef = 3.915248046963283
-#vtrace_c_clip = 1.018588814067991
-#vtrace_rho_clip = 2.4215244529216466
-
-# New sweep best params
-total_timesteps = 435_000_000
-adam_beta1 = 0.9493079570168755
-adam_beta2 = 0.9998213228757207
-adam_eps = 2.16720639574209e-8
-bptt_horizon = 64
-clip_coef = 0.399530686596841
-ent_coef = 0.0017271288609381147
-gae_lambda = 0.9491722822649111
-gamma = 0.9877360824574745
-learning_rate = 0.0012892859713461897
-max_grad_norm = 3.016348031602564
-minibatch_size = 8192
-prio_alpha = 0.8219794821639037
-prio_beta0 = 0.9447478232810274
-vf_clip_coef = 0.6051579400844748
-vf_coef = 2.323141961227481
-vtrace_c_clip = 1.2499497264614237
-vtrace_rho_clip = 4.7398234531013985
-
-[sweep]
-downsample = 0
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 3e8
-max = 6e8
-mean = 3e8
-scale = time
diff --git a/pufferlib/config/ocean/impulse_wars.ini b/pufferlib/config/ocean/impulse_wars.ini
deleted file mode 100644
index d4d1ad7b5..000000000
--- a/pufferlib/config/ocean/impulse_wars.ini
+++ /dev/null
@@ -1,118 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_impulse_wars
-policy_name = ImpulseWarsPolicy
-rnn_name = ImpulseWarsLSTM
-max_suggestion_cost = 10_800
-
-[policy]
-cnn_channels = 64
-input_size = 512
-hidden_size = 512
-
-# These must match what's set in env below
-continuous = False
-num_drones = 2
-is_training = True
-
-[vec]
-num_envs = 16
-num_workers = 16
-batch_size = 4
-
-[env]
-num_envs = 256
-num_drones = 2
-num_agents = 1
-enable_teams = False
-sitting_duck = False
-continuous = False
-is_training = True
-
-[train]
-total_timesteps = 100_000_000
-checkpoint_interval = 250
-
-learning_rate = 0.005
-
-compile = False
-compile_mode = reduce-overhead
-compile_fullgraph = False
-device = cuda
-
-[sweep.env.num_envs]
-distribution = uniform_pow2
-min = 16
-max = 512
-mean = 128
-scale = auto
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 250_000_000
-max = 1_500_000_000
-mean = 500_000_000
-scale = time
-
-[sweep.train.batch_size]
-distribution = uniform_pow2
-min = 65_536
-max = 1_048_576
-mean = 262_144
-scale = auto
-
-[sweep.train.bptt_horizon]
-distribution = uniform_pow2
-min = 64
-max = 256
-mean = 128
-scale = auto
-
-[sweep.train.minibatch_size]
-distribution = uniform_pow2
-min = 1024
-max = 262_144
-mean = 16_384
-scale = auto
-
-[sweep.train.learning_rate]
-distribution = log_normal
-min = 0.00001
-mean = 0.001
-max = 0.1
-scale = 0.5
-
-[sweep.train.ent_coef]
-distribution = log_normal
-min = 0.000001
-mean = 0.001
-max = 0.2
-scale = auto
-
-[sweep.train.gamma]
-distribution = logit_normal
-min = 0.8
-mean = 0.98
-max = 0.99999
-scale = auto
-
-[sweep.train.gae_lambda]
-distribution = logit_normal
-min = 0.6
-mean = 0.93
-max = 0.995
-scale = auto
-
-[sweep.train.vf_coef]
-distribution = uniform
-min = 0.0
-max = 5.0
-mean = 1.0
-scale = auto
-
-[sweep.train.max_grad_norm]
-distribution = uniform
-min = 0.0
-mean = 1.0
-max = 5.0
-scale = auto
diff --git a/pufferlib/config/ocean/matsci.ini b/pufferlib/config/ocean/matsci.ini
deleted file mode 100644
index 9183c27fa..000000000
--- a/pufferlib/config/ocean/matsci.ini
+++ /dev/null
@@ -1,17 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_matsci
-policy_name = Policy
-
-[vec]
-num_envs = 8
-
-[env]
-num_envs = 8
-num_atoms = 128
-
-[train]
-total_timesteps = 50_000_000
-minibatch_size = 32768
-
-
diff --git a/pufferlib/config/ocean/memory.ini b/pufferlib/config/ocean/memory.ini
deleted file mode 100644
index 2bb5abeb8..000000000
--- a/pufferlib/config/ocean/memory.ini
+++ /dev/null
@@ -1,15 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_memory
-policy_name = Policy
-rnn_name = Recurrent
-
-[env]
-num_envs = 1024
-
-[vec]
-num_envs = 8
-
-[train]
-total_timesteps = 50_000_000
-minibatch_size = 32768
diff --git a/pufferlib/config/ocean/moba.ini b/pufferlib/config/ocean/moba.ini
deleted file mode 100644
index 2e0e8cea3..000000000
--- a/pufferlib/config/ocean/moba.ini
+++ /dev/null
@@ -1,46 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_moba
-policy_name = MOBA
-rnn_name = Recurrent
-
-[env]
-reward_death = 0.0
-reward_xp = 0.0016926873475313188
-reward_distance = 0.0
-reward_tower = 4.525112152099609
-num_envs = 128
-
-[vec]
-num_envs = 8
-
-[train]
-total_timesteps = 150_000_000
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 2e7
-max = 2e8
-mean = 1e8
-scale = auto
-
-[sweep.env.reward_death]
-distribution = uniform
-min = -1.0
-max = 0
-mean = 0
-scale = auto
-
-[sweep.env.reward_xp]
-distribution = uniform
-min = 0.0
-max = 0.05
-mean = 0.0015
-scale = auto
-
-[sweep.env.reward_tower]
-distribution = uniform
-min = 0.0
-max = 1.0
-mean = 1.0
-scale = auto
diff --git a/pufferlib/config/ocean/nmmo3.ini b/pufferlib/config/ocean/nmmo3.ini
deleted file mode 100644
index c04c77dc3..000000000
--- a/pufferlib/config/ocean/nmmo3.ini
+++ /dev/null
@@ -1,75 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_nmmo3
-policy_name = NMMO3
-rnn_name = NMMO3LSTM
-
-[vec]
-num_envs = 8
-
-[env]
-reward_combat_level = 1.0
-reward_prof_level = 1.0
-reward_item_level = 1.0
-reward_market = 0.0
-reward_death = -1.0
-num_envs = 1
-
-[train]
-total_timesteps = 107000000000
-checkpoint_interval = 1000
-learning_rate = 0.0004573146765703167
-gamma = 0.7647543366891623
-gae_lambda = 0.996005622445478
-ent_coef = 0.01210084358004069
-max_grad_norm = 0.6075578331947327
-vf_coef = 0.3979089612467003
-bptt_horizon = 64
-batch_size = 524288
-minibatch_size = 32768
-max_minibatch_size = 32768
-
-[sweep]
-metric = min_comb_prof
-
-[sweep.env.num_envs]
-distribution = uniform_pow2
-min = 1
-max = 8
-mean = 4
-scale = 0.5
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 2e8
-max = 1e9
-mean = 5e8
-scale = 0.5
-
-[sweep.env.reward_combat_level]
-distribution = uniform
-min = 0.0
-max = 1.0
-mean = 0.5
-scale = auto
-
-[sweep.env.reward_prof_level]
-distribution = uniform
-min = 0.0
-max = 1.0
-mean = 0.5
-scale = auto
-
-[sweep.env.reward_item_level]
-distribution = uniform
-min = 0.0
-max = 1.0
-mean = 1.0
-scale = auto
-
-[sweep.env.reward_death]
-distribution = uniform
-min = -1.0
-max = 0.0
-mean = -1.0
-scale = auto
diff --git a/pufferlib/config/ocean/oldgrid.ini b/pufferlib/config/ocean/oldgrid.ini
deleted file mode 100644
index 3cae63aa9..000000000
--- a/pufferlib/config/ocean/oldgrid.ini
+++ /dev/null
@@ -1,79 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_oldgrid
-vec = multiprocessing
-policy_name = Policy
-rnn_name = Recurrent
-
-#[policy]
-#hidden_size = 512
-
-#[rnn]
-#input_size = 512
-#hidden_size = 512
-
-[env]
-#map_size = 31
-max_map_size = 31
-num_envs = 512
-num_maps = 8192
-#num_maps = 1
-
-[train]
-total_timesteps = 180_000_000
-checkpoint_interval = 1000
-learning_rate = 0.0005978750098629419
-gamma = 0.9944336976183826
-gae_lambda = 0.9474288929489364
-ent_coef = 0.00001
-use_e3b = True
-
-num_envs = 1
-num_workers = 1
-env_batch_size = 1
-update_epochs = 4
-bptt_horizon = 16
-batch_size = 131072
-minibatch_size = 16384
-compile = False
-device = cuda
-e3b_coef = 0.01
-
-[sweep]
-method = protein
-name = sweep
-
-[sweep.metric]
-goal = maximize
-name = score
-min = 0
-max = 1
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 5e7
-max = 2e8
-mean = 1e8
-scale = auto
-
-[sweep.train.e3b_coef]
-distribution = logit_normal
-min = 0.0001
-max = 0.99
-mean = 0.001
-scale = auto
-
-[sweep.train.e3b_lambda]
-distribution = log_normal
-min = 0.01
-max = 10.0
-mean = 0.1
-scale = auto
-
-[sweep.train.e3b_norm]
-distribution = log_normal
-min = 0.0001
-max = 0.1
-mean = 0.001
-scale = auto
-
diff --git a/pufferlib/config/ocean/pacman.ini b/pufferlib/config/ocean/pacman.ini
deleted file mode 100644
index 45055e79b..000000000
--- a/pufferlib/config/ocean/pacman.ini
+++ /dev/null
@@ -1,33 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_pacman
-policy_name = Policy
-rnn_name = Recurrent
-
-[vec]
-num_envs = 8
-
-[env]
-num_envs = 1024
-randomize_starting_position = 1
-
-[train]
-total_timesteps = 110_000_000
-adam_beta1 = 0.9038605017693528
-adam_beta2 = 0.9974184818428597
-adam_eps = 0.000023302187415940045
-bptt_horizon = 64
-clip_coef = 0.08819998793159559
-ent_coef = 0.003877776836171818
-gae_lambda = 0.9548561279014964
-gamma = 0.9808956918725869
-learning_rate = 0.07834293253084383
-max_grad_norm = 1.4336515067572169
-minibatch_size = 32768
-prio_alpha = 0.912262602688309
-prio_beta0 = 0.8868847849454541
-vf_clip_coef = 0.2143010707893266
-vf_coef = 0.31518694995467555
-vtrace_c_clip = 0.30575543665366217
-vtrace_rho_clip = 1.5301756939690652
-
diff --git a/pufferlib/config/ocean/pong.ini b/pufferlib/config/ocean/pong.ini
deleted file mode 100644
index a0bf24d93..000000000
--- a/pufferlib/config/ocean/pong.ini
+++ /dev/null
@@ -1,46 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_pong
-policy_name = Policy
-rnn_name = Recurrent
-
-[vec]
-num_envs = 4
-
-[env]
-num_envs = 1024
-frameskip = 8
-
-[train]
-total_timesteps = 12_000_000
-adam_beta1 = 0.9766295300012044
-adam_beta2 = 0.9998113167362397
-adam_eps = 6.301709731262074e-9
-bptt_horizon = 64
-clip_coef = 0.22131450913204256
-ent_coef = 0.0020310049268479863
-gae_lambda = 0.8854219852971792
-gamma = 0.9608378504980243
-learning_rate = 0.07109386062895108
-max_grad_norm = 1.7820203601055993
-minibatch_size = 32768
-prio_alpha = 0.09999999999999998
-prio_beta0 = 0.7475661360032159
-vf_clip_coef = 2.7025841941932303
-vf_coef = 1.9960893747329385
-vtrace_c_clip = 1.0873122745787867
-vtrace_rho_clip = 2.784150207139061
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 1e7
-max = 2e8
-mean = 8e7
-scale = auto
-
-[sweep.env.frameskip]
-distribution = int_uniform
-min = 1
-max = 8
-mean = 4
-scale = 2.0
diff --git a/pufferlib/config/ocean/pysquared.ini b/pufferlib/config/ocean/pysquared.ini
deleted file mode 100644
index 7ff0653bc..000000000
--- a/pufferlib/config/ocean/pysquared.ini
+++ /dev/null
@@ -1,16 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_pysquared
-policy_name = Policy
-rnn_name = Recurrent
-
-# Set up to match our C version defaults for speed comparison
-[vec]
-num_envs = 8192
-num_workers = 2
-
-[train]
-total_timesteps = 20_000_000
-gamma = 0.95
-learning_rate = 0.05
-minibatch_size = 32768
diff --git a/pufferlib/config/ocean/rware.ini b/pufferlib/config/ocean/rware.ini
deleted file mode 100644
index 705e0af3e..000000000
--- a/pufferlib/config/ocean/rware.ini
+++ /dev/null
@@ -1,26 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_rware
-policy_name = Policy
-rnn_name = Recurrent
-
-[vec]
-num_envs = 8
-
-[env]
-num_envs = 128
-map_choice = 2
-num_agents = 8
-num_requested_shelves = 8
-
-[train]
-total_timesteps = 100_000_000
-learning_rate = 0.05
-minibatch_size = 32768
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 3e7
-max = 3e8
-mean = 1e8
-scale = 0.25
diff --git a/pufferlib/config/ocean/sanity.ini b/pufferlib/config/ocean/sanity.ini
deleted file mode 100644
index 7d7abc40b..000000000
--- a/pufferlib/config/ocean/sanity.ini
+++ /dev/null
@@ -1,30 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_bandit puffer_memory puffer_multiagent puffer_password puffer_spaces puffer_stochastic
-policy_name = Policy
-rnn_name = Recurrent
-
-[train]
-total_timesteps = 50_000
-learning_rate = 0.017
-num_envs = 8
-num_workers = 2
-env_batch_size = 8
-batch_size = 1024
-minibatch_size = 128
-bptt_horizon = 4
-device = cpu
-
-[sweep.train.batch_size]
-distribution = uniform
-min = 512
-max = 2048
-mean = 1024
-scale = 0.5
-
-[sweep.train.minibatch_size]
-distribution = uniform
-min = 64
-max = 512
-mean = 128
-scale = 0.5
diff --git a/pufferlib/config/ocean/snake.ini b/pufferlib/config/ocean/snake.ini
deleted file mode 100644
index 3827b0252..000000000
--- a/pufferlib/config/ocean/snake.ini
+++ /dev/null
@@ -1,62 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_snake
-policy_name = Snake
-#policy_name = Policy
-rnn_name = Recurrent
-
-[env]
-num_envs = 4
-width = 640
-height = 360
-num_snakes = 256
-num_food = 4096
-vision = 5
-leave_corpse_on_death = True
-reward_food = 0.1
-reward_corpse = 0.1
-reward_death = -1.0
-
-[vec]
-num_envs = 16
-
-[train]
-total_timesteps = 500_000_000
-adam_beta1 = 0.6762060389098516
-adam_beta2 = 0.9
-adam_eps = 0.000002764249390410885
-bptt_horizon = 64
-clip_coef = 0.7379459916127813
-ent_coef = 0.010507292602201058
-gae_lambda = 0.6006253996849398
-gamma = 0.9997067226101388
-learning_rate = 0.016779905178021273
-max_grad_norm = 0.6504710763256233
-minibatch_size = 32768
-prio_alpha = 0.6082618023318664
-prio_beta0 = 0.447524297405661
-vf_clip_coef = 2.830994746057568
-vf_coef = 3.9655925817980053
-vtrace_c_clip = 0
-vtrace_rho_clip = 0.9285200248552337
-
-[sweep.env.reward_food]
-distribution = uniform
-min = 0.0
-max = 1.0
-mean = 0.0
-scale = auto
-
-[sweep.env.reward_death]
-distribution = uniform
-min = -1.0
-max = 0.0
-mean = 0.0
-scale = auto
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 5e7
-max = 2e8
-mean = 1e8
-scale = auto
diff --git a/pufferlib/config/ocean/squared.ini b/pufferlib/config/ocean/squared.ini
deleted file mode 100644
index ac9f69d0f..000000000
--- a/pufferlib/config/ocean/squared.ini
+++ /dev/null
@@ -1,14 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_squared
-policy_name = Policy
-rnn_name = Recurrent
-
-[env]
-num_envs = 4096
-
-[train]
-total_timesteps = 20_000_000
-gamma = 0.95
-learning_rate = 0.05
-minibatch_size = 32768
diff --git a/pufferlib/config/ocean/tactical.ini b/pufferlib/config/ocean/tactical.ini
deleted file mode 100644
index 762cd1005..000000000
--- a/pufferlib/config/ocean/tactical.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_tactical
diff --git a/pufferlib/config/ocean/target.ini b/pufferlib/config/ocean/target.ini
deleted file mode 100644
index a65bdad32..000000000
--- a/pufferlib/config/ocean/target.ini
+++ /dev/null
@@ -1,18 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_target
-policy_name = Policy
-rnn_name = Recurrent
-
-[env]
-num_envs = 512
-num_agents = 8
-num_goals = 4
-
-[train]
-total_timesteps = 100_000_000
-gamma = 0.99
-learning_rate = 0.015
-minibatch_size = 32768
-ent_coef = 0.02
-
diff --git a/pufferlib/config/ocean/template.ini b/pufferlib/config/ocean/template.ini
deleted file mode 100644
index 4784c83e7..000000000
--- a/pufferlib/config/ocean/template.ini
+++ /dev/null
@@ -1,10 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_template
-policy_name = Policy
-
-[env]
-num_envs = 4096
-
-[train]
-total_timesteps = 10_000_000
diff --git a/pufferlib/config/ocean/terraform.ini b/pufferlib/config/ocean/terraform.ini
deleted file mode 100644
index b64d19dc0..000000000
--- a/pufferlib/config/ocean/terraform.ini
+++ /dev/null
@@ -1,61 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_terraform
-policy_name = Terraform
-rnn_name = Recurrent
-
-[vec]
-num_envs = 8
-#backend = Serial
-[env]
-num_envs = 1024
-num_agents = 1
-reset_frequency = 1024
-reward_scale = 0.11
-
-[policy]
-hidden_size = 256
-
-[rnn]
-input_size = 256
-hidden_size = 256
-
-[train]
-total_timesteps = 1_000_000_000
-adam_beta1 = 0.8792313963264954
-adam_beta2 = 0.9980457691558037
-adam_eps = 0.0000060001757672174796
-bptt_horizon = 64
-ent_coef = 0.007047731279570716
-gae_lambda = 0.95
-gamma = 0.98
-learning_rate = 0.005
-max_grad_norm = 1.1870216773228415
-minibatch_size = 32768
-prio_alpha = 0.498348178927537
-prio_beta0 = 0.7687009564385903
-vf_clip_coef = 1.4509861770544443
-vf_coef = 3.175722544969796
-vtrace_c_clip = 0.937506506536413
-vtrace_rho_clip = 1.208308436542831
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 2e8
-max = 6e8
-mean = 4e8
-scale = time
-
-#[sweep.env.reset_frequency]
-#distribution = int_uniform
-#min = 1024
-#max = 16384
-#mean = 8192
-#scale = auto
-
-[sweep.env.reward_scale]
-distribution = log_normal
-min = 0.01
-max = 1
-mean = 0.5
-scale = auto
diff --git a/pufferlib/config/ocean/tetris.ini b/pufferlib/config/ocean/tetris.ini
deleted file mode 100644
index 0391ca317..000000000
--- a/pufferlib/config/ocean/tetris.ini
+++ /dev/null
@@ -1,29 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_tetris
-policy_name = Policy
-rnn_name = Recurrent
-
-[vec]
-num_envs = 8
-
-[env]
-num_envs = 1024
-deck_size = 3
-
-[train]
-total_timesteps = 2_000_000_000
-batch_size = auto
-bptt_horizon = 64
-minibatch_size = 32768
-
-[sweep]
-metric = score
-goal = maximize
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 2e8
-max = 4e8
-mean = 3e8
-scale = auto
diff --git a/pufferlib/config/ocean/tower_climb.ini b/pufferlib/config/ocean/tower_climb.ini
deleted file mode 100644
index ce6f75d59..000000000
--- a/pufferlib/config/ocean/tower_climb.ini
+++ /dev/null
@@ -1,57 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_tower_climb
-policy_name = TowerClimb
-rnn_name = TowerClimbLSTM
-
-[vec]
-num_envs = 8
-
-[env]
-num_envs = 1024
-num_maps = 50
-reward_climb_row = 0.636873185634613
-reward_fall_row = -0.15898257493972778
-reward_illegal_move = -0.003928301855921745
-reward_move_block = 0.235064297914505
-
-[train]
-total_timesteps = 150_000_000
-#gamma = 0.98
-#learning_rate = 0.05
-minibatch_size = 32768
-
-[sweep.train.total_timesteps]
-distribution = uniform
-min = 50_000_000
-max = 200_000_000
-mean = 100_000_000
-scale = 0.5
-
-[sweep.env.reward_climb_row]
-distribution = uniform
-min = 0.0
-max = 1.0
-mean = 0.5
-scale = auto
-
-[sweep.env.reward_fall_row]
-distribution = uniform
-min = -1.0
-max = 0.0
-mean = -0.5
-scale = auto
-
-[sweep.env.reward_illegal_move]
-distribution = uniform
-min = -1e-2
-max = -1e-4
-mean = -1e-3
-scale = auto
-
-[sweep.env.reward_move_block]
-distribution = uniform
-min = 0.0
-max = 1.0
-mean = 0.5
-scale = auto
diff --git a/pufferlib/config/ocean/trash_pickup.ini b/pufferlib/config/ocean/trash_pickup.ini
deleted file mode 100644
index bb235abab..000000000
--- a/pufferlib/config/ocean/trash_pickup.ini
+++ /dev/null
@@ -1,28 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_trash_pickup
-policy_name = TrashPickup
-rnn_name = Recurrent
-
-[vec]
-num_envs = 8
-
-[env]
-num_envs = 128
-grid_size = 20
-num_agents = 8
-num_trash = 40
-num_bins = 2
-max_steps = 500
-report_interval = 32
-agent_sight_range = 5
-
-[train]
-total_timesteps = 100_000_000
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 3e7
-max = 2e8
-mean = 1e8
-scale = 0.5
diff --git a/pufferlib/config/ocean/tripletriad.ini b/pufferlib/config/ocean/tripletriad.ini
deleted file mode 100644
index aae55d096..000000000
--- a/pufferlib/config/ocean/tripletriad.ini
+++ /dev/null
@@ -1,21 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_tripletriad
-policy_name = Policy
-rnn_name = Recurrent
-
-[env]
-num_envs = 1024
-
-[vec]
-num_envs = 8
-
-[train]
-total_timesteps = 100_000_000
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 5e7
-max = 2e8
-mean = 1e8
-scale = 0.25
diff --git a/pufferlib/config/ocean/whisker_racer.ini b/pufferlib/config/ocean/whisker_racer.ini
deleted file mode 100644
index b7dd87f11..000000000
--- a/pufferlib/config/ocean/whisker_racer.ini
+++ /dev/null
@@ -1,176 +0,0 @@
-[base]
-package = ocean
-env_name = puffer_whisker_racer
-policy_name = Policy
-rnn_name = Recurrent
-
-[vec]
-num_envs = 8
-
-[env]
-num_envs = 1024
-frameskip = 4
-width = 1080
-height = 720
-track_width = 75
-num_radial_sectors = 180
-num_points = 16
-bezier_resolution = 4
-turn_pi_frac = 40
-w_ang = 0.777 # 0.586 # 0.523
-reward_yellow = 0.2
-reward_green = -0.001
-corner_thresh = 0.5 # dot product for hairpins
-ftmp1 = 0.5 #0.9
-ftmp2 = 3.0 #1.05
-ftmp3 = 0.3 # 0.2
-ftmp4 = 0.0
-mode7 = 0
-render_many = 0
-rng = 6
-method = 2
-
-[policy]
-hidden_size = 128
-
-[rnn]
-input_size = 128
-hidden_size = 128
-
-[train]
-adam_beta1 = 0.9446160612709289
-adam_beta2 = 0.9898294105500932
-adam_eps = 3.599894131847621e-14
-batch_size = auto
-bptt_horizon = 64
-clip_coef = 0.18182501031893042
-ent_coef = 0.014660408908451323
-gae_lambda = 0.9560790493173461
-gamma = 0.9966518685154753
-learning_rate = 0.009774918469042404
-max_grad_norm = 1.1402446026380597
-#max_minibatch_size = 32768
-#min_minibatch_size = 32768
-minibatch_size = 32768 #16384 32768
-prio_alpha = 0.8186786991771018
-prio_beta0 = 0.49639773186725333
-total_timesteps = 200_000_000
-vf_clip_coef = 1.1492700894337171
-vf_coef = 1.2551354745222134
-vtrace_c_clip = 0
-vtrace_rho_clip = 2.2637237926128577
-
-[sweep]
-method = Protein
-metric = score
-goal = maximize
-downsample = 10
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 19_000_000
-max = 20_000_000
-mean = 19_500_000
-scale = auto
-
-[sweep.env.track_width]
-distribution = log_normal
-min = 30
-max = 75
-mean = 50
-scale = auto
-
-[sweep.train.learning_rate]
-distribution = log_normal
-min = 0.03
-mean = 0.08
-max = 0.15
-scale = 0.5
-
-[sweep.env.turn_pi_frac]
-distribution = uniform
-min = 30
-max = 75
-mean = 50
-scale = auto
-
-[sweep.env.num_radial_sectors]
-distribution = uniform
-min = 8
-max = 100
-mean = 18
-scale = auto
-
-[sweep.env.w_ang]
-distribution = uniform
-min = 0.523 # PI / 6
-max = 0.785 # PI / 4
-mean = 0.654
-scale = auto
-
-#[sweep.env.frameskip]
-#distribution = categorical
-#values = 1, 4, 8
-
-[sweep.env.reward_yellow]
-distribution = uniform
-min = 0.20
-max = 0.50
-mean = 0.30
-scale = auto
-
-[sweep.env.reward_green]
-distribution = uniform
-min = -0.001
-max = 0.0
-mean = -0.0001
-scale = auto
-
-#[sweep.train.vtrace_rho_clip]
-#distribution = uniform
-#min = 1.0
-#max = 5.0
-#mean = 1.5
-#scale = auto
-
-#[sweep.train.max_grad_norm]
-#distribution = uniform
-#min = 1.0
-#mean = 1.25
-#max = 5.0
-#scale = auto
-
-#[sweep.train.vf_coef]
-#distribution = uniform
-#min = 0.0
-#max = 1.0
-#mean = 1.8
-#scale = auto
-
-#[sweep.train.gae_lambda]
-#distribution = logit_normal
-#min = 0.96
-#mean = 0.984
-#max = 0.9995
-#scale = auto
-
-#[sweep.train.vtrace_c_clip]
-#distribution = uniform
-#min = 0.0
-#max = 4.0
-#mean = 1.0
-#scale = auto
-
-[sweep.train.minibatch_size]
-distribution = uniform_pow2
-min = 8192
-max = 32768
-mean = 16384
-scale = auto
-
-#[sweep.train.ent_coef]
-#distribution = log_normal
-#min = 0.00001
-#mean = 0.005
-#max = 0.05
-#scale = auto
diff --git a/pufferlib/config/open_spiel.ini b/pufferlib/config/open_spiel.ini
deleted file mode 100644
index a3210cb79..000000000
--- a/pufferlib/config/open_spiel.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[base]
-package = open_spiel
-env_name = connect_four
-
-[train]
-num_envs = 32
-batch_size = 4096
diff --git a/pufferlib/config/pokemon_red.ini b/pufferlib/config/pokemon_red.ini
deleted file mode 100644
index a0c2485ce..000000000
--- a/pufferlib/config/pokemon_red.ini
+++ /dev/null
@@ -1,17 +0,0 @@
-[base]
-package = pokemon_red
-env_name = pokemon_red
-
-[train]
-total_timesteps = 1_000_000
-num_envs = 96
-num_workers = 24
-env_batch_size = 32
-zero_copy = False
-update_epochs = 3
-gamma = 0.998
-batch_size = 65536
-minibatch_size = 2048
-compile = True
-learning_rate = 2.0e-4
-anneal_lr = False
diff --git a/pufferlib/config/procgen.ini b/pufferlib/config/procgen.ini
deleted file mode 100644
index cc7c6cba8..000000000
--- a/pufferlib/config/procgen.ini
+++ /dev/null
@@ -1,15 +0,0 @@
-[base]
-package = procgen
-env_name = bigfish bossfight caveflyer chaser climber coinrun dodgeball fruitbot heist jumper leaper maze miner ninja plunder starpilot
-
-[vec]
-num_envs = 128
-num_workers = 16
-batch_size = 64
-
-[train]
-batch_size = 8192
-minibatch_size = 2048
-update_epochs = 1
-bptt_horizon = 64
-total_timesteps = 25_000_000
diff --git a/pufferlib/config/slimevolley.ini b/pufferlib/config/slimevolley.ini
deleted file mode 100644
index 847672f6d..000000000
--- a/pufferlib/config/slimevolley.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[base]
-package = slimevolley
-env_name = slimevolley
-
-[train]
-num_envs=1536
-num_workers=24
-env_batch_size=512
-zero_copy=False
-batch_size=65536
-minibatch_size=8192
-update_epochs=1
diff --git a/pufferlib/config/stable_retro.ini b/pufferlib/config/stable_retro.ini
deleted file mode 100644
index 8f2239986..000000000
--- a/pufferlib/config/stable_retro.ini
+++ /dev/null
@@ -1,3 +0,0 @@
-[base]
-package = stable_retro
-env_name = Airstriker-Genesis
diff --git a/pufferlib/config/starcraft.ini b/pufferlib/config/starcraft.ini
deleted file mode 100644
index 9af2bfb11..000000000
--- a/pufferlib/config/starcraft.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[base]
-package = smac
diff --git a/pufferlib/config/trade_sim.ini b/pufferlib/config/trade_sim.ini
deleted file mode 100644
index 2a7f5b405..000000000
--- a/pufferlib/config/trade_sim.ini
+++ /dev/null
@@ -1,30 +0,0 @@
-[base]
-package = trade_sim
-env_name = trade_sim
-policy_name = Policy
-rnn_name = Recurrent
-
-[vec]
-backend = Multiprocessing
-num_envs = 1024
-num_workers = 16
-batch_size = 512
-
-#[env]
-#num_envs = 128
-
-[train]
-total_timesteps = 100_000_000
-gamma = 0.95
-learning_rate = 0.05
-minibatch_size = 32768
-
-[sweep]
-metric = final_capital
-
-[sweep.train.total_timesteps]
-distribution = log_normal
-min = 2e7
-max = 1e8
-mean = 5e7
-scale = auto
diff --git a/pufferlib/emulation.py b/pufferlib/emulation.py
index f576f530f..f50ec03b1 100644
--- a/pufferlib/emulation.py
+++ b/pufferlib/emulation.py
@@ -1,5 +1,3 @@
-from pdb import set_trace as T
-
import numpy as np
import warnings
@@ -10,24 +8,26 @@
import pufferlib.spaces
from pufferlib.spaces import Discrete, Tuple, Dict
+
def emulate(struct, sample):
if isinstance(sample, dict):
for k, v in sample.items():
emulate(struct[k], v)
elif isinstance(sample, tuple):
for i, v in enumerate(sample):
- emulate(struct[f'f{i}'], v)
+ emulate(struct[f"f{i}"], v)
else:
struct[()] = sample
+
def make_buffer(arr_dtype, struct_dtype, struct, n=None):
- '''None instead of 1 makes it work for 1 agent PZ envs'''
- '''
+ """None instead of 1 makes it work for 1 agent PZ envs"""
+ """
if n is None:
struct = np.zeros(1, dtype=struct_dtype)
else:
struct = np.zeros(n, dtype=struct_dtype)
- '''
+ """
arr = struct.view(arr_dtype)
@@ -38,29 +38,31 @@ def make_buffer(arr_dtype, struct_dtype, struct, n=None):
return arr
+
def _nativize(struct, space):
if isinstance(space, Discrete):
return struct.item()
elif isinstance(space, Tuple):
- return tuple(_nativize(struct[f'f{i}'], elem)
- for i, elem in enumerate(space))
+ return tuple(_nativize(struct[f"f{i}"], elem) for i, elem in enumerate(space))
elif isinstance(space, Dict):
- return {k: _nativize(struct[k], value)
- for k, value in space.items()}
+ return {k: _nativize(struct[k], value) for k, value in space.items()}
else:
return struct
+
def nativize(arr, space, struct_dtype):
struct = np.asarray(arr).view(struct_dtype)[0]
return _nativize(struct, space)
+
# TODO: Uncomment?
-'''
+"""
try:
from pufferlib.extensions import emulate, nativize
except ImportError:
warnings.warn('PufferLib Cython extensions not installed. Using slow Python versions')
-'''
+"""
+
def get_dtype_bounds(dtype):
if dtype == bool:
@@ -80,7 +82,7 @@ def dtype_from_space(space):
if isinstance(space, pufferlib.spaces.Tuple):
dtype = []
for i, elem in enumerate(space):
- dtype.append((f'f{i}', dtype_from_space(elem)))
+ dtype.append((f"f{i}", dtype_from_space(elem)))
elif isinstance(space, pufferlib.spaces.Dict):
dtype = []
for k, value in space.items():
@@ -94,6 +96,7 @@ def dtype_from_space(space):
return np.dtype(dtype, align=True)
+
def flatten_space(space):
if isinstance(space, pufferlib.spaces.Tuple):
subspaces = []
@@ -108,6 +111,7 @@ def flatten_space(space):
else:
return [space]
+
def emulate_observation_space(space):
emulated_dtype = dtype_from_space(space)
@@ -126,6 +130,7 @@ def emulate_observation_space(space):
emulated_space = gymnasium.spaces.Box(low=mmin, high=mmax, shape=(numel,), dtype=dtype)
return emulated_space, emulated_dtype
+
def emulate_action_space(space):
if isinstance(space, pufferlib.spaces.Box):
return space, space.dtype
@@ -148,10 +153,8 @@ def __init__(self, env=None, env_creator=None, env_args=[], env_kwargs={}, buf=N
self.is_observation_checked = False
self.is_action_checked = False
- self.observation_space, self.obs_dtype = emulate_observation_space(
- self.env.observation_space)
- self.action_space, self.atn_dtype = emulate_action_space(
- self.env.action_space)
+ self.observation_space, self.obs_dtype = emulate_observation_space(self.env.observation_space)
+ self.action_space, self.atn_dtype = emulate_action_space(self.env.action_space)
self.single_observation_space = self.observation_space
self.single_action_space = self.action_space
self.num_agents = 1
@@ -163,14 +166,14 @@ def __init__(self, env=None, env_creator=None, env_args=[], env_kwargs={}, buf=N
emulated_observation_dtype=self.obs_dtype,
)
- self.render_modes = 'human rgb_array'.split()
+ self.render_modes = "human rgb_array".split()
pufferlib.set_buffers(self, buf)
if isinstance(self.env.observation_space, pufferlib.spaces.Box):
self.obs_struct = self.observations
else:
self.obs_struct = self.observations.view(self.obs_dtype)
-
+
@property
def render_mode(self):
return self.env.render_mode
@@ -184,8 +187,7 @@ def reset(self, seed=None):
ob, info = _seed_and_reset(self.env, seed)
if not self.is_observation_checked:
- self.is_observation_checked = check_space(
- ob, self.env.observation_space)
+ self.is_observation_checked = check_space(ob, self.env.observation_space)
if self.is_obs_emulated:
emulate(self.obs_struct, ob)
@@ -196,15 +198,15 @@ def reset(self, seed=None):
self.terminals[0] = False
self.truncations[0] = False
self.masks[0] = True
-
+
return self.observations, info
-
+
def step(self, action):
- '''Execute an action and return (observation, reward, done, info)'''
+ """Execute an action and return (observation, reward, done, info)"""
if not self.initialized:
- raise pufferlib.APIUsageError('step() called before reset()')
+ raise pufferlib.APIUsageError("step() called before reset()")
if self.done:
- raise pufferlib.APIUsageError('step() called after environment is done')
+ raise pufferlib.APIUsageError("step() called after environment is done")
# Unpack actions from multidiscrete into the original action space
if self.is_atn_emulated:
@@ -216,12 +218,10 @@ def step(self, action):
action = action[0]
if not self.is_action_checked:
- self.is_action_checked = check_space(
- action, self.env.action_space)
+ self.is_action_checked = check_space(action, self.env.action_space)
ob, reward, done, truncated, info = self.env.step(action)
-
if self.is_obs_emulated:
emulate(self.obs_struct, ob)
else:
@@ -231,7 +231,7 @@ def step(self, action):
self.terminals[0] = done
self.truncations[0] = truncated
self.masks[0] = True
-
+
self.done = done or truncated
return self.observations, reward, done, truncated, info
@@ -241,6 +241,7 @@ def render(self):
def close(self):
return self.env.close()
+
class PettingZooPufferEnv:
def __init__(self, env=None, env_creator=None, env_args=[], env_kwargs={}, buf=None, seed=0):
self.env = make_object(env, env_creator, env_args, env_kwargs)
@@ -254,15 +255,13 @@ def __init__(self, env=None, env_creator=None, env_args=[], env_kwargs={}, buf=N
single_agent = self.possible_agents[0]
self.env_single_observation_space = self.env.observation_space(single_agent)
self.env_single_action_space = self.env.action_space(single_agent)
- self.single_observation_space, self.obs_dtype = (
- emulate_observation_space(self.env_single_observation_space))
- self.single_action_space, self.atn_dtype = (
- emulate_action_space(self.env_single_action_space))
+ self.single_observation_space, self.obs_dtype = emulate_observation_space(self.env_single_observation_space)
+ self.single_action_space, self.atn_dtype = emulate_action_space(self.env_single_action_space)
self.is_obs_emulated = self.single_observation_space is not self.env_single_observation_space
self.is_atn_emulated = self.single_action_space is not self.env_single_action_space
self.emulated = dict(
- observation_dtype = self.single_observation_space.dtype,
- emulated_observation_dtype = self.obs_dtype,
+ observation_dtype=self.single_observation_space.dtype,
+ emulated_observation_dtype=self.obs_dtype,
)
self.num_agents = len(self.possible_agents)
@@ -290,14 +289,14 @@ def done(self):
return len(self.agents) == 0 or self.all_done
def observation_space(self, agent):
- '''Returns the observation space for a single agent'''
+ """Returns the observation space for a single agent"""
if agent not in self.possible_agents:
raise pufferlib.InvalidAgentError(agent, self.possible_agents)
return self.single_observation_space
def action_space(self, agent):
- '''Returns the action space for a single agent'''
+ """Returns the action space for a single agent"""
if agent not in self.possible_agents:
raise pufferlib.InvalidAgentError(agent, self.possible_agents)
@@ -315,8 +314,7 @@ def reset(self, seed=None):
if not self.is_observation_checked:
for k, ob in obs.items():
- self.is_observation_checked = check_space(
- ob, self.env.observation_space(k))
+ self.is_observation_checked = check_space(ob, self.env.observation_space(k))
# Call user featurizer and flatten the observations
self.observations[:] = 0
@@ -338,16 +336,17 @@ def reset(self, seed=None):
return self.dict_obs, info
def step(self, actions):
- '''Step the environment and return (observations, rewards, dones, infos)'''
+ """Step the environment and return (observations, rewards, dones, infos)"""
if not self.initialized:
- raise pufferlib.APIUsageError('step() called before reset()')
+ raise pufferlib.APIUsageError("step() called before reset()")
if self.done:
- raise pufferlib.APIUsageError('step() called after environment is done')
+ raise pufferlib.APIUsageError("step() called after environment is done")
if isinstance(actions, np.ndarray):
if not self.is_action_checked and len(actions) != self.num_agents:
raise pufferlib.APIUsageError(
- f'Actions specified as len {len(actions)} but environment has {self.num_agents} agents')
+ f"Actions specified as len {len(actions)} but environment has {self.num_agents} agents"
+ )
actions = {agent: actions[i] for i, agent in enumerate(self.possible_agents)}
@@ -357,10 +356,7 @@ def step(self, actions):
if agent not in self.possible_agents:
raise pufferlib.InvalidAgentError(agent, self.possible_agents)
- self.is_action_checked = check_space(
- next(iter(actions.values())),
- self.single_action_space
- )
+ self.is_action_checked = check_space(next(iter(actions.values())), self.single_action_space)
# Unpack actions from multidiscrete into the original action space
unpacked_actions = {}
@@ -393,7 +389,7 @@ def step(self, actions):
self.masks[i] = False
continue
- ob = obs[agent]
+ ob = obs[agent]
self.mask[agent] = True
if self.is_obs_emulated:
emulate(self.obs_struct[i], ob)
@@ -404,10 +400,12 @@ def step(self, actions):
self.terminals[i] = dones[agent]
self.truncations[i] = truncateds[agent]
self.masks[i] = True
-
+
self.all_done = all(dones.values()) or all(truncateds.values())
rewards = pad_agent_data(rewards, self.possible_agents, 0)
- dones = pad_agent_data(dones, self.possible_agents, True) # You changed this from false to match api test... is this correct?
+ dones = pad_agent_data(
+ dones, self.possible_agents, True
+ ) # You changed this from false to match api test... is this correct?
truncateds = pad_agent_data(truncateds, self.possible_agents, False)
return self.dict_obs, rewards, dones, truncateds, infos
@@ -417,23 +415,24 @@ def render(self):
def close(self):
return self.env.close()
+
def pad_agent_data(data, agents, pad_value):
- return {agent: data[agent] if agent in data else pad_value
- for agent in agents}
-
+ return {agent: data[agent] if agent in data else pad_value for agent in agents}
+
+
def make_object(object_instance=None, object_creator=None, creator_args=[], creator_kwargs={}):
if (object_instance is None) == (object_creator is None):
- raise ValueError('Exactly one of object_instance or object_creator must be provided')
+ raise ValueError("Exactly one of object_instance or object_creator must be provided")
if object_instance is not None:
if callable(object_instance) or inspect.isclass(object_instance):
- raise TypeError('object_instance must be an instance, not a function or class')
+ raise TypeError("object_instance must be an instance, not a function or class")
return object_instance
if object_creator is not None:
if not callable(object_creator):
- raise TypeError('object_creator must be a callable')
-
+ raise TypeError("object_creator must be a callable")
+
if creator_args is None:
creator_args = []
@@ -442,19 +441,19 @@ def make_object(object_instance=None, object_creator=None, creator_args=[], crea
return object_creator(*creator_args, **creator_kwargs)
+
def check_space(data, space):
try:
contains = space.contains(data)
except:
- raise pufferlib.APIUsageError(
- f'Error checking space {space} with sample :\n{data}')
+ raise pufferlib.APIUsageError(f"Error checking space {space} with sample :\n{data}")
if not contains:
- raise pufferlib.APIUsageError(
- f'Data:\n{data}\n not in space:\n{space}')
-
+ raise pufferlib.APIUsageError(f"Data:\n{data}\n not in space:\n{space}")
+
return True
+
def _seed_and_reset(env, seed):
if seed is None:
# Gym bug: does not reset env correctly
@@ -469,10 +468,11 @@ def _seed_and_reset(env, seed):
obs, info = env.reset()
except:
obs, info = env.reset()
- warnings.warn('WARNING: Environment does not support seeding.', DeprecationWarning)
+ warnings.warn("WARNING: Environment does not support seeding.", DeprecationWarning)
return obs, info
+
class GymnaxPufferEnv(pufferlib.PufferEnv):
def __init__(self, env, env_params, num_envs=1, buf=None):
from gymnax.spaces import gymnax_space_to_gym_space
@@ -490,27 +490,32 @@ def __init__(self, env, env_params, num_envs=1, buf=None):
self.env = env
import jax
+
self.reset_fn = jax.jit(jax.vmap(env.reset, in_axes=(0, None)))
self.step_fn = jax.jit(jax.vmap(env.step, in_axes=(0, 0, 0, None)))
self.rng = jax.random.PRNGKey(0)
def reset(self, rng, params=None):
import jax
+
self.rng, _rng = jax.random.split(self.rng)
self.rngs = jax.random.split(_rng, self.num_agents)
obs, self.state = self.reset_fn(self.rngs, params)
from torch.utils import dlpack as torch_dlpack
+
self.observations = torch_dlpack.from_dlpack(jax.dlpack.to_dlpack(obs))
return self.observations, []
def step(self, action):
import jax
- #self.rng, _rng = jax.random.split(self.rng)
- #rngs = jax.random.split(_rng, self.num_agents)
+
+ # self.rng, _rng = jax.random.split(self.rng)
+ # rngs = jax.random.split(_rng, self.num_agents)
obs, self.state, reward, done, info = self.step_fn(self.rngs, self.state, action, self.env_params)
# Convert JAX array to DLPack, then to PyTorch tensor
from torch.utils import dlpack as torch_dlpack
+
self.observations = torch_dlpack.from_dlpack(jax.dlpack.to_dlpack(obs))
self.rewards = np.asarray(reward)
self.terminals = np.asarray(done)
diff --git a/pufferlib/environments/__init__.py b/pufferlib/environments/__init__.py
deleted file mode 100644
index d6c969523..000000000
--- a/pufferlib/environments/__init__.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from pdb import set_trace as T
-import pufferlib
-
-def try_import(module_path, package_name=None):
- if package_name is None:
- package_name = module_path
- try:
- package = __import__(module_path)
- except ImportError as e:
- raise ImportError(
- f'{e.args[0]}\n\n'
- 'This is probably an installation error. Try: '
- f'pip install pufferlib[{package_name}]. '
-
- 'Note that some environments have non-python dependencies. '
- 'These are included in PufferTank. Or, you can install '
- 'manually by following the instructions provided by the '
- 'environment meaintainers. But some are finicky, so we '
- 'recommend using PufferTank.'
- ) from e
- return package
diff --git a/pufferlib/environments/atari/__init__.py b/pufferlib/environments/atari/__init__.py
deleted file mode 100644
index 59cda9e7c..000000000
--- a/pufferlib/environments/atari/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/atari/environment.py b/pufferlib/environments/atari/environment.py
deleted file mode 100644
index 92295ecaa..000000000
--- a/pufferlib/environments/atari/environment.py
+++ /dev/null
@@ -1,215 +0,0 @@
-from pdb import set_trace as T
-import numpy as np
-import functools
-
-import gymnasium as gym
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.environments
-
-def env_creator(name='breakout'):
- return functools.partial(make, name)
-
-def make(name, obs_type='grayscale', frameskip=4,
- full_action_space=False, framestack=1,
- repeat_action_probability=0.0, render_mode='rgb_array',
- buf=None, seed=0):
- '''Atari creation function'''
- pufferlib.environments.try_import('ale_py', 'AtariEnv')
-
- ale_render_mode = render_mode
- if render_mode == 'human':
- ale_render_mode = 'rgb_array'
- obs_type = 'rgb'
- frameskip = 1
- full_action_space = True
- upscale = 4
- elif render_mode == 'raylib':
- ale_render_mode = 'rgb_array'
- upscale = 8
-
- from ale_py import AtariEnv
- env = AtariEnv(name, obs_type=obs_type, frameskip=frameskip,
- repeat_action_probability=repeat_action_probability,
- full_action_space=full_action_space,
- render_mode=ale_render_mode)
-
- action_set = env._action_set
-
- if render_mode != 'human':
- env = pufferlib.ResizeObservation(env, downscale=2)
-
- if framestack > 1:
- env = gym.wrappers.FrameStack(env, framestack)
-
- if render_mode in ('human', 'raylib'):
- env = RaylibClient(env, action_set, frameskip, upscale)
- else:
- env = AtariPostprocessor(env) # Don't use standard postprocessor
-
- env = pufferlib.EpisodeStats(env)
- env = pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
- return env
-
-class AtariPostprocessor(gym.Wrapper):
- '''Atari breaks the normal PufferLib postprocessor because
- it sends terminal=True every live, not every episode'''
- def __init__(self, env):
- super().__init__(env)
- shape = env.observation_space.shape
- if len(shape) < 3:
- shape = (1, *shape)
- else:
- shape = (shape[2], shape[0], shape[1])
-
- self.observation_space = gym.spaces.Box(low=0, high=255,
- shape=shape, dtype=env.observation_space.dtype)
-
- def unsqueeze_transpose(self, obs):
- if len(obs.shape) == 3:
- return np.transpose(obs, (2, 0, 1))
- else:
- return np.expand_dims(obs, 0)
-
- def reset(self, seed=None, options=None):
- obs, _ = self.env.reset(seed=seed)
- return self.unsqueeze_transpose(obs), {}
-
- def step(self, action):
- obs, reward, terminal, truncated, _ = self.env.step(action)
- return self.unsqueeze_transpose(obs), reward, terminal, truncated, {}
-
-class RaylibClient(gym.Wrapper):
- def __init__(self, env, action_set, frameskip=4, upscale=4):
- self.env = env
-
- self.keymap = {}
- for i, atn in enumerate(action_set):
- self.keymap[atn.value] = i
-
- obs_shape = env.observation_space.shape
- if len(obs_shape) == 2:
- height, width = obs_shape
- channels = 1
- else:
- height, width, channels = obs_shape
-
- height *= upscale
- width *= upscale
- from raylib import rl, colors
- rl.InitWindow(width, height, "Atari".encode())
- rl.SetTargetFPS(60//frameskip)
- self.rl = rl
- self.colors = colors
-
-
- import numpy as np
- rendered = np.zeros((width, height, 4), dtype=np.uint8)
-
- import pyray
- from cffi import FFI
- raylib_image = pyray.Image(FFI().from_buffer(rendered.data),
- width, height, 1, pyray.PIXELFORMAT_UNCOMPRESSED_R8G8B8)
- self.texture = rl.LoadTextureFromImage(raylib_image)
- self.action = 0
-
- self.upscale = upscale
- self.rescaler = np.ones((upscale, upscale, 1), dtype=np.uint8)
-
- def any_key_pressed(self, keys):
- for key in keys:
- if self.rl.IsKeyPressed(key):
- return True
- return False
-
- def any_key_down(self, keys):
- for key in keys:
- if self.rl.IsKeyDown(key):
- return True
- return False
-
- def down(self):
- return self.any_key_down([self.rl.KEY_S, self.rl.KEY_DOWN])
-
- def up(self):
- return self.any_key_down([self.rl.KEY_W, self.rl.KEY_UP])
-
- def left(self):
- return self.any_key_down([self.rl.KEY_A, self.rl.KEY_LEFT])
-
- def right(self):
- return self.any_key_down([self.rl.KEY_D, self.rl.KEY_RIGHT])
-
- def render(self):
- from ale_py import Action
-
- rl = self.rl
- if rl.IsKeyPressed(rl.KEY_ESCAPE):
- exit(0)
-
- elif rl.IsKeyDown(rl.KEY_SPACE):
- if self.left() and self.down():
- action = Action.DOWNLEFTFIRE.value
- elif self.right() and self.down():
- action = Action.DOWNRIGHTFIRE.value
- elif self.left() and self.up():
- action = Action.UPLEFTFIRE.value
- elif self.right() and self.up():
- action = Action.UPRIGHTFIRE.value
- elif self.left():
- action = Action.LEFTFIRE.value
- elif self.right():
- action = Action.RIGHTFIRE.value
- elif self.up():
- action = Action.UPFIRE.value
- elif self.down():
- action = Action.DOWNFIRE.value
- else:
- action = Action.FIRE.value
- elif self.left() and self.down():
- action = Action.DOWNLEFT.value
- elif self.right() and self.down():
- action = Action.DOWNRIGHT.value
- elif self.left() and self.up():
- action = Action.UPLEFT.value
- elif self.right() and self.up():
- action = Action.UPRIGHT.value
- elif self.left():
- action = Action.LEFT.value
- elif self.right():
- action = Action.RIGHT.value
- elif self.up():
- action = Action.UP.value
- else:
- action = Action.NOOP.value
-
- if action in self.keymap:
- self.action = self.keymap[action]
- else:
- self.action = Action.NOOP.value
-
- #frame = self.env.render()
- frame = self.frame
- if len(frame.shape) < 3:
- frame = np.expand_dims(frame, 2)
- frame = np.repeat(frame, 3, axis=2)
-
- if self.upscale > 1:
- frame = np.kron(frame, self.rescaler)
-
- rl.BeginDrawing()
- rl.ClearBackground(self.colors.BLACK)
- rl.UpdateTexture(self.texture, frame.tobytes())
- rl.DrawTextureEx(self.texture, (0, 0), 0, 1, self.colors.WHITE)
- rl.EndDrawing()
-
- def reset(self, seed=None, options=None):
- obs, info = self.env.reset(seed=seed, options=options)
- self.frame = obs
- return obs, info
-
- def step(self, action):
- obs, reward, terminal, truncated, info = self.env.step(self.action)
- self.frame = obs
- return obs, reward, terminal, truncated, info
diff --git a/pufferlib/environments/atari/torch.py b/pufferlib/environments/atari/torch.py
deleted file mode 100644
index cae86bbe4..000000000
--- a/pufferlib/environments/atari/torch.py
+++ /dev/null
@@ -1,18 +0,0 @@
-import pufferlib.models
-
-
-class Recurrent(pufferlib.models.LSTMWrapper):
- def __init__(self, env, policy, input_size=512, hidden_size=512):
- super().__init__(env, policy, input_size, hidden_size)
-
-class Policy(pufferlib.models.Convolutional):
- def __init__(self, env, input_size=512, hidden_size=512, output_size=512,
- framestack=1, flat_size=64*6*9, **kwargs):
- super().__init__(
- env=env,
- input_size=input_size,
- hidden_size=hidden_size,
- output_size=output_size,
- framestack=framestack,
- flat_size=flat_size,
- )
diff --git a/pufferlib/environments/box2d/__init__.py b/pufferlib/environments/box2d/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/box2d/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/box2d/environment.py b/pufferlib/environments/box2d/environment.py
deleted file mode 100644
index f2fd12b7e..000000000
--- a/pufferlib/environments/box2d/environment.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from pdb import set_trace as T
-
-import gymnasium
-import functools
-
-import pufferlib.emulation
-import pufferlib.environments
-import pufferlib.postprocess
-
-
-def env_creator(name='car-racing'):
- return functools.partial(make, name=name)
-
-def make(name, domain_randomize=True, continuous=False, render_mode='rgb_array', buf=None):
- if name == 'car-racing':
- name = 'CarRacing-v2'
-
- env = gymnasium.make(name, render_mode=render_mode,
- domain_randomize=domain_randomize, continuous=continuous)
- env = pufferlib.postprocess.EpisodeStats(env)
- return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
diff --git a/pufferlib/environments/box2d/torch.py b/pufferlib/environments/box2d/torch.py
deleted file mode 100644
index b7cdd6acb..000000000
--- a/pufferlib/environments/box2d/torch.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from functools import partial
-import torch
-
-import pufferlib.models
-
-class Recurrent(pufferlib.models.LSTMWrapper):
- def __init__(self, env, policy,
- input_size=128, hidden_size=128, num_layers=1):
- super().__init__(env, policy,
- input_size, hidden_size, num_layers)
-
-class Policy(pufferlib.models.Convolutional):
- def __init__(self, env,
- input_size=128, hidden_size=128, output_size=128,
- framestack=3, flat_size=64*8*8):
- super().__init__(
- env=env,
- input_size=input_size,
- hidden_size=hidden_size,
- output_size=output_size,
- framestack=framestack,
- flat_size=flat_size,
- channels_last=True,
- )
diff --git a/pufferlib/environments/bsuite/__init__.py b/pufferlib/environments/bsuite/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/bsuite/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/bsuite/environment.py b/pufferlib/environments/bsuite/environment.py
deleted file mode 100644
index f39c661e5..000000000
--- a/pufferlib/environments/bsuite/environment.py
+++ /dev/null
@@ -1,44 +0,0 @@
-from pdb import set_trace as T
-import gym
-import functools
-
-import pufferlib.emulation
-import pufferlib.wrappers
-
-import bsuite
-from bsuite.utils import gym_wrapper
-
-def env_creator(name='bandit/0'):
- return functools.partial(make, name)
-
-def make(name='bandit/0', results_dir='experiments/bsuite', overwrite=True, buf=None):
- '''BSuite environments'''
- bsuite = pufferlib.environments.try_import('bsuite')
- from bsuite.utils import gym_wrapper
- env = bsuite.load_and_record_to_csv(name, results_dir, overwrite=overwrite)
- env = gym_wrapper.GymFromDMEnv(env)
- env = BSuiteStopper(env)
- env = pufferlib.wrappers.GymToGymnasium(env)
- env = pufferlib.emulation.GymnasiumPufferEnv(env, buf=buf)
- return env
-
-class BSuiteStopper:
- def __init__(self, env):
- self.env = env
- self.num_episodes = 0
-
- self.step = self.env.step
- self.render = self.env.render
- self.close = self.env.close
- self.observation_space = self.env.observation_space
- self.action_space = self.env.action_space
-
- def reset(self):
- '''Forces the environment to stop after the
- number of episodes required by bsuite'''
- self.num_episodes += 1
-
- if self.num_episodes >= self.env.bsuite_num_episodes:
- exit(0)
-
- return self.env.reset()
diff --git a/pufferlib/environments/bsuite/torch.py b/pufferlib/environments/bsuite/torch.py
deleted file mode 100644
index 8b13194e9..000000000
--- a/pufferlib/environments/bsuite/torch.py
+++ /dev/null
@@ -1 +0,0 @@
-from pufferlib.models import Default as Policy
diff --git a/pufferlib/environments/butterfly/__init__.py b/pufferlib/environments/butterfly/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/butterfly/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/butterfly/environment.py b/pufferlib/environments/butterfly/environment.py
deleted file mode 100644
index 994e53e9e..000000000
--- a/pufferlib/environments/butterfly/environment.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from pdb import set_trace as T
-from pettingzoo.utils.conversions import aec_to_parallel_wrapper
-import functools
-
-import pufferlib.emulation
-import pufferlib.environments
-
-
-def env_creator(name='cooperative_pong_v5'):
- return functools.partial(make, name)
-
-def make(name, buf=None):
- pufferlib.environments.try_import('pettingzoo.butterfly', 'butterfly')
- if name == 'cooperative_pong_v5':
- from pettingzoo.butterfly import cooperative_pong_v5 as pong
- env_cls = pong.raw_env
- elif name == 'knights_archers_zombies_v10':
- from pettingzoo.butterfly import knights_archers_zombies_v10 as kaz
- env_cls = kaz.raw_env
- else:
- raise ValueError(f'Unknown environment: {name}')
-
- env = env_cls()
- env = aec_to_parallel_wrapper(env)
- return pufferlib.emulation.PettingZooPufferEnv(env=env, buf=buf)
diff --git a/pufferlib/environments/butterfly/torch.py b/pufferlib/environments/butterfly/torch.py
deleted file mode 100644
index 5965a3971..000000000
--- a/pufferlib/environments/butterfly/torch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import pufferlib.models
-
-
-class Policy(pufferlib.models.Convolutional):
- def __init__(
- self,
- env,
- flat_size=3520,
- channels_last=True,
- downsample=4,
- input_size=512,
- hidden_size=128,
- output_size=128,
- **kwargs
- ):
- super().__init__(
- env,
- framestack=3,
- flat_size=flat_size,
- channels_last=channels_last,
- downsample=downsample,
- input_size=input_size,
- hidden_size=hidden_size,
- output_size=output_size,
- **kwargs
- )
diff --git a/pufferlib/environments/classic_control/__init__.py b/pufferlib/environments/classic_control/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/classic_control/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/classic_control/environment.py b/pufferlib/environments/classic_control/environment.py
deleted file mode 100644
index 9da76d3e9..000000000
--- a/pufferlib/environments/classic_control/environment.py
+++ /dev/null
@@ -1,40 +0,0 @@
-import gymnasium
-from gymnasium.envs import classic_control
-import functools
-import numpy as np
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.postprocess
-
-ALIASES = {
- 'cartpole': 'CartPole-v0',
- 'mountaincar': 'MountainCar-v0',
-}
-
-def env_creator(name='cartpole'):
- return functools.partial(make, name)
-
-def make(name, render_mode='rgb_array', buf=None):
- '''Create an environment by name'''
-
- if name in ALIASES:
- name = ALIASES[name]
-
- env = gymnasium.make(name, render_mode=render_mode)
- if name == 'MountainCar-v0':
- env = MountainCarWrapper(env)
-
- #env = gymnasium.wrappers.NormalizeObservation(env)
- env = gymnasium.wrappers.TransformObservation(env, lambda obs: np.clip(obs, -1, 1))
- #env = gymnasium.wrappers.NormalizeReward(env, gamma=gamma)
- env = gymnasium.wrappers.TransformReward(env, lambda reward: np.clip(reward, -1, 1))
- env = pufferlib.postprocess.EpisodeStats(env)
- return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
-
-class MountainCarWrapper(gymnasium.Wrapper):
- def step(self, action):
- obs, reward, terminated, truncated, info = self.env.step(action)
- reward = abs(obs[0]+0.5)
- return obs, reward, terminated, truncated, info
-
diff --git a/pufferlib/environments/classic_control/torch.py b/pufferlib/environments/classic_control/torch.py
deleted file mode 100644
index ed3afb863..000000000
--- a/pufferlib/environments/classic_control/torch.py
+++ /dev/null
@@ -1,6 +0,0 @@
-import pufferlib.models
-
-
-class Policy(pufferlib.models.Default):
- def __init__(self, env, hidden_size=64):
- super().__init__(env, hidden_size)
diff --git a/pufferlib/environments/classic_control_continuous/__init__.py b/pufferlib/environments/classic_control_continuous/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/classic_control_continuous/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/classic_control_continuous/environment.py b/pufferlib/environments/classic_control_continuous/environment.py
deleted file mode 100644
index 47f293657..000000000
--- a/pufferlib/environments/classic_control_continuous/environment.py
+++ /dev/null
@@ -1,27 +0,0 @@
-import gymnasium
-import functools
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.postprocess
-
-
-def env_creator(name='MountainCarContinuous-v0'):
- return functools.partial(make, name)
-
-def make(name, render_mode='rgb_array', buf=None):
- '''Create an environment by name'''
- env = gymnasium.make(name, render_mode=render_mode)
- if name == 'MountainCarContinuous-v0':
- env = MountainCarWrapper(env)
-
- env = pufferlib.postprocess.ClipAction(env)
- env = pufferlib.postprocess.EpisodeStats(env)
- return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
-
-class MountainCarWrapper(gymnasium.Wrapper):
- def step(self, action):
- obs, reward, terminated, truncated, info = self.env.step(action)
- reward = abs(obs[0]+0.5)
- return obs, reward, terminated, truncated, info
-
diff --git a/pufferlib/environments/classic_control_continuous/torch.py b/pufferlib/environments/classic_control_continuous/torch.py
deleted file mode 100644
index ed3afb863..000000000
--- a/pufferlib/environments/classic_control_continuous/torch.py
+++ /dev/null
@@ -1,6 +0,0 @@
-import pufferlib.models
-
-
-class Policy(pufferlib.models.Default):
- def __init__(self, env, hidden_size=64):
- super().__init__(env, hidden_size)
diff --git a/pufferlib/environments/craftax/__init__.py b/pufferlib/environments/craftax/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/craftax/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/craftax/environment.py b/pufferlib/environments/craftax/environment.py
deleted file mode 100644
index deb85ccd9..000000000
--- a/pufferlib/environments/craftax/environment.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import functools
-
-import pufferlib
-import pufferlib.emulation
-
-def env_creator(name='Craftax-Symbolic-v1'):
- return functools.partial(make, name)
-
-def make(name, num_envs=2048, buf=None):
- from craftax.craftax_env import make_craftax_env_from_name
- env = make_craftax_env_from_name(name, auto_reset=True)
- env_params = env.default_params
- return pufferlib.emulation.GymnaxPufferEnv(env, env_params, num_envs=num_envs, buf=buf)
diff --git a/pufferlib/environments/craftax/torch.py b/pufferlib/environments/craftax/torch.py
deleted file mode 100644
index dded19779..000000000
--- a/pufferlib/environments/craftax/torch.py
+++ /dev/null
@@ -1,72 +0,0 @@
-import torch
-from torch import nn
-
-import pufferlib.models
-
-Recurrent = pufferlib.models.LSTMWrapper
-
-'''
-CRAFTAX_CHANNELS = 83
-
-# Are these transposed?
-CRAFTAX_ROWS = 11
-CRAFTAX_COLS = 9
-
-N_MAP = CRAFTAX_ROWS * CRAFTAX_COLS * CRAFTAX_CHANNELS
-N_FLAT = 51
-'''
-
-CRAFTAX_ROWS = 7
-CRAFTAX_COLS = 9
-CRAFTAX_CHANNELS = 21
-N_MAP = CRAFTAX_ROWS * CRAFTAX_COLS * CRAFTAX_CHANNELS
-N_FLAT = 22
-
-
-class Policy(nn.Module):
- def __init__(self, env, cnn_channels=32, hidden_size=128, **kwargs):
- super().__init__()
- self.map_encoder = nn.Sequential(
- pufferlib.pytorch.layer_init(
- nn.Conv2d(21, cnn_channels, 3, stride=2)),
- nn.ReLU(),
- pufferlib.pytorch.layer_init(
- nn.Conv2d(cnn_channels, cnn_channels, 3, stride=1)),
- nn.ReLU(),
- nn.Flatten(),
- )
- self.flat_encoder = nn.Sequential(
- pufferlib.pytorch.layer_init(nn.Linear(N_FLAT, hidden_size)),
- nn.ReLU(),
- )
- self.proj = nn.Sequential(
- pufferlib.pytorch.layer_init(nn.Linear(2*cnn_channels + hidden_size, hidden_size)),
- nn.ReLU(),
- )
- self.actor = pufferlib.pytorch.layer_init(
- nn.Linear(hidden_size, env.single_action_space.n), std=0.01)
- self.value_fn = pufferlib.pytorch.layer_init(
- nn.Linear(hidden_size, 1), std=1)
-
- self.is_continuous = False
-
- def forward(self, observations):
- hidden, lookup = self.encode_observations(observations)
- actions, value = self.decode_actions(hidden, lookup)
- return actions, value
-
- def encode_observations(self, observations):
- map_obs = observations[:, :N_MAP].view(
- -1, CRAFTAX_ROWS, CRAFTAX_COLS, CRAFTAX_CHANNELS
- ).permute(0, 3, 1, 2)
- map_obs = self.map_encoder(map_obs)
- flat_obs = observations[:, N_MAP:]
- flat_obs = self.flat_encoder(flat_obs)
- features = torch.cat([map_obs, flat_obs], dim=1)
- features = self.proj(features)
- return features, None
-
- def decode_actions(self, flat_hidden, lookup, concat=None):
- action = self.actor(flat_hidden)
- value = self.value_fn(flat_hidden)
- return action, value
diff --git a/pufferlib/environments/crafter/__init__.py b/pufferlib/environments/crafter/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/crafter/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/crafter/environment.py b/pufferlib/environments/crafter/environment.py
deleted file mode 100644
index e320e347d..000000000
--- a/pufferlib/environments/crafter/environment.py
+++ /dev/null
@@ -1,46 +0,0 @@
-from pdb import set_trace as T
-
-import gym
-import gymnasium
-import shimmy
-import functools
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.environments
-import pufferlib.postprocess
-import pufferlib.utils
-
-
-class TransposeObs(gym.Wrapper):
- def observation(self, observation):
- return observation.transpose(2, 0, 1)
-
-def env_creator(name='crafter'):
- return functools.partial(make, name)
-
-def make(name, buf=None):
- '''Crafter creation function'''
- if name == 'crafter':
- name = 'CrafterReward-v1'
-
- pufferlib.environments.try_import('crafter')
- env = gym.make(name)
- env.reset = pufferlib.utils.silence_warnings(env.reset)
- env = shimmy.GymV21CompatibilityV0(env=env)
- env = RenderWrapper(env)
- env = TransposeObs(env)
- env = pufferlib.postprocess.EpisodeStats(env)
- return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
-
-class RenderWrapper(gym.Wrapper):
- def __init__(self, env):
- super().__init__(env)
- self.env = env
-
- @property
- def render_mode(self):
- return 'rgb_array'
-
- def render(self, *args, **kwargs):
- return self.env.unwrapped.env.unwrapped.render((256,256))
diff --git a/pufferlib/environments/crafter/torch.py b/pufferlib/environments/crafter/torch.py
deleted file mode 100644
index f6f4e5237..000000000
--- a/pufferlib/environments/crafter/torch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import pufferlib.models
-
-
-class Policy(pufferlib.models.Convolutional):
- def __init__(
- self,
- env,
- flat_size=1024,
- channels_last=True,
- downsample=1,
- input_size=512,
- hidden_size=128,
- output_size=128,
- **kwargs
- ):
- super().__init__(
- env,
- framestack=3,
- flat_size=flat_size,
- channels_last=channels_last,
- downsample=downsample,
- input_size=input_size,
- hidden_size=hidden_size,
- output_size=output_size,
- **kwargs
- )
diff --git a/pufferlib/environments/dm_control/__init__.py b/pufferlib/environments/dm_control/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/dm_control/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/dm_control/environment.py b/pufferlib/environments/dm_control/environment.py
deleted file mode 100644
index f492fa659..000000000
--- a/pufferlib/environments/dm_control/environment.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from pdb import set_trace as T
-
-import gym
-import shimmy
-import functools
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.environments
-
-
-def env_creator(name='walker'):
- '''Deepmind Control environment creation function
-
- No support for bindings yet because PufferLib does
- not support continuous action spaces.'''
- return functools.partial(make, name)
-
-def make(name, task_name='walk', buf=None):
- '''Untested. Let us know in Discord if you want to use dmc in PufferLib.'''
- dm_control = pufferlib.environments.try_import('dm_control.suite', 'dmc')
- env = dm_control.suite.load(name, task_name)
- env = shimmy.DmControlCompatibilityV0(env=env)
- return pufferlib.emulation.GymnasiumPufferEnv(env, buf=buf)
diff --git a/pufferlib/environments/dm_control/torch.py b/pufferlib/environments/dm_control/torch.py
deleted file mode 100644
index 8b13194e9..000000000
--- a/pufferlib/environments/dm_control/torch.py
+++ /dev/null
@@ -1 +0,0 @@
-from pufferlib.models import Default as Policy
diff --git a/pufferlib/environments/dm_lab/__init__.py b/pufferlib/environments/dm_lab/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/dm_lab/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/dm_lab/environment.py b/pufferlib/environments/dm_lab/environment.py
deleted file mode 100644
index 17bbde770..000000000
--- a/pufferlib/environments/dm_lab/environment.py
+++ /dev/null
@@ -1,24 +0,0 @@
-from pdb import set_trace as T
-
-import gym
-import shimmy
-import functools
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.environments
-
-
-def env_creator(name='seekavoid_arena_01'):
- '''Deepmind Lab binding creation function
- dm-lab requires extensive setup. Use PufferTank.'''
- return functools.partial(make, name=name)
-
-def make(name, buf=None):
- '''Deepmind Lab binding creation function
- dm-lab requires extensive setup. Currently dropped frop PufferTank.
- Let us know if you need this for your work.'''
- dm_lab = pufferlib.environments.try_import('deepmind_lab', 'dm-lab')
- env = dm_lab.Lab(name, ['RGB_INTERLEAVED'])
- env = shimmy.DmLabCompatibilityV0(env=env)
- return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
diff --git a/pufferlib/environments/dm_lab/torch.py b/pufferlib/environments/dm_lab/torch.py
deleted file mode 100644
index c8e411498..000000000
--- a/pufferlib/environments/dm_lab/torch.py
+++ /dev/null
@@ -1,26 +0,0 @@
-import pufferlib.models
-
-
-class Policy(pufferlib.models.Convolutional):
- def __init__(
- self,
- env,
- flat_size=3136,
- channels_last=True,
- downsample=1,
- input_size=512,
- hidden_size=128,
- output_size=128,
- **kwargs
- ):
- super().__init__(
- env,
- framestack=3,
- flat_size=flat_size,
- channels_last=channels_last,
- downsample=downsample,
- input_size=input_size,
- hidden_size=hidden_size,
- output_size=output_size,
- **kwargs
- )
diff --git a/pufferlib/environments/gpudrive/__init__.py b/pufferlib/environments/gpudrive/__init__.py
deleted file mode 100644
index 59cda9e7c..000000000
--- a/pufferlib/environments/gpudrive/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/gpudrive/environment.py b/pufferlib/environments/gpudrive/environment.py
deleted file mode 100644
index 31302e65d..000000000
--- a/pufferlib/environments/gpudrive/environment.py
+++ /dev/null
@@ -1,146 +0,0 @@
-import os
-import numpy as np
-from pathlib import Path
-import torch
-import gymnasium
-
-from pygpudrive.env.config import EnvConfig, RenderConfig, SceneConfig, SelectionDiscipline
-from pygpudrive.env.env_torch import GPUDriveTorchEnv
-
-def env_creator(name='gpudrive'):
- return PufferGPUDrive
-
-class PufferGPUDrive:
- def __init__(self, device='cuda', max_cont_agents=64, num_worlds=64, k_unique_scenes=1):
- self.device = device
- self.max_cont_agents = max_cont_agents
- self.num_worlds = num_worlds
- self.k_unique_scenes = k_unique_scenes
- self.total_agents = max_cont_agents * num_worlds
-
- # Set working directory to the base directory 'gpudrive'
- working_dir = os.path.join(Path.cwd(), '../gpudrive')
- os.chdir(working_dir)
-
- scene_config = SceneConfig(
- path='biggest_file/',
- num_scenes=num_worlds,
- discipline=SelectionDiscipline.K_UNIQUE_N,
- k_unique_scenes=k_unique_scenes,
- )
-
- env_config = EnvConfig(
- steer_actions = torch.round(
- torch.linspace(-1.0, 1.0, 3), decimals=3),
- accel_actions = torch.round(
- torch.linspace(-3, 3, 3), decimals=3
- )
- )
-
- render_config = RenderConfig(
- resolution=(512, 512), # Quality of the rendered images
- )
-
- self.env = GPUDriveTorchEnv(
- config=env_config,
- scene_config=scene_config,
- render_config=render_config,
- max_cont_agents=max_cont_agents,
- device=device,
- )
-
- self.obs_size = self.env.observation_space.shape[-1]
- self.action_space = self.env.action_space
- self.observation_space = self.env.observation_space
- self.observation_space = gymnasium.spaces.Box(
- low=0, high=255, shape=(self.obs_size,), dtype=np.float32)
- self.single_observation_space = self.observation_space
- self.single_action_space = self.action_space
- self.done = False
- self.emulated = None
- self.render_mode = 'rgb_array'
- self.num_live = []
-
- self.controlled_agent_mask = self.env.cont_agent_mask.clone()
- self.obs = self.env.reset()[self.controlled_agent_mask]
- self.num_controlled = self.controlled_agent_mask.sum().item()
- self.num_agents = self.obs.shape[0]
- self.env_id = np.array([i for i in range(self.num_agents)])
- self.mask = np.ones(self.num_agents, dtype=bool)
- self.actions = torch.zeros((num_worlds, max_cont_agents),
- dtype=torch.int64).to(self.device)
-
- def _obs_and_mask(self, obs):
- #self.buf.masks[:] = self.env.cont_agent_mask.numpy().ravel() * self.live_agent_mask
- #return np.asarray(obs).reshape(NUM_WORLDS*MAX_NUM_OBJECTS, self.obs_size)
- #return obs.numpy().reshape(NUM_WORLDS*MAX_NUM_OBJECTS, self.obs_size)[:, :6]
- return obs.view(self.total_agents, self.obs_size)
-
- def close(self):
- '''There is no point in closing the env because
- Madrona doesn't close correctly anyways. You will want
- to cache this copy for later use. Cuda errors if you don't'''
- pass
- #self.env.close()
- #del self.env.sim
-
- def reset(self, seed=None, options=None):
- self.reward = torch.zeros(self.num_agents, dtype=torch.float32).to(self.device)
- self.terminal = torch.zeros(self.num_agents, dtype=torch.bool).to(self.device)
- self.truncated = torch.zeros(self.num_agents, dtype=torch.bool).to(self.device)
-
- self.episode_returns = torch.zeros(self.num_agents, dtype=torch.float32).to(self.device)
- self.episode_lengths = torch.zeros(self.num_agents, dtype=torch.float32).to(self.device)
- self.live_agent_mask = torch.ones((self.num_worlds, self.max_cont_agents), dtype=bool).to(self.device)
- return self.obs, self.reward, self.terminal, self.truncated, [], self.env_id, self.mask
-
- def step(self, action):
- action = torch.from_numpy(action).to(self.device)
- self.actions[self.controlled_agent_mask] = action
- self.env.step_dynamics(self.actions)
-
- obs = self.env.get_obs()[self.controlled_agent_mask]
- reward = self.env.get_rewards()[self.controlled_agent_mask]
- terminal = self.env.get_dones().bool()
-
- done_worlds = torch.where(
- (terminal.nan_to_num(0) * self.controlled_agent_mask).sum(dim=1)
- == self.controlled_agent_mask.sum(dim=1)
- )[0].cpu()
-
- self.episode_returns += reward
- self.episode_lengths += 1
- self.mask = self.live_agent_mask[self.controlled_agent_mask].cpu().numpy()
- self.live_agent_mask[terminal] = 0
- terminal = terminal[self.controlled_agent_mask]
-
- info = []
- self.num_live.append(self.mask.sum())
-
- if len(done_worlds) > 0:
- controlled_mask = self.controlled_agent_mask[done_worlds]
- info_tensor = self.env.get_infos()[done_worlds][controlled_mask]
- num_finished_agents = controlled_mask.sum().item()
- info.append({
- 'off_road': info_tensor[:, 0].sum().item() / num_finished_agents,
- 'veh_collisions': info_tensor[:, 1].sum().item() / num_finished_agents,
- 'non_veh_collisions': info_tensor[:, 2].sum().item() / num_finished_agents,
- 'goal_achieved': info_tensor[:, 3].sum().item() / num_finished_agents,
- 'num_finished_agents': num_finished_agents,
- 'episode_length': self.episode_lengths[done_worlds].mean().item(),
- 'mean_reward_per_episode': self.episode_returns[done_worlds].mean().item(),
- 'control_density': self.num_controlled / self.num_agents,
- 'data_density': np.mean(self.num_live) / self.num_agents,
- })
-
- self.num_live = []
- for idx in done_worlds:
- self.env.sim.reset(idx)
- self.episode_returns[idx] = 0
- self.episode_lengths[idx] = 0
- self.live_agent_mask[idx] = self.controlled_agent_mask[idx]
-
- return obs, reward, terminal, self.truncated, info, self.env_id, self.mask
-
- def render(self, world_render_idx=0):
- return self.env.render(world_render_idx=world_render_idx)
diff --git a/pufferlib/environments/gpudrive/torch.py b/pufferlib/environments/gpudrive/torch.py
deleted file mode 100644
index 5e684e507..000000000
--- a/pufferlib/environments/gpudrive/torch.py
+++ /dev/null
@@ -1,90 +0,0 @@
-from torch import nn
-import torch
-import torch.nn.functional as F
-
-from functools import partial
-import pufferlib.models
-
-from pufferlib.models import Default as Policy
-Recurrent = pufferlib.models.LSTMWrapper
-
-EGO_STATE_DIM = 6
-PARTNER_DIM = 10
-ROAD_MAP_DIM = 13
-
-MAX_CONTROLLED_VEHICLES = 32
-ROADMAP_AGENT_FEAT_DIM = MAX_CONTROLLED_VEHICLES - 1
-TOP_K_ROADPOINTS = 64 # Number of visible roadpoints from the road graph
-
-def unpack_obs(obs_flat):
- """
- Unpack the flattened observation into the ego state and visible state.
- Args:
- obs_flat (torch.Tensor): flattened observation tensor of shape (batch_size, obs_dim)
- Return:
- ego_state, road_objects, stop_signs, road_graph (torch.Tensor).
- """
- # Unpack ego and visible state
- ego_state = obs_flat[:, :EGO_STATE_DIM]
- vis_state = obs_flat[:, EGO_STATE_DIM :]
- # Visible state object order: road_objects, road_points
- # Find the ends of each section
- ro_end_idx = PARTNER_DIM * ROADMAP_AGENT_FEAT_DIM
- rg_end_idx = ro_end_idx + (ROAD_MAP_DIM * TOP_K_ROADPOINTS)
-
- # Unflatten and reshape to (batch_size, num_objects, object_dim)
- road_objects = (vis_state[:, :ro_end_idx]).reshape(
- -1, ROADMAP_AGENT_FEAT_DIM, PARTNER_DIM
- )
- road_graph = (vis_state[:, ro_end_idx:rg_end_idx]).reshape(
- -1,
- TOP_K_ROADPOINTS,
- ROAD_MAP_DIM,
- )
- return ego_state, road_objects, road_graph
-
-class Policy(nn.Module):
- def __init__(self, env, input_size=64, hidden_size=128, **kwargs):
- super().__init__()
- self.ego_embed = nn.Sequential(
- pufferlib.pytorch.layer_init(nn.Linear(EGO_STATE_DIM, input_size)),
- torch.nn.ReLU(),
- pufferlib.pytorch.layer_init(nn.Linear(input_size, input_size)),
- )
-
- self.partner_embed = nn.Sequential(
- pufferlib.pytorch.layer_init(nn.Linear(PARTNER_DIM, input_size)),
- torch.nn.ReLU(),
- pufferlib.pytorch.layer_init(nn.Linear(input_size, input_size)),
- )
-
- self.road_map_embed = nn.Sequential(
- pufferlib.pytorch.layer_init(nn.Linear(ROAD_MAP_DIM, input_size)),
- torch.nn.ReLU(),
- pufferlib.pytorch.layer_init(nn.Linear(input_size, input_size)),
- )
-
- self.proj = pufferlib.pytorch.layer_init(nn.Linear(3*input_size, hidden_size))
-
- self.actor = pufferlib.pytorch.layer_init(
- nn.Linear(hidden_size, env.single_action_space.n), std=0.01)
- self.value_fn = pufferlib.pytorch.layer_init(
- nn.Linear(hidden_size, 1), std=1)
-
- def forward(self, observations):
- hidden, lookup = self.encode_observations(observations)
- actions, value = self.decode_actions(hidden, lookup)
- return actions, value
-
- def encode_observations(self, observations):
- ego_state, road_objects, road_graph = unpack_obs(observations)
- ego_embed = self.ego_embed(ego_state)
- partner_embed, _ = self.partner_embed(road_objects).max(dim=1)
- road_map_embed, _ = self.road_map_embed(road_graph).max(dim=1)
- embed = torch.cat([ego_embed, partner_embed, road_map_embed], dim=1)
- return self.proj(embed), None
-
- def decode_actions(self, flat_hidden, lookup, concat=None):
- action = self.actor(flat_hidden)
- value = self.value_fn(flat_hidden)
- return action, value
diff --git a/pufferlib/environments/griddly/__init__.py b/pufferlib/environments/griddly/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/griddly/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/griddly/environment.py b/pufferlib/environments/griddly/environment.py
deleted file mode 100644
index fdf8c2430..000000000
--- a/pufferlib/environments/griddly/environment.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from pdb import set_trace as T
-
-import gym
-import shimmy
-import functools
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.environments
-import pufferlib.postprocess
-
-ALIASES = {
- 'spiders': 'GDY-Spiders-v0',
-}
-
-def env_creator(name='spiders'):
- return functools.partial(make, name)
-
-# TODO: fix griddly
-def make(name, buf=None):
- '''Griddly creation function
-
- Note that Griddly environments do not have observation spaces until
- they are created and reset'''
- if name in ALIASES:
- name = ALIASES[name]
-
- import warnings
- warnings.warn('Griddly has been segfaulting in the latest build and we do not know why. Submit a PR if you find a fix!')
- pufferlib.environments.try_import('griddly')
- with pufferlib.utils.Suppress():
- env = gym.make(name)
- env.reset() # Populate observation space
-
- env = shimmy.GymV21CompatibilityV0(env=env)
- env = pufferlib.postprocess.EpisodeStats(env)
- return pufferlib.emulation.GymnasiumPufferEnv(env, buf=buf)
diff --git a/pufferlib/environments/griddly/torch.py b/pufferlib/environments/griddly/torch.py
deleted file mode 100644
index 8b13194e9..000000000
--- a/pufferlib/environments/griddly/torch.py
+++ /dev/null
@@ -1 +0,0 @@
-from pufferlib.models import Default as Policy
diff --git a/pufferlib/environments/gvgai/environment.py b/pufferlib/environments/gvgai/environment.py
deleted file mode 100644
index fa4da86fd..000000000
--- a/pufferlib/environments/gvgai/environment.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from pdb import set_trace as T
-import numpy as np
-import functools
-
-import gym
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.environments
-import pufferlib.utils
-import pufferlib.postprocess
-import pufferlib.wrappers
-
-def env_creator(name='zelda'):
- if name == 'zelda':
- name = 'gvgai-zelda-lvl0-v0'
- return functools.partial(make, name)
-
-def make(name, obs_type='grayscale', frameskip=4, full_action_space=False,
- repeat_action_probability=0.0, render_mode='rgb_array', buf=None):
- '''Atari creation function'''
- pufferlib.environments.try_import('gym_gvgai')
- env = gym.make(name)
- env = pufferlib.wrappers.GymToGymnasium(env)
- env = pufferlib.postprocess.EpisodeStats(env)
- env = pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
- return env
-
diff --git a/pufferlib/environments/kinetix/__init__.py b/pufferlib/environments/kinetix/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/kinetix/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/kinetix/environment.py b/pufferlib/environments/kinetix/environment.py
deleted file mode 100644
index 116a5e12e..000000000
--- a/pufferlib/environments/kinetix/environment.py
+++ /dev/null
@@ -1,180 +0,0 @@
-import functools
-import numpy as np
-
-import pufferlib
-
-train_levels = [
- "s/h0_weak_thrust",
- "s/h7_unicycle_left",
- "s/h3_point_the_thruster",
- "s/h4_thrust_aim",
- "s/h1_thrust_over_ball",
- "s/h5_rotate_fall",
- "s/h9_explode_then_thrust_over",
- "s/h6_unicycle_right",
- "s/h8_unicycle_balance",
- "s/h2_one_wheel_car",
- "m/h0_unicycle",
- "m/h1_car_left",
- "m/h2_car_right",
- "m/h3_car_thrust",
- "m/h4_thrust_the_needle",
- "m/h5_angry_birds",
- "m/h6_thrust_over",
- "m/h7_car_flip",
- "m/h8_weird_vehicle",
- "m/h9_spin_the_right_way",
- "m/h10_thrust_right_easy",
- "m/h11_thrust_left_easy",
- "m/h12_thrustfall_left",
- "m/h13_thrustfall_right",
- "m/h14_thrustblock",
- "m/h15_thrustshoot",
- "m/h16_thrustcontrol_right",
- "m/h17_thrustcontrol_left",
- "m/h18_thrust_right_very_easy",
- "m/h19_thrust_left_very_easy",
- "m/arm_left",
- "m/arm_right",
- "m/arm_up",
- "m/arm_hard",
- "l/h0_angrybirds",
- "l/h1_car_left",
- "l/h2_car_ramp",
- "l/h3_car_right",
- "l/h4_cartpole",
- "l/h5_flappy_bird",
- "l/h6_lorry",
- "l/h7_maze_1",
- "l/h8_maze_2",
- "l/h9_morph_direction",
- "l/h10_morph_direction_2",
- "l/h11_obstacle_avoidance",
- "l/h12_platformer_1",
- "l/h13_platformer_2",
- "l/h14_simple_thruster",
- "l/h15_swing_up",
- "l/h16_thruster_goal",
- "l/h17_unicycle",
- "l/hard_beam_balance",
- "l/hard_cartpole_thrust",
- "l/hard_cartpole_wheels",
- "l/hard_lunar_lander",
- "l/hard_pinball",
- "l/grasp_hard",
- "l/grasp_easy",
- "l/mjc_half_cheetah",
- "l/mjc_half_cheetah_easy",
- "l/mjc_hopper",
- "l/mjc_hopper_easy",
- "l/mjc_swimmer",
- "l/mjc_walker",
- "l/mjc_walker_easy",
- "l/car_launch",
- "l/car_swing_around",
- "l/chain_lander",
- "l/chain_thrust",
- "l/gears",
- "l/lever_puzzle",
- "l/pr",
- "l/rail",
-]
-
-
-def env_creator(name="kinetix"):
- from kinetix.environment.env import ObservationType, ActionType
-
- _, obs, act = name.split("-")
- if obs == "symbolic": obs = "symbolic_flat"
-
- try:
- obs = ObservationType.from_string(obs)
- except ValueError:
- raise ValueError(f"Unknown observation type: {obs}.")
- try:
- act = ActionType.from_string(act)
- except ValueError:
- raise ValueError(f"Unknown action type: {act}.")
-
- return functools.partial(KinetixPufferEnv, observation_type=obs, action_type=act)
-
-
-def make(name, *args, **kwargs):
- return KinetixPufferEnv(*args, **kwargs)
-
-
-class KinetixPufferEnv(pufferlib.environment.PufferEnv):
- def __init__(self, observation_type, action_type, num_envs=1, buf=None):
-
- from kinetix.environment.env import make_kinetix_env, ObservationType, ActionType
- from kinetix.environment.env_state import EnvParams, StaticEnvParams
- from kinetix.environment.ued.ued_state import UEDParams
- from kinetix.environment.ued.ued import make_reset_fn_list_of_levels
-
- import jax
- from gymnax.environments.spaces import gymnax_space_to_gym_space
-
- self.observation_type = observation_type
- self.action_type = action_type
-
- # Use default parameters
- env_params = EnvParams()
- static_env_params = StaticEnvParams().replace()
-
- # Create the environment
- env = make_kinetix_env(
- observation_type=observation_type, # ObservationType.PIXELS,
- action_type=action_type, # ActionType.DISCRETE,
- reset_fn=make_reset_fn_list_of_levels(train_levels, static_env_params),
- env_params=env_params,
- static_env_params=static_env_params,
- )
-
- self.single_observation_space = gymnax_space_to_gym_space(env.observation_space(env_params))
- self.single_action_space = gymnax_space_to_gym_space(env.action_space(env_params))
- self.num_agents = num_envs
-
- self.env = env
-
- super().__init__(buf)
- self.env_params = env_params
- self.env = env
-
- self.reset_fn = jax.jit(jax.vmap(env.reset, in_axes=(0, None)))
- self.step_fn = jax.jit(jax.vmap(env.step, in_axes=(0, 0, 0, None)))
- self.rng = jax.random.PRNGKey(0)
-
- def reset(self, rng, params=None):
- import jax
- from torch.utils import dlpack as torch_dlpack
-
- self.rng, _rng = jax.random.split(self.rng)
- self.rngs = jax.random.split(_rng, self.num_agents)
- obs, self.state = self.reset_fn(self.rngs, params)
- obs = self._obs_to_tensor(obs)
-
- self.observations = torch_dlpack.from_dlpack(jax.dlpack.to_dlpack(obs))
- return self.observations, []
-
- def step(self, action):
- import jax
- from torch.utils import dlpack as torch_dlpack
-
- obs, self.state, reward, done, info = self.step_fn(self.rngs, self.state, action, self.env_params)
- obs = self._obs_to_tensor(obs)
-
- # Convert JAX array to DLPack, then to PyTorch tensor
- self.observations = torch_dlpack.from_dlpack(jax.dlpack.to_dlpack(obs))
- self.rewards = np.asarray(reward)
- self.terminals = np.asarray(done)
- infos = [{k: v.mean().item() for k, v in info.items()} | {"reward": self.rewards.mean()} ]
- return self.observations, self.rewards, self.terminals, self.terminals, infos
-
- def _obs_to_tensor(self, obs):
- from kinetix.environment.env import ObservationType
- if self.observation_type == ObservationType.PIXELS:
- return obs.image
- elif self.observation_type == ObservationType.SYMBOLIC_FLAT:
- return obs
- else:
- raise ValueError(f"Unknown observation type: {self.observation_type}.")
diff --git a/pufferlib/environments/kinetix/torch.py b/pufferlib/environments/kinetix/torch.py
deleted file mode 100644
index d713d3d27..000000000
--- a/pufferlib/environments/kinetix/torch.py
+++ /dev/null
@@ -1,44 +0,0 @@
-import torch
-from torch import nn
-
-import pufferlib.models
-
-Recurrent = pufferlib.models.LSTMWrapper
-
-from pufferlib.models import Default as Policy
-SymbolicPolicy = Policy
-
-class PixelsPolicy(nn.Module):
- def __init__(self, env, cnn_channels=32, hidden_size=128, **kwargs):
- super().__init__()
- self.hidden_size = 128
- self.map_encoder = nn.Sequential(
- pufferlib.pytorch.layer_init(nn.Conv2d(3, cnn_channels, 8, stride=4)),
- nn.ReLU(),
- pufferlib.pytorch.layer_init(nn.Conv2d(cnn_channels, cnn_channels, 4, stride=2)),
- nn.ReLU(),
- nn.Flatten(),
- )
- self.proj = nn.Sequential(
- pufferlib.pytorch.layer_init(nn.Linear(14 * 14 * cnn_channels, hidden_size)),
- nn.ReLU(),
- )
- self.actor = pufferlib.pytorch.layer_init(nn.Linear(hidden_size, env.single_action_space.n), std=0.01)
- self.value_fn = pufferlib.pytorch.layer_init(nn.Linear(hidden_size, 1), std=1)
-
- self.is_continuous = False
-
- def forward(self, observations):
- hidden = self.encode_observations(observations)
- actions, value = self.decode_actions(hidden)
- return actions, value
-
- def encode_observations(self, observations):
- encoded = self.map_encoder(observations.permute(0, 3, 1, 2))
- features = self.proj(encoded)
- return features
-
- def decode_actions(self, flat_hidden, concat=None):
- action = self.actor(flat_hidden)
- value = self.value_fn(flat_hidden)
- return action, value
diff --git a/pufferlib/environments/links_awaken/__init__.py b/pufferlib/environments/links_awaken/__init__.py
deleted file mode 100644
index 1a9590595..000000000
--- a/pufferlib/environments/links_awaken/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make_env
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/links_awaken/environment.py b/pufferlib/environments/links_awaken/environment.py
deleted file mode 100644
index 8016c3cf5..000000000
--- a/pufferlib/environments/links_awaken/environment.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from pdb import set_trace as T
-
-import gymnasium
-
-from links_awaken import LinksAwakenV1 as env_creator
-
-import pufferlib.emulation
-
-
-def make_env(headless: bool = True, state_path=None, buf=None):
- '''Links Awakening'''
- env = env_creator(headless=headless, state_path=state_path)
- env = gymnasium.wrappers.ResizeObservation(env, shape=(72, 80))
- return pufferlib.emulation.GymnasiumPufferEnv(env=env,
- postprocessor_cls=pufferlib.emulation.BasicPostprocessor, buf=buf)
diff --git a/pufferlib/environments/links_awaken/torch.py b/pufferlib/environments/links_awaken/torch.py
deleted file mode 100644
index 4c92d2fde..000000000
--- a/pufferlib/environments/links_awaken/torch.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import pufferlib.models
-from pufferlib.pytorch import LSTM
-
-
-class Recurrent:
- input_size = 512
- hidden_size = 512
- num_layers = 1
-
-class Policy(pufferlib.models.Convolutional):
- def __init__(self, env, input_size=512, hidden_size=512, output_size=512,
- framestack=3, flat_size=64*5*6):
- super().__init__(
- env=env,
- input_size=input_size,
- hidden_size=hidden_size,
- output_size=output_size,
- framestack=framestack,
- flat_size=flat_size,
- channels_last=True,
- )
diff --git a/pufferlib/environments/magent/__init__.py b/pufferlib/environments/magent/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/magent/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/magent/environment.py b/pufferlib/environments/magent/environment.py
deleted file mode 100644
index 10fbfc2ad..000000000
--- a/pufferlib/environments/magent/environment.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from pdb import set_trace as T
-from pettingzoo.utils.conversions import aec_to_parallel_wrapper
-import functools
-
-import pufferlib.emulation
-import pufferlib.environments
-import pufferlib.wrappers
-
-
-def env_creator(name='battle_v4'):
- return functools.partial(make, name)
- pufferlib.environments.try_import('pettingzoo.magent', 'magent')
-
-def make(name, buf=None):
- '''MAgent Battle V4 creation function'''
- if name == 'battle_v4':
- from pettingzoo.magent import battle_v4
- env_cls = battle_v4.env
- else:
- raise ValueError(f'Unknown environment name {name}')
-
- env = env_cls()
- env = aec_to_parallel_wrapper(env)
- env = pufferlib.wrappers.PettingZooTruncatedWrapper(env)
- return pufferlib.emulation.PettingZooPufferEnv(env=env, buf=buf)
diff --git a/pufferlib/environments/magent/torch.py b/pufferlib/environments/magent/torch.py
deleted file mode 100644
index eb43bcd72..000000000
--- a/pufferlib/environments/magent/torch.py
+++ /dev/null
@@ -1,41 +0,0 @@
-from torch import nn
-
-import pufferlib.models
-
-
-class Policy(pufferlib.models.Policy):
- '''Based off of the DQN policy in MAgent'''
- def __init__(self, env, hidden_size=256, output_size=256, kernel_num=32):
- '''The CleanRL default Atari policy: a stack of three convolutions followed by a linear layer
-
- Takes framestack as a mandatory keyword arguments. Suggested default is 1 frame
- with LSTM or 4 frames without.'''
- super().__init__(env)
- self.num_actions = self.action_space.n
-
- self.network = nn.Sequential(
- pufferlib.pytorch.layer_init(nn.Conv2d(5, kernel_num, 3)),
- nn.ReLU(),
- pufferlib.pytorch.layer_init(nn.Conv2d(kernel_num, kernel_num, 3)),
- nn.ReLU(),
- nn.Flatten(),
- pufferlib.pytorch.layer_init(nn.Linear(kernel_num*9*9, hidden_size)),
- nn.ReLU(),
- pufferlib.pytorch.layer_init(nn.Linear(hidden_size, hidden_size)),
- nn.ReLU(),
- )
-
- self.actor = pufferlib.pytorch.layer_init(nn.Linear(output_size, self.num_actions), std=0.01)
- self.value_function = pufferlib.pytorch.layer_init(nn.Linear(output_size, 1), std=1)
-
- def critic(self, hidden):
- return self.value_function(hidden)
-
- def encode_observations(self, observations):
- observations = observations.permute(0, 3, 1, 2)
- return self.network(observations), None
-
- def decode_actions(self, hidden, lookup):
- action = self.actor(hidden)
- value = self.value_function(hidden)
- return action, value
diff --git a/pufferlib/environments/mani_skill/__init__.py b/pufferlib/environments/mani_skill/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/mani_skill/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/mani_skill/environment.py b/pufferlib/environments/mani_skill/environment.py
deleted file mode 100644
index 1d42c5ebf..000000000
--- a/pufferlib/environments/mani_skill/environment.py
+++ /dev/null
@@ -1,118 +0,0 @@
-import functools
-import numpy as np
-from collections import defaultdict
-
-import mani_skill.envs
-from mani_skill.vector.wrappers.gymnasium import ManiSkillVectorEnv
-
-import gymnasium as gym
-import torch
-
-import pufferlib
-
-ALIASES = {
- 'mani_pickcube': 'PickCube-v1',
- 'mani_pushcube': 'PushCube-v1',
- 'mani_stackcube': 'StackCube-v1',
- 'mani_peginsertion': 'PegInsertionSide-v1',
-}
-
-def env_creator(name='PickCube-v1', **kwargs):
- return functools.partial(make, name)
-
-def make(name, num_envs=1, render_mode='rgb_array', buf=None, seed=0, **kwargs):
- '''Create an environment by name'''
-
- if name in ALIASES:
- name = ALIASES[name]
-
- return ManiPufferEnv(name, num_envs=num_envs, render_mode=render_mode, buf=buf, seed=seed, **kwargs)
-
-class ManiPufferEnv(pufferlib.PufferEnv):
- def __init__(self, name, num_envs=1, solver_position_iterations=15,
- sim_steps_per_control=5, control_freq=20, render_mode='rgb_array',
- log_interval=16, buf=None, seed=0):
- sim_freq = int(sim_steps_per_control * control_freq)
- sim_config = {
- 'scene_config': {
- 'solver_position_iterations': solver_position_iterations
- },
- 'sim_freq': sim_freq,
- 'control_freq': control_freq
- }
- self.env = gym.make(name, reward_mode='delta', num_envs=num_envs,
- render_mode=render_mode, sim_config=sim_config)
- self.env = ManiSkillVectorEnv(self.env, auto_reset=True, ignore_terminations=False, record_metrics=True)
- self.agents_per_batch = num_envs
-
- obs_space = self.env.observation_space
- self.single_observation_space = gym.spaces.Box(
- low=obs_space.low[0],
- high=obs_space.high[0],
- shape=obs_space.shape[1:],
- dtype=obs_space.dtype,
- )
-
- atn_space = self.env.action_space
- self.single_action_space = gym.spaces.Box(
- low=atn_space.low[0],
- high=atn_space.high[0],
- shape=atn_space.shape[1:],
- dtype=atn_space.dtype,
- )
-
- self.render_mode = render_mode
- self.num_agents = num_envs
- self.log_interval = log_interval
- self.tick = 0
-
- self.env_id = np.arange(num_envs)
-
- self.logs = defaultdict(list)
-
- super().__init__(buf)
-
- def _flatten_info(self, info):
- if "final_info" in info:
- mask = info["_final_info"]
- for k, v in info["final_info"]["episode"].items():
- self.logs[k].append(v[mask].float().mean().item())
-
- def reset(self, seed=0):
- obs, info = self.env.reset()
- #self.observations = torch.nan_to_num(obs)
- self.observations = torch.clamp(torch.nan_to_num(obs), -5, 5)
- self.observations = obs / 20.0
- self._flatten_info(info)
- return obs, []
-
- def step(self, actions):
- obs, reward, terminated, truncated, info = self.env.step(actions)
- collapsed = torch.where(torch.isnan(obs).sum(1) > 0)[0]
- if len(collapsed) > 0:
- obs, _ = self.env.reset(options={'env_idx': collapsed})
-
- self.observations = torch.clamp(torch.nan_to_num(obs), -5, 5)
- #self.observations = obs / 20.0 #torch.nan_to_num(obs)
- self.rewards = reward
- self.terminated = terminated
- self.truncated = truncated
- self._flatten_info(info)
-
- self.infos = []
- self.tick += 1
- if self.tick % self.log_interval == 0:
- info = {}
- for k, v in self.logs.items():
- info[k] = np.mean(v)
-
- self.logs = defaultdict(list)
- self.infos.append(info)
-
- return obs, reward, terminated, truncated, self.infos
-
- def render(self):
- return self.env.render()[0].cpu().numpy()
-
- def close(self):
- self.env.close()
diff --git a/pufferlib/environments/mani_skill/torch.py b/pufferlib/environments/mani_skill/torch.py
deleted file mode 100644
index abb8eaa18..000000000
--- a/pufferlib/environments/mani_skill/torch.py
+++ /dev/null
@@ -1,71 +0,0 @@
-import numpy as np
-
-import torch
-import torch.nn as nn
-
-import pufferlib
-from pufferlib.models import Default as Policy
-from pufferlib.models import LSTMWrapper as Recurrent
-
-class FakePolicy(nn.Module):
- '''Default PyTorch policy. Flattens obs and applies a linear layer.
-
- PufferLib is not a framework. It does not enforce a base class.
- You can use any PyTorch policy that returns actions and values.
- We structure our forward methods as encode_observations and decode_actions
- to make it easier to wrap policies with LSTMs. You can do that and use
- our LSTM wrapper or implement your own. To port an existing policy
- for use with our LSTM wrapper, simply put everything from forward() before
- the recurrent cell into encode_observations and put everything after
- into decode_actions.
- '''
- def __init__(self, env, hidden_size=256):
- super().__init__()
- self.hidden_size = hidden_size
-
- n_obs = np.prod(env.single_observation_space.shape)
- n_atn = env.single_action_space.shape[0]
- self.decoder_mean = nn.Sequential(
- pufferlib.pytorch.layer_init(nn.Linear(n_obs, 256)),
- nn.Tanh(),
- pufferlib.pytorch.layer_init(nn.Linear(256, 256)),
- nn.Tanh(),
- pufferlib.pytorch.layer_init(nn.Linear(256, 256)),
- nn.Tanh(),
- pufferlib.pytorch.layer_init(nn.Linear(256, n_atn), std=0.01),
- )
- self.decoder_logstd = nn.Parameter(torch.zeros(
- 1, env.single_action_space.shape[0]))
-
- self.value = nn.Sequential(
- pufferlib.pytorch.layer_init(nn.Linear(n_obs, 256)),
- nn.Tanh(),
- pufferlib.pytorch.layer_init(nn.Linear(256, 256)),
- nn.Tanh(),
- pufferlib.pytorch.layer_init(nn.Linear(256, 256)),
- nn.Tanh(),
- pufferlib.pytorch.layer_init(nn.Linear(256, 1), std=1),
- )
-
- def forward_eval(self, observations, state=None):
- hidden = self.encode_observations(observations, state=state)
- logits, values = self.decode_actions(hidden)
- return logits, values
-
- def forward(self, observations, state=None):
- return self.forward_eval(observations, state)
-
- def encode_observations(self, observations, state=None):
- '''Encodes a batch of observations into hidden states. Assumes
- no time dimension (handled by LSTM wrappers).'''
- return observations
-
- def decode_actions(self, hidden):
- '''Decodes a batch of hidden states into (multi)discrete actions.
- Assumes no time dimension (handled by LSTM wrappers).'''
- mean = self.decoder_mean(hidden)
- logstd = self.decoder_logstd.expand_as(mean)
- std = torch.exp(logstd)
- logits = torch.distributions.Normal(mean, std)
- values = self.value(hidden)
- return logits, values
diff --git a/pufferlib/environments/metta/__init__.py b/pufferlib/environments/metta/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/metta/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/metta/environment.py b/pufferlib/environments/metta/environment.py
deleted file mode 100644
index 21acc4610..000000000
--- a/pufferlib/environments/metta/environment.py
+++ /dev/null
@@ -1,74 +0,0 @@
-import functools
-import numpy as np
-import gymnasium
-
-import pufferlib
-
-from omegaconf import OmegaConf
-from metta.mettagrid.mettagrid_env import MettaGridEnv
-from metta.mettagrid.curriculum.core import SingleTaskCurriculum
-from metta.mettagrid.replay_writer import ReplayWriter
-
-def env_creator(name='metta'):
- return functools.partial(make, name)
-
-def make(name, config='pufferlib/environments/metta/metta.yaml', render_mode='auto', buf=None, seed=0,
- ore_reward=0.17088483842567775, battery_reward=0.9882859711234822, heart_reward=1.0):
- '''Metta creation function'''
-
- OmegaConf.register_new_resolver("div", oc_divide, replace=True)
- cfg = OmegaConf.load(config)
-
- # Update rewards under the new structure: agent.rewards.inventory
- inventory_rewards = cfg['game']['agent']['rewards']['inventory']
- inventory_rewards['ore_red'] = float(ore_reward)
- inventory_rewards['heart'] = float(heart_reward)
- inventory_rewards['battery_red'] = float(battery_reward)
-
- curriculum = SingleTaskCurriculum('puffer', cfg)
- return MettaPuff(curriculum, render_mode=render_mode, buf=buf, seed=seed)
-
-def oc_divide(a, b):
- """
- Divide a by b, returning an int if both inputs are ints and result is a whole number,
- otherwise return a float.
- """
- result = a / b
- # If both inputs are integers and the result is a whole number, return as int
- if isinstance(a, int) and isinstance(b, int) and result.is_integer():
- return int(result)
- return result
-
-class MettaPuff(MettaGridEnv):
- def __init__(self, curriculum, render_mode='human', buf=None, seed=0):
- self.replay_writer = None
- #if render_mode == 'auto':
- # self.replay_writer = ReplayWriter("metta/")
-
- super().__init__(
- curriculum=curriculum,
- render_mode=render_mode,
- buf=buf,
- replay_writer=self.replay_writer
- )
- self.action_space = pufferlib.spaces.joint_space(self.single_action_space, self.num_agents)
- self.actions = self.actions.astype(np.int32)
-
- @property
- def single_action_space(self):
- return gymnasium.spaces.MultiDiscrete(super().single_action_space.nvec, dtype=np.int32)
-
- def step(self, actions):
- obs, rew, term, trunc, info = super().step(actions)
-
- if all(term) or all(trunc):
- self.reset()
- if 'agent_raw' in info:
- del info['agent_raw']
- if 'episode_rewards' in info:
- info['score'] = info['episode_rewards']
-
- else:
- info = []
-
- return obs, rew, term, trunc, [info]
diff --git a/pufferlib/environments/metta/metta.yaml b/pufferlib/environments/metta/metta.yaml
deleted file mode 100644
index 6d66806fc..000000000
--- a/pufferlib/environments/metta/metta.yaml
+++ /dev/null
@@ -1,251 +0,0 @@
-name: "GDY-MettaGrid"
-
-report_stats_interval: 100
-normalize_rewards: false
-
-sampling: 0
-desync_episodes: true
-
-game:
- # Required list of inventory items
- inventory_item_names:
- - ore_red
- - ore_blue
- - ore_green
- - battery_red
- - battery_blue
- - battery_green
- - heart
- - armor
- - laser
- - blueprint
-
- num_agents: 64
- obs_width: 11
- obs_height: 11
- num_observation_tokens: 200
- max_steps: 1000
-
- # Global observation tokens configuration
- global_obs:
- episode_completion_pct: true
- last_action: true
- last_reward: true
- resource_rewards: false
-
- # Show recipe inputs in observations for all converters
- recipe_details_obs: false
-
- agent:
- default_resource_limit: 10
- resource_limits:
- heart: 255
- freeze_duration: 10
- action_failure_penalty: 0.0
-
- rewards:
- inventory:
- heart: 1
- stats: {}
-
- groups:
- agent:
- id: 0
- sprite: 0
- props: {}
-
- objects:
- altar:
- type_id: 8
- input_resources:
- battery_red: 3
- output_resources:
- heart: 1
- max_output: 5
- conversion_ticks: 1
- cooldown: 10
- initial_resource_count: 0
-
- wall:
- type_id: 1
- swappable: false
-
- block:
- type_id: 14
- swappable: true
-
- mine_red:
- type_id: 2
- output_resources:
- ore_red: 1
- color: 0
- max_output: 5
- conversion_ticks: 1
- cooldown: 50
- initial_resource_count: 0
-
- mine_blue:
- type_id: 3
- color: 1
- output_resources:
- ore_blue: 1
- max_output: 5
- conversion_ticks: 1
- cooldown: 50
- initial_resource_count: 0
-
- mine_green:
- type_id: 4
- output_resources:
- ore_green: 1
- color: 2
- max_output: 5
- conversion_ticks: 1
- cooldown: 50
- initial_resource_count: 0
-
- generator_red:
- type_id: 5
- input_resources:
- ore_red: 1
- output_resources:
- battery_red: 1
- color: 0
- max_output: 5
- conversion_ticks: 1
- cooldown: 25
- initial_resource_count: 0
-
- generator_blue:
- type_id: 6
- input_resources:
- ore_blue: 1
- output_resources:
- battery_blue: 1
- color: 1
- max_output: 5
- conversion_ticks: 1
- cooldown: 25
- initial_resource_count: 0
-
- generator_green:
- type_id: 7
- input_resources:
- ore_green: 1
- output_resources:
- battery_green: 1
- color: 2
- max_output: 5
- conversion_ticks: 1
- cooldown: 25
- initial_resource_count: 0
-
- armory:
- type_id: 9
- input_resources:
- ore_red: 3
- output_resources:
- armor: 1
- max_output: 5
- conversion_ticks: 1
- cooldown: 10
- initial_resource_count: 0
-
- lasery:
- type_id: 10
- input_resources:
- ore_red: 1
- battery_red: 2
- output_resources:
- laser: 1
- max_output: 5
- conversion_ticks: 1
- cooldown: 10
- initial_resource_count: 0
-
- lab:
- type_id: 11
- input_resources:
- ore_red: 3
- battery_red: 3
- output_resources:
- blueprint: 1
- max_output: 5
- conversion_ticks: 1
- cooldown: 5
- initial_resource_count: 0
-
- factory:
- type_id: 12
- input_resources:
- blueprint: 1
- ore_red: 5
- battery_red: 5
- output_resources:
- armor: 5
- laser: 5
- max_output: 5
- conversion_ticks: 1
- cooldown: 5
- initial_resource_count: 0
-
- temple:
- type_id: 13
- input_resources:
- heart: 1
- blueprint: 1
- output_resources:
- heart: 5
- max_output: 5
- conversion_ticks: 1
- cooldown: 5
- initial_resource_count: 0
-
- actions:
- noop:
- enabled: true
- move:
- enabled: true
- rotate:
- enabled: true
- put_items:
- enabled: true
- get_items:
- enabled: true
- attack:
- enabled: true
- consumed_resources:
- laser: 1
- defense_resources:
- armor: 1
- swap:
- enabled: true
- change_color:
- enabled: false
- change_glyph:
- enabled: false
- number_of_glyphs: 4
-
- map_builder:
- _target_: metta.mettagrid.room.multi_room.MultiRoom
- num_rooms: 1
- border_width: 6
-
- room:
- _target_: metta.mettagrid.room.random.Random
- width: 64
- height: 64
- border_width: 0
-
- agents: 64
-
- objects:
- mine_red: 128
- generator_red: 64
- altar: 32
- armory: 0
- lasery: 0
- lab: 0
- factory: 0
- temple: 0
- wall: 0
diff --git a/pufferlib/environments/metta/torch.py b/pufferlib/environments/metta/torch.py
deleted file mode 100644
index 62aa4be3a..000000000
--- a/pufferlib/environments/metta/torch.py
+++ /dev/null
@@ -1,119 +0,0 @@
-import numpy as np
-import einops
-import torch
-from torch import nn
-from torch.nn import functional as F
-
-import pufferlib.models
-
-class Recurrent(pufferlib.models.LSTMWrapper):
- def __init__(self, env, policy, input_size=512, hidden_size=512):
- super().__init__(env, policy, input_size, hidden_size)
-
-class Policy(nn.Module):
- def __init__(self, env, cnn_channels=128, hidden_size=512, **kwargs):
- super().__init__()
- self.hidden_size = hidden_size
- self.is_continuous = False
-
- self.out_width = 11
- self.out_height = 11
- self.num_layers = 22
-
- self.network= nn.Sequential(
- pufferlib.pytorch.layer_init(
- nn.Conv2d(self.num_layers, cnn_channels, 5, stride=3)),
- nn.ReLU(),
- pufferlib.pytorch.layer_init(
- nn.Conv2d(cnn_channels, cnn_channels, 3, stride=1)),
- nn.ReLU(),
- nn.Flatten(),
- pufferlib.pytorch.layer_init(nn.Linear(cnn_channels, hidden_size//2)),
- nn.ReLU(),
- )
-
- self.self_encoder = nn.Sequential(
- pufferlib.pytorch.layer_init(nn.Linear(self.num_layers, hidden_size//2)),
- nn.ReLU(),
- )
-
- #max_vec = torch.tensor([ 1., 9., 1., 30., 1., 3., 255., 26., 1., 1., 1., 1.,
- # 1., 47., 3., 3., 2., 1., 1., 1., 1., 1.])[None, :, None, None]
- max_vec = torch.tensor([9., 1., 1., 10., 3., 254., 1., 1., 235., 8., 9., 250., 29., 1., 1., 8., 1., 1., 6., 3., 1., 2.])[None, :, None, None]
- #max_vec = torch.ones(22)[None, :, None, None]
- self.register_buffer('max_vec', max_vec)
-
- action_nvec = env.single_action_space.nvec
- self.actor = nn.ModuleList([pufferlib.pytorch.layer_init(
- nn.Linear(hidden_size, n), std=0.01) for n in action_nvec])
-
- self.value = pufferlib.pytorch.layer_init(
- nn.Linear(hidden_size, 1), std=1)
-
- def forward(self, observations, state=None):
- hidden, lookup = self.encode_observations(observations)
- actions, value = self.decode_actions(hidden, lookup)
- return (actions, value), hidden
-
- def encode_observations(self, observations, state=None):
-
- token_observations = observations
- B = token_observations.shape[0]
- TT = 1
- if token_observations.dim() != 3: # hardcoding for shape [B, M, 3]
- TT = token_observations.shape[1]
- token_observations = einops.rearrange(token_observations, "b t m c -> (b t) m c")
-
- assert token_observations.shape[-1] == 3, f"Expected 3 channels per token. Got shape {token_observations.shape}"
- token_observations[token_observations == 255] = 0
-
- # coords_byte contains x and y coordinates in a single byte (first 4 bits are x, last 4 bits are y)
- coords_byte = token_observations[..., 0].to(torch.uint8)
-
- # Extract x and y coordinate indices (0-15 range, but we need to make them long for indexing)
- x_coord_indices = ((coords_byte >> 4) & 0x0F).long() # Shape: [B_TT, M]
- y_coord_indices = (coords_byte & 0x0F).long() # Shape: [B_TT, M]
- atr_indices = token_observations[..., 1].long() # Shape: [B_TT, M], ready for embedding
- atr_values = token_observations[..., 2].float() # Shape: [B_TT, M]
-
- # In ObservationShaper we permute. Here, we create the observations pre-permuted.
- # We'd like to pre-create this as part of initialization, but we don't know the batch size or time steps at
- # that point.
- box_obs = torch.zeros(
- (B * TT, 22, self.out_width, self.out_height),
- dtype=atr_values.dtype,
- device=token_observations.device,
- )
- batch_indices = torch.arange(B * TT, device=token_observations.device).unsqueeze(-1).expand_as(atr_values)
-
- # Add bounds checking to prevent out-of-bounds access
- valid_tokens = coords_byte != 0xFF
- valid_tokens = valid_tokens & (x_coord_indices < self.out_width) & (y_coord_indices < self.out_height)
- valid_tokens = valid_tokens & (atr_indices < 22) # Also check attribute indices
-
- box_obs[
- batch_indices[valid_tokens],
- atr_indices[valid_tokens],
- x_coord_indices[valid_tokens],
- y_coord_indices[valid_tokens],
- ] = atr_values[valid_tokens]
-
- observations = box_obs
-
- #max_vec = box_obs.max(0)[0].max(1)[0].max(1)[0]
- #self.max_vec = torch.maximum(self.max_vec, max_vec[None, :, None, None])
- #if (np.random.rand() < 0.001):
- # breakpoint()
-
- features = observations / self.max_vec
- #mmax = features.max(0)[0].max(1)[0].max(1)[0]
- #self.max_vec = torch.maximum(self.max_vec, mmax[None, :, None, None])
- self_features = self.self_encoder(features[:, :, 5, 5])
- cnn_features = self.network(features)
- return torch.cat([self_features, cnn_features], dim=1)
-
- def decode_actions(self, hidden):
- #hidden = self.layer_norm(hidden)
- logits = [dec(hidden) for dec in self.actor]
- value = self.value(hidden)
- return logits, value
diff --git a/pufferlib/environments/microrts/__init__.py b/pufferlib/environments/microrts/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/microrts/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/microrts/environment.py b/pufferlib/environments/microrts/environment.py
deleted file mode 100644
index 6c00f4d52..000000000
--- a/pufferlib/environments/microrts/environment.py
+++ /dev/null
@@ -1,50 +0,0 @@
-from pdb import set_trace as T
-import numpy as np
-
-import warnings
-import shimmy
-import functools
-
-import pufferlib.emulation
-import pufferlib.environments
-
-
-def env_creator(name='GlobalAgentCombinedRewardEnv'):
- return functools.partial(make, name)
-
-def make(name, buf=None):
- '''Gym MicroRTS creation function
-
- This library appears broken. Step crashes in Java.
- '''
- pufferlib.environments.try_import('gym_microrts')
- if name == 'GlobalAgentCombinedRewardEnv':
- from gym_microrts.envs import GlobalAgentCombinedRewardEnv
- else:
- raise ValueError(f'Unknown environment: {name}')
-
- with pufferlib.utils.Suppress():
- return GlobalAgentCombinedRewardEnv()
-
- env.reset = pufferlib.utils.silence_warnings(env.reset)
- env.step = pufferlib.utils.silence_warnings(env.step)
-
- env = MicroRTS(env)
- env = shimmy.GymV21CompatibilityV0(env=env)
- return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
-
-class MicroRTS:
- def __init__(self, env):
- self.env = env
- self.observation_space = self.env.observation_space
- self.action_space = self.env.action_space
- self.render = self.env.render
- self.close = self.env.close
- self.seed = self.env.seed
-
- def reset(self):
- return self.env.reset().astype(np.int32)
-
- def step(self, action):
- o, r, d, i = self.env.step(action)
- return o.astype(np.int32), r, d, i
diff --git a/pufferlib/environments/microrts/torch.py b/pufferlib/environments/microrts/torch.py
deleted file mode 100644
index 8b13194e9..000000000
--- a/pufferlib/environments/microrts/torch.py
+++ /dev/null
@@ -1 +0,0 @@
-from pufferlib.models import Default as Policy
diff --git a/pufferlib/environments/minerl/__init__.py b/pufferlib/environments/minerl/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/minerl/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/minerl/environment.py b/pufferlib/environments/minerl/environment.py
deleted file mode 100644
index 771c3c600..000000000
--- a/pufferlib/environments/minerl/environment.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from pdb import set_trace as T
-
-import gym
-import shimmy
-import functools
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.environments
-import pufferlib.utils
-
-
-def env_creator(name='MineRLBasaltFindCave-v0'):
- return functools.partial(make, name=name)
-
-def make(name, buf=None):
- '''Minecraft environment creation function'''
-
- pufferlib.environments.try_import('minerl')
-
- # Monkey patch to add .itmes to old gym.spaces.Dict
- #gym.spaces.Dict.items = lambda self: self.spaces.items()
-
- #with pufferlib.utils.Suppress():
- env = gym.make(name)
-
- env = shimmy.GymV21CompatibilityV0(env=env)
- return pufferlib.emulation.GymnasiumPufferEnv(env, buf=buf)
diff --git a/pufferlib/environments/minerl/torch.py b/pufferlib/environments/minerl/torch.py
deleted file mode 100644
index 8b13194e9..000000000
--- a/pufferlib/environments/minerl/torch.py
+++ /dev/null
@@ -1 +0,0 @@
-from pufferlib.models import Default as Policy
diff --git a/pufferlib/environments/minigrid/__init__.py b/pufferlib/environments/minigrid/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/minigrid/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/minigrid/environment.py b/pufferlib/environments/minigrid/environment.py
deleted file mode 100644
index 2bf373b7e..000000000
--- a/pufferlib/environments/minigrid/environment.py
+++ /dev/null
@@ -1,54 +0,0 @@
-from pdb import set_trace as T
-
-import gymnasium
-import functools
-
-import pufferlib.emulation
-import pufferlib.environments
-
-ALIASES = {
- 'minigrid': 'MiniGrid-LavaGapS7-v0',
-}
-
-
-def env_creator(name='minigrid'):
- return functools.partial(make, name=name)
-
-def make(name, render_mode='rgb_array', buf=None, seed=0):
- if name in ALIASES:
- name = ALIASES[name]
-
- minigrid = pufferlib.environments.try_import('minigrid')
- env = gymnasium.make(name, render_mode=render_mode)
- env = MiniGridWrapper(env)
- env = pufferlib.EpisodeStats(env)
- return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
-
-class MiniGridWrapper:
- def __init__(self, env):
- self.env = env
- self.observation_space = gymnasium.spaces.Dict({
- k: v for k, v in self.env.observation_space.items() if
- k != 'mission'
- })
- self.action_space = self.env.action_space
- self.close = self.env.close
- self.render = self.env.render
- self.close = self.env.close
- self.render_mode = 'rgb_array'
-
- def reset(self, seed=None, options=None):
- self.tick = 0
- obs, info = self.env.reset(seed=seed)
- del obs['mission']
- return obs, info
-
- def step(self, action):
- obs, reward, done, truncated, info = self.env.step(action)
- del obs['mission']
-
- self.tick += 1
- if self.tick == 100:
- done = True
-
- return obs, reward, done, truncated, info
diff --git a/pufferlib/environments/minigrid/torch.py b/pufferlib/environments/minigrid/torch.py
deleted file mode 100644
index 8b13194e9..000000000
--- a/pufferlib/environments/minigrid/torch.py
+++ /dev/null
@@ -1 +0,0 @@
-from pufferlib.models import Default as Policy
diff --git a/pufferlib/environments/minihack/__init__.py b/pufferlib/environments/minihack/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/minihack/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/minihack/environment.py b/pufferlib/environments/minihack/environment.py
deleted file mode 100644
index d70ea03d5..000000000
--- a/pufferlib/environments/minihack/environment.py
+++ /dev/null
@@ -1,62 +0,0 @@
-from pdb import set_trace as T
-
-import gym
-import shimmy
-import functools
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.environments
-
-
-EXTRA_OBS_KEYS = [
- 'tty_chars',
- 'tty_colors',
- 'tty_cursor',
-]
-
-ALIASES = {
- 'minihack': 'MiniHack-River-v0',
-}
-
-def env_creator(name='minihack'):
- return functools.partial(make, name)
-
-def make(name, buf=None, seed=0):
- '''NetHack binding creation function'''
- if name in ALIASES:
- name = ALIASES[name]
-
- import minihack
- pufferlib.environments.try_import('minihack')
- obs_key = minihack.base.MH_DEFAULT_OBS_KEYS + EXTRA_OBS_KEYS
- env = gym.make(name, observation_keys=obs_key)
- env = shimmy.GymV21CompatibilityV0(env=env)
- env = MinihackWrapper(env)
- return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
-
-class MinihackWrapper:
- def __init__(self, env):
- self.env = env
- self.observation_space = self.env.observation_space
- self.action_space = self.env.action_space
- self.close = self.env.close
- self.close = self.env.close
- self.render_mode = 'ansi'
-
- def reset(self, seed=None):
- obs, info = self.env.reset(seed=seed)
- self.obs = obs
- return obs, info
-
- def step(self, action):
- obs, reward, done, truncated, info = self.env.step(action)
- self.obs = obs
- return obs, reward, done, truncated, info
-
- def render(self):
- import nle
- chars = nle.nethack.tty_render(
- self.obs['tty_chars'], self.obs['tty_colors'], self.obs['tty_cursor'])
- return chars
-
diff --git a/pufferlib/environments/minihack/torch.py b/pufferlib/environments/minihack/torch.py
deleted file mode 100644
index 7781cb677..000000000
--- a/pufferlib/environments/minihack/torch.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from pdb import set_trace as T
-
-import pufferlib.pytorch
-from pufferlib.environments.nethack import Policy
-
-class Recurrent(pufferlib.models.LSTMWrapper):
- def __init__(self, env, policy, input_size=512, hidden_size=512, num_layers=1):
- super().__init__(env, policy, input_size, hidden_size, num_layers)
diff --git a/pufferlib/environments/mujoco/__init__.py b/pufferlib/environments/mujoco/__init__.py
deleted file mode 100644
index 1c91a2b0f..000000000
--- a/pufferlib/environments/mujoco/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import *
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/mujoco/environment.py b/pufferlib/environments/mujoco/environment.py
deleted file mode 100644
index f9adad9f8..000000000
--- a/pufferlib/environments/mujoco/environment.py
+++ /dev/null
@@ -1,59 +0,0 @@
-
-from pdb import set_trace as T
-
-import functools
-
-import numpy as np
-import gymnasium
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.environments
-
-
-def single_env_creator(env_name, capture_video, gamma,
- run_name=None, idx=None, obs_norm=True, pufferl=False, render_mode='rgb_array', buf=None, seed=0):
- if capture_video and idx == 0:
- assert run_name is not None, "run_name must be specified when capturing videos"
- env = gymnasium.make(env_name, render_mode="rgb_array")
- env = gymnasium.wrappers.RecordVideo(env, f"videos/{run_name}")
- else:
- env = gymnasium.make(env_name, render_mode=render_mode)
-
- env = pufferlib.ClipAction(env) # NOTE: this changed actions space
- env = pufferlib.EpisodeStats(env)
-
- if obs_norm:
- env = gymnasium.wrappers.NormalizeObservation(env)
- env = gymnasium.wrappers.TransformObservation(env, lambda obs: np.clip(obs, -10, 10), env.observation_space)
-
- env = gymnasium.wrappers.NormalizeReward(env, gamma=gamma)
- env = gymnasium.wrappers.TransformReward(env, lambda reward: np.clip(reward, -10, 10))
-
- if pufferl is True:
- env = pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
-
- return env
-
-
-def cleanrl_env_creator(env_name, run_name, capture_video, gamma, idx):
- kwargs = {
- "env_name": env_name,
- "run_name": run_name,
- "capture_video": capture_video,
- "gamma": gamma,
- "idx": idx,
- "pufferl": False,
- }
- return functools.partial(single_env_creator, **kwargs)
-
-
-# Keep it simple for pufferl demo, for now
-def env_creator(env_name="HalfCheetah-v4", gamma=0.99):
- default_kwargs = {
- "env_name": env_name,
- "capture_video": False,
- "gamma": gamma,
- "pufferl": True,
- }
- return functools.partial(single_env_creator, **default_kwargs)
diff --git a/pufferlib/environments/mujoco/torch.py b/pufferlib/environments/mujoco/torch.py
deleted file mode 100644
index aca09b55d..000000000
--- a/pufferlib/environments/mujoco/torch.py
+++ /dev/null
@@ -1,3 +0,0 @@
-
-from pufferlib.models import LSTMWrapper as Recurrent
-from pufferlib.models import Default as Policy
diff --git a/pufferlib/environments/nethack/Hack-Regular.ttf b/pufferlib/environments/nethack/Hack-Regular.ttf
deleted file mode 100644
index 097db1814..000000000
Binary files a/pufferlib/environments/nethack/Hack-Regular.ttf and /dev/null differ
diff --git a/pufferlib/environments/nethack/__init__.py b/pufferlib/environments/nethack/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/nethack/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/nethack/environment.py b/pufferlib/environments/nethack/environment.py
deleted file mode 100644
index 3bda89f9b..000000000
--- a/pufferlib/environments/nethack/environment.py
+++ /dev/null
@@ -1,51 +0,0 @@
-from pdb import set_trace as T
-
-import shimmy
-import gym
-import functools
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.environments
-#from .wrapper import RenderCharImagesWithNumpyWrapper
-
-def env_creator(name='nethack'):
- return functools.partial(make, name)
-
-def make(name, buf=None, seed=0):
- '''NetHack binding creation function'''
- if name == 'nethack':
- name = 'NetHackScore-v0'
-
- nle = pufferlib.environments.try_import('nle')
- env = gym.make(name)
- #env = RenderCharImagesWithNumpyWrapper(env)
- env = shimmy.GymV21CompatibilityV0(env=env)
- env = NethackWrapper(env)
- env = pufferlib.EpisodeStats(env)
- return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
-
-class NethackWrapper:
- def __init__(self, env):
- self.env = env
- self.observation_space = self.env.observation_space
- self.action_space = self.env.action_space
- self.close = self.env.close
- self.close = self.env.close
- self.render_mode = 'ansi'
-
- def reset(self, seed=None):
- obs, info = self.env.reset(seed=seed)
- self.obs = obs
- return obs, info
-
- def step(self, action):
- obs, reward, done, truncated, info = self.env.step(action)
- self.obs = obs
- return obs, reward, done, truncated, info
-
- def render(self):
- import nle
- chars = nle.nethack.tty_render(
- self.obs['tty_chars'], self.obs['tty_colors'], self.obs['tty_cursor'])
- return chars
diff --git a/pufferlib/environments/nethack/torch.py b/pufferlib/environments/nethack/torch.py
deleted file mode 100644
index 4530f06a9..000000000
--- a/pufferlib/environments/nethack/torch.py
+++ /dev/null
@@ -1,68 +0,0 @@
-from pdb import set_trace as T
-
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-
-import pufferlib.models
-import pufferlib.pytorch
-from pufferlib.pytorch import layer_init
-
-
-class Recurrent(pufferlib.models.LSTMWrapper):
- def __init__(self, env, policy, input_size=256, hidden_size=256, num_layers=1):
- super().__init__(env, policy, input_size, hidden_size, num_layers)
-
-class Policy(nn.Module):
- def __init__(self, env):
- super().__init__()
- self.dtype = pufferlib.pytorch.nativize_dtype(env.emulated)
-
- self.blstats_net = nn.Sequential(
- nn.Embedding(256, 32),
- nn.Flatten(),
- )
-
- self.char_embed = nn.Embedding(256, 32)
- self.chars_net = nn.Sequential(
- layer_init(nn.Conv2d(32, 32, 5, stride=(2, 3))),
- nn.ReLU(),
- layer_init(nn.Conv2d(32, 64, 5, stride=(1, 3))),
- nn.ReLU(),
- layer_init(nn.Conv2d(64, 64, 3, stride=1)),
- nn.ReLU(),
- nn.Flatten(),
- )
-
- self.proj = nn.Linear(864+960, 256)
- self.actor = layer_init(nn.Linear(256, 8), std=0.01)
- self.critic = layer_init(nn.Linear(256, 1), std=1)
-
- def forward(self, x, state=None):
- hidden = self.encode_observations(x)
- actions, value = self.decode_actions(hidden)
- return actions, value
-
- def forward_train(self, x, state=None):
- hidden = self.encode_observations(x)
- actions, value = self.decode_actions(hidden)
- return actions, value
-
- def encode_observations(self, x):
- x = x.type(torch.uint8) # Undo bad cleanrl cast
- x = pufferlib.pytorch.nativize_tensor(x, self.dtype)
-
- blstats = torch.clip(x['blstats'] + 1, 0, 255).int()
- blstats = self.blstats_net(blstats)
-
- chars = self.char_embed(x['chars'].int())
- chars = torch.permute(chars, (0, 3, 1, 2))
- chars = self.chars_net(chars)
-
- concat = torch.cat([blstats, chars], dim=1)
- return self.proj(concat)
-
- def decode_actions(self, hidden):
- value = self.critic(hidden)
- action = self.actor(hidden)
- return action, value
diff --git a/pufferlib/environments/nethack/wrapper.py b/pufferlib/environments/nethack/wrapper.py
deleted file mode 100644
index 17781a6ac..000000000
--- a/pufferlib/environments/nethack/wrapper.py
+++ /dev/null
@@ -1,306 +0,0 @@
-"""Taken & adapted from Chaos Dwarf in Nethack Challenge Starter Kit:
-https://github.com/Miffyli/nle-sample-factory-baseline
-
-
-MIT License
-
-Copyright (c) 2021 Anssi
-
-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 cv2
-import gym
-import numpy as np
-from numba import njit
-from nle import nethack
-from PIL import Image
-from PIL import ImageDraw
-from PIL import ImageFont
-
-#import render_utils
-
-SMALL_FONT_PATH = os.path.join(__package__.replace(".", "/"), "Hack-Regular.ttf")
-
-# Mapping of 0-15 colors used.
-# Taken from bottom image here. It seems about right
-# https://i.stack.imgur.com/UQVe5.png
-COLORS = [
- "#000000",
- "#800000",
- "#008000",
- "#808000",
- "#000080",
- "#800080",
- "#008080",
- "#808080", # - flipped these ones around
- "#C0C0C0", # | the gray-out dull stuff
- "#FF0000",
- "#00FF00",
- "#FFFF00",
- "#0000FF",
- "#FF00FF",
- "#00FFFF",
- "#FFFFFF",
-]
-
-
-@njit
-def _tile_characters_to_image(
- out_image,
- chars,
- colors,
- output_height_chars,
- output_width_chars,
- char_array,
- offset_h,
- offset_w,
-):
- """
- Build an image using cached images of characters in char_array to out_image
- """
- char_height = char_array.shape[3]
- char_width = char_array.shape[4]
- for h in range(output_height_chars):
- h_char = h + offset_h
- # Stuff outside boundaries is not visible, so
- # just leave it black
- if h_char < 0 or h_char >= chars.shape[0]:
- continue
- for w in range(output_width_chars):
- w_char = w + offset_w
- if w_char < 0 or w_char >= chars.shape[1]:
- continue
- char = chars[h_char, w_char]
- color = colors[h_char, w_char]
- h_pixel = h * char_height
- w_pixel = w * char_width
- out_image[
- :, h_pixel : h_pixel + char_height, w_pixel : w_pixel + char_width
- ] = char_array[char, color]
-
-
-def _initialize_char_array(font_size, rescale_font_size):
- """Draw all characters in PIL and cache them in numpy arrays
-
- if rescale_font_size is given, assume it is (width, height)
-
- Returns a np array of (num_chars, num_colors, char_height, char_width, 3)
- """
- font = ImageFont.truetype(SMALL_FONT_PATH, font_size)
- dummy_text = "".join(
- [(chr(i) if chr(i).isprintable() else " ") for i in range(256)]
- )
- _, _, image_width, image_height = font.getbbox(dummy_text)
- # Above can not be trusted (or its siblings)....
- image_width = int(np.ceil(image_width / 256) * 256)
-
- char_width = rescale_font_size[0]
- char_height = rescale_font_size[1]
-
- char_array = np.zeros((256, 16, char_height, char_width, 3), dtype=np.uint8)
- image = Image.new("RGB", (image_width, image_height))
- image_draw = ImageDraw.Draw(image)
- for color_index in range(16):
- image_draw.rectangle((0, 0, image_width, image_height), fill=(0, 0, 0))
- image_draw.text((0, 0), dummy_text, fill=COLORS[color_index], spacing=0)
-
- arr = np.array(image).copy()
- arrs = np.array_split(arr, 256, axis=1)
- for char_index in range(256):
- char = arrs[char_index]
- if rescale_font_size:
- char = cv2.resize(char, rescale_font_size, interpolation=cv2.INTER_AREA)
- char_array[char_index, color_index] = char
- return char_array
-
-
-class RenderCharImagesWithNumpyWrapper(gym.Wrapper):
- """
- Render characters as images, using PIL to render characters like we humans see on screen
- but then some caching and numpy stuff to speed up things.
-
- To speed things up, crop image around the player.
- """
-
- def __init__(
- self,
- env,
- font_size=9,
- crop_size=12,
- rescale_font_size=(6, 6),
- blstats_cursor=False,
- ):
- super().__init__(env)
- self.char_array = _initialize_char_array(font_size, rescale_font_size)
- self.char_height = self.char_array.shape[2]
- self.char_width = self.char_array.shape[3]
- # Transpose for CHW
- self.char_array = self.char_array.transpose(0, 1, 4, 2, 3)
-
- self.crop_size = crop_size
- self.blstats_cursor = blstats_cursor
-
- self.half_crop_size = crop_size // 2
- self.output_height_chars = crop_size
- self.output_width_chars = crop_size
- self.chw_image_shape = (
- 3,
- self.output_height_chars * self.char_height,
- self.output_width_chars * self.char_width,
- )
-
- self.observation_space = gym.spaces.Box(
- low=0, high=255, shape=self.chw_image_shape, dtype=np.uint8
- )
-
- '''
- obs_spaces = {
- "screen_image": gym.spaces.Box(
- low=0, high=255, shape=self.chw_image_shape, dtype=np.uint8
- )
- }
- obs_spaces.update(
- [
- (k, self.env.observation_space[k])
- for k in self.env.observation_space
- if k not in ["tty_chars", "tty_colors"]
- ]
- )
- self.observation_space = gym.spaces.Dict(obs_spaces)
- '''
-
- self.render_mode = 'rgb_array'
-
- def _render_text_to_image(self, obs):
- chars = obs["tty_chars"]
- colors = obs["tty_colors"]
- offset_w = 0
- offset_h = 0
- if self.crop_size:
- # Center around player
- if self.blstats_cursor:
- center_x, center_y = obs["blstats"][:2]
- else:
- center_y, center_x = obs["tty_cursor"]
- offset_h = center_y - self.half_crop_size
- offset_w = center_x - self.half_crop_size
-
- out_image = np.zeros(self.chw_image_shape, dtype=np.uint8)
-
- _tile_characters_to_image(
- out_image=out_image,
- chars=chars,
- colors=colors,
- output_height_chars=self.output_height_chars,
- output_width_chars=self.output_width_chars,
- char_array=self.char_array,
- offset_h=offset_h,
- offset_w=offset_w,
- )
-
- return out_image
- obs["screen_image"] = out_image
- del obs["tty_chars"]
- del obs["tty_colors"]
- return obs
-
- def step(self, action):
- obs, reward, done, info = self.env.step(action)
- self.obs = obs
- obs = self._render_text_to_image(obs)
- return obs, reward, done, info
-
- def reset(self):
- obs = self.env.reset()
- self.obs = obs
- obs = self._render_text_to_image(obs)
- return obs
-
- def render(self, mode='rgb_array'):
- return self.obs
-
-
-class RenderCharImagesWithNumpyWrapperV2(gym.Wrapper):
- """
- Same as V1, but simpler and faster.
- """
-
- def __init__(
- self,
- env,
- font_size=9,
- crop_size=12,
- rescale_font_size=(6, 6),
- ):
- super().__init__(env)
- self.char_array = _initialize_char_array(font_size, rescale_font_size)
- self.char_height = self.char_array.shape[2]
- self.char_width = self.char_array.shape[3]
- # Transpose for CHW
- self.char_array = self.char_array.transpose(0, 1, 4, 2, 3)
- self.char_array = np.ascontiguousarray(self.char_array)
- self.crop_size = crop_size
-
- crop_rows = crop_size or nethack.nethack.TERMINAL_SHAPE[0]
- crop_cols = crop_size or nethack.nethack.TERMINAL_SHAPE[1]
-
- self.chw_image_shape = (
- 3,
- crop_rows * self.char_height,
- crop_cols * self.char_width,
- )
-
- obs_spaces = {
- "screen_image": gym.spaces.Box(
- low=0, high=255, shape=self.chw_image_shape, dtype=np.uint8
- )
- }
- obs_spaces.update(
- [
- (k, self.env.observation_space[k])
- for k in self.env.observation_space
- if k not in ["tty_chars", "tty_colors"]
- ]
- )
- self.observation_space = gym.spaces.Dict(obs_spaces)
-
- def _populate_obs(self, obs):
- screen = np.zeros(self.chw_image_shape, order="C", dtype=np.uint8)
- render_utils.render_crop(
- obs["tty_chars"],
- obs["tty_colors"],
- obs["tty_cursor"],
- self.char_array,
- screen,
- crop_size=self.crop_size,
- )
- obs["screen_image"] = screen
-
- def step(self, action):
- obs, reward, done, info = self.env.step(action)
- self._populate_obs(obs)
- return obs, reward, done, info
-
- def reset(self):
- obs = self.env.reset()
- self._populate_obs(obs)
- return obs
diff --git a/pufferlib/environments/nmmo/__init__.py b/pufferlib/environments/nmmo/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/nmmo/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/nmmo/environment.py b/pufferlib/environments/nmmo/environment.py
deleted file mode 100644
index f4ef1c998..000000000
--- a/pufferlib/environments/nmmo/environment.py
+++ /dev/null
@@ -1,77 +0,0 @@
-from pdb import set_trace as T
-import numpy as np
-import functools
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.environments
-import pufferlib.wrappers
-import pufferlib.postprocess
-
-
-def env_creator(name='nmmo'):
- return functools.partial(make, name)
-
-def make(name, *args, buf=None, **kwargs):
- '''Neural MMO creation function'''
- nmmo = pufferlib.environments.try_import('nmmo')
- env = nmmo.Env(*args, **kwargs)
- env = NMMOWrapper(env)
- env = pufferlib.postprocess.MultiagentEpisodeStats(env)
- env = pufferlib.postprocess.MeanOverAgents(env)
- return pufferlib.emulation.PettingZooPufferEnv(env=env, buf=buf)
-
-class NMMOWrapper(pufferlib.postprocess.PettingZooWrapper):
- '''Remove task spam'''
- @property
- def render_mode(self):
- return 'rgb_array'
-
- def render(self):
- '''Quick little renderer for NMMO'''
- tiles = self.env.tile_map[:, :, 2].astype(np.uint8)
- render = np.zeros((tiles.shape[0], tiles.shape[1], 3), dtype=np.uint8)
- BROWN = (136, 69, 19)
- render[tiles == 1] = (0, 0, 255)
- render[tiles == 2] = (0, 255, 0)
- render[tiles == 3] = BROWN
- render[tiles == 4] = (64, 255, 64)
- render[tiles == 5] = (128, 128, 128)
- render[tiles == 6] = BROWN
- render[tiles == 7] = (255, 128, 128)
- render[tiles == 8] = BROWN
- render[tiles == 9] = (128, 255, 128)
- render[tiles == 10] = BROWN
- render[tiles == 11] = (128, 128, 255)
- render[tiles == 12] = BROWN
- render[tiles == 13] = (192, 255, 192)
- render[tiles == 14] = (0, 0, 255)
- render[tiles == 15] = (64, 64, 255)
-
- for agent in self.env.realm.players.values():
- agent_r = agent.row.val
- agent_c = agent.col.val
- render[agent_r, agent_c, :] = (255, 255, 0)
-
- for npc in self.env.realm.npcs.values():
- agent_r = npc.row.val
- agent_c = npc.col.val
- render[agent_r, agent_c, :] = (255, 0, 0)
-
- return render
-
- def reset(self, seed=None):
- obs, infos = self.env.reset(seed=seed)
- self.obs = obs
- return obs, infos
-
- def step(self, actions):
- obs, rewards, dones, truncateds, infos = self.env.step(actions)
- infos = {k: list(v['task'].values())[0] for k, v in infos.items()}
- self.obs = obs
- return obs, rewards, dones, truncateds, infos
-
- def close(self):
- return self.env.close()
-
-
diff --git a/pufferlib/environments/nmmo/torch.py b/pufferlib/environments/nmmo/torch.py
deleted file mode 100644
index e98134f3a..000000000
--- a/pufferlib/environments/nmmo/torch.py
+++ /dev/null
@@ -1,96 +0,0 @@
-from pdb import set_trace as T
-
-import torch
-import torch.nn.functional as F
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.models
-import pufferlib.pytorch
-from pufferlib.environments import try_import
-
-try_import("nmmo")
-from nmmo.entity.entity import EntityState
-
-
-class Recurrent(pufferlib.models.LSTMWrapper):
- def __init__(self, env, policy, input_size=256, hidden_size=256, num_layers=1):
- super().__init__(env, policy, input_size, hidden_size, num_layers)
-
-class Policy(torch.nn.Module):
- NUM_ATTRS = 34
- EntityId = EntityState.State.attr_name_to_col["id"]
- tile_offset = torch.tensor([i*256 for i in range(3)])
- entity_offset = torch.tensor([i*256 for i in range(3, 34)])
-
- def __init__(self, env, input_size=256, hidden_size=256, output_size=256):
- super().__init__()
- self.dtype = pufferlib.pytorch.nativize_dtype(env.emulated)
-
- # A dumb example encoder that applies a linear layer to agent self features
- self.embedding = torch.nn.Embedding(self.NUM_ATTRS*256, 32)
- self.tile_conv_1 = torch.nn.Conv2d(96, 32, 3)
- self.tile_conv_2 = torch.nn.Conv2d(32, 8, 3)
- self.tile_fc = torch.nn.Linear(8*11*11, input_size)
-
- self.entity_fc = torch.nn.Linear(31*32, input_size)
-
- self.proj_fc = torch.nn.Linear(2*input_size, input_size)
-
- self.decoders = torch.nn.ModuleList([torch.nn.Linear(hidden_size, n)
- for n in env.single_action_space.nvec])
- self.value_head = torch.nn.Linear(hidden_size, 1)
-
- def forward(self, x):
- hidden, lookup = self.encode_observations(x)
- actions, value = self.decode_actions(hidden, lookup)
- return actions, value
-
- def encode_observations(self, env_outputs):
- env_outputs = pufferlib.pytorch.nativize_tensor(env_outputs, self.dtype)
-
- tile = env_outputs['Tile']
- # Center on player
- # This is cursed without clone??
- tile[:, :, :2] -= tile[:, 112:113, :2].clone()
- tile[:, :, :2] += 7
- tile = self.embedding(
- tile.long().clip(0, 255) + self.tile_offset.to(tile.device)
- )
-
- agents, tiles, features, embed = tile.shape
- tile = tile.view(agents, tiles, features*embed).transpose(1, 2).view(agents, features*embed, 15, 15)
-
- tile = self.tile_conv_1(tile)
- tile = F.relu(tile)
- tile = self.tile_conv_2(tile)
- tile = F.relu(tile)
- tile = tile.contiguous().view(agents, -1)
- tile = self.tile_fc(tile)
- tile = F.relu(tile)
-
- # Pull out rows corresponding to the agent
- agentEmb = env_outputs["Entity"]
- my_id = env_outputs["AgentId"][:,0]
- entity_ids = agentEmb[:,:,self.EntityId]
- mask = (entity_ids == my_id.unsqueeze(1)) & (entity_ids != 0)
- mask = mask.int()
- row_indices = torch.where(mask.any(dim=1), mask.argmax(dim=1), torch.zeros_like(mask.sum(dim=1)))
- entity = agentEmb[torch.arange(agentEmb.shape[0]), row_indices]
-
- entity = self.embedding(
- entity.long().clip(0, 255) + self.entity_offset.to(entity.device)
- )
- agents, attrs, embed = entity.shape
- entity = entity.view(agents, attrs*embed)
-
- entity = self.entity_fc(entity)
- entity = F.relu(entity)
-
- obs = torch.cat([tile, entity], dim=-1)
- return self.proj_fc(obs), None
-
- def decode_actions(self, hidden, lookup, concat=True):
- value = self.value_head(hidden)
- actions = [dec(hidden) for dec in self.decoders]
- return actions, value
diff --git a/pufferlib/environments/open_spiel/__init__.py b/pufferlib/environments/open_spiel/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/open_spiel/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/open_spiel/environment.py b/pufferlib/environments/open_spiel/environment.py
deleted file mode 100644
index a5679b759..000000000
--- a/pufferlib/environments/open_spiel/environment.py
+++ /dev/null
@@ -1,56 +0,0 @@
-from pdb import set_trace as T
-import numpy as np
-import functools
-
-import pufferlib
-from pufferlib import namespace
-import pufferlib.emulation
-import pufferlib.environments
-
-
-def env_creator(name='connect_four'):
- '''OpenSpiel creation function'''
- return functools.partial(make, name)
-
-def make(
- name,
- multiplayer=False,
- n_rollouts=5,
- max_simulations=10,
- min_simulations=None,
- buf=None
- ):
- '''OpenSpiel creation function'''
- pyspiel = pufferlib.environments.try_import('pyspiel', 'open_spiel')
- env = pyspiel.load_game(name)
-
- if min_simulations is None:
- min_simulations = max_simulations
-
- from pufferlib.environments.open_spiel.gymnasium_environment import (
- OpenSpielGymnasiumEnvironment
- )
- from pufferlib.environments.open_spiel.pettingzoo_environment import (
- OpenSpielPettingZooEnvironment
- )
-
- kwargs = dict(
- env=env,
- n_rollouts=int(n_rollouts),
- min_simulations=int(min_simulations),
- max_simulations=int(max_simulations),
- )
-
- if multiplayer:
- env = OpenSpielPettingZooEnvironment(**kwargs)
- wrapper_cls = pufferlib.emulation.PettingZooPufferEnv
- else:
- env = OpenSpielGymnasiumEnvironment(**kwargs)
- wrapper_cls = pufferlib.emulation.GymnasiumPufferEnv
-
- return wrapper_cls(
- env=env,
- postprocessor_cls=pufferlib.emulation.BasicPostprocessor,
- buf=buf,
- )
-
diff --git a/pufferlib/environments/open_spiel/gymnasium_environment.py b/pufferlib/environments/open_spiel/gymnasium_environment.py
deleted file mode 100644
index ae5bfba59..000000000
--- a/pufferlib/environments/open_spiel/gymnasium_environment.py
+++ /dev/null
@@ -1,88 +0,0 @@
-from pdb import set_trace as T
-import numpy as np
-
-from open_spiel.python.algorithms import mcts
-
-import pufferlib
-from pufferlib import namespace
-from pufferlib.environments.open_spiel.utils import (
- solve_chance_nodes,
- get_obs_and_infos,
- observation_space,
- action_space,
- init,
- render,
- close,
-)
-
-
-def create_bots(state, seed):
- assert seed is not None, 'seed must be set'
- rnd_state = np.random.RandomState(seed)
-
- evaluator = mcts.RandomRolloutEvaluator(
- n_rollouts=state.n_rollouts,
- random_state=rnd_state
- )
-
- return [mcts.MCTSBot(
- game=state.env,
- uct_c=2,
- max_simulations=a,
- evaluator=evaluator,
- random_state=rnd_state,
- child_selection_fn=mcts.SearchNode.puct_value,
- solve=True,
- ) for a in range(state.min_simulations, state.max_simulations + 1)]
-
-def reset(state, seed = None, options = None):
- state.state = state.env.new_initial_state()
-
- if not state.has_reset:
- state.has_reset = True
- state.seed_value = seed
- np.random.seed(seed)
- state.all_bots = create_bots(state, seed)
-
- state.bot = np.random.choice(state.all_bots)
-
- if np.random.rand() < 0.5:
- bot_atn = state.bot.step(state.state)
- state.state.apply_action(bot_atn)
-
- obs, infos = get_obs_and_infos(state)
- player = state.state.current_player()
- return obs[player], infos[player]
-
-def step(state, action):
- player = state.state.current_player()
- solve_chance_nodes(state)
- state.state.apply_action(action)
-
- # Take other move with a bot
- if not state.state.is_terminal():
- bot_atn = state.bot.step(state.state)
- solve_chance_nodes(state)
- state.state.apply_action(bot_atn)
-
- # Now that we have applied all actions, get the next obs.
- obs, all_infos = get_obs_and_infos(state)
- reward = state.state.returns()[player]
- info = all_infos[player]
-
- # Are we done?
- terminated = state.state.is_terminal()
- if terminated:
- key = f'win_mcts_{state.bot.max_simulations}'
- info[key] = int(reward==1)
-
- return obs[player], reward, terminated, False, info
-
-class OpenSpielGymnasiumEnvironment:
- __init__ = init
- step = step
- reset = reset
- observation_space = property(observation_space)
- action_space = property(action_space)
- render = render
- close = close
diff --git a/pufferlib/environments/open_spiel/pettingzoo_environment.py b/pufferlib/environments/open_spiel/pettingzoo_environment.py
deleted file mode 100644
index cbfca0af4..000000000
--- a/pufferlib/environments/open_spiel/pettingzoo_environment.py
+++ /dev/null
@@ -1,68 +0,0 @@
-from pdb import set_trace as T
-import numpy as np
-
-import pufferlib
-from pufferlib import namespace
-
-from pufferlib.environments.open_spiel.utils import (
- solve_chance_nodes,
- get_obs_and_infos,
- observation_space,
- action_space,
- init,
- render,
- close,
-)
-
-def agents(state):
- return state.agents
-
-def possible_agents(state):
- return list(range(state.env.num_players()))
-
-def pz_observation_space(state, agent):
- return observation_space(state)
-
-def pz_action_space(state, agent):
- return action_space(state)
-
-def reset(state, seed = None, options = None):
- state.state = state.env.new_initial_state()
- obs, infos = get_obs_and_infos(state)
- state.agents = state.possible_agents
-
- if not state.has_reset:
- state.has_reset = True
- state.seed_value = seed
- np.random.seed(seed)
-
- return obs, infos
-
-def step(state, actions):
- curr_player = state.state.current_player()
- solve_chance_nodes(state)
- state.state.apply_action(actions[curr_player])
- obs, infos = get_obs_and_infos(state)
- rewards = {ag: r for ag, r in enumerate(state.state.returns())}
-
- # Are we done?
- is_terminated = state.state.is_terminal()
- terminateds = {a: False for a in obs}
- truncateds = {a: False for a in obs}
-
- if is_terminated:
- terminateds = {a: True for a in state.possible_agents}
- state.agents = []
-
- return obs, rewards, terminateds, truncateds, infos
-
-class OpenSpielPettingZooEnvironment:
- __init__ = init
- step = step
- reset = reset
- agents = lambda state: state.agents
- possible_agents = property(possible_agents)
- observation_space = pz_observation_space
- action_space = pz_action_space
- render = render
- close = close
diff --git a/pufferlib/environments/open_spiel/torch.py b/pufferlib/environments/open_spiel/torch.py
deleted file mode 100644
index 4d1845b6b..000000000
--- a/pufferlib/environments/open_spiel/torch.py
+++ /dev/null
@@ -1,44 +0,0 @@
-from pdb import set_trace as T
-import numpy as np
-
-import torch
-from torch import nn
-
-import pufferlib.emulation
-from pufferlib.models import Policy as Base
-
-class Policy(Base):
- def __init__(self, env, input_size=128, hidden_size=128):
- '''Default PyTorch policy, meant for debugging.
- This should run with any environment but is unlikely to learn anything.
-
- Uses a single linear layer + relu to encode observations and a list of
- linear layers to decode actions. The value function is a single linear layer.
- '''
- super().__init__(env)
-
- self.flat_observation_space = env.flat_observation_space
- self.flat_observation_structure = env.flat_observation_structure
-
- self.encoder = nn.Linear(np.prod(
- env.structured_observation_space['obs'].shape), hidden_size)
- self.decoder = nn.Linear(hidden_size, self.action_space.n)
-
- self.value_head = nn.Linear(hidden_size, 1)
-
- def encode_observations(self, observations):
- '''Linear encoder function'''
- observations = pufferlib.emulation.unpack_batched_obs(observations,
- self.flat_observation_space, self.flat_observation_structure)
- obs = observations['obs'].view(observations['obs'].shape[0], -1)
- self.action_mask = observations['action_mask']
-
- hidden = torch.relu(self.encoder(obs))
- return hidden, None
-
- def decode_actions(self, hidden, lookup, concat=True):
- '''Concatenated linear decoder function'''
- value = self.value_head(hidden)
- action = self.decoder(hidden)
- action = action.masked_fill(self.action_mask == 0, -1e9)
- return action, value
\ No newline at end of file
diff --git a/pufferlib/environments/open_spiel/utils.py b/pufferlib/environments/open_spiel/utils.py
deleted file mode 100644
index 8eab105c2..000000000
--- a/pufferlib/environments/open_spiel/utils.py
+++ /dev/null
@@ -1,99 +0,0 @@
-from pdb import set_trace as T
-import numpy as np
-
-import gymnasium
-
-from pufferlib import namespace
-
-
-def init(self,
- env,
- n_rollouts,
- min_simulations,
- max_simulations
- ):
- #state.num_agents = state.env.num_players()
- return namespace(self,
- env=env,
- type=env.get_type(),
- n_rollouts=n_rollouts,
- min_simulations=min_simulations,
- max_simulations=max_simulations,
- state=None,
- agents=[],
- has_reset=False,
- )
-
-def observation_space(state):
- return gymnasium.spaces.Dict({
- 'obs': gymnasium.spaces.Box(
- low=0.0,
- high=1.0,
- shape=(state.env.observation_tensor_size(),),
- dtype=np.float32,
- ),
- 'action_mask': gymnasium.spaces.Box(
- low=0,
- high=1,
- shape=(action_space(state).n,),
- dtype=np.int8
- )
- })
-
-def action_space(state):
- return gymnasium.spaces.Discrete(
- state.env.num_distinct_actions())
-
-def render(state, mode=None) -> None:
- if mode == "human":
- print(state.state)
-
-def close(state):
- pass
-
-def act(state, action):
- solve_chance_nodes(state)
- state.state.apply_action(action)
-
-def get_obs_and_infos(state):
- # Before calculating an observation, there could be chance nodes
- # (that may have an effect on the actual observations).
- # E.g. After reset, figure out initial (random) positions of the
- # agents.
- solve_chance_nodes(state)
-
- if state.state.is_terminal():
- return (
- state.last_obs,
- {player: {} for player in range(state.env.num_players())},
- )
-
- # Sequential game:
- curr_player = state.state.current_player()
- mask = state.state.legal_actions(curr_player)
- np_mask = np.zeros(action_space(state).n)
- np_mask[mask] = 1
-
- state.last_obs = {player: {
- 'obs': np.reshape(state.state.observation_tensor(),
- [-1]).astype(np.float32),
- 'action_mask': np_mask.astype(np.int8),
- } for player in range(state.env.num_players())}
-
- state.last_info = {curr_player: {}}
-
- return (
- {curr_player: state.last_obs[curr_player]},
- state.last_info,
- )
-
-def solve_chance_nodes(state):
- # Before applying action(s), there could be chance nodes.
- # E.g. if env has to figure out, which agent's action should get
- # resolved first in a simultaneous node.
- # Chance node(s): Sample a (non-player) action and apply.
- while state.state.is_chance_node():
- assert state.state.current_player() == -1
- actions, probs = zip(*state.state.chance_outcomes())
- action = np.random.choice(actions, p=probs)
- state.state.apply_action(action)
diff --git a/pufferlib/environments/pokemon_red/__init__.py b/pufferlib/environments/pokemon_red/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/pokemon_red/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/pokemon_red/environment.py b/pufferlib/environments/pokemon_red/environment.py
deleted file mode 100644
index fe0bd85e7..000000000
--- a/pufferlib/environments/pokemon_red/environment.py
+++ /dev/null
@@ -1,31 +0,0 @@
-from pdb import set_trace as T
-
-import gymnasium
-import functools
-
-from pokegym import Environment
-
-import pufferlib.emulation
-import pufferlib.postprocess
-
-
-def env_creator(name='pokemon_red'):
- return functools.partial(make, name)
-
-def make(name, headless: bool = True, state_path=None, buf=None, seed=0):
- '''Pokemon Red'''
- env = Environment(headless=headless, state_path=state_path)
- env = RenderWrapper(env)
- env = pufferlib.postprocess.EpisodeStats(env)
- return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf, seed=seed)
-
-class RenderWrapper(gymnasium.Wrapper):
- def __init__(self, env):
- self.env = env
-
- @property
- def render_mode(self):
- return 'rgb_array'
-
- def render(self):
- return self.env.screen.screen_ndarray()
diff --git a/pufferlib/environments/pokemon_red/torch.py b/pufferlib/environments/pokemon_red/torch.py
deleted file mode 100644
index 370b023bf..000000000
--- a/pufferlib/environments/pokemon_red/torch.py
+++ /dev/null
@@ -1,36 +0,0 @@
-from functools import partial
-import torch
-
-import pufferlib.models
-
-
-class Recurrent(pufferlib.models.LSTMWrapper):
- def __init__(self, env, policy,
- input_size=512, hidden_size=512, num_layers=1):
- super().__init__(env, policy,
- input_size, hidden_size, num_layers)
-
-class Policy(pufferlib.models.Convolutional):
- def __init__(self, env,
- input_size=512, hidden_size=512, output_size=512,
- framestack=4, flat_size=64*5*6):
- super().__init__(
- env=env,
- input_size=input_size,
- hidden_size=hidden_size,
- output_size=output_size,
- framestack=framestack,
- flat_size=flat_size,
- channels_last=True,
- )
-
-
-'''
-class Policy(pufferlib.models.ProcgenResnet):
- def __init__(self, env, cnn_width=16, mlp_width=512):
- super().__init__(
- env=env,
- cnn_width=cnn_width,
- mlp_width=mlp_width,
- )
-'''
diff --git a/pufferlib/environments/procgen/__init__.py b/pufferlib/environments/procgen/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/procgen/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/procgen/environment.py b/pufferlib/environments/procgen/environment.py
deleted file mode 100644
index 3d889b73f..000000000
--- a/pufferlib/environments/procgen/environment.py
+++ /dev/null
@@ -1,74 +0,0 @@
-from pdb import set_trace as T
-import numpy as np
-
-import gym
-import gymnasium
-import shimmy
-import functools
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.environments
-
-from stable_baselines3.common.atari_wrappers import (
- MaxAndSkipEnv,
-)
-
-def env_creator(name='bigfish'):
- return functools.partial(make, name)
-
-def make(name, num_envs=1, num_levels=0, start_level=0,
- distribution_mode='easy', render_mode=None, buf=None, seed=0):
- '''Atari creation function with default CleanRL preprocessing based on Stable Baselines3 wrappers'''
- assert int(num_envs) == float(num_envs), "num_envs must be an integer"
- num_envs = int(num_envs)
-
- procgen = pufferlib.environments.try_import('procgen')
- envs = procgen.ProcgenEnv(
- env_name=name,
- num_envs=num_envs,
- num_levels=num_levels,
- start_level=start_level,
- distribution_mode=distribution_mode,
- render_mode=render_mode,
- )
- envs = gym.wrappers.TransformObservation(envs, lambda obs: obs["rgb"])
- envs.single_action_space = envs.action_space
- envs.single_observation_space = envs.observation_space["rgb"]
- envs.is_vector_env = True
- envs = gym.wrappers.RecordEpisodeStatistics(envs)
- envs = gym.wrappers.NormalizeReward(envs)
- envs = gym.wrappers.TransformReward(envs, lambda reward: np.clip(reward, -10, 10))
- assert isinstance(envs.single_action_space, gym.spaces.Discrete), "only discrete action space is supported"
- envs = ProcgenWrapper(envs)
- envs = shimmy.GymV21CompatibilityV0(env=envs, render_mode=render_mode)
- #envs = gymnasium.wrappers.GrayScaleObservation(envs)
- #envs = gymnasium.wrappers.FrameStack(envs, 4)#, framestack)
- #envs = MaxAndSkipEnv(envs, skip=2)
- envs = pufferlib.EpisodeStats(envs)
- return pufferlib.emulation.GymnasiumPufferEnv(env=envs, buf=buf)
-
-class ProcgenWrapper:
- def __init__(self, env):
- self.env = env
- self.observation_space = self.env.observation_space['rgb']
- self.action_space = self.env.action_space
-
- @property
- def render_mode(self):
- return 'rgb_array'
-
- def reset(self, seed=None):
- obs = self.env.reset()[0]
- return obs
-
- def render(self, mode=None):
- return self.env.env.env.env.env.env.get_info()[0]['rgb']
-
- def close(self):
- return self.env.close()
-
- def step(self, actions):
- actions = np.asarray(actions).reshape(1)
- obs, rewards, dones, infos = self.env.step(actions)
- return obs[0], rewards[0], dones[0], infos[0]
diff --git a/pufferlib/environments/procgen/torch.py b/pufferlib/environments/procgen/torch.py
deleted file mode 100644
index 924926c34..000000000
--- a/pufferlib/environments/procgen/torch.py
+++ /dev/null
@@ -1,50 +0,0 @@
-from pdb import set_trace as T
-from torch import nn
-import pufferlib.models
-
-# This policy ended up being useful broadly
-# so I included it in the defaults
-
-class Recurrent(pufferlib.models.LSTMWrapper):
- def __init__(self, env, policy, input_size=256, hidden_size=256, num_layers=1):
- super().__init__(env, policy, input_size, hidden_size, num_layers)
-
-class Policy (nn.Module):
- def __init__(self, env, *args, input_size=256, hidden_size=256,
- output_size=256, **kwargs):
- '''The CleanRL default NatureCNN policy used for Atari.
- It's just a stack of three convolutions followed by a linear layer
-
- Takes framestack as a mandatory keyword argument. Suggested default is 1 frame
- with LSTM or 4 frames without.'''
- super().__init__()
-
- self.network= nn.Sequential(
- pufferlib.pytorch.layer_init(nn.Conv2d(3, 16, 8, stride=4)),
- nn.ReLU(),
- pufferlib.pytorch.layer_init(nn.Conv2d(16, 32, 4, stride=2)),
- nn.ReLU(),
- nn.Flatten(),
- pufferlib.pytorch.layer_init(nn.Linear(1152, hidden_size)),
- nn.ReLU(),
- )
- self.actor = pufferlib.pytorch.layer_init(
- nn.Linear(hidden_size, env.single_action_space.n), std=0.01)
- self.value_fn = pufferlib.pytorch.layer_init(
- nn.Linear(output_size, 1), std=1)
-
- def forward(self, observations):
- hidden, lookup = self.encode_observations(observations)
- actions, value = self.decode_actions(hidden, lookup)
- return actions, value
-
- def encode_observations(self, observations):
- observations = observations.permute(0, 3, 1, 2)
- return self.network(observations.float() / 255.0), None
-
- def decode_actions(self, flat_hidden, lookup, concat=None):
- action = self.actor(flat_hidden)
- value = self.value_fn(flat_hidden)
- return action, value
-
-Policy = pufferlib.models.ProcgenResnet
diff --git a/pufferlib/environments/slimevolley/__init__.py b/pufferlib/environments/slimevolley/__init__.py
deleted file mode 100644
index 59cda9e7c..000000000
--- a/pufferlib/environments/slimevolley/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/slimevolley/environment.py b/pufferlib/environments/slimevolley/environment.py
deleted file mode 100644
index a46d79562..000000000
--- a/pufferlib/environments/slimevolley/environment.py
+++ /dev/null
@@ -1,70 +0,0 @@
-from pdb import set_trace as T
-import numpy as np
-import functools
-
-import gym
-import shimmy
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.environments
-import pufferlib.utils
-import pufferlib.postprocess
-
-
-def env_creator(name='SlimeVolley-v0'):
- return functools.partial(make, name)
-
-def make(name, render_mode='rgb_array', buf=None):
- if name == 'slimevolley':
- name = 'SlimeVolley-v0'
-
- from slimevolleygym import SlimeVolleyEnv
- SlimeVolleyEnv.atari_mode = True
- env = SlimeVolleyEnv()
- env.policy.predict = lambda obs: np.random.randint(0, 2, 3)
- env = SlimeVolleyMultiDiscrete(env)
- env = SkipWrapper(env, repeat_count=4)
- env = shimmy.GymV21CompatibilityV0(env=env)
- env = pufferlib.postprocess.EpisodeStats(env)
- return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
-
-class SlimeVolleyMultiDiscrete(gym.Wrapper):
- def __init__(self, env):
- super().__init__(env)
- #self.action_space = gym.spaces.MultiDiscrete(
- # [2 for _ in range(env.action_space.n)])
-
- def reset(self, seed=None):
- return self.env.reset().astype(np.float32)
-
- def step(self, action):
- obs, reward, done, info = self.env.step(action)
- return obs.astype(np.float32), reward, done, info
-
-class SkipWrapper(gym.Wrapper):
- """
- Generic common frame skipping wrapper
- Will perform action for `x` additional steps
- """
- def __init__(self, env, repeat_count):
- super(SkipWrapper, self).__init__(env)
- self.repeat_count = repeat_count
- self.stepcount = 0
-
- def step(self, action):
- done = False
- total_reward = 0
- current_step = 0
- while current_step < (self.repeat_count + 1) and not done:
- self.stepcount += 1
- obs, reward, done, info = self.env.step(action)
- total_reward += reward
- current_step += 1
-
- return obs, total_reward, done, info
-
- def reset(self):
- self.stepcount = 0
- return self.env.reset()
-
diff --git a/pufferlib/environments/slimevolley/torch.py b/pufferlib/environments/slimevolley/torch.py
deleted file mode 100644
index e5188f3b7..000000000
--- a/pufferlib/environments/slimevolley/torch.py
+++ /dev/null
@@ -1,4 +0,0 @@
-import pufferlib.models
-
-Recurrent = pufferlib.models.LSTMWrapper
-Policy = pufferlib.models.Default
diff --git a/pufferlib/environments/smac/__init__.py b/pufferlib/environments/smac/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/smac/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/smac/environment.py b/pufferlib/environments/smac/environment.py
deleted file mode 100644
index e104e860b..000000000
--- a/pufferlib/environments/smac/environment.py
+++ /dev/null
@@ -1,23 +0,0 @@
-import functools
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.environments
-import pufferlib.wrappers
-
-
-def env_creator(name='smac'):
- return functools.partial(make, name)
-
-def make(name, buf=None):
- '''Starcraft Multiagent Challenge creation function
-
- Support for SMAC is WIP because environments do not function without
- an action-masked baseline policy.'''
- pufferlib.environments.try_import('smac')
- from smac.env.pettingzoo.StarCraft2PZEnv import _parallel_env as smac_env
-
- env = smac_env(1000)
- env = pufferlib.wrappers.PettingZooTruncatedWrapper(env)
- env = pufferlib.emulation.PettingZooPufferEnv(env, buf=buf)
- return env
diff --git a/pufferlib/environments/smac/torch.py b/pufferlib/environments/smac/torch.py
deleted file mode 100644
index 8b13194e9..000000000
--- a/pufferlib/environments/smac/torch.py
+++ /dev/null
@@ -1 +0,0 @@
-from pufferlib.models import Default as Policy
diff --git a/pufferlib/environments/stable_retro/__init__.py b/pufferlib/environments/stable_retro/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/stable_retro/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/stable_retro/environment.py b/pufferlib/environments/stable_retro/environment.py
deleted file mode 100644
index 092708613..000000000
--- a/pufferlib/environments/stable_retro/environment.py
+++ /dev/null
@@ -1,72 +0,0 @@
-from pdb import set_trace as T
-import numpy as np
-
-import gymnasium as gym
-import functools
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.environments
-
-
-def env_creator(name='Airstriker-Genesis'):
- return functools.partial(make, name)
-
-def make(name='Airstriker-Genesis', framestack=4, buf=None):
- '''Atari creation function with default CleanRL preprocessing based on Stable Baselines3 wrappers'''
- retro = pufferlib.environments.try_import('retro', 'stable-retro')
-
- from stable_baselines3.common.atari_wrappers import (
- ClipRewardEnv,
- EpisodicLifeEnv,
- FireResetEnv,
- MaxAndSkipEnv,
- )
- with pufferlib.utils.Suppress():
- env = retro.make(name)
-
- env = gym.wrappers.RecordEpisodeStatistics(env)
- env = MaxAndSkipEnv(env, skip=4)
- env = ClipRewardEnv(env)
- env = gym.wrappers.ResizeObservation(env, (84, 84))
- env = gym.wrappers.GrayScaleObservation(env)
- env = gym.wrappers.FrameStack(env, framestack)
- return pufferlib.emulation.GymnasiumPufferEnv(
- env=env, postprocessor_cls=AtariFeaturizer, buf=buf)
-
-class AtariFeaturizer(pufferlib.emulation.Postprocessor):
- def reset(self, obs):
- self.epoch_return = 0
- self.epoch_length = 0
- self.done = False
-
- #@property
- #def observation_space(self):
- # return gym.spaces.Box(0, 255, (1, 84, 84), dtype=np.uint8)
-
- def observation(self, obs):
- return np.array(obs)
- return np.array(obs[1], dtype=np.float32)
-
- def reward_done_truncated_info(self, reward, done, truncated, info):
- return reward, done, truncated, info
- if 'lives' in info:
- if info['lives'] == 0 and done:
- info['return'] = info['episode']['r']
- info['length'] = info['episode']['l']
- info['time'] = info['episode']['t']
- return reward, True, info
- return reward, False, info
-
- if self.done:
- return reward, done, info
-
- if done:
- info['return'] = self.epoch_return
- info['length'] = self.epoch_length
- self.done = True
- else:
- self.epoch_length += 1
- self.epoch_return += reward
-
- return reward, done, info
diff --git a/pufferlib/environments/stable_retro/torch.py b/pufferlib/environments/stable_retro/torch.py
deleted file mode 100644
index 0ab602183..000000000
--- a/pufferlib/environments/stable_retro/torch.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import pufferlib.models
-
-
-class Recurrent:
- input_size = 512
- hidden_size = 512
- num_layers = 1
-
-class Policy(pufferlib.models.Convolutional):
- def __init__(self, env, input_size=512, hidden_size=512, output_size=512,
- framestack=4, flat_size=64*7*7):
- super().__init__(
- env=env,
- input_size=input_size,
- hidden_size=hidden_size,
- output_size=output_size,
- framestack=framestack,
- flat_size=flat_size,
- )
diff --git a/pufferlib/environments/test/__init__.py b/pufferlib/environments/test/__init__.py
deleted file mode 100644
index 9d3bfe421..000000000
--- a/pufferlib/environments/test/__init__.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from .environment import (
- GymnasiumPerformanceEnv,
- PettingZooPerformanceEnv,
- GymnasiumTestEnv,
- PettingZooTestEnv,
- make_all_mock_environments,
- MOCK_OBSERVATION_SPACES,
- MOCK_ACTION_SPACES,
-)
-
-from .mock_environments import MOCK_SINGLE_AGENT_ENVIRONMENTS
-from .mock_environments import MOCK_MULTI_AGENT_ENVIRONMENTS
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/test/environment.py b/pufferlib/environments/test/environment.py
deleted file mode 100644
index ff82c6e47..000000000
--- a/pufferlib/environments/test/environment.py
+++ /dev/null
@@ -1,439 +0,0 @@
-from pdb import set_trace as T
-import numpy as np
-
-import time
-import hashlib
-
-import gym
-import gymnasium
-from gymnasium.spaces import Box, Discrete, Dict, Tuple
-from pufferlib import spaces
-from pettingzoo.utils.env import ParallelEnv
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.utils
-
-
-HIGH = 100
-LOW = 0
-
-MOCK_OBSERVATION_SPACES = [
- # Atari space
- Box(low=0, high=255, shape=(4, 84, 84), dtype=np.uint8),
-
- # NetHack space
- Dict({
- 'blstats': Box(-2147483648, 2147483647, (27,), 'int64'),
- 'chars': Box(0, 255, (21, 79), 'uint8'),
- 'colors': Box(0, 15, (21, 79), 'uint8'),
- 'glyphs': Box(0, 5976, (21, 79), 'int16'),
- 'inv_glyphs': Box(0, 5976, (55,), 'int16'),
- 'inv_letters': Box(0, 127, (55,), 'uint8'),
- 'inv_oclasses': Box(0, 18, (55,), 'uint8'),
- 'inv_strs': Box(0, 255, (55, 80), 'uint8'),
- 'message': Box(0, 255, (256,), 'uint8'),
- 'screen_descriptions': Box(0, 127, (21, 79, 80), 'uint8'),
- 'specials': Box(0, 255, (21, 79), 'uint8'),
- 'tty_chars': Box(0, 255, (24, 80), 'uint8'),
- 'tty_colors': Box(0, 31, (24, 80), 'int8'),
- 'tty_cursor': Box(0, 255, (2,), 'uint8'),
- }),
-
- # Neural MMO space
- Dict({
- 'ActionTargets': Dict({
- 'Attack': Dict({
- 'Style': Box(0, 1, (3,), 'int8'),
- 'Target': Box(0, 1, (100,), 'int8'),
- }),
- 'Buy': Dict({
- 'MarketItem': Box(0, 1, (1024,), 'int8'),
- }),
- 'Comm': Dict({
- 'Token': Box(0, 1, (50,), 'int8'),
- }),
- 'Destroy': Dict({
- 'InventoryItem': Box(0, 1, (12,), 'int8'),
- }),
- 'Give': Dict({
- 'InventoryItem': Box(0, 1, (12,), 'int8'),
- 'Target': Box(0, 1, (100,), 'int8'),
- }),
- 'GiveGold': Dict({
- 'Price': Box(0, 1, (99,), 'int8'),
- 'Target': Box(0, 1, (100,), 'int8'),
- }),
- 'Move': Dict({
- 'Direction': Box(0, 1, (5,), 'int8'),
- }),
- 'Sell': Dict({
- 'InventoryItem': Box(0, 1, (12,), 'int8'),
- 'Price': Box(0, 1, (99,), 'int8'),
- }),
- 'Use': Dict({
- 'InventoryItem': Box(0, 1, (12,), 'int8'),
- })
- }),
- 'AgentId': Discrete(129),
- 'CurrentTick': Discrete(1025),
- 'Entity': Box(-32768, 32767, (100, 23), 'int16'),
- 'Inventory': Box(-32768, 32767, (12, 16), 'int16'),
- 'Market': Box(-32768, 32767, (1024, 16), 'int16'),
- 'Task': Box(-32770.0, 32770.0, (1024,), 'float16'),
- 'Tile': Box(-32768, 32767, (225, 3), 'int16'),
- }),
-
- # Simple spaces
- Discrete(5),
- Box(low=LOW, high=HIGH, shape=(4,), dtype=np.float32),
-
- # Nested spaces
- Dict({
- "foo": Box(low=LOW, high=HIGH, shape=(2,), dtype=np.float32),
- "bar": Box(low=LOW, high=HIGH, shape=(2,), dtype=np.float32),
- }),
- Tuple((Discrete(3), Discrete(4))),
- Tuple((
- Box(low=LOW, high=HIGH, shape=(2,), dtype=np.float32),
- Discrete(3),
- Dict({
- "baz": Box(low=LOW, high=HIGH, shape=(1,), dtype=np.float32),
- "qux": Box(low=LOW, high=HIGH, shape=(1,), dtype=np.float32),
- }),
- )),
- Dict({
- "foo": Tuple((
- Box(low=LOW, high=HIGH, shape=(2,), dtype=np.float32),
- Discrete(3),
- )),
- "bar": Dict({
- "baz": Discrete(2),
- "qux": Discrete(4),
- }),
- }),
-]
-
-MOCK_ACTION_SPACES = [
- # NetHack action space
- Discrete(5),
-
- # Neural MMO action space
- Dict({
- 'Attack': Dict({
- 'Style': Discrete(3),
- 'Target': Discrete(100),
- }),
- 'Buy': Dict({
- 'MarketItem': Discrete(1024),
- }),
- 'Comm': Dict({
- 'Token': Discrete(50),
- }),
- 'Destroy': Dict({
- 'InventoryItem': Discrete(12),
- }),
- 'Give': Dict({
- 'InventoryItem': Discrete(12),
- 'Target': Discrete(100),
- }),
- 'GiveGold': Dict({
- 'Price': Discrete(99),
- 'Target': Discrete(100),
- }),
- 'Move': Dict({
- 'Direction': Discrete(5),
- }),
- 'Sell': Dict({
- 'InventoryItem': Discrete(12),
- 'Price': Discrete(99),
- }),
- 'Use': Dict({
- 'InventoryItem': Discrete(12),
- })
- }),
-
- # Nested spaces
- Tuple((Discrete(2), Discrete(3))),
- Dict({
- "foo": Discrete(4),
- "bar": Discrete(2),
- }),
- Tuple((
- Discrete(4),
- Dict({
- "baz": Discrete(2),
- "qux": Discrete(2),
- }),
- )),
- Dict({
- "foo": Tuple((
- Discrete(2),
- Discrete(3),
- )),
- "bar": Dict({
- "baz": Discrete(2),
- "qux": Discrete(4),
- }),
- }),
-]
-
-MOCK_TEAMS = {
- 'None': None,
- 'single': {
- 'team_1': ['agent_1'],
- 'team_2': ['agent_2'],
- 'team_3': ['agent_3'],
- 'team_4': ['agent_4'],
- 'team_5': ['agent_5'],
- 'team_6': ['agent_6'],
- 'team_7': ['agent_7'],
- 'team_8': ['agent_8'],
- 'team_9': ['agent_9'],
- 'team_10': ['agent_10'],
- 'team_11': ['agent_11'],
- 'team_12': ['agent_12'],
- 'team_13': ['agent_13'],
- 'team_14': ['agent_14'],
- 'team_15': ['agent_15'],
- 'team_16': ['agent_16'],
- },
- 'pairs': {
- 'team_1': ['agent_1', 'agent_2'],
- 'team_2': ['agent_3', 'agent_4'],
- 'team_3': ['agent_5', 'agent_6'],
- 'team_4': ['agent_7', 'agent_8'],
- 'team_5': ['agent_9', 'agent_10'],
- 'team_6': ['agent_11', 'agent_12'],
- 'team_7': ['agent_13', 'agent_14'],
- 'team_8': ['agent_15', 'agent_16'],
- },
- 'mixed': {
- 'team_1': ['agent_1', 'agent_2'],
- 'team_2': ['agent_3', 'agent_4', 'agent_5', 'agent_6'],
- 'team_3': ['agent_7', 'agent_8', 'agent_9'],
- 'team_4': ['agent_10', 'agent_11', 'agent_12', 'agent_13', 'agent_14'],
- 'team_5': ['agent_15', 'agent_16'],
- },
-}
-
-DEFAULT_OBSERVATION_SPACE = gymnasium.spaces.Box(
- low=-2**20, high=2**20,
- shape=(1,), dtype=np.float32
-)
-DEFAULT_ACTION_SPACE = gymnasium.spaces.Discrete(2)
-
-
-def make_all_mock_environments():
- mock_single_agent_environments = []
- mock_multi_agent_environments = []
- for obs_space in MOCK_OBSERVATION_SPACES:
- for act_space in MOCK_ACTION_SPACES:
- mock_single_agent_environments.append(
- GymnasiumTestEnv(
- observation_space=obs_space,
- action_space=act_space,
- )
- )
-
- mock_multi_agent_environments.append(
- PettingZooTestEnv(
- observation_space=obs_space,
- action_space=act_space,
- initial_agents=16,
- max_agents=16,
- spawn_per_tick=0,
- death_per_tick=1,
- )
- )
- return mock_single_agent_environments, mock_multi_agent_environments
-
-def do_work(delay_mean, delay_std):
- start, idx = time.process_time(), 0
- target_time = delay_mean + delay_std*np.random.randn()
- while time.process_time() - start < target_time:
- idx += 1
- return
-
-class GymnasiumPerformanceEnv:
- def __init__(self, delay_mean=0, delay_std=0):
- self.observation_space = DEFAULT_OBSERVATION_SPACE
- self.action_space = DEFAULT_ACTION_SPACE
- self.observation = self.observation_space.sample()
-
- self.delay_mean = delay_mean
- self.delay_std = delay_std
-
- # Test performance independent of PufferLib seeding
- np.random.seed(time.time_ns() % 2**32)
-
- def reset(self, seed=None):
- return self.observation, {}
-
- def step(self, action):
- do_work(self.delay_mean, self.delay_std)
- return self.observation, 0, False, False, {}
-
- def close(self):
- pass
-
-class PettingZooPerformanceEnv:
- def __init__(self, delay_mean, delay_std):
- self.possible_agents = [1]
- self.agents = [1]
- self.done = False
-
- self.delay_mean = delay_mean
- self.delay_std = delay_std
-
- def observation_space(self, agent):
- return DEFAULT_OBSERVATION_SPACE
-
- def action_space(self, agent):
- return DEFAULT_ACTION_SPACE
-
- def reset(self, seed=None):
- return {1: self.observation_space(1).sample()}, {1: {}}
-
- def step(self, actions):
- obs = {1: np.array([0], dtype=np.float32)}
- rewards = {1: 1}
- dones = {1: False}
- truncateds = {1: False}
- infos = {1: {}}
-
- do_work(self.delay_mean, self.delay_std)
-
- return obs, rewards, dones, truncateds, infos
-
- def close(self):
- pass
-
-class GymnasiumTestEnv(gym.Env):
- def __init__(self,
- observation_space=DEFAULT_OBSERVATION_SPACE,
- action_space=DEFAULT_ACTION_SPACE):
- self.observation_space = observation_space
- self.action_space = action_space
-
- def reset(self, seed=None):
- self.tick = 0
- self.rng = pufferlib.utils.RandomState(seed)
-
- ob = _sample_space('agent_1', self.tick, self.observation_space)
- return ob, {}
-
- def step(self, actions):
- reward = self.tick
- done = self.tick < 10
- self.tick += 1
-
- ob = _sample_space('agent_1', self.tick, self.observation_space)
- return ob, reward, done, False, {'dead': done}
-
- def close(self):
- pass
-
-class PettingZooTestEnv(ParallelEnv):
- def __init__(self,
- observation_space=DEFAULT_OBSERVATION_SPACE,
- action_space=DEFAULT_ACTION_SPACE,
- initial_agents=16, max_agents=16,
- spawn_per_tick=0, death_per_tick=1,
- homogeneous_spaces=True):
- self._observation_space = observation_space
- self._action_space = action_space
- self.initial_agents = initial_agents
- self.max_agents = max_agents
- self.spawn_per_tick = spawn_per_tick
- self.death_per_tick = death_per_tick
- self.homogeneous_spaces = homogeneous_spaces
-
- self.possible_agents = [f'agent_{i+1}' for i in range(max_agents)]
- self.agents = []
-
- def reset(self, seed=None):
- self.tick = 0
- self.agents = self.possible_agents[:self.initial_agents]
-
- obs = {a: _sample_space(a, self.tick, self._observation_space)
- for a in self.agents}
- infos = {a: {} for a in self.agents}
- return obs, infos
-
- def step(self, actions):
- obs, rewards, dones, truncateds, infos = {}, {}, {}, {}, {}
- self.tick += 1
-
- dead = self.agents[:self.death_per_tick]
- for kill in dead:
- self.agents.remove(kill)
- # TODO: Make pufferlib work without pad obs
- # but still require rewards, dones, and optionally infos
- obs[kill] = _sample_space(kill, self.tick,
- self._observation_space, zero=True)
- rewards[kill] = -1
- dones[kill] = True
- truncateds[kill] = False
- infos[kill] = {'dead': True}
-
- # TODO: Fix this
- assert self.spawn_per_tick == 0
- for spawn in range(self.spawn_per_tick):
- # TODO: Make pufferlib check if an agent respawns on the
- # Same tick as it dies (is this good or bad?)
- spawn = self.rng.choice(self.possible_agents)
- if spawn not in self.agents + dead:
- self.agents.append(spawn)
-
- for agent in self.agents:
- obs[agent] = _sample_space(agent, self.tick, self._observation_space)
- rewards[agent] = 0.1 * _agent_str_to_int(agent)
- dones[agent] = False
- truncateds[agent] = False
- infos[agent] = {'dead': False}
-
- return obs, rewards, dones, truncateds, infos
-
- def observation_space(self, agent) -> gym.Space:
- return self._observation_space
-
- def action_space(self, agent) -> gym.Space:
- return self._action_space
-
- def render(self, mode='human'):
- pass
-
- def close(self):
- pass
-
-### Other Mock environments and utilities
-def _agent_str_to_int(agent):
- return int(agent.split('_')[-1])
-
-def _sample_space(agent, tick, space, zero=False):
- if isinstance(agent, str):
- agent = float(agent.split('_')[-1])
-
- if isinstance(space, spaces.Discrete):
- if zero:
- return 0
- return int((10*agent + tick) % space.n)
- elif isinstance(space, spaces.Box):
- if zero:
- return np.zeros(space.shape, dtype=space.dtype)
-
- # Try to make a relatively unique data pattern
- # without using RNG
- nonce = 10*agent + tick
- low = space.low
- high = space.high
- sample = low + np.arange(low.size).reshape(space.shape) + nonce
- sample = (sample % high).astype(space.dtype)
- return sample
- elif isinstance(space, spaces.Tuple):
- return tuple(_sample_space(agent, tick, s, zero) for s in space.spaces)
- elif isinstance(space, spaces.Dict):
- return {k: _sample_space(agent, tick, v, zero) for k, v in space.spaces.items()}
- else:
- raise ValueError(f"Invalid space type: {type(space)}")
diff --git a/pufferlib/environments/test/mock_environments.py b/pufferlib/environments/test/mock_environments.py
deleted file mode 100644
index 8e8db330e..000000000
--- a/pufferlib/environments/test/mock_environments.py
+++ /dev/null
@@ -1,429 +0,0 @@
-from pdb import set_trace as T
-import numpy as np
-
-import time
-import hashlib
-from functools import partial
-
-import gymnasium as gym
-from gymnasium.spaces import Box, Discrete, Dict, Tuple
-from pettingzoo.utils.env import ParallelEnv
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.utils
-
-
-HIGH = 100
-LOW = 0
-
-def make_performance_env(delay=0, bandwidth=1):
- return pufferlib.emulation.PettingZooPufferEnv(
- env_creator=PerformanceEnv,
- env_args=[delay, bandwidth],
- )
-
-class PerformanceEnv:
- def __init__(self, delay=0, bandwith=1):
- self.agents = [1]
- self.possible_agents = [1]
- self.done = False
-
- self.delay = delay
- assert bandwith > 0
- self.bandwidth = bandwith
-
- def reset(self, seed=None):
- return {1: self.observation_space(1).sample()}, {1: {}}
-
- def step(self, actions):
- obs = {1: np.array([0], dtype=np.float32)}
- rewards = {1: 1}
- dones = {1: False}
- truncateds = {1: False}
- infos = {1: {}}
-
- # Busy wait so process does not swap on sleep
- end = time.perf_counter() + self.delay
- while time.perf_counter() < end:
- pass
-
- return obs, rewards, dones, truncateds, infos
-
- def observation_space(self, agent):
- return Box(
- low=-2**20, high=2**20,
- shape=(self.bandwidth,), dtype=np.float32
- )
-
- def action_space(self, agent):
- return Discrete(2)
-
-
-### Other Mock environments and utilities
-def _agent_str_to_int(agent):
- return int(agent.split('_')[-1])
-
-
-def _sample_space(agent, tick, space, zero=False):
- if isinstance(agent, str):
- agent = float(agent.split('_')[-1])
-
- if isinstance(space, Discrete):
- if zero:
- return 0
- return int((10*agent + tick) % space.n)
- elif isinstance(space, Box):
- if zero:
- return np.zeros(space.shape, dtype=space.dtype)
-
- # Try to make a relatively unique data pattern
- # without using RNG
- nonce = 10*agent + tick
- low = space.low
- high = space.high
- sample = low + np.arange(low.size).reshape(space.shape) + nonce
- sample = (sample % high).astype(space.dtype)
- return sample
- elif isinstance(space, Tuple):
- return tuple(_sample_space(agent, tick, s, zero) for s in space.spaces)
- elif isinstance(space, Dict):
- return {k: _sample_space(agent, tick, v, zero) for k, v in space.spaces.items()}
- else:
- raise ValueError(f"Invalid space type: {type(space)}")
-
-class GymnasiumTestEnv(gym.Env):
- def __init__(self, observation_space, action_space):
- self.observation_space = observation_space
- self.action_space = action_space
-
- def reset(self, seed=None):
- self.tick = 0
- self.rng = pufferlib.utils.RandomState(seed)
-
- ob = _sample_space('agent_1', self.tick, self.observation_space)
- return ob, {}
-
- def step(self, actions):
- reward = self.tick
- done = self.tick < 10
- self.tick += 1
-
- ob = _sample_space('agent_1', self.tick, self.observation_space)
- return ob, reward, done, False, {'dead': done}
-
-
-def make_mock_singleagent_env(observation_space, action_space):
- return partial(
- GymnasiumTestEnv,
- observation_space=observation_space,
- action_space=action_space,
- )
-
-class TestEnv(ParallelEnv):
- def __init__(self, observation_space, action_space, initial_agents,
- max_agents, spawn_per_tick, death_per_tick):
- self.single_observation_space = observation_space
- self.single_action_space = action_space
- self.initial_agents = initial_agents
- self.max_agents = max_agents
- self.spawn_per_tick = spawn_per_tick
- self.death_per_tick = death_per_tick
-
- self.possible_agents = [f'agent_{i+1}' for i in range(max_agents)]
- self.agents = []
-
- def reset(self, seed=None):
- self.tick = 0
- self.agents = self.possible_agents[:self.initial_agents]
-
- obs = {a: _sample_space(a, self.tick, self.single_observation_space)
- for a in self.agents}
- infos = {a: {} for a in self.agents}
- return obs, infos
-
- def step(self, actions):
- obs, rewards, dones, truncateds, infos = {}, {}, {}, {}, {}
- self.tick += 1
-
- dead = self.agents[:self.death_per_tick]
- for kill in dead:
- self.agents.remove(kill)
- # TODO: Make pufferlib work without pad obs
- # but still require rewards, dones, and optionally infos
- obs[kill] = _sample_space(kill, self.tick, self.single_observation_space, zero=True)
- rewards[kill] = -1
- dones[kill] = True
- truncateds[kill] = False
- infos[kill] = {'dead': True}
-
- # TODO: Fix this
- assert self.spawn_per_tick == 0
- for spawn in range(self.spawn_per_tick):
- # TODO: Make pufferlib check if an agent respawns on the
- # Same tick as it dies (is this good or bad?)
- spawn = self.rng.choice(self.possible_agents)
- if spawn not in self.agents + dead:
- self.agents.append(spawn)
-
- for agent in self.agents:
- obs[agent] = _sample_space(agent, self.tick, self.single_observation_space)
- rewards[agent] = 0.1 * _agent_str_to_int(agent)
- dones[agent] = False
- truncateds[agent] = False
- infos[agent] = {'dead': False}
-
- return obs, rewards, dones, truncateds, infos
-
- def observation_space(self, agent) -> gym.Space:
- return self.single_observation_space
-
- def action_space(self, agent) -> gym.Space:
- return self.single_action_space
-
- def render(self, mode='human'):
- pass
-
- def close(self):
- pass
-
-def make_mock_multiagent_env(
- observation_space,
- action_space,
- initial_agents,
- max_agents,
- spawn_per_tick,
- death_per_tick,
- homogeneous_spaces=True):
- return partial(
- TestEnv,
- observation_space=observation_space,
- action_space=action_space,
- initial_agents=initial_agents,
- max_agents=max_agents,
- spawn_per_tick=spawn_per_tick,
- death_per_tick=death_per_tick,
- )
-
-
-MOCK_OBSERVATION_SPACES = [
- # Atari space
- Box(low=0, high=255, shape=(4, 84, 84), dtype=np.uint8),
-
- # NetHack space
- Dict({
- 'blstats': Box(-2147483648, 2147483647, (27,), 'int64'),
- 'chars': Box(0, 255, (21, 79), 'uint8'),
- 'colors': Box(0, 15, (21, 79), 'uint8'),
- 'glyphs': Box(0, 5976, (21, 79), 'int16'),
- 'inv_glyphs': Box(0, 5976, (55,), 'int16'),
- 'inv_letters': Box(0, 127, (55,), 'uint8'),
- 'inv_oclasses': Box(0, 18, (55,), 'uint8'),
- 'inv_strs': Box(0, 255, (55, 80), 'uint8'),
- 'message': Box(0, 255, (256,), 'uint8'),
- 'screen_descriptions': Box(0, 127, (21, 79, 80), 'uint8'),
- 'specials': Box(0, 255, (21, 79), 'uint8'),
- 'tty_chars': Box(0, 255, (24, 80), 'uint8'),
- 'tty_colors': Box(0, 31, (24, 80), 'int8'),
- 'tty_cursor': Box(0, 255, (2,), 'uint8'),
- }),
-
- # Neural MMO space
- Dict({
- 'ActionTargets': Dict({
- 'Attack': Dict({
- 'Style': Box(0, 1, (3,), 'int8'),
- 'Target': Box(0, 1, (100,), 'int8'),
- }),
- 'Buy': Dict({
- 'MarketItem': Box(0, 1, (1024,), 'int8'),
- }),
- 'Comm': Dict({
- 'Token': Box(0, 1, (50,), 'int8'),
- }),
- 'Destroy': Dict({
- 'InventoryItem': Box(0, 1, (12,), 'int8'),
- }),
- 'Give': Dict({
- 'InventoryItem': Box(0, 1, (12,), 'int8'),
- 'Target': Box(0, 1, (100,), 'int8'),
- }),
- 'GiveGold': Dict({
- 'Price': Box(0, 1, (99,), 'int8'),
- 'Target': Box(0, 1, (100,), 'int8'),
- }),
- 'Move': Dict({
- 'Direction': Box(0, 1, (5,), 'int8'),
- }),
- 'Sell': Dict({
- 'InventoryItem': Box(0, 1, (12,), 'int8'),
- 'Price': Box(0, 1, (99,), 'int8'),
- }),
- 'Use': Dict({
- 'InventoryItem': Box(0, 1, (12,), 'int8'),
- })
- }),
- 'AgentId': Discrete(129),
- 'CurrentTick': Discrete(1025),
- 'Entity': Box(-32768, 32767, (100, 23), 'int16'),
- 'Inventory': Box(-32768, 32767, (12, 16), 'int16'),
- 'Market': Box(-32768, 32767, (1024, 16), 'int16'),
- 'Task': Box(-32770.0, 32770.0, (1024,), 'float16'),
- 'Tile': Box(-32768, 32767, (225, 3), 'int16'),
- }),
-
- # Simple spaces
- Discrete(5),
- Box(low=LOW, high=HIGH, shape=(4,), dtype=np.float32),
-
- # Nested spaces
- Dict({
- "foo": Box(low=LOW, high=HIGH, shape=(2,), dtype=np.float32),
- "bar": Box(low=LOW, high=HIGH, shape=(2,), dtype=np.float32),
- }),
- Tuple((Discrete(3), Discrete(4))),
- Tuple((
- Box(low=LOW, high=HIGH, shape=(2,), dtype=np.float32),
- Discrete(3),
- Dict({
- "baz": Box(low=LOW, high=HIGH, shape=(1,), dtype=np.float32),
- "qux": Box(low=LOW, high=HIGH, shape=(1,), dtype=np.float32),
- }),
- )),
- Dict({
- "foo": Tuple((
- Box(low=LOW, high=HIGH, shape=(2,), dtype=np.float32),
- Discrete(3),
- )),
- "bar": Dict({
- "baz": Discrete(2),
- "qux": Discrete(4),
- }),
- }),
-]
-
-
-MOCK_ACTION_SPACES = [
- # NetHack action space
- Discrete(5),
-
- # Neural MMO action space
- Dict({
- 'Attack': Dict({
- 'Style': Discrete(3),
- 'Target': Discrete(100),
- }),
- 'Buy': Dict({
- 'MarketItem': Discrete(1024),
- }),
- 'Comm': Dict({
- 'Token': Discrete(50),
- }),
- 'Destroy': Dict({
- 'InventoryItem': Discrete(12),
- }),
- 'Give': Dict({
- 'InventoryItem': Discrete(12),
- 'Target': Discrete(100),
- }),
- 'GiveGold': Dict({
- 'Price': Discrete(99),
- 'Target': Discrete(100),
- }),
- 'Move': Dict({
- 'Direction': Discrete(5),
- }),
- 'Sell': Dict({
- 'InventoryItem': Discrete(12),
- 'Price': Discrete(99),
- }),
- 'Use': Dict({
- 'InventoryItem': Discrete(12),
- })
- }),
-
- # Nested spaces
- Tuple((gym.spaces.Discrete(2), gym.spaces.Discrete(3))),
- Dict({
- "foo": Discrete(4),
- "bar": Discrete(2),
- }),
- Tuple((
- Discrete(4),
- Dict({
- "baz": Discrete(2),
- "qux": Discrete(2),
- }),
- )),
- Dict({
- "foo": Tuple((
- Discrete(2),
- Discrete(3),
- )),
- "bar": Dict({
- "baz": Discrete(2),
- "qux": Discrete(4),
- }),
- }),
-]
-
-MOCK_TEAMS = {
- 'None': None,
- 'single': {
- 'team_1': ['agent_1'],
- 'team_2': ['agent_2'],
- 'team_3': ['agent_3'],
- 'team_4': ['agent_4'],
- 'team_5': ['agent_5'],
- 'team_6': ['agent_6'],
- 'team_7': ['agent_7'],
- 'team_8': ['agent_8'],
- 'team_9': ['agent_9'],
- 'team_10': ['agent_10'],
- 'team_11': ['agent_11'],
- 'team_12': ['agent_12'],
- 'team_13': ['agent_13'],
- 'team_14': ['agent_14'],
- 'team_15': ['agent_15'],
- 'team_16': ['agent_16'],
- },
- 'pairs': {
- 'team_1': ['agent_1', 'agent_2'],
- 'team_2': ['agent_3', 'agent_4'],
- 'team_3': ['agent_5', 'agent_6'],
- 'team_4': ['agent_7', 'agent_8'],
- 'team_5': ['agent_9', 'agent_10'],
- 'team_6': ['agent_11', 'agent_12'],
- 'team_7': ['agent_13', 'agent_14'],
- 'team_8': ['agent_15', 'agent_16'],
- },
- 'mixed': {
- 'team_1': ['agent_1', 'agent_2'],
- 'team_2': ['agent_3', 'agent_4', 'agent_5', 'agent_6'],
- 'team_3': ['agent_7', 'agent_8', 'agent_9'],
- 'team_4': ['agent_10', 'agent_11', 'agent_12', 'agent_13', 'agent_14'],
- 'team_5': ['agent_15', 'agent_16'],
- },
-}
-
-MOCK_SINGLE_AGENT_ENVIRONMENTS = []
-MOCK_MULTI_AGENT_ENVIRONMENTS = []
-for obs_space in MOCK_OBSERVATION_SPACES:
- for act_space in MOCK_ACTION_SPACES:
- MOCK_SINGLE_AGENT_ENVIRONMENTS.append(
- make_mock_singleagent_env(
- observation_space=obs_space,
- action_space=act_space,
- )
- )
-
- MOCK_MULTI_AGENT_ENVIRONMENTS.append(
- make_mock_multiagent_env(
- observation_space=obs_space,
- action_space=act_space,
- initial_agents=16,
- max_agents=16,
- spawn_per_tick=0,
- death_per_tick=1,
- )
- )
diff --git a/pufferlib/environments/test/torch.py b/pufferlib/environments/test/torch.py
deleted file mode 100644
index 8b13194e9..000000000
--- a/pufferlib/environments/test/torch.py
+++ /dev/null
@@ -1 +0,0 @@
-from pufferlib.models import Default as Policy
diff --git a/pufferlib/environments/trade_sim/__init__.py b/pufferlib/environments/trade_sim/__init__.py
deleted file mode 100644
index eff86ef02..000000000
--- a/pufferlib/environments/trade_sim/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator, make
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/trade_sim/environment.py b/pufferlib/environments/trade_sim/environment.py
deleted file mode 100644
index 0c245c0b2..000000000
--- a/pufferlib/environments/trade_sim/environment.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import functools
-import numpy as np
-
-import pufferlib
-
-from nof1.simulation.env import TradingEnvironment
-
-def env_creator(name='metta'):
- return functools.partial(make, name)
-
-def make(name, config_path='../nof1-trading-sim/config/experiment_cv.yaml', render_mode='human', buf=None, seed=1):
- '''Crafter creation function'''
- from nof1.utils.config_manager import ConfigManager
- from nof1.data_ingestion.historical_data_reader import HistoricalDataReader
-
- config_manager = ConfigManager(config_path)
- config = config_manager.config
- data_reader = HistoricalDataReader(config_manager)
- states, prices, atrs, timestamps = data_reader.preprocess_data()
-
- # Create environment
- env = TradingEnvironmentPuff(config_manager.config, states=states, prices=prices, atrs=atrs, timestamps=timestamps)
- return pufferlib.emulation.GymnasiumPufferEnv(env, buf=buf)
-
-class TradingEnvironmentPuff(TradingEnvironment):
- def reset(self):
- obs, info = super().reset()
- return obs.astype(np.float32), info
-
- def step(self, action):
- obs, reward, terminated, truncated, info = super().step(action)
-
- if not terminated and not truncated:
- info = {}
-
- return obs.astype(np.float32), reward, terminated, truncated, info
-
diff --git a/pufferlib/environments/trade_sim/torch.py b/pufferlib/environments/trade_sim/torch.py
deleted file mode 100644
index be832843f..000000000
--- a/pufferlib/environments/trade_sim/torch.py
+++ /dev/null
@@ -1,4 +0,0 @@
-import pufferlib.models
-
-Policy = pufferlib.models.Default
-Recurrent = pufferlib.models.LSTMWrapper
diff --git a/pufferlib/environments/vizdoom/__init__.py b/pufferlib/environments/vizdoom/__init__.py
deleted file mode 100644
index 59cda9e7c..000000000
--- a/pufferlib/environments/vizdoom/__init__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .environment import env_creator
-
-try:
- import torch
-except ImportError:
- pass
-else:
- from .torch import Policy
- try:
- from .torch import Recurrent
- except:
- Recurrent = None
diff --git a/pufferlib/environments/vizdoom/environment.py b/pufferlib/environments/vizdoom/environment.py
deleted file mode 100644
index d98a263f9..000000000
--- a/pufferlib/environments/vizdoom/environment.py
+++ /dev/null
@@ -1,69 +0,0 @@
-from pdb import set_trace as T
-import numpy as np
-import functools
-
-import gymnasium as gym
-
-import pufferlib
-import pufferlib.emulation
-import pufferlib.environments
-import pufferlib.utils
-import pufferlib.postprocess
-
-
-def env_creator(name='doom'):
- return functools.partial(make, name)
-
-def make(name, framestack=1, render_mode='rgb_array', buf=None):
- '''Atari creation function with default CleanRL preprocessing based on Stable Baselines3 wrappers'''
- if name == 'doom':
- name = 'VizdoomHealthGatheringSupreme-v0'
-
- #pufferlib.environments.try_import('vizdoom', 'gymnasium_wrapper')
- from stable_baselines3.common.atari_wrappers import (
- ClipRewardEnv,
- EpisodicLifeEnv,
- FireResetEnv,
- MaxAndSkipEnv,
- NoopResetEnv,
- )
- # Make does not work without this imported
- # TODO: Fix try_import
- from vizdoom import gymnasium_wrapper
- with pufferlib.utils.Suppress():
- env = gym.make(name, render_mode=render_mode)
-
- env = DoomWrapper(env) # Don't use standard postprocessor
-
- #env = gym.wrappers.RecordEpisodeStatistics(env)
- #env = NoopResetEnv(env, noop_max=30)
- #env = MaxAndSkipEnv(env, skip=4)
- #env = EpisodicLifeEnv(env)
- #if "FIRE" in env.unwrapped.get_action_meanings():
- # env = FireResetEnv(env)
- #env = ClipRewardEnv(env)
- #env = gym.wrappers.GrayScaleObservation(env)
- #env = gym.wrappers.FrameStack(env, framestack)
- return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
-
-class DoomWrapper(gym.Wrapper):
- '''Gymnasium env does not expose proper options for screen scale and
- render format. This is slow. So we do it ourselves. Not it is fast. Yay!'''
- def __init__(self, env):
- super().__init__(env.unwrapped)
- if env.observation_space['screen'].shape[0] != 120:
- raise ValueError('Wrong screen resolution. Doom does not provide '
- 'a way to change this. You must edit scenarios/.cfg'
- 'This is inside your local ViZDoom installation. Likely in python system packages'
- 'Set screen resolution to RES_160X120 and screen format to GRAY8')
-
- self.observation_space = gym.spaces.Box(
- low=0, high=255, shape=(60, 80, 1), dtype=np.uint8)
-
- def reset(self, seed=None, options=None):
- obs, info = self.env.reset(seed=seed, options=options)
- return obs['screen'][::2, ::2], {}
-
- def step(self, action):
- obs, reward, terminal, truncated, info = self.env.step(action)
- return obs['screen'][::2, ::2], reward, terminal, truncated, info
diff --git a/pufferlib/environments/vizdoom/torch.py b/pufferlib/environments/vizdoom/torch.py
deleted file mode 100644
index 4fd6964a5..000000000
--- a/pufferlib/environments/vizdoom/torch.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import pufferlib.models
-
-
-class Recurrent(pufferlib.models.LSTMWrapper):
- def __init__(self, env, policy, input_size=512, hidden_size=512, num_layers=1):
- super().__init__(env, policy, input_size, hidden_size, num_layers)
-
-class Policy(pufferlib.models.Convolutional):
- def __init__(self, env, input_size=512, hidden_size=512, output_size=512,
- framestack=1, flat_size=64*4*6):
- super().__init__(
- env=env,
- input_size=input_size,
- hidden_size=hidden_size,
- output_size=output_size,
- framestack=framestack,
- flat_size=flat_size,
- channels_last=True
- )
diff --git a/pufferlib/extensions/puffernet.h b/pufferlib/extensions/puffernet.h
index 414cd74ac..ac1a19e29 100644
--- a/pufferlib/extensions/puffernet.h
+++ b/pufferlib/extensions/puffernet.h
@@ -39,18 +39,38 @@ struct Weights {
void _load_weights(const char* filename, float* weights, size_t num_weights) {
FILE* file = fopen(filename, "rb");
if (!file) {
- perror("Error opening file");
+ fprintf(stderr, "Error: Could not open weights file: %s\n", filename);
+ exit(1);
}
+
+ // Get file size
fseek(file, 0, SEEK_END);
+ long file_size = ftell(file);
rewind(file);
+
size_t read_size = fread(weights, sizeof(float), num_weights, file);
fclose(file);
if (read_size != num_weights) {
- perror("Error reading file");
+ fprintf(stderr, "Error: Failed to read weights from file: %s\n", filename);
+ fprintf(stderr, " Expected to read: %zu weights\n", num_weights);
+ fprintf(stderr, " Actually read: %zu weights\n", read_size);
+ exit(1);
}
}
-Weights* load_weights(const char* filename, size_t num_weights) {
+Weights* load_weights(const char* filename) {
+ FILE* file = fopen(filename, "rb");
+ if (!file) {
+ perror("Error opening weights file");
+ return NULL;
+ }
+ fseek(file, 0, SEEK_END);
+ size_t file_size = ftell(file);
+ fclose(file);
+
+ size_t num_weights = file_size / sizeof(float);
+ printf("Loading %zu weights from %s\n", num_weights, filename);
+
Weights* weights = calloc(1, sizeof(Weights) + num_weights*sizeof(float));
weights->data = (float*)(weights + 1);
_load_weights(filename, weights->data, num_weights);
@@ -76,7 +96,7 @@ void _relu(float* input, float* output, int size) {
void _gelu(float* input, float* output, int size) {
for (int i = 0; i < size; i++) {
- output[i] = 0.5f*input[i]*(1 + tanhf(0.6628526501011142 * (input[i] + 0.044715f*input[i]*input[i]*input[i])));
+ output[i] = 0.5f*input[i]*(1 + tanhf(0.7978845608028654 * (input[i] + 0.044715f*input[i]*input[i]*input[i])));
}
}
@@ -120,7 +140,7 @@ void _conv2d(float* input, float* weights, float* bias,
for (int w = 0; w < w_out; w++) {
int out_adr = (
b*out_channels*h_out*w_out
- + oc*h_out*w_out+
+ + oc*h_out*w_out+
+ h*w_out
+ w
);
@@ -516,7 +536,7 @@ struct Conv3D {
Conv3D* make_conv3d(Weights* weights, int batch_size, int in_width, int in_height, int in_depth,
int in_channels, int out_channels, int kernel_size, int stride) {
-
+
size_t buffer_size = batch_size*out_channels*in_depth*in_height*in_width*sizeof(float);
int num_weights = out_channels*in_channels*kernel_size*kernel_size*kernel_size;
Conv3D* layer = calloc(1, sizeof(Conv3D) + buffer_size);
@@ -629,7 +649,7 @@ LayerNorm* make_layernorm(Weights* weights, int batch_size, int input_dim) {
};
return layer;
}
-
+
void layernorm(LayerNorm* layer, float* input) {
_layernorm(input, layer->weights, layer->bias, layer->output,
layer->batch_size, layer->input_dim);
diff --git a/pufferlib/extensions/puffernet.pyx b/pufferlib/extensions/puffernet.pyx
index c2dffd200..6dfac40c2 100644
--- a/pufferlib/extensions/puffernet.pyx
+++ b/pufferlib/extensions/puffernet.pyx
@@ -91,4 +91,3 @@ def puf_argmax_multidiscrete(cnp.ndarray input, cnp.ndarray output,
int batch_size, cnp.ndarray logit_sizes, int num_actions):
_argmax_multidiscrete( input.data, output.data,
batch_size, logit_sizes.data, num_actions)
-
diff --git a/pufferlib/models.py b/pufferlib/models.py
index fa43d7071..0893a9db4 100644
--- a/pufferlib/models.py
+++ b/pufferlib/models.py
@@ -1,4 +1,3 @@
-from pdb import set_trace as T
import numpy as np
import torch
@@ -10,7 +9,7 @@
class Default(nn.Module):
- '''Default PyTorch policy. Flattens obs and applies a linear layer.
+ """Default PyTorch policy. Flattens obs and applies a linear layer.
PufferLib is not a framework. It does not enforce a base class.
You can use any PyTorch policy that returns actions and values.
@@ -20,18 +19,17 @@ class Default(nn.Module):
for use with our LSTM wrapper, simply put everything from forward() before
the recurrent cell into encode_observations and put everything after
into decode_actions.
- '''
+ """
+
def __init__(self, env, hidden_size=128):
super().__init__()
self.hidden_size = hidden_size
- self.is_multidiscrete = isinstance(env.single_action_space,
- pufferlib.spaces.MultiDiscrete)
- self.is_continuous = isinstance(env.single_action_space,
- pufferlib.spaces.Box)
+ self.is_multidiscrete = isinstance(env.single_action_space, pufferlib.spaces.MultiDiscrete)
+ self.is_continuous = isinstance(env.single_action_space, pufferlib.spaces.Box)
try:
- self.is_dict_obs = isinstance(env.env.observation_space, pufferlib.spaces.Dict)
+ self.is_dict_obs = isinstance(env.env.observation_space, pufferlib.spaces.Dict)
except:
- self.is_dict_obs = isinstance(env.observation_space, pufferlib.spaces.Dict)
+ self.is_dict_obs = isinstance(env.observation_space, pufferlib.spaces.Dict)
if self.is_dict_obs:
self.dtype = pufferlib.pytorch.nativize_dtype(env.emulated)
@@ -43,24 +41,21 @@ def __init__(self, env, hidden_size=128):
pufferlib.pytorch.layer_init(nn.Linear(num_obs, hidden_size)),
nn.GELU(),
)
-
+
if self.is_multidiscrete:
self.action_nvec = tuple(env.single_action_space.nvec)
num_atns = sum(self.action_nvec)
- self.decoder = pufferlib.pytorch.layer_init(
- nn.Linear(hidden_size, num_atns), std=0.01)
+ self.decoder = pufferlib.pytorch.layer_init(nn.Linear(hidden_size, num_atns), std=0.01)
elif not self.is_continuous:
num_atns = env.single_action_space.n
- self.decoder = pufferlib.pytorch.layer_init(
- nn.Linear(hidden_size, num_atns), std=0.01)
+ self.decoder = pufferlib.pytorch.layer_init(nn.Linear(hidden_size, num_atns), std=0.01)
else:
self.decoder_mean = pufferlib.pytorch.layer_init(
- nn.Linear(hidden_size, env.single_action_space.shape[0]), std=0.01)
- self.decoder_logstd = nn.Parameter(torch.zeros(
- 1, env.single_action_space.shape[0]))
+ nn.Linear(hidden_size, env.single_action_space.shape[0]), std=0.01
+ )
+ self.decoder_logstd = nn.Parameter(torch.zeros(1, env.single_action_space.shape[0]))
- self.value = pufferlib.pytorch.layer_init(
- nn.Linear(hidden_size, 1), std=1)
+ self.value = pufferlib.pytorch.layer_init(nn.Linear(hidden_size, 1), std=1)
def forward_eval(self, observations, state=None):
hidden = self.encode_observations(observations, state=state)
@@ -71,19 +66,19 @@ def forward(self, observations, state=None):
return self.forward_eval(observations, state)
def encode_observations(self, observations, state=None):
- '''Encodes a batch of observations into hidden states. Assumes
- no time dimension (handled by LSTM wrappers).'''
+ """Encodes a batch of observations into hidden states. Assumes
+ no time dimension (handled by LSTM wrappers)."""
batch_size = observations.shape[0]
if self.is_dict_obs:
observations = pufferlib.pytorch.nativize_tensor(observations, self.dtype)
observations = torch.cat([v.view(batch_size, -1) for v in observations.values()], dim=1)
- else:
+ else:
observations = observations.view(batch_size, -1)
return self.encoder(observations.float())
def decode_actions(self, hidden):
- '''Decodes a batch of hidden states into (multi)discrete actions.
- Assumes no time dimension (handled by LSTM wrappers).'''
+ """Decodes a batch of hidden states into (multi)discrete actions.
+ Assumes no time dimension (handled by LSTM wrappers)."""
if self.is_multidiscrete:
logits = self.decoder(hidden).split(self.action_nvec, dim=1)
elif self.is_continuous:
@@ -97,12 +92,13 @@ def decode_actions(self, hidden):
values = self.value(hidden)
return logits, values
+
class LSTMWrapper(nn.Module):
def __init__(self, env, policy, input_size=128, hidden_size=128):
- '''Wraps your policy with an LSTM without letting you shoot yourself in the
+ """Wraps your policy with an LSTM without letting you shoot yourself in the
foot with bad transpose and shape operations. This saves much pain.
Requires that your policy define encode_observations and decode_actions.
- See the Default policy for an example.'''
+ See the Default policy for an example."""
super().__init__()
self.obs_shape = env.single_observation_space.shape
@@ -112,7 +108,7 @@ def __init__(self, env, policy, input_size=128, hidden_size=128):
self.is_continuous = self.policy.is_continuous
for name, param in self.named_parameters():
- if 'layer_norm' in name:
+ if "layer_norm" in name:
continue
if "bias" in name:
nn.init.constant_(param, 0)
@@ -127,96 +123,107 @@ def __init__(self, env, policy, input_size=128, hidden_size=128):
self.cell.bias_ih = self.lstm.bias_ih_l0
self.cell.bias_hh = self.lstm.bias_hh_l0
- #self.pre_layernorm = nn.LayerNorm(hidden_size)
- #self.post_layernorm = nn.LayerNorm(hidden_size)
+ # self.pre_layernorm = nn.LayerNorm(hidden_size)
+ # self.post_layernorm = nn.LayerNorm(hidden_size)
def forward_eval(self, observations, state):
- '''Forward function for inference. 3x faster than using LSTM directly'''
+ """Forward function for inference. 3x faster than using LSTM directly"""
hidden = self.policy.encode_observations(observations, state=state)
- h = state['lstm_h']
- c = state['lstm_c']
+ h = state["lstm_h"]
+ c = state["lstm_c"]
# TODO: Don't break compile
if h is not None:
- assert h.shape[0] == c.shape[0] == observations.shape[0], 'LSTM state must be (h, c)'
+ assert h.shape[0] == c.shape[0] == observations.shape[0], "LSTM state must be (h, c)"
lstm_state = (h, c)
else:
lstm_state = None
- #hidden = self.pre_layernorm(hidden)
+ # hidden = self.pre_layernorm(hidden)
hidden, c = self.cell(hidden, lstm_state)
- #hidden = self.post_layernorm(hidden)
- state['hidden'] = hidden
- state['lstm_h'] = hidden
- state['lstm_c'] = c
+ # hidden = self.post_layernorm(hidden)
+ state["hidden"] = hidden
+ state["lstm_h"] = hidden
+ state["lstm_c"] = c
logits, values = self.policy.decode_actions(hidden)
return logits, values
def forward(self, observations, state):
- '''Forward function for training. Uses LSTM for fast time-batching'''
+ """Forward function for training. Uses LSTM for fast time-batching"""
x = observations
- lstm_h = state['lstm_h']
- lstm_c = state['lstm_c']
+ lstm_h = state["lstm_h"]
+ lstm_c = state["lstm_c"]
x_shape, space_shape = x.shape, self.obs_shape
x_n, space_n = len(x_shape), len(space_shape)
if x_shape[-space_n:] != space_shape:
- raise ValueError('Invalid input tensor shape', x.shape)
+ raise ValueError("Invalid input tensor shape", x.shape)
if x_n == space_n + 1:
B, TT = x_shape[0], 1
elif x_n == space_n + 2:
B, TT = x_shape[:2]
else:
- raise ValueError('Invalid input tensor shape', x.shape)
+ raise ValueError("Invalid input tensor shape", x.shape)
if lstm_h is not None:
- assert lstm_h.shape[1] == lstm_c.shape[1] == B, 'LSTM state must be (h, c)'
+ assert lstm_h.shape[1] == lstm_c.shape[1] == B, "LSTM state must be (h, c)"
lstm_state = (lstm_h, lstm_c)
else:
lstm_state = None
- x = x.reshape(B*TT, *space_shape)
+ x = x.reshape(B * TT, *space_shape)
hidden = self.policy.encode_observations(x, state)
- assert hidden.shape == (B*TT, self.input_size)
+ assert hidden.shape == (B * TT, self.input_size)
hidden = hidden.reshape(B, TT, self.input_size)
hidden = hidden.transpose(0, 1)
- #hidden = self.pre_layernorm(hidden)
+ # hidden = self.pre_layernorm(hidden)
hidden, (lstm_h, lstm_c) = self.lstm.forward(hidden, lstm_state)
hidden = hidden.float()
-
- #hidden = self.post_layernorm(hidden)
+
+ # hidden = self.post_layernorm(hidden)
hidden = hidden.transpose(0, 1)
- flat_hidden = hidden.reshape(B*TT, self.hidden_size)
+ flat_hidden = hidden.reshape(B * TT, self.hidden_size)
logits, values = self.policy.decode_actions(flat_hidden)
values = values.reshape(B, TT)
- #state.batch_logits = logits.reshape(B, TT, -1)
- state['hidden'] = hidden
- state['lstm_h'] = lstm_h.detach()
- state['lstm_c'] = lstm_c.detach()
+ # state.batch_logits = logits.reshape(B, TT, -1)
+ state["hidden"] = hidden
+ state["lstm_h"] = lstm_h.detach()
+ state["lstm_c"] = lstm_c.detach()
return logits, values
+
class Convolutional(nn.Module):
- def __init__(self, env, *args, framestack, flat_size,
- input_size=512, hidden_size=512, output_size=512,
- channels_last=False, downsample=1, **kwargs):
- '''The CleanRL default NatureCNN policy used for Atari.
+ def __init__(
+ self,
+ env,
+ *args,
+ framestack,
+ flat_size,
+ input_size=512,
+ hidden_size=512,
+ output_size=512,
+ channels_last=False,
+ downsample=1,
+ **kwargs,
+ ):
+ """The CleanRL default NatureCNN policy used for Atari.
It's just a stack of three convolutions followed by a linear layer
-
+
Takes framestack as a mandatory keyword argument. Suggested default is 1 frame
- with LSTM or 4 frames without.'''
+ with LSTM or 4 frames without."""
super().__init__()
self.channels_last = channels_last
self.downsample = downsample
- #TODO: Remove these from required params
+ # TODO: Remove these from required params
self.hidden_size = hidden_size
self.is_continuous = False
- self.network= nn.Sequential(
+ self.network = nn.Sequential(
pufferlib.pytorch.layer_init(nn.Conv2d(framestack, 32, 8, stride=4)),
nn.ReLU(),
pufferlib.pytorch.layer_init(nn.Conv2d(32, 64, 4, stride=2)),
@@ -227,10 +234,8 @@ def __init__(self, env, *args, framestack, flat_size,
pufferlib.pytorch.layer_init(nn.Linear(flat_size, hidden_size)),
nn.ReLU(),
)
- self.actor = pufferlib.pytorch.layer_init(
- nn.Linear(hidden_size, env.single_action_space.n), std=0.01)
- self.value_fn = pufferlib.pytorch.layer_init(
- nn.Linear(output_size, 1), std=1)
+ self.actor = pufferlib.pytorch.layer_init(nn.Linear(hidden_size, env.single_action_space.n), std=0.01)
+ self.value_fn = pufferlib.pytorch.layer_init(nn.Linear(output_size, 1), std=1)
def forward(self, observations, state=None):
hidden = self.encode_observations(observations)
@@ -244,7 +249,7 @@ def encode_observations(self, observations, state=None):
if self.channels_last:
observations = observations.permute(0, 3, 1, 2)
if self.downsample > 1:
- observations = observations[:, :, ::self.downsample, ::self.downsample]
+ observations = observations[:, :, :: self.downsample, :: self.downsample]
return self.network(observations.float() / 255.0)
def decode_actions(self, flat_hidden):
@@ -252,15 +257,17 @@ def decode_actions(self, flat_hidden):
value = self.value_fn(flat_hidden)
return action, value
+
class ProcgenResnet(nn.Module):
- '''Procgen baseline from the AICrowd NeurIPS 2020 competition
- Based on the ResNet architecture that was used in the Impala paper.'''
+ """Procgen baseline from the AICrowd NeurIPS 2020 competition
+ Based on the ResNet architecture that was used in the Impala paper."""
+
def __init__(self, env, cnn_width=16, mlp_width=256):
super().__init__()
h, w, c = env.single_observation_space.shape
shape = (c, h, w)
conv_seqs = []
- for out_channels in [cnn_width, 2*cnn_width, 2*cnn_width]:
+ for out_channels in [cnn_width, 2 * cnn_width, 2 * cnn_width]:
conv_seq = ConvSequence(shape, out_channels)
shape = conv_seq.get_output_shape()
conv_seqs.append(conv_seq)
@@ -271,10 +278,8 @@ def __init__(self, env, cnn_width=16, mlp_width=256):
nn.ReLU(),
]
self.network = nn.Sequential(*conv_seqs)
- self.actor = pufferlib.pytorch.layer_init(
- nn.Linear(mlp_width, env.single_action_space.n), std=0.01)
- self.value = pufferlib.pytorch.layer_init(
- nn.Linear(mlp_width, 1), std=1)
+ self.actor = pufferlib.pytorch.layer_init(nn.Linear(mlp_width, env.single_action_space.n), std=0.01)
+ self.value = pufferlib.pytorch.layer_init(nn.Linear(mlp_width, 1), std=1)
def forward(self, observations, state=None):
hidden = self.encode_observations(observations)
@@ -287,13 +292,14 @@ def forward_train(self, observations, state=None):
def encode_observations(self, x):
hidden = self.network(x.permute((0, 3, 1, 2)) / 255.0)
return hidden
-
+
def decode_actions(self, hidden):
- '''linear decoder function'''
+ """linear decoder function"""
action = self.actor(hidden)
value = self.value(hidden)
return action, value
+
class ResidualBlock(nn.Module):
def __init__(self, channels):
super().__init__()
@@ -308,12 +314,15 @@ def forward(self, x):
x = self.conv1(x)
return x + inputs
+
class ConvSequence(nn.Module):
def __init__(self, input_shape, out_channels):
super().__init__()
self._input_shape = input_shape
self._out_channels = out_channels
- self.conv = nn.Conv2d(in_channels=self._input_shape[0], out_channels=self._out_channels, kernel_size=3, padding=1)
+ self.conv = nn.Conv2d(
+ in_channels=self._input_shape[0], out_channels=self._out_channels, kernel_size=3, padding=1
+ )
self.res_block0 = ResidualBlock(self._out_channels)
self.res_block1 = ResidualBlock(self._out_channels)
diff --git a/pufferlib/ocean/__init__.py b/pufferlib/ocean/__init__.py
index 1c91a2b0f..55822f8a5 100644
--- a/pufferlib/ocean/__init__.py
+++ b/pufferlib/ocean/__init__.py
@@ -6,6 +6,7 @@
pass
else:
from .torch import Policy
+
try:
from .torch import Recurrent
except:
diff --git a/pufferlib/ocean/asteroids/asteroids.c b/pufferlib/ocean/asteroids/asteroids.c
deleted file mode 100644
index b74aae994..000000000
--- a/pufferlib/ocean/asteroids/asteroids.c
+++ /dev/null
@@ -1,36 +0,0 @@
-#include "asteroids.h"
-
-int main() {
- Asteroids env = {.size = 500, .frameskip = 1};
- env.observations = (float *)calloc(4 + 2 * 50, sizeof(float));
- env.actions = (int *)calloc(1, sizeof(int));
- env.rewards = (float *)calloc(1, sizeof(float));
- env.terminals = (unsigned char *)calloc(1, sizeof(unsigned char));
-
- c_reset(&env);
- c_render(&env);
- while (!WindowShouldClose()) {
- if (IsKeyDown(KEY_LEFT_SHIFT)) {
- if (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP)) {
- env.actions[0] = 0;
- } else if (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT)) {
- env.actions[0] = 1;
- } else if (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT)) {
- env.actions[0] = 2;
- } else if (IsKeyDown(KEY_SPACE)) {
- env.actions[0] = 3;
- } else {
- env.actions[0] = -1;
- }
- } else {
- env.actions[0] = rand() % 4;
- }
- c_step(&env);
- c_render(&env);
- }
- free(env.observations);
- free(env.actions);
- free(env.rewards);
- free(env.terminals);
- c_close(&env);
-}
diff --git a/pufferlib/ocean/asteroids/asteroids.h b/pufferlib/ocean/asteroids/asteroids.h
deleted file mode 100644
index 50569831b..000000000
--- a/pufferlib/ocean/asteroids/asteroids.h
+++ /dev/null
@@ -1,600 +0,0 @@
-#pragma once
-
-#include "raylib.h"
-#include
-#include
-#include
-#include
-
-#define MAX_PARTICLES 10
-#define MAX_ASTEROIDS 20
-
-const unsigned char FORWARD = 0;
-const unsigned char TURN_LEFT = 1;
-const unsigned char TURN_RIGHT = 2;
-const unsigned char SHOOT = 3;
-
-const float FRICTION = 0.95f;
-const float SPEED = 0.6f;
-const float PARTICLE_SPEED = 7.0f;
-const float ROTATION_SPEED = 0.1f;
-const float ASTEROID_SPEED = 3.0f;
-const int SHOOT_DELAY = 18;
-
-const int MAX_TICK = 3600;
-
-const int DEBUG = 0;
-
-// for render only game over state
-static int global_game_over_timer = 0;
-static int global_game_over_started = 0;
-static int global_render_flag = 0;
-
-typedef struct {
- float perf;
- float score;
- float episode_return;
- float episode_length;
- float n;
-} Log;
-
-typedef struct {
- Vector2 position;
- Vector2 velocity;
-} Particle;
-
-typedef struct {
- Vector2 position;
- Vector2 velocity;
- int radius;
- int radius_sq;
- Vector2 shape[12];
- int num_vertices;
-} Asteroid;
-
-typedef struct {
- Asteroid asteroid;
- float distance;
-} AsteroidDistance;
-
-typedef struct {
- Log log;
- float *observations;
- int *actions;
- float *rewards;
- unsigned char *terminals;
- int size;
- Vector2 player_position;
- Vector2 player_vel;
- float player_angle;
- int player_radius;
- int thruster_on;
- Particle particles[MAX_PARTICLES];
- int particle_index;
- Asteroid asteroids[MAX_ASTEROIDS];
- int asteroid_index;
- int last_shot;
- int tick;
- int score;
- float episode_return;
- int frameskip;
-} Asteroids;
-
-float random_float(float low, float high) {
- return low + (high - low) * ((float)rand() / (float)RAND_MAX);
-}
-
-void generate_asteroid_shape(Asteroid *as) {
- as->num_vertices = 8 + (as->radius / 10);
-
- for (int v = 0; v < as->num_vertices; v++) {
- float angle = (2.0f * PI * v) / as->num_vertices;
- float radius_variation =
- as->radius * (0.7f + 0.6f * random_float(0.0f, 1.0f));
- as->shape[v].x = cosf(angle) * radius_variation;
- as->shape[v].y = sinf(angle) * radius_variation;
- }
-}
-
-float clamp(float val, float low, float high) {
- return fmin(fmax(val, low), high);
-}
-
-Vector2 rotate_vector(Vector2 point, Vector2 center, float angle) {
- float s = sinf(angle);
- float c = cosf(angle);
-
- // Translate point back to origin:
- point.x -= center.x;
- point.y -= center.y;
-
- // Rotate point
- float xnew = point.x * c - point.y * s;
- float ynew = point.x * s + point.y * c;
-
- // Translate point back:
- point.x = xnew + center.x;
- point.y = ynew + center.y;
- return point;
-}
-
-Vector2 get_direction_vector(Asteroids *env) {
- float px = env->player_position.x;
- float py = env->player_position.y;
- Vector2 dir = (Vector2){px, py - 1};
- dir = rotate_vector(dir, env->player_position, env->player_angle);
- return (Vector2){dir.x - px, dir.y - py};
-}
-
-void move_particles(Asteroids *env) {
- Particle p;
- for (int i = 0; i < MAX_PARTICLES; i++) {
- p = env->particles[i];
- p.position.x += p.velocity.x * PARTICLE_SPEED;
- p.position.y += p.velocity.y * PARTICLE_SPEED;
- env->particles[i] = p;
- }
-}
-
-void move_asteroids(Asteroids *env) {
- Asteroid *as;
- for (int i = 0; i < MAX_ASTEROIDS; i++) {
- as = &env->asteroids[i];
- if (as->radius == 0)
- continue;
-
- as->position.x += as->velocity.x * ASTEROID_SPEED;
- as->position.y += as->velocity.y * ASTEROID_SPEED;
- }
-}
-
-Vector2 angle_to_vector(float angle) {
- Vector2 v;
- v.x = cosf(angle);
- v.y = sinf(angle);
- return v;
-}
-
-void spawn_asteroids(Asteroids *env) {
- float px, py;
- float angle;
- if (rand() % 10 == 0) {
- switch (rand() % 4) {
- case 0:
- // left edge
- px = 0;
- py = rand() % env->size;
- angle = random_float(-PI / 2, PI / 2);
- break;
- case 1:
- // right edge
- px = env->size;
- py = rand() % env->size;
- angle = random_float(PI / 2, 3 * PI / 2);
- break;
- case 2:
- // top edge
- px = rand() % env->size;
- py = 0;
- angle = random_float(PI, 2 * PI);
- break;
- default:
- // bottom edge
- px = rand() % env->size;
- py = env->size;
- angle = random_float(0, PI);
- break;
- }
-
- Vector2 direction = angle_to_vector(angle);
- Vector2 start_pos = (Vector2){px, py};
- Asteroid as;
- switch (rand() % 3) {
- case 0:
- // small
- as = (Asteroid){start_pos, direction, 10, 100};
- break;
- case 1:
- // medium
- as = (Asteroid){start_pos, direction, 20, 400};
- break;
- default:
- // big
- as = (Asteroid){start_pos, direction, 40, 1600};
- break;
- }
- env->asteroid_index = (env->asteroid_index + 1) % MAX_ASTEROIDS;
- env->asteroids[env->asteroid_index] = as;
- if (global_render_flag)
- generate_asteroid_shape(&env->asteroids[env->asteroid_index]);
- }
-}
-
-int particle_asteroid_collision(Asteroids *env, Particle *p, Asteroid *as) {
- float dx = p->position.x - as->position.x;
- float dy = p->position.y - as->position.y;
- return as->radius_sq > dx * dx + dy * dy;
-}
-
-void split_asteroid(Asteroids *env, Asteroid *as) {
- int new_radius = as->radius == 40 ? 20 : 10;
-
- float original_angle = atan2f(as->velocity.y, as->velocity.x);
-
- float offset1 = random_float(-PI / 4, PI / 4);
- float offset2 = random_float(-PI / 4, PI / 4);
-
- float angle1 = original_angle + offset1;
- float angle2 = original_angle + offset2;
-
- Vector2 direction1 = angle_to_vector(angle1);
- Vector2 direction2 = angle_to_vector(angle2);
-
- float len1 = sqrtf(direction1.x * direction1.x + direction1.y * direction1.y);
- float len2 = sqrtf(direction2.x * direction2.x + direction2.y * direction2.y);
- if (len1 > 0) {
- direction1.x /= len1;
- direction1.y /= len1;
- }
- if (len2 > 0) {
- direction2.x /= len2;
- direction2.y /= len2;
- }
-
- Vector2 start_pos = (Vector2){as->position.x, as->position.y};
-
- int new_index1 = (env->asteroid_index + 1) % MAX_ASTEROIDS;
- int new_index2 = (new_index1 + 1) % MAX_ASTEROIDS;
-
- as->position = start_pos;
- as->velocity = direction1;
- as->radius = new_radius;
- as->radius_sq = new_radius * new_radius;
- env->asteroids[new_index1] = (Asteroid){start_pos, direction2, new_radius};
- env->asteroid_index = new_index2;
-
- // Generate shapes for the new asteroids
- generate_asteroid_shape(as);
- generate_asteroid_shape(&env->asteroids[new_index1]);
-}
-
-void check_particle_asteroid_collision(Asteroids *env) {
- Particle *p;
- Asteroid *as;
- for (int i = 0; i < MAX_PARTICLES; i++) {
- p = &env->particles[i];
- if (p->position.x == 0 && p->position.y == 0)
- continue;
-
- for (int j = 0; j < MAX_ASTEROIDS; j++) {
- as = &env->asteroids[j];
- if (as->radius == 0)
- continue;
-
- if (particle_asteroid_collision(env, p, as)) {
- memset(p, 0, sizeof(*p));
- env->score += 1;
- env->rewards[0] += 1.0f;
-
- switch (as->radius) {
- case 10:
- memset(as, 0, sizeof(*as));
- break;
- case 20:
- split_asteroid(env, as);
- break;
- default:
- split_asteroid(env, as);
- break;
- }
- break;
- }
- }
- }
-}
-
-void check_player_asteroid_collision(Asteroids *env) {
- float min_dist;
- float dx, dy;
- Asteroid *as;
- for (int i = 0; i < MAX_ASTEROIDS; i++) {
- as = &env->asteroids[i];
- if (as->radius == 0)
- continue;
-
- min_dist = env->player_radius + as->radius;
- dx = env->player_position.x - as->position.x;
- dy = env->player_position.y - as->position.y;
- if (min_dist * min_dist > dx * dx + dy * dy) {
- env->terminals[0] = 1;
- env->rewards[0] = -1.0f;
- return;
- }
- }
-}
-
-void compute_observations(Asteroids *env) {
- int observation_indx = 0;
- env->observations[observation_indx++] = env->player_position.x / env->size;
- env->observations[observation_indx++] = env->player_position.y / env->size;
- env->observations[observation_indx++] = env->player_vel.x;
- env->observations[observation_indx++] = env->player_vel.y;
-
- // Create temporary array to store asteroids with their distances
- AsteroidDistance asteroid_distances[MAX_ASTEROIDS];
-
- int num_active_asteroids = 0;
-
- // Calculate distances and store active asteroids
- for (int i = 0; i < MAX_ASTEROIDS; i++) {
- Asteroid as = env->asteroids[i];
- if (as.radius == 0)
- continue;
-
- float dx = as.position.x - env->player_position.x;
- float dy = as.position.y - env->player_position.y;
- float distance = dx * dx + dy * dy;
-
- asteroid_distances[num_active_asteroids].asteroid = as;
- asteroid_distances[num_active_asteroids].distance = distance;
- num_active_asteroids++;
- }
-
- // Sort asteroids by distance (bubble sort for simplicity)
- for (int i = 0; i < num_active_asteroids - 1; i++) {
- for (int j = 0; j < num_active_asteroids - i - 1; j++) {
- if (asteroid_distances[j].distance > asteroid_distances[j + 1].distance) {
- AsteroidDistance temp = asteroid_distances[j];
- asteroid_distances[j] = asteroid_distances[j + 1];
- asteroid_distances[j + 1] = temp;
- }
- }
- }
-
- // Output sorted asteroids to observations (up to MAX_ASTEROIDS)
- for (int i = 0; i < MAX_ASTEROIDS; i++) {
- if (i < num_active_asteroids) {
- Asteroid as = asteroid_distances[i].asteroid;
- env->observations[observation_indx++] =
- (as.position.x - env->player_position.x) / env->size;
- env->observations[observation_indx++] =
- (as.position.y - env->player_position.y) / env->size;
- env->observations[observation_indx++] = as.velocity.x;
- env->observations[observation_indx++] = as.velocity.y;
- env->observations[observation_indx++] = (float)as.radius / 40;
- } else {
- // Pad with zeros for missing asteroids to ensure fixed observation size
- env->observations[observation_indx++] = 0.0f; // relative x
- env->observations[observation_indx++] = 0.0f; // relative y
- env->observations[observation_indx++] = 0.0f; // velocity x
- env->observations[observation_indx++] = 0.0f; // velocity y
- env->observations[observation_indx++] = 0.0f; // radius
- }
- }
-}
-
-void add_log(Asteroids *env) {
- env->log.perf += env->score / 100.0f;
- env->log.score += env->score;
- env->log.episode_length += env->tick;
- env->log.episode_return += env->episode_return;
- env->log.n++;
-}
-
-void c_reset(Asteroids *env) {
- env->player_position = (Vector2){env->size / 2.0f, env->size / 2.0f};
- env->player_angle = 0.0f;
- env->player_radius = 12;
- env->player_vel = (Vector2){0, 0};
- env->thruster_on = 0;
- memset(env->particles, 0, sizeof(Particle) * MAX_PARTICLES);
- memset(env->asteroids, 0, sizeof(Asteroid) * MAX_ASTEROIDS);
- env->particle_index = 0;
- env->asteroid_index = 0;
- env->tick = 0;
- env->score = 0;
- env->episode_return = 0;
- env->last_shot = 0;
-}
-
-void step_frame(Asteroids *env, int action) {
- // slow down each step
- env->player_vel.x *= FRICTION;
- env->player_vel.y *= FRICTION;
-
- Vector2 dir = get_direction_vector(env);
-
- if (action == TURN_LEFT)
- env->player_angle -= ROTATION_SPEED;
- if (action == TURN_RIGHT)
- env->player_angle += ROTATION_SPEED;
- if (action == FORWARD) {
- env->player_vel.x += dir.x * SPEED;
- env->player_vel.y += dir.y * SPEED;
- env->thruster_on = 1;
- }
-
- int elapsed = env->tick - env->last_shot;
-
- if (action == SHOOT && elapsed >= SHOOT_DELAY) {
- env->last_shot = env->tick;
- env->particle_index = (env->particle_index + 1) % MAX_PARTICLES;
- Vector2 start_pos = (Vector2){env->player_position.x + 20 * dir.x,
- env->player_position.y + 20 * dir.y};
- env->particles[env->particle_index] = (Particle){start_pos, dir};
- }
-
- // Explicit Euler
- env->player_position.x += env->player_vel.x;
- env->player_position.y += env->player_vel.y;
-
- move_particles(env);
- spawn_asteroids(env);
- move_asteroids(env);
- check_particle_asteroid_collision(env);
- check_player_asteroid_collision(env);
-
- if (env->player_position.x < 0)
- env->player_position.x = env->size;
- if (env->player_position.y < 0)
- env->player_position.y = env->size;
- if (env->player_position.x > env->size)
- env->player_position.x = 0;
- if (env->player_position.y > env->size)
- env->player_position.y = 0;
-}
-
-void c_step(Asteroids *env) {
- env->rewards[0] = 0;
- env->terminals[0] = 0;
- env->thruster_on = 0;
-
- // only when rendering
- if (global_game_over_timer > 0)
- return;
-
- int action = env->actions[0];
- for (int i = 0; i < env->frameskip; i++) {
- env->tick += 1;
- step_frame(env, action);
- }
-
- env->episode_return += env->rewards[0];
- if (env->terminals[0] == 1 || env->tick > MAX_TICK) {
- env->terminals[0] = 1;
- add_log(env);
- c_reset(env);
- return;
- }
-
- // env->rewards[0] = env->score;
- compute_observations(env);
-}
-
-const Color PUFF_RED = (Color){187, 0, 0, 255};
-const Color PUFF_CYAN = (Color){0, 187, 187, 255};
-const Color PUFF_WHITE = (Color){241, 241, 241, 241};
-const Color PUFF_BACKGROUND = (Color){6, 24, 24, 255};
-
-void draw_player(Asteroids *env) {
- if (global_game_over_timer > 0)
- return;
-
- float px = env->player_position.x;
- float py = env->player_position.y;
-
- if (DEBUG) {
- DrawPixel(px, py, RED);
- Vector2 dir = get_direction_vector(env);
- dir = (Vector2){dir.x * 10.0f, dir.y * 10.f};
- Vector2 t = (Vector2){dir.x + px, dir.y + py};
- DrawLineV(env->player_position, t, RED);
- DrawCircleLines(px, py, env->player_radius, RED);
- }
-
- Vector2 ps[8];
-
- // ship
- ps[0] = (Vector2){px - 10, py + 10};
- ps[1] = (Vector2){px + 10, py + 10};
- ps[2] = (Vector2){px, py - 20};
- ps[3] = (Vector2){px - 9, py + 6};
- ps[4] = (Vector2){px + 9, py + 6};
- ps[5] = (Vector2){px - 5, py + 6};
- ps[6] = (Vector2){px + 5, py + 6};
- ps[7] = (Vector2){px, py + 14};
-
- for (int i = 0; i < 8; i++)
- ps[i] = rotate_vector(ps[i], env->player_position, env->player_angle);
-
- DrawLineV(ps[0], ps[2], PUFF_RED);
- DrawLineV(ps[1], ps[2], PUFF_RED);
-
- DrawLineV(ps[3], ps[4], PUFF_RED);
-
- if (env->thruster_on) {
- DrawLineV(ps[5], ps[7], PUFF_RED);
- DrawLineV(ps[6], ps[7], PUFF_RED);
- }
-}
-
-void draw_particles(Asteroids *env) {
- for (int i = 0; i < MAX_PARTICLES; i++) {
- DrawCircle(env->particles[i].position.x, env->particles[i].position.y, 2, PUFF_RED);
- }
-}
-
-void draw_asteroids(Asteroids *env) {
- Asteroid as;
- for (int i = 0; i < MAX_ASTEROIDS; i++) {
- as = env->asteroids[i];
- if (as.radius == 0)
- continue;
-
- if (DEBUG)
- DrawCircleLines(as.position.x, as.position.y, as.radius, RED);
-
- for (int v = 0; v < as.num_vertices; v++) {
- int next_v = (v + 1) % as.num_vertices;
- Vector2 pos1 = {as.position.x + as.shape[v].x,
- as.position.y + as.shape[v].y};
- Vector2 pos2 = {as.position.x + as.shape[next_v].x,
- as.position.y + as.shape[next_v].y};
- DrawLineV(pos1, pos2, PUFF_CYAN);
- }
- }
-}
-
-void c_render(Asteroids *env) {
- if (!IsWindowReady()) {
- InitWindow(env->size, env->size, "PufferLib Asteroids");
- SetConfigFlags(FLAG_MSAA_4X_HINT);
- SetTargetFPS(60);
- global_render_flag = 1;
- }
-
- if (IsKeyDown(KEY_ESCAPE)) {
- exit(0);
- }
-
- if (env->terminals[0] == 1 && !global_game_over_started) {
- global_game_over_started = 1;
- global_game_over_timer = 120;
- }
-
- if (global_game_over_timer > 0) {
- global_game_over_timer--;
- } else {
- global_game_over_started = 0;
- }
-
- BeginDrawing();
- ClearBackground(PUFF_BACKGROUND);
- draw_player(env);
- draw_particles(env);
- draw_asteroids(env);
-
- DrawText(TextFormat("Score: %d", env->score), 10, 10, 20, PUFF_WHITE);
- DrawText(TextFormat("%d s", (int)(env->tick / 60)), env->size - 40, 10, 20, PUFF_WHITE);
-
- if (global_game_over_timer > 0) {
- const char *game_over_text = "GAME OVER";
- int text_width = MeasureText(game_over_text, 40);
- int x = (env->size - text_width) / 2;
- int y = env->size / 2 - 20;
-
- float alpha = (float)global_game_over_timer / 120.0f;
- int alpha_value = (int)(alpha * 255);
-
- Color text_color = ColorAlpha(PUFF_RED, alpha_value);
- DrawTextEx(GetFontDefault(), game_over_text, (Vector2){x, y}, 40, 2, text_color);
- }
-
- EndDrawing();
-}
-
-void c_close(Asteroids *env) {
- if (IsWindowReady()) {
- CloseWindow();
- }
-}
diff --git a/pufferlib/ocean/asteroids/asteroids.py b/pufferlib/ocean/asteroids/asteroids.py
deleted file mode 100644
index cc3f6f9eb..000000000
--- a/pufferlib/ocean/asteroids/asteroids.py
+++ /dev/null
@@ -1,53 +0,0 @@
-import gymnasium
-import numpy as np
-
-import pufferlib
-from pufferlib.ocean.asteroids import binding
-
-class Asteroids(pufferlib.PufferEnv):
- def __init__(self, num_envs=1, render_mode=None, log_interval=128, buf=None, seed=0, size=500, frameskip=4):
- obs_shape = 4 + 5 * 20 # player pos, player vel, [asteroid pos, asteroid vel, asteroid size] x num asteroids
- self.single_observation_space = gymnasium.spaces.Box(low=-5, high=5,
- shape=(obs_shape,), dtype=np.float32)
- self.single_action_space = gymnasium.spaces.Discrete(4) # forward, left, right, shoot
- self.render_mode = render_mode
- self.num_agents = num_envs
-
- super().__init__(buf)
- self.c_envs = binding.vec_init(self.observations, self.actions, self.rewards,
- self.terminals, self.truncations, num_envs, seed, size=size, frameskip=frameskip)
-
- def reset(self, seed=0):
- binding.vec_reset(self.c_envs, seed)
- return self.observations, []
-
- def step(self, actions):
- self.actions[:] = actions
- binding.vec_step(self.c_envs)
- info = [binding.vec_log(self.c_envs)]
- return (self.observations, self.rewards,
- self.terminals, self.truncations, info)
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-if __name__ == '__main__':
- N = 4096
- env = Asteroids(num_envs=N)
- env.reset()
- steps = 0
-
- CACHE = 1024
- actions = np.random.randint(0, 5, (CACHE, N))
-
- import time
- start = time.time()
- while time.time() - start < 10:
- env.step(actions[steps % CACHE])
- steps += 1
-
- sps = int(env.num_agents*steps / (time.time() - start))
- print(f'Asteroids SPS: {sps:,}')
diff --git a/pufferlib/ocean/asteroids/binding.c b/pufferlib/ocean/asteroids/binding.c
deleted file mode 100644
index 493d3ab9d..000000000
--- a/pufferlib/ocean/asteroids/binding.c
+++ /dev/null
@@ -1,18 +0,0 @@
-#include "asteroids.h"
-
-#define Env Asteroids
-#include "../env_binding.h"
-
-static int my_init(Env *env, PyObject *args, PyObject *kwargs) {
- env->size = unpack(kwargs, "size");
- env->frameskip = unpack(kwargs, "frameskip");
- return 0;
-}
-
-static int my_log(PyObject *dict, Log *log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "episode_length", log->episode_length);
- return 0;
-}
diff --git a/pufferlib/ocean/battle/battle.c b/pufferlib/ocean/battle/battle.c
deleted file mode 100644
index c6193318f..000000000
--- a/pufferlib/ocean/battle/battle.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/* Pure C demo file for Battle. Build it with:
- * bash scripts/build_ocean.sh battle local (debug)
- * bash scripts/build_ocean.sh battle fast
- * We suggest building and debugging your env in pure C first. You
- * get faster builds and better error messages
- */
-#include "battle.h"
-
-/* Puffernet is our lightweight cpu inference library that
- * lets you load basic PyTorch model architectures so that
- * you can run them in pure C or on the web via WASM
- */
-#include "puffernet.h"
-
-int main() {
- // Weights are exported by running puffer export
- //Weights* weights = load_weights("resources/puffer_battle_weights.bin", 137743);
-
- //int logit_sizes[2] = {9, 5};
- //LinearLSTM* net = make_linearlstm(weights, num_agents, num_obs, logit_sizes, 2);
-
- Battle env = {
- .width = 1980,
- .height = 1020,
- .size_x = 8,
- .size_y = 2.0,
- .size_z = 8,
- .num_agents = 1024,
- .num_armies = 8,
- };
- init(&env);
-
- // Allocate these manually since they aren't being passed from Python
- int num_obs = 3*env.num_armies + 4*16 + 22 + 8;
- env.observations = calloc(env.num_agents*num_obs, sizeof(float));
- env.actions = calloc(3*env.num_agents, sizeof(int));
- env.rewards = calloc(env.num_agents, sizeof(float));
- env.terminals = calloc(env.num_agents, sizeof(unsigned char));
-
- // Always call reset and render first
- c_reset(&env);
- c_render(&env);
-
- int ctrl = 0;
-
- while (!WindowShouldClose()) {
- /*
- for (int i=0; iarmy;
- float vx = env.observations[num_obs*i + 3*army];
- float vz = env.observations[num_obs*i + 3*army + 2];
- float yaw = env.observations[num_obs*i + 3*army + 3];
- float pitch = env.observations[num_obs*i + 3*army + 4];
- float x = env.observations[num_obs*i + 3*army + 6];
- float y = env.observations[num_obs*i + 3*army + 7];
- float z = env.observations[num_obs*i + 3*army + 8];
-
- if (agent->unit == INFANTRY || agent->unit == TANK || agent->unit == ARTILLERY) {
- env.actions[3*i] = (vx > 0.0f) ? 6 : 2;
- env.actions[3*i + 2] = (vz > 0.0f) ? 6 : 2;
- } else {
- float desired_pitch = atan2f(-y, sqrt(x*x + z*z));
- float pitch_error = desired_pitch - pitch;
- if (pitch_error > 0) {
- env.actions[3*i] = 6; // pitch up
- } else if (pitch_error < 0) {
- env.actions[3*i] = 2; // pitch down
- }
- env.actions[3*i] = 4;
-
- env.actions[3*i + 1] = 4;
-
- // Roll control
- float desired_yaw = atan2f(-x, -z); // Direction to origin
- float yaw_error = desired_yaw - yaw;
-
- // Normalize yaw_error to [-PI, PI]
- if (yaw_error > PI) yaw_error -= 2*PI;
- if (yaw_error < -PI) yaw_error += 2*PI;
-
- //printf("%f %f\n", yaw_error, yaw);
-
- if (yaw_error > 0.1f) {
- env.actions[3*i + 1] = 2; // roll left
- } else if (yaw_error < -0.1f) {
- env.actions[3*i + 1] = 6; // roll right
- } else {
- env.actions[3*i + 1] = 4; // neutral roll (assuming 0 is valid)
- }
-
- }
- //env.actions[3*i] = 4;
- //env.actions[3*i + 1] = 4;
- //env.actions[3*i + 2] = 4;
- //float dpitch = atan2f(dz, sqrtf(dx*dx + dy*dy));
- //float droll = asinf(dz/sqrtf(dx*dx + dy*dy + dz*dz));
- //env.actions[3*i] = 6;
- //env.actions[3*i + 1] = (dpitch > 0.0f) ? 6 : 2;
- //env.actions[3*i + 2] = (droll > 0.0f) ? 6 : 2;
- //env.actions[3*i] = rand() % 9;
- //env.actions[3*i + 1] = rand() % 9;
- //env.actions[3*i + 2] = rand() % 9;
- //env.actions[3*i] = 4.0f;
- //env.actions[3*i + 1] = 4.0f;
- //env.actions[3*i + 2] = 4.0f;
- }
- */
-
- if (IsKeyDown(KEY_LEFT_SHIFT)) {
- if (IsKeyPressed(KEY_TAB)) {
- ctrl = (ctrl + 1) % env.num_agents;
- }
- int i = ctrl;
- float x = env.observations[num_obs*i + 3*env.num_armies + 6];
- float y = env.observations[num_obs*i + 3*env.num_armies + 7];
- float z = env.observations[num_obs*i + 3*env.num_armies + 8];
-
- Camera3D* camera = &(env.client->camera);
- camera->target = (Vector3){x, y, z};
-
-
- Entity* agent = &env.agents[i];
- Vector3 forward = Vector3RotateByQuaternion((Vector3){0, 0, 1}, agent->orientation);
-
- Vector3 local_up = Vector3RotateByQuaternion((Vector3){0, 1, 0}, agent->orientation);
- local_up = Vector3Normalize(local_up);
-
- camera->target = (Vector3){agent->x, agent->y, agent->z};
-
- camera->position = (Vector3){
- agent->x + 0.5*(- forward.x),
- agent->y + 0.5*(- forward.y) + 0.5f,
- agent->z + 0.5*(- forward.z)
- };
-
-
- /*
- Entity* agent = &env.agents[i];
- Vec3 forward = quat_rotate(agent->orientation, (Vec3){0, 0, -1}); // Ship's local forward
- vec3_normalize(&forward);
-
- Vec3 local_up = quat_rotate(agent->orientation, (Vec3){0, 1, 0}); // Ship's local up
- vec3_normalize(&local_up);
-
- // Compute negative forward and negative local up
- Vec3 neg_forward = {-forward.x, -forward.y, -forward.z};
- Vec3 neg_local_up = {-local_up.x, -local_up.y, -local_up.z};
-
- // Compute the vector 45 degrees between neg_forward and neg_local_up
- // Since forward and local_up are orthogonal, averaging gives a 45-degree angle
- Vec3 camera_dir = {
- neg_forward.x + neg_local_up.x,
- neg_forward.y + neg_local_up.y,
- neg_forward.z + neg_local_up.z
- };
- vec3_normalize(&camera_dir);
- printf("camera_dir: %f %f %f\n", camera_dir.x, camera_dir.y, camera_dir.z);
-
- // Scale by desired distance and offset from ship's position
- camera->position = (Vector3){
- agent->x + 1.0f*camera_dir.x,
- agent->y + 1.0f*camera_dir.y,
- agent->z + 1.0f*camera_dir.z
- };
-
- float dd = sqrtf(vx*vx + vy*vy + vz*vz);
- float forward_x = vx / dd;
- float forward_y = vy / dd;
- float forward_z = vz / dd;
-
- float dist = 0.5f;
- camera->position = (Vector3){
- x - dist*forward_x,
- y - dist*forward_y + 0.5f,
- z - dist*forward_z
- };
- */
-
- env.actions[3*i] = 4;
- if (IsKeyDown(KEY_W)) {
- env.actions[3*i] = 6;
- } else if (IsKeyDown(KEY_S)) {
- env.actions[3*i] = 2;
- }
-
- env.actions[3*i + 1] = 4;
- if (IsKeyDown(KEY_A)) {
- env.actions[3*i + 1] = 2;
- } else if (IsKeyDown(KEY_D)) {
- env.actions[3*i + 1] = 6;
- }
- }
-
- //forward_linearlstm(net, env.observations, env.actions);
- compute_observations(&env);
- c_step(&env);
- c_render(&env);
- }
-
- // Try to clean up after yourself
- //free_linearlstm(net);
- free(env.observations);
- free(env.actions);
- free(env.rewards);
- free(env.terminals);
- c_close(&env);
-}
-
diff --git a/pufferlib/ocean/battle/battle.h b/pufferlib/ocean/battle/battle.h
deleted file mode 100644
index 35d97c77e..000000000
--- a/pufferlib/ocean/battle/battle.h
+++ /dev/null
@@ -1,1199 +0,0 @@
-/* Battle: a sample multiagent env about puffers eating stars.
- * Use this as a tutorial and template for your own multiagent envs.
- * We suggest starting with the Squared env for a simpler intro.
- * Star PufferLib on GitHub to support. It really, really helps!
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include "raylib.h"
-#include "raymath.h"
-#include "rlgl.h"
-#include "simplex.h"
-
-#define RLIGHTS_IMPLEMENTATION
-#include "rlights.h"
-
-
-#if defined(PLATFORM_DESKTOP)
- #define GLSL_VERSION 330
-#else
- #define GLSL_VERSION 100
-#endif
-
-#define MAX_SPEED 0.01f
-#define MAX_FACTORY_SPEED 0.001f
-
-#define DRONE 0
-#define MOTHERSHIP 1
-#define FIGHTER 2
-#define BOMBER 3
-#define INFANTRY 4
-#define TANK 5
-#define ARTILLERY 6
-#define BASE 7
-
-#define AGENT_OBS 16
-
-static inline float clampf(float v, float min, float max) {
- if (v < min)
- return min;
- if (v > max)
- return max;
- return v;
-}
-
-float clip(float val, float min, float max) {
- if (val < min) {
- return min;
- } else if (val > max) {
- return max;
- }
- return val;
-}
-
-float clip_angle(float theta) {
- if (theta < -PI) {
- return theta + 2.0f*PI;
- } else if (theta > PI) {
- return theta - 2.0f*PI;
- }
- return theta;
-}
-
-float randf(float min, float max) {
- return min + (max - min)*(float)rand()/(float)RAND_MAX;
-}
-
-float randi(int min, int max) {
- return min + (max - min)*(float)rand()/(float)RAND_MAX;
-}
-
-typedef struct {
- float perf;
- float score;
- float collision_rate;
- float oob_rate;
- float episode_return;
- float episode_length;
- float n;
-} Log;
-
-typedef struct {
- Camera3D camera;
- Light light;
- Model models[8];
- Mesh* mesh;
- Model model;
- Shader light_shader;
- Shader terrain_shader;
- Texture2D terrain_texture;
- Texture2D vehicle_texture;
- int terrain_shader_loc;
- unsigned char *terrain_data;
-} Client;
-
-typedef struct {
- float x;
- float y;
- float z;
- float vx;
- float vy;
- float vz;
- float speed;
- float health;
- float max_turn;
- float max_speed;
- float attack_damage;
- float attack_range;
- Quaternion orientation;
- int army;
- int unit;
- int target;
- int episode_length;
- float episode_return;
-} Entity;
-
-typedef struct {
- Log log;
- Client* client;
- Entity* agents;
- Entity* bases;
- float* observations;
- float* actions;
- float* rewards;
- unsigned char* terminals;
- int width;
- int height;
- float size_x;
- float size_y;
- float size_z;
- int terrain_width;
- int terrain_height;
- int num_agents;
- int num_armies;
- float* terrain;
-} Battle;
-
-int map_idx(Battle* env, float x, float y) {
- return env->terrain_width*(int)y + (int)x;
-}
-
-float ground_height(Battle* env, float x, float z) {
- int agent_map_x = 128*x + 128*env->size_x;
- int agent_map_z = 128*z + 128*env->size_z;
- if (agent_map_x == 256*env->size_x) {
- agent_map_x -= 1;
- }
- if (agent_map_z == 256*env->size_z) {
- agent_map_z -= 1;
- }
- int idx = map_idx(env, agent_map_x, agent_map_z);
- float terrain_height = env->terrain[idx];
- return (terrain_height - 128.0f*env->size_y) / 128.0f;
-}
-
-void perlin_noise(float* map, int width, int height,
- float base_frequency, int octaves, int offset_x, int offset_y, float glob_scale) {
- float frequencies[octaves];
- for (int i = 0; i < octaves; i++) {
- frequencies[i] = base_frequency*pow(2, i);
- }
-
- float min_value = FLT_MAX;
- float max_value = FLT_MIN;
- for (int r = 0; r < height; r++) {
- for (int c = 0; c < width; c++) {
- int adr = r*width + c;
- for (int oct = 0; oct < octaves; oct++) {
- float freq = frequencies[oct];
- map[adr] += (1.0/pow(2, oct))*noise2(freq*c + offset_x, freq*r + offset_y);
- }
- float val = map[adr];
- if (val < min_value) {
- min_value = val;
- }
- if (val > max_value) {
- max_value = val;
- }
- }
- }
-
- float scale = 1.0/(max_value - min_value);
- for (int r = 0; r < height; r++) {
- for (int c = 0; c < width; c++) {
- int adr = r*width + c;
- map[adr] = glob_scale * scale * (map[adr] - min_value);
- if (map[adr] < 16.0f) {
- map[adr] = 0.0f;
- } else {
- map[adr] -= 16.0f;
- }
- }
- }
-}
-
-void init(Battle* env) {
- env->agents = calloc(env->num_agents, sizeof(Entity));
- env->bases = calloc(env->num_armies, sizeof(Entity));
- env->terrain_width = 256*env->size_x;
- env->terrain_height = 256*env->size_z;
- env->terrain = calloc(env->terrain_width*env->terrain_height, sizeof(float));
- perlin_noise(env->terrain, env->terrain_width, env->terrain_height, 1.0/2048.0, 8, 0, 0, 256);
-}
-
-void update_abilities(Entity* agent) {
- if (agent->unit == DRONE) {
- agent->health = 0.4f;
- agent->attack_damage = 0.1f;
- agent->attack_range = 0.15f;
- agent->max_turn = 2.0f;
- agent->max_speed = 1.0f;
- } else if (agent->unit == FIGHTER) {
- agent->health = 1.0f;
- agent->attack_damage = 0.5f;
- agent->attack_range = 0.25f;
- agent->max_turn = 1.0f;
- agent->max_speed = 0.75f;
- } else if (agent->unit == MOTHERSHIP) {
- agent->health = 10.0f;
- agent->attack_damage = 2.0f;
- agent->attack_range = 0.4f;
- agent->max_turn = 0.5f;
- agent->max_speed = 0.5f;
- } else if (agent->unit == BOMBER) {
- agent->health = 1.0f;
- agent->attack_damage = 1.0f;
- agent->attack_range = 0.1f;
- agent->max_turn = 0.5f;
- agent->max_speed = 0.5f;
- } else if (agent->unit == INFANTRY) {
- agent->health = 0.2f;
- agent->attack_damage = 0.2f;
- agent->attack_range = 0.2f;
- agent->max_turn = 2.0f;
- agent->max_speed = 0.25f;
- } else if (agent->unit == TANK) {
- agent->health = 2.0f;
- agent->attack_damage = 0.5f;
- agent->attack_range = 0.25f;
- agent->max_turn = 0.25f;
- agent->max_speed = 0.75f;
- } else if (agent->unit == ARTILLERY) {
- agent->health = 2.0f;
- agent->attack_damage = 2.0f;
- agent->attack_range = 0.7f;
- agent->max_turn = 0.5f;
- agent->max_speed = 0.25f;
- }
-}
-
-void respawn(Battle* env, int idx) {
- Entity* agent = &env->agents[idx];
- int army = agent->army;
- agent->orientation = QuaternionIdentity();
- agent->vx = 0;
- agent->vy = 0;
- agent->vz = 0;
-
- if (agent->unit == DRONE) {
- int team_mothership_idx = 64*(idx / 64); // Hardcoded per army
- agent->x = env->agents[team_mothership_idx].x;
- agent->y = env->agents[team_mothership_idx].y;
- agent->z = env->agents[team_mothership_idx].z;
- if (agent->unit == INFANTRY || agent->unit == TANK || agent->unit == ARTILLERY) {
- agent->y = ground_height(env, agent->x, agent->z);
- }
- return;
- }
-
- Entity* base = &env->bases[army];
- agent->x = base->x;
- agent->z = base->z;
- float height = ground_height(env, agent->x, agent->z);
- if (agent->unit == INFANTRY || agent->unit == TANK || agent->unit == ARTILLERY) {
- agent->y = height;
- } else {
- agent->y = clampf(height + 0.2f, -env->size_y, env->size_y);
- }
-
- return;
-}
-
-
-bool attack_air(Entity *agent, Entity *target) {
- float dx = target->x - agent->x;
- float dy = target->y - agent->y;
- float dz = target->z - agent->z;
- float dd = sqrtf(dx*dx + dy*dy + dz*dz);
-
- if (dd > agent->attack_range) {
- return false;
- }
-
- Vector3 forward = Vector3RotateByQuaternion((Vector3){0, 0, 1}, agent->orientation);
- forward = Vector3Normalize(forward);
-
- // Unit vec to target
- Vector3 to_target = {dx, dy, dz};
- to_target = Vector3Normalize(to_target);
-
- float angle = Vector3Angle(forward, to_target);
- if (angle < PI/6.0f) {
- return true;
- }
- return false;
-}
-
-bool attack_ground(Entity *agent, Entity *target) {
- if (target->unit == FIGHTER) {
- return false;
- }
- if (target->unit == MOTHERSHIP) {
- return false;
- }
- if (target->unit == BOMBER) {
- return false;
- }
- if (target->unit == DRONE) {
- return false;
- }
-
- float dx = target->x - agent->x;
- float dz = target->z - agent->z;
- float dd = sqrtf(dx*dx + dz*dz);
-
- if (dd > agent->attack_range) {
- return false;
- }
-
- Vector3 forward = Vector3RotateByQuaternion((Vector3){0, 0, 1}, agent->orientation);
- forward = Vector3Normalize(forward);
-
- // Unit vec to target
- Vector3 to_target = {dx, 0, dz};
- to_target = Vector3Normalize(to_target);
-
- float angle = Vector3Angle(forward, to_target);
- if (angle < PI/6) {
- return true;
- }
- return false;
-}
-
-bool attack_bomber(Entity *agent, Entity *target) {
- if (target->unit == DRONE) {
- return false;
- }
- if (target->unit == FIGHTER) {
- return false;
- }
- if (target->unit == MOTHERSHIP) {
- return false;
- }
- if (target->unit == BOMBER) {
- return false;
- }
-
- float dx = target->x - agent->x;
- float dz = target->z - agent->z;
- float dd = sqrtf(dx*dx + dz*dz);
-
- if (dd > agent->attack_range) {
- return false;
- }
-
- return true;
-}
-
-bool attack_aa(Entity *agent, Entity *target) {
- if (target->unit == INFANTRY) {
- return false;
- }
- if (target->unit == TANK) {
- return false;
- }
- if (target->unit == ARTILLERY) {
- return false;
- }
-
- float dx = target->x - agent->x;
- float dy = target->y - agent->y;
- float dz = target->z - agent->z;
- float dd = sqrtf(dx*dx + dz*dz);
-
- if (dd > agent->attack_range) {
- return false;
- }
-
- Vector3 forward = Vector3RotateByQuaternion((Vector3){0, 0, 1}, agent->orientation);
- forward = Vector3Normalize(forward);
-
- // Unit vec to target
- Vector3 to_target = {dx, dy, dz};
- to_target = Vector3Normalize(to_target);
-
- float angle = Vector3Angle(forward, to_target);
- if (angle < PI/6) {
- return true;
- }
-}
-
-void move_basic(Battle* env, Entity* agent, float* actions) {
- float d_vx = actions[0]/100.0f;
- float d_vy = actions[1]/100.0f;
- float d_vz = actions[2]/100.0f;
-
- agent->vx += d_vx;
- agent->vy += d_vy;
- agent->vz += d_vz;
-
- agent->vx = clip(agent->vx, -MAX_SPEED, MAX_SPEED);
- agent->vy = clip(agent->vy, -MAX_SPEED, MAX_SPEED);
- agent->vz = clip(agent->vz, -MAX_SPEED, MAX_SPEED);
-
- agent->x += agent->vx;
- agent->y += agent->vy;
- agent->z += agent->vz;
-
- agent->x = clip(agent->x, -env->size_x, env->size_x);
- agent->y = clip(agent->y, -env->size_y, env->size_y);
- agent->z = clip(agent->z, -env->size_z, env->size_z);
-}
-
-void move_ground(Battle* env, Entity* agent, float* actions) {
- float d_theta = -actions[1]/10.0f;
-
- // Update speed and clamp
- agent->speed = agent->max_speed * MAX_SPEED;
-
- Quaternion q_y = QuaternionFromAxisAngle((Vector3){0, 1, 0}, d_theta);
- agent->orientation = QuaternionMultiply(q_y, agent->orientation);
-
- Vector3 forward = Vector3RotateByQuaternion((Vector3){0, 0, 1}, agent->orientation);
- forward = Vector3Normalize(forward);
-
- agent->speed = agent->max_speed * MAX_SPEED;
- agent->vx = agent->speed * forward.x;
- agent->vz = agent->speed * forward.z;
- agent->x += agent->vx;
- agent->z += agent->vz;
-
- agent->x = clip(agent->x, -env->size_x, env->size_x);
- agent->z = clip(agent->z, -env->size_z, env->size_z);
- agent->y = ground_height(env, agent->x, agent->z);
-}
-
-Entity* nearest_enemy(Battle* env, Entity* agent) {
- Entity* nearest = NULL;
- float nearest_dist = 999999;
- for (int i=0; inum_agents; i++) {
- Entity* other = &env->agents[i];
- if (other->army == agent->army) {
- continue;
- }
- float dx = other->x - agent->x;
- float dy = other->y - agent->y;
- float dz = other->z - agent->z;
- float dd = dx*dx + dy*dy + dz*dz;
- if (dd < nearest_dist) {
- nearest_dist = dd;
- nearest = other;
- }
- }
- return nearest;
-}
-
-// Cheats physics and moves directly to the nearest enemy
-void scripted_move(Battle* env, Entity* agent, bool is_air) {
- Entity* target = nearest_enemy(env, agent);
- if (target == NULL) {
- return;
- }
- float dx = target->x - agent->x;
- float dy = target->y - agent->y;
- float dz = target->z - agent->z;
-
- // Add some noise
- dx += randf(-0.1f, 0.1f);
- dy += randf(-0.1f, 0.1f);
- dz += randf(-0.1f, 0.1f);
-
- float dd = dx*dx + dz*dz;
- if (is_air) {
- dd += dy*dy;
- }
-
- dd = sqrtf(dd);
- dx /= dd;
- dy /= dd;
- dz /= dd;
-
-
- float target_x;
- float target_y;
- float target_z;
- if (dd > 0.05f) {
- target_x = agent->x + dx*agent->max_speed*MAX_SPEED;
- target_y = agent->y + dy*agent->max_speed*MAX_SPEED;
- target_z = agent->z + dz*agent->max_speed*MAX_SPEED;
- } else {
- target_x = agent->x - dx*agent->max_speed*MAX_SPEED;
- target_y = agent->y - dy*agent->max_speed*MAX_SPEED;
- target_z = agent->z - dz*agent->max_speed*MAX_SPEED;
- }
-
- float height = ground_height(env, target_x, target_z);
- if (is_air) {
- if (target_y < height + 0.5f) {
- target_y = height + 0.5f;
- }
- } else {
- target_y = height;
- }
-
- agent->x = target_x;
- agent->y = target_y;
- agent->z = target_z;
-
- agent->x = clip(agent->x, -env->size_x, env->size_x);
- agent->y = clip(agent->y, -env->size_y, env->size_y);
- agent->z = clip(agent->z, -env->size_z, env->size_z);
-
- // Update orientation to target
- Vector3 target_forward = {dx, 0, dz};
- if (is_air) {
- target_forward.y = dy;
- }
- target_forward = Vector3Normalize(target_forward);
-
- Vector3 current_forward = Vector3RotateByQuaternion((Vector3){0, 0, 1}, agent->orientation);
- current_forward = Vector3Normalize(current_forward);
-
- Quaternion q = QuaternionFromVector3ToVector3(current_forward, target_forward);
- agent->orientation = QuaternionMultiply(q, agent->orientation);
-}
-
-void move_ship(Battle* env, Entity* agent, float* actions, int i) {
- // Compute deltas from actions (same as original)
- float d_pitch = agent->max_turn * actions[0] / 10.0f;
- float d_roll = agent->max_turn * actions[1] / 10.0f;
-
- // Update speed and clamp
- agent->speed = agent->max_speed * MAX_SPEED;
-
- Vector3 forward = Vector3RotateByQuaternion((Vector3){0, 0, 1}, agent->orientation);
- forward = Vector3Normalize(forward);
-
- Vector3 local_up = Vector3RotateByQuaternion((Vector3){0, 1, 0}, agent->orientation);
- local_up = Vector3Normalize(local_up);
-
- Vector3 right = Vector3CrossProduct(forward, local_up); // Ship's local right
- right = Vector3Normalize(right);
-
- // Create rotation quaternions
- /*
- if (i == 0) {
- printf("actions: %d %d %d\n", actions[0], actions[1], actions[2]);
- printf("orientation: %f %f %f %f\n", agent->orientation.w, agent->orientation.x, agent->orientation.y, agent->orientation.z);
- printf("Local up: %f %f %f\n", local_up.x, local_up.y, local_up.z);
- printf("Forward: %f %f %f\n", forward.x, forward.y, forward.z);
- printf("Right: %f %f %f\n", right.x, right.y, right.z);
- printf("d_pitch: %f\n, d_roll: %f\n", d_pitch, d_roll);
- }
- */
-
- float d_yaw = 0.0;
- Quaternion q_yaw = QuaternionFromAxisAngle(local_up, d_yaw);
- Quaternion q_roll = QuaternionFromAxisAngle(forward, d_roll);
- Quaternion q_pitch = QuaternionFromAxisAngle(right, d_pitch);
-
- /*
- if (i == 0) {
- printf("q_yaw: %f %f %f %f\n", q_yaw.w, q_yaw.x, q_yaw.y, q_yaw.z);
- printf("q_roll: %f %f %f %f\n", q_roll.w, q_roll.x, q_roll.y, q_roll.z);
- printf("q_pitch: %f %f %f %f\n", q_pitch.w, q_pitch.x, q_pitch.y, q_pitch.z);
- }
- */
-
- Quaternion q = QuaternionMultiply(q_roll, QuaternionMultiply(q_pitch, q_yaw));
- q = QuaternionNormalize(q);
-
- forward = Vector3RotateByQuaternion(forward, q);
- forward = Vector3Normalize(forward);
-
- agent->orientation = QuaternionMultiply(q, agent->orientation);
-
- // Jank plane physics
- Vector3 v = {
- agent->speed * (forward.x + local_up.x),
- agent->speed * (forward.y + local_up.y - 1.0f),
- agent->speed * (forward.z + local_up.z)
- };
-
- agent->x += v.x;
- agent->y += v.y;
- agent->z += v.z;
-
- // Just for visualization
- agent->vx = v.x;
- agent->vy = v.y;
- agent->vz = v.z;
-
- // Clamp position to environment bounds
- agent->x = clampf(agent->x, -env->size_x, env->size_x);
- agent->y = clampf(agent->y, -env->size_y, env->size_y);
- agent->z = clampf(agent->z, -env->size_z, env->size_z);
-}
-
-typedef struct {
- float distance;
- float dx;
- float dy;
- float dz;
- float same_team;
- int idx;
-} AgentObs;
-
-int compare_agent_obs(const void* a, const void* b) {
- AgentObs* oa = (AgentObs*)a;
- AgentObs* ob = (AgentObs*)b;
- if (oa->distance < ob->distance) {
- return -1;
- } else if (oa->distance > ob->distance) {
- return 1;
- }
- return 0;
-}
-
-void compute_observations(Battle* env) {
- AgentObs agent_obs[env->num_agents];
-
- int obs_idx = 0;
- for (int a=0; anum_agents/2; a++) {
- assert(obs_idx == a*(6*env->num_armies + 19 + 8));
-
- // Distance to each base
- Entity* agent = &env->agents[a];
- int team = agent->army;
- float dists[env->num_armies];
- for (int i=0; inum_armies; i++) {
- dists[i] = 999999;
- }
- for (int f=0; fnum_armies; f++) {
- Entity* base = &env->bases[f];
- float dx = base->x - agent->x;
- float dy = base->y - agent->y;
- float dz = base->z - agent->z;
- float dd = dx*dx + dy*dy + dz*dz;
- int type = f % env->num_armies;
- if (dd < dists[type]) {
- dists[type] = dd;
- env->observations[obs_idx + 3*type] = dx;
- env->observations[obs_idx + 3*type + 1] = dy;
- env->observations[obs_idx + 3*type + 2] = dz;
- }
- }
- obs_idx += 3*env->num_armies;
-
-
- // Distance to each agent. Slow O(n^2) naive implementation
- float x = agent->x;
- float y = agent->y;
- float z = agent->z;
- for (int i=0; inum_agents; i++) {
- Entity* other = &env->agents[i];
- float dx = other->x - x;
- float dy = other->y - y;
- float dz = other->z - z;
- float distance = dx*dx + dy*dy + dz*dz;
- AgentObs* o = &agent_obs[i];
- o->dx = dx;
- o->dy = dy;
- o->dz = dz;
- if (other->army == agent->army) {
- o->same_team = 1.0f;
- o->distance = 99999.0f;
- } else {
- o->same_team = 0.0f;
- o->distance = distance;
- }
- o->idx = i;
- }
- qsort(agent_obs, env->num_agents, sizeof(AgentObs), compare_agent_obs);
-
- for (int i=0; iobservations[obs_idx++] = agent_obs[i].dx;
- env->observations[obs_idx++] = agent_obs[i].dy;
- env->observations[obs_idx++] = agent_obs[i].dz;
- env->observations[obs_idx++] = agent_obs[i].same_team;
- }
-
- // Individual agent stats
- env->observations[obs_idx++] = agent->vx/MAX_SPEED;
- env->observations[obs_idx++] = agent->vy/MAX_SPEED;
- env->observations[obs_idx++] = agent->vz/MAX_SPEED;
- env->observations[obs_idx++] = agent->orientation.w;
- env->observations[obs_idx++] = agent->orientation.x;
- env->observations[obs_idx++] = agent->orientation.y;
- env->observations[obs_idx++] = agent->orientation.z;
- env->observations[obs_idx++] = agent->x;
- env->observations[obs_idx++] = agent->y;
- env->observations[obs_idx++] = agent->z;
- env->observations[obs_idx++] = agent->y - ground_height(env, agent->x, agent->z);
- env->observations[obs_idx++] = abs(agent->x) - 0.95f*env->size_x;
- env->observations[obs_idx++] = abs(agent->z) - 0.95f*env->size_z;
- env->observations[obs_idx++] = abs(agent->y) - 0.95f*env->size_y;
- env->observations[obs_idx++] = agent->speed;
- env->observations[obs_idx++] = agent->health;
- env->observations[obs_idx++] = agent->max_turn;
- env->observations[obs_idx++] = agent->max_speed;
- env->observations[obs_idx++] = agent->attack_damage;
- env->observations[obs_idx++] = agent->attack_range;
- env->observations[obs_idx++] = env->rewards[a];
- env->observations[obs_idx++] = env->terminals[a];
-
- // Hardcoded 8 unit types
- memset(&env->observations[obs_idx], 0, 8*sizeof(float));
- env->observations[obs_idx + agent->unit] = 1.0f;
- obs_idx += 8;
- }
-}
-
-// Required function
-void c_reset(Battle* env) {
- int agents_per_army = env->num_agents / env->num_armies;
- for (int i=0; inum_armies; i++) {
- bool spawn = false;
- Entity* base = &env->bases[i];
- while (!spawn) {
- base->x = randf(0.5 - env->size_x, env->size_x - 0.5);
- base->z = randf(0.5 - env->size_z, env->size_z - 0.5);
- base->y = ground_height(env, base->x, base->z);
- base->army = i;
- spawn = true;
-
- for (int j=0; jbases[j];
- float dx = other->x - base->x;
- float dz = other->z - base->z;
- float dd = sqrtf(dx*dx + dz*dz);
- if (dd < 2.0f) {
- spawn = false;
- break;
- }
- }
- }
- }
-
- for (int army=0; armynum_armies; army++) {
- for (int i=0; iagents[idx];
- if (i % 64 == 0) {
- agent->unit = MOTHERSHIP;
- } else if (i % 64 <= 4) {
- agent->unit = TANK;
- } else if (i % 64 <= 6) {
- agent->unit = ARTILLERY;
- } else if (i % 64 <= 10) {
- agent->unit = BOMBER;
- } else if (i % 64 <= 14) {
- agent->unit = FIGHTER;
- } else if (i % 64 <= 32) {
- agent->unit = INFANTRY;
- } else {
- agent->unit = DRONE;
- }
-
- agent->army = army;
- agent->orientation = QuaternionIdentity();
- agent->episode_length = 0;
- agent->target = -1;
- update_abilities(agent);
- respawn(env, idx);
- }
- }
- compute_observations(env);
-}
-
-void c_step(Battle* env) {
- memset(env->rewards, 0, env->num_agents/2*sizeof(float));
- memset(env->terminals, 0, env->num_agents/2*sizeof(unsigned char));
-
- for (int i=0; inum_agents; i++) {
- Entity* agent = &env->agents[i];
- agent->episode_length += 1;
- agent->target = -1;
-
- bool done = false;
- float collision = 0.0f;
- float oob = 0.0f;
- float reward = 0.0f;
- if (agent->health <= 0) {
- done = true;
- reward = 0.0f;
- }
- if (agent->unit == DRONE || agent->unit == FIGHTER || agent->unit == BOMBER || agent->unit == MOTHERSHIP) {
- // Crash into terrain
- float terrain_height = ground_height(env, agent->x, agent->z);
- if (agent->y < terrain_height) {
- collision = 1.0f;
- done = true;
- reward = -1.0f;
- }
- }
- if (
- agent->x < -0.95f*env->size_x || agent->x > 0.95f*env->size_x ||
- agent->z < -0.95f*env->size_z || agent->z > 0.95f*env->size_z ||
- agent->y > 0.95f*env->size_y
- ) {
- done = true;
- reward = -1.0f;
- oob = 1.0f;
- }
-
- if (done) {
- update_abilities(agent);
- respawn(env, i);
- agent->episode_return += reward;
- if (i < env->num_agents/2) {
- env->rewards[i] = reward;
- env->terminals[i] = 1;
- env->log.score = env->log.episode_return;
- env->log.episode_length += agent->episode_length;
- env->log.episode_return += agent->episode_return;
- env->log.collision_rate += collision;
- env->log.oob_rate += oob;
- env->log.n++;
-
- }
- agent->episode_length = 0;
- agent->episode_return = 0;
- }
-
- //move_basic(env, agent, env->actions + 3*i);
- if (agent->unit == INFANTRY || agent->unit == TANK || agent->unit == ARTILLERY) {
- if (i < env->num_agents/2) {
- move_ground(env, agent, env->actions + 3*i);
- } else {
- scripted_move(env, agent, false);
- }
- } else {
- if (i < env->num_agents/2) {
- move_ship(env, agent, env->actions + 3*i, i);
- } else {
- scripted_move(env, agent, true);
- }
- }
- }
-
- for (int i=0; inum_agents; i++) {
- Entity* agent = &env->agents[i];
- for (int j=0; jnum_agents; j++) {
- if (j == i) {
- continue;
- }
- Entity* target = &env->agents[j];
- if (agent->army == target->army) {
- continue;
- }
- bool can_attack = false;
- if (agent->unit == INFANTRY || agent->unit == TANK) {
- can_attack = attack_ground(agent, target);
- } else if (agent->unit == ARTILLERY) {
- can_attack = attack_aa(agent, target);
- } else if (agent->unit == BOMBER) {
- can_attack = attack_bomber(agent, target);
- } else {
- can_attack = attack_air(agent, target);
- }
- if (!can_attack) {
- continue;
- }
- agent->target = j;
- if (i < env->num_agents/2) {
- env->rewards[i] += 0.25f;
- agent->episode_return += 0.25f;
- }
- target->health -= agent->attack_damage;
- break;
- }
- }
-
- if (rand() % 9000 == 0) {
- c_reset(env);
- }
-
- compute_observations(env);
-}
-
-Color COLORS[8] = {
- (Color){0, 255, 255, 255},
- (Color){255, 0, 0, 255},
- (Color){0, 255, 0, 255},
- (Color){255, 255, 0, 255},
- (Color){255, 0, 255, 255},
- (Color){0, 0, 255, 255},
- (Color){128, 255, 0, 255},
- (Color){255, 128, 0, 255},
-};
-
-Mesh* create_heightmap_mesh(float* heightMap, Vector3 size) {
- int mapX = size.x;
- int mapZ = size.z;
-
- // NOTE: One vertex per pixel
- Mesh* mesh = (Mesh*)calloc(1, sizeof(Mesh));
- mesh->triangleCount = (mapX - 1)*(mapZ - 1)*2; // One quad every four pixels
-
- mesh->vertexCount = mesh->triangleCount*3;
-
- mesh->vertices = (float *)RL_MALLOC(mesh->vertexCount*3*sizeof(float));
- mesh->normals = (float *)RL_MALLOC(mesh->vertexCount*3*sizeof(float));
- mesh->texcoords = (float *)RL_MALLOC(mesh->vertexCount*2*sizeof(float));
- mesh->colors = NULL;
- UploadMesh(mesh, false);
- return mesh;
-}
-
-void update_heightmap_mesh(Mesh* mesh, float* heightMap, Vector3 size) {
- int mapX = size.x;
- int mapZ = size.z;
-
- int vCounter = 0; // Used to count vertices float by float
- int tcCounter = 0; // Used to count texcoords float by float
- int nCounter = 0; // Used to count normals float by float
-
- //Vector3 scaleFactor = { size.x/(mapX - 1), 1.0f, size.z/(mapZ - 1) };
- Vector3 scaleFactor = { 1.0f, 1.0f, 1.0f};
-
- Vector3 vA = { 0 };
- Vector3 vB = { 0 };
- Vector3 vC = { 0 };
- Vector3 vN = { 0 };
-
- for (int z = 0; z < mapZ-1; z++)
- {
- for (int x = 0; x < mapX-1; x++)
- {
- // Fill vertices array with data
- //----------------------------------------------------------
-
- // one triangle - 3 vertex
- mesh->vertices[vCounter] = (float)x*scaleFactor.x;
- mesh->vertices[vCounter + 1] = heightMap[x + z*mapX]*scaleFactor.y;
- mesh->vertices[vCounter + 2] = (float)z*scaleFactor.z;
-
- mesh->vertices[vCounter + 3] = (float)x*scaleFactor.x;
- mesh->vertices[vCounter + 4] = heightMap[x + (z + 1)*mapX]*scaleFactor.y;
- mesh->vertices[vCounter + 5] = (float)(z + 1)*scaleFactor.z;
-
- mesh->vertices[vCounter + 6] = (float)(x + 1)*scaleFactor.x;
- mesh->vertices[vCounter + 7] = heightMap[(x + 1) + z*mapX]*scaleFactor.y;
- mesh->vertices[vCounter + 8] = (float)z*scaleFactor.z;
-
- // Another triangle - 3 vertex
- mesh->vertices[vCounter + 9] = mesh->vertices[vCounter + 6];
- mesh->vertices[vCounter + 10] = mesh->vertices[vCounter + 7];
- mesh->vertices[vCounter + 11] = mesh->vertices[vCounter + 8];
-
- mesh->vertices[vCounter + 12] = mesh->vertices[vCounter + 3];
- mesh->vertices[vCounter + 13] = mesh->vertices[vCounter + 4];
- mesh->vertices[vCounter + 14] = mesh->vertices[vCounter + 5];
-
- mesh->vertices[vCounter + 15] = (float)(x + 1)*scaleFactor.x;
- mesh->vertices[vCounter + 16] = heightMap[(x + 1) + (z + 1)*mapX]*scaleFactor.y;
- mesh->vertices[vCounter + 17] = (float)(z + 1)*scaleFactor.z;
- vCounter += 18; // 6 vertex, 18 floats
-
- // Fill texcoords array with data
- //--------------------------------------------------------------
- mesh->texcoords[tcCounter] = (float)x/(mapX - 1);
- mesh->texcoords[tcCounter + 1] = (float)z/(mapZ - 1);
-
- mesh->texcoords[tcCounter + 2] = (float)x/(mapX - 1);
- mesh->texcoords[tcCounter + 3] = (float)(z + 1)/(mapZ - 1);
-
- mesh->texcoords[tcCounter + 4] = (float)(x + 1)/(mapX - 1);
- mesh->texcoords[tcCounter + 5] = (float)z/(mapZ - 1);
-
- mesh->texcoords[tcCounter + 6] = mesh->texcoords[tcCounter + 4];
- mesh->texcoords[tcCounter + 7] = mesh->texcoords[tcCounter + 5];
-
- mesh->texcoords[tcCounter + 8] = mesh->texcoords[tcCounter + 2];
- mesh->texcoords[tcCounter + 9] = mesh->texcoords[tcCounter + 3];
-
- mesh->texcoords[tcCounter + 10] = (float)(x + 1)/(mapX - 1);
- mesh->texcoords[tcCounter + 11] = (float)(z + 1)/(mapZ - 1);
- tcCounter += 12; // 6 texcoords, 12 floats
-
- // Fill normals array with data
- //--------------------------------------------------------------
- for (int i = 0; i < 18; i += 9)
- {
- vA.x = mesh->vertices[nCounter + i];
- vA.y = mesh->vertices[nCounter + i + 1];
- vA.z = mesh->vertices[nCounter + i + 2];
-
- vB.x = mesh->vertices[nCounter + i + 3];
- vB.y = mesh->vertices[nCounter + i + 4];
- vB.z = mesh->vertices[nCounter + i + 5];
-
- vC.x = mesh->vertices[nCounter + i + 6];
- vC.y = mesh->vertices[nCounter + i + 7];
- vC.z = mesh->vertices[nCounter + i + 8];
-
- vN = Vector3Normalize(Vector3CrossProduct(Vector3Subtract(vB, vA), Vector3Subtract(vC, vA)));
-
- mesh->normals[nCounter + i] = vN.x;
- mesh->normals[nCounter + i + 1] = vN.y;
- mesh->normals[nCounter + i + 2] = vN.z;
-
- mesh->normals[nCounter + i + 3] = vN.x;
- mesh->normals[nCounter + i + 4] = vN.y;
- mesh->normals[nCounter + i + 5] = vN.z;
-
- mesh->normals[nCounter + i + 6] = vN.x;
- mesh->normals[nCounter + i + 7] = vN.y;
- mesh->normals[nCounter + i + 8] = vN.z;
- }
-
- nCounter += 18; // 6 vertex, 18 floats
- }
- }
-
- // Upload vertex data to GPU (static mesh)
- UpdateMeshBuffer(*mesh, 0, mesh->vertices, mesh->vertexCount * 3 * sizeof(float), 0); // Update vertices
- UpdateMeshBuffer(*mesh, 2, mesh->normals, mesh->vertexCount * 3 * sizeof(float), 0); // Update normals
-}
-
-
-// Required function. Should handle creating the client on first call
-void c_render(Battle* env) {
- if (env->client == NULL) {
- SetConfigFlags(FLAG_MSAA_4X_HINT);
- InitWindow(env->width, env->height, "PufferLib Battle");
- SetTargetFPS(30);
- Client* client = (Client*)calloc(1, sizeof(Client));
- env->client = client;
- client->models[DRONE] = LoadModel("resources/battle/drone.glb");
- client->models[FIGHTER] = LoadModel("resources/battle/fighter.glb");
- client->models[MOTHERSHIP] = LoadModel("resources/battle/mothership.glb");
- client->models[BOMBER] = LoadModel("resources/battle/bomber.glb");
- client->models[INFANTRY] = LoadModel("resources/battle/car.glb");
- client->models[TANK] = LoadModel("resources/battle/tank.glb");
- client->models[ARTILLERY] = LoadModel("resources/battle/artillery.glb");
- client->models[BASE] = LoadModel("resources/battle/base.glb");
- //env->client->ship = LoadModel("resources/puffer.glb");
-
- char vsPath[256];
- char fsPath[256];
- sprintf(vsPath, "resources/tower_climb/shaders/gls%i/lighting.vs", GLSL_VERSION);
- sprintf(fsPath, "resources/tower_climb/shaders/gls%i/lighting.fs", GLSL_VERSION);
- client->light_shader = LoadShader(vsPath, fsPath);
- client->light = CreateLight(LIGHT_DIRECTIONAL,
- (Vector3){ 0.0f, 10.0f, 0.0f }, // High above for top lighting
- (Vector3){ 0.5f, -1.0f, 0.3f }, // Direction: down and slightly forward
- (Color){ 180, 180, 190, 255 }, // Softer warm white for tops
- client->light_shader);
-
- for (int i = 0; i < 8; i++) {
- Model* m = &client->models[i];
- for (int j = 0; j < m->materialCount; j++) {
- //m->materials[j].maps[MATERIAL_MAP_DIFFUSE].texture = client->vehicle_texture;
- m->materials[j].shader = client->light_shader;
- }
- }
-
- Camera3D camera = { 0 };
- camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target)
- camera.fovy = 45.0f; // Camera field-of-view Y
- camera.projection = CAMERA_PERSPECTIVE; // Camera projection type
- camera.position = (Vector3){ 0, 5*env->size_y, -3*env->size_z};
- camera.target = (Vector3){ 0, 0, 0};
- client->camera = camera;
-
- client->mesh = create_heightmap_mesh(env->terrain, (Vector3){env->terrain_width, 1, env->terrain_height});
- client->model = LoadModelFromMesh(*client->mesh);
- update_heightmap_mesh(client->mesh, env->terrain, (Vector3){env->terrain_width, 1, env->terrain_height});
-
- client->terrain_shader = LoadShader(
- TextFormat("resources/battle/shader_%i.vs", GLSL_VERSION),
- TextFormat("resources/battle/shader_%i.fs", GLSL_VERSION)
- );
-
- Image img = GenImageColor(env->terrain_width, env->terrain_height, WHITE);
- ImageFormat(&img, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8);
- client->terrain_texture = LoadTextureFromImage(img);
- UnloadImage(img);
-
- client->terrain_shader_loc = GetShaderLocation(client->terrain_shader, "terrain");
- SetShaderValueTexture(client->terrain_shader, client->terrain_shader_loc, client->terrain_texture);
-
- client->terrain_data = calloc(4*env->terrain_width*env->terrain_height, sizeof(unsigned char));
- for (int i = 0; i < env->terrain_width*env->terrain_height; i++) {
- client->terrain_data[4*i] = env->terrain[i];
- client->terrain_data[4*i+3] = 255;
- }
- UpdateTexture(client->terrain_texture, client->terrain_data);
- SetShaderValueTexture(client->terrain_shader, client->terrain_shader_loc, client->terrain_texture);
-
- int shader_width_loc = GetShaderLocation(client->terrain_shader, "width");
- SetShaderValue(client->terrain_shader, shader_width_loc, &env->terrain_width, SHADER_UNIFORM_INT);
-
- int shader_height_loc = GetShaderLocation(client->terrain_shader, "height");
- SetShaderValue(client->terrain_shader, shader_height_loc, &env->terrain_height, SHADER_UNIFORM_INT);
-
- }
-
- // Standard across our envs so exiting is always the same
- if (IsKeyDown(KEY_ESCAPE)) {
- exit(0);
- }
-
- Client* client = env->client;
- UpdateCamera(&client->camera, CAMERA_THIRD_PERSON);
- //UpdateLightValues(client->light);
- BeginDrawing();
- ClearBackground((Color){6, 24, 24, 255});
- BeginMode3D(client->camera);
-
- //BeginShaderMode(client->terrain_shader);
- client->model.materials[0].shader = client->terrain_shader;
- Vector3 pos = {-env->size_x, -env->size_y, -env->size_z};
- DrawModel(client->model, pos, 1.0/128.0f, (Color){156, 50, 20, 255});
- //EndShaderMode();
-
-
- for (int f=0; fnum_armies; f++) {
- Entity* base = &env->bases[f];
- float y = ground_height(env, base->x, base->z);
- DrawModel(client->models[BASE], (Vector3){base->x, y, base->z}, 0.05f, COLORS[base->army]);
- }
-
- for (int i=0; inum_agents; i++) {
- Entity* agent = &env->agents[i];
-
- Vector3 pos = {agent->x, agent->y, agent->z};
- Matrix transform = QuaternionToMatrix(agent->orientation);
- Model model = client->models[agent->unit];
- model.transform = transform;
-
- Vector3 scale = (Vector3){0.01f, 0.01f, 0.01f};
- if (agent->unit == DRONE) {
- scale = (Vector3){0.01f, 0.01f, 0.01f};
- } else if (agent->unit == MOTHERSHIP) {
- scale = (Vector3){0.03f, 0.03f, 0.03f};
- } else if (agent->unit == FIGHTER) {
- scale = (Vector3){0.015f, 0.015f, 0.015f};
- } else if (agent->unit == BOMBER) {
- scale = (Vector3){0.015f, 0.015f, 0.015f};
- } else if (agent->unit == INFANTRY) {
- scale = (Vector3){0.005f, 0.005f, 0.005f};
- } else if (agent->unit == TANK) {
- scale = (Vector3){0.01f, 0.01f, 0.01f};
- } else if (agent->unit == ARTILLERY) {
- scale = (Vector3){0.02f, 0.02f, 0.02f};
- }
-
- Color color = COLORS[agent->army];
- Vector3 rot = {0.0f, 1.0f, 0.0f};
- DrawModelEx(model, pos, rot, 0, scale, color);
-
- if (agent->target >= 0) {
- Entity* target = &env->agents[agent->target];
- DrawLine3D(
- (Vector3){agent->x, agent->y, agent->z},
- (Vector3){target->x, target->y, target->z},
- COLORS[agent->army]
- );
- }
- }
-
- DrawCubeWires(
- (Vector3){0, 0, 0},
- 2*env->size_x, 2*env->size_y, 2*env->size_z,
- (Color){0, 255, 255, 128}
- );
-
- EndMode3D();
- EndDrawing();
-}
-
-// Required function. Should clean up anything you allocated
-// Do not free env->observations, actions, rewards, terminals
-void c_close(Battle* env) {
- free(env->agents);
- free(env->bases);
- if (env->client != NULL) {
- Client* client = env->client;
- //UnloadTexture(client->sprites);
- CloseWindow();
- free(client);
- }
-}
diff --git a/pufferlib/ocean/battle/battle.py b/pufferlib/ocean/battle/battle.py
deleted file mode 100644
index 2beb888e5..000000000
--- a/pufferlib/ocean/battle/battle.py
+++ /dev/null
@@ -1,85 +0,0 @@
-'''A simple sample environment. Use this as a template for your own envs.'''
-
-import gymnasium
-import numpy as np
-
-import pufferlib
-from pufferlib.ocean.battle import binding
-
-class Battle(pufferlib.PufferEnv):
- def __init__(self, num_envs=1, width=1920, height=1080, size_x=1.0,
- size_y=1.0, size_z=1.0, num_agents=1024, num_factories=32,
- num_armies=4, render_mode=None, log_interval=128, buf=None, seed=0):
- self.single_observation_space = gymnasium.spaces.Box(low=0, high=1,
- shape=(num_armies*3 + 4*16 + 22 + 8,), dtype=np.float32)
- self.single_action_space = gymnasium.spaces.Box(
- low=-1, high=1, shape=(3,), dtype=np.float32)
- self.render_mode = render_mode
- self.num_agents = num_envs*num_agents
- self.log_interval = log_interval
-
- if num_armies < 1 or num_armies > 8:
- raise pufferlib.APIUsageError('num_armies must be in [1, 8]')
- if num_agents % num_armies != 0:
- raise pufferlib.APIUsageError('num_agents must be a multiple of num_armies')
-
- super().__init__(buf)
- c_envs = []
- for i in range(num_envs):
- c_env = binding.env_init(
- self.observations[i*num_agents:(i+1)*num_agents],
- self.actions[i*num_agents:(i+1)*num_agents],
- self.rewards[i*num_agents:(i+1)*num_agents],
- self.terminals[i*num_agents:(i+1)*num_agents],
- self.truncations[i*num_agents:(i+1)*num_agents],
- seed, width=width, height=height, size_x=size_x, size_y=size_y, size_z=size_z,
- num_agents=num_agents*2, num_factories=num_factories,
- num_armies=num_armies)
- c_envs.append(c_env)
-
- self.c_envs = binding.vectorize(*c_envs)
-
- def reset(self, seed=0):
- binding.vec_reset(self.c_envs, seed)
- self.tick = 0
- return self.observations, []
-
- def step(self, actions):
- self.tick += 1
- self.actions[:] = actions
- binding.vec_step(self.c_envs)
-
- info = []
- if self.tick % self.log_interval == 0:
- log = binding.vec_log(self.c_envs)
- if log:
- info.append(log)
-
- return (self.observations, self.rewards,
- self.terminals, self.truncations, info)
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-if __name__ == '__main__':
- N = 512
-
- env = Battle(num_envs=N)
- env.reset()
- steps = 0
-
- CACHE = 1024
- actions = np.random.randint(env.single_action_space.nvec, size=(CACHE, 2))
-
- i = 0
- import time
- start = time.time()
- while time.time() - start < 10:
- env.step(actions[i % CACHE])
- steps += env.num_agents
- i += 1
-
- print('Battle SPS:', int(steps / (time.time() - start)))
diff --git a/pufferlib/ocean/battle/binding.c b/pufferlib/ocean/battle/binding.c
deleted file mode 100644
index 255c6988d..000000000
--- a/pufferlib/ocean/battle/binding.c
+++ /dev/null
@@ -1,26 +0,0 @@
-#include "battle.h"
-
-#define Env Battle
-#include "../env_binding.h"
-
-static int my_init(Env* env, PyObject* args, PyObject* kwargs) {
- env->width = unpack(kwargs, "width");
- env->height = unpack(kwargs, "height");
- env->size_x = unpack(kwargs, "size_x");
- env->size_y = unpack(kwargs, "size_y");
- env->size_z = unpack(kwargs, "size_z");
- env->num_agents = unpack(kwargs, "num_agents");
- env->num_armies = unpack(kwargs, "num_armies");
- init(env);
- return 0;
-}
-
-static int my_log(PyObject* dict, Log* log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "collision_rate", log->collision_rate);
- assign_to_dict(dict, "oob_rate", log->oob_rate);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "episode_length", log->episode_length);
- return 0;
-}
diff --git a/pufferlib/ocean/battle/rlights.h b/pufferlib/ocean/battle/rlights.h
deleted file mode 100644
index a6ca56995..000000000
--- a/pufferlib/ocean/battle/rlights.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/**********************************************************************************************
-*
-* raylib.lights - Some useful functions to deal with lights data
-*
-* CONFIGURATION:
-*
-* #define RLIGHTS_IMPLEMENTATION
-* Generates the implementation of the library into the included file.
-* If not defined, the library is in header only mode and can be included in other headers
-* or source files without problems. But only ONE file should hold the implementation.
-*
-* LICENSE: zlib/libpng
-*
-* Copyright (c) 2017-2024 Victor Fisac (@victorfisac) and Ramon Santamaria (@raysan5)
-*
-* This software is provided "as-is", without any express or implied warranty. In no event
-* will the authors be held liable for any damages arising from the use of this software.
-*
-* Permission is granted to anyone to use this software for any purpose, including commercial
-* applications, and to alter it and redistribute it freely, subject to the following restrictions:
-*
-* 1. The origin of this software must not be misrepresented; you must not claim that you
-* wrote the original software. If you use this software in a product, an acknowledgment
-* in the product documentation would be appreciated but is not required.
-*
-* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
-* as being the original software.
-*
-* 3. This notice may not be removed or altered from any source distribution.
-*
-**********************************************************************************************/
-
-#ifndef RLIGHTS_H
-#define RLIGHTS_H
-
-//----------------------------------------------------------------------------------
-// Defines and Macros
-//----------------------------------------------------------------------------------
-#define MAX_LIGHTS 4 // Max dynamic lights supported by shader
-
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-
-// Light data
-typedef struct {
- int type;
- bool enabled;
- Vector3 position;
- Vector3 target;
- Color color;
- float attenuation;
-
- // Shader locations
- int enabledLoc;
- int typeLoc;
- int positionLoc;
- int targetLoc;
- int colorLoc;
- int attenuationLoc;
-} Light;
-
-// Light type
-typedef enum {
- LIGHT_DIRECTIONAL = 0,
- LIGHT_POINT
-} LightType;
-
-#ifdef __cplusplus
-extern "C" { // Prevents name mangling of functions
-#endif
-
-//----------------------------------------------------------------------------------
-// Module Functions Declaration
-//----------------------------------------------------------------------------------
-Light CreateLight(int type, Vector3 position, Vector3 target, Color color, Shader shader); // Create a light and get shader locations
-void UpdateLightValues(Shader shader, Light light); // Send light properties to shader
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // RLIGHTS_H
-
-
-/***********************************************************************************
-*
-* RLIGHTS IMPLEMENTATION
-*
-************************************************************************************/
-
-#if defined(RLIGHTS_IMPLEMENTATION)
-
-#include "raylib.h"
-
-//----------------------------------------------------------------------------------
-// Defines and Macros
-//----------------------------------------------------------------------------------
-// ...
-
-//----------------------------------------------------------------------------------
-// Types and Structures Definition
-//----------------------------------------------------------------------------------
-// ...
-
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-static int lightsCount = 0; // Current amount of created lights
-
-//----------------------------------------------------------------------------------
-// Module specific Functions Declaration
-//----------------------------------------------------------------------------------
-// ...
-
-//----------------------------------------------------------------------------------
-// Module Functions Definition
-//----------------------------------------------------------------------------------
-
-// Create a light and get shader locations
-Light CreateLight(int type, Vector3 position, Vector3 target, Color color, Shader shader)
-{
- Light light = { 0 };
-
- if (lightsCount < MAX_LIGHTS)
- {
- light.enabled = true;
- light.type = type;
- light.position = position;
- light.target = target;
- light.color = color;
-
- // NOTE: Lighting shader naming must be the provided ones
- light.enabledLoc = GetShaderLocation(shader, TextFormat("lights[%i].enabled", lightsCount));
- light.typeLoc = GetShaderLocation(shader, TextFormat("lights[%i].type", lightsCount));
- light.positionLoc = GetShaderLocation(shader, TextFormat("lights[%i].position", lightsCount));
- light.targetLoc = GetShaderLocation(shader, TextFormat("lights[%i].target", lightsCount));
- light.colorLoc = GetShaderLocation(shader, TextFormat("lights[%i].color", lightsCount));
-
- UpdateLightValues(shader, light);
-
- lightsCount++;
- }
-
- return light;
-}
-
-// Send light properties to shader
-// NOTE: Light shader locations should be available
-void UpdateLightValues(Shader shader, Light light)
-{
- // Send to shader light enabled state and type
- SetShaderValue(shader, light.enabledLoc, &light.enabled, SHADER_UNIFORM_INT);
- SetShaderValue(shader, light.typeLoc, &light.type, SHADER_UNIFORM_INT);
-
- // Send to shader light position values
- float position[3] = { light.position.x, light.position.y, light.position.z };
- SetShaderValue(shader, light.positionLoc, position, SHADER_UNIFORM_VEC3);
-
- // Send to shader light target position values
- float target[3] = { light.target.x, light.target.y, light.target.z };
- SetShaderValue(shader, light.targetLoc, target, SHADER_UNIFORM_VEC3);
-
- // Send to shader light color values
- float color[4] = { (float)light.color.r/(float)255, (float)light.color.g/(float)255,
- (float)light.color.b/(float)255, (float)light.color.a/(float)255 };
- SetShaderValue(shader, light.colorLoc, color, SHADER_UNIFORM_VEC4);
-}
-
-#endif // RLIGHTS_IMPLEMENTATION
diff --git a/pufferlib/ocean/battle/simplex.h b/pufferlib/ocean/battle/simplex.h
deleted file mode 100644
index 07b3e7db3..000000000
--- a/pufferlib/ocean/battle/simplex.h
+++ /dev/null
@@ -1,148 +0,0 @@
-// Original work (noise library) Copyright (c) 2008 Casey Duncan
-// Modified work (vec_noise library) Copyright (c) 2017 Zev Benjamin
-// Single-file C port (this file) Copyright (c) 2024 Joseph Suarez
-// Distributed under the MIT license. This is a simple copy-paste job.
-// I did this because the original code mixed Python bindings into the
-// C source, so there wasn't a clean way to use it as a C standalone.
-
-#include
-const float GRAD3[][3] = {
- {1,1,0},{-1,1,0},{1,-1,0},{-1,-1,0},
- {1,0,1},{-1,0,1},{1,0,-1},{-1,0,-1},
- {0,1,1},{0,-1,1},{0,1,-1},{0,-1,-1},
- {1,0,-1},{-1,0,-1},{0,-1,1},{0,1,1}};
-
-const float GRAD4[][4] = {
- {0,1,1,1}, {0,1,1,-1}, {0,1,-1,1}, {0,1,-1,-1},
- {0,-1,1,1}, {0,-1,1,-1}, {0,-1,-1,1}, {0,-1,-1,-1},
- {1,0,1,1}, {1,0,1,-1}, {1,0,-1,1}, {1,0,-1,-1},
- {-1,0,1,1}, {-1,0,1,-1}, {-1,0,-1,1}, {-1,0,-1,-1},
- {1,1,0,1}, {1,1,0,-1}, {1,-1,0,1}, {1,-1,0,-1},
- {-1,1,0,1}, {-1,1,0,-1}, {-1,-1,0,1}, {-1,-1,0,-1},
- {1,1,1,0}, {1,1,-1,0}, {1,-1,1,0}, {1,-1,-1,0},
- {-1,1,1,0}, {-1,1,-1,0}, {-1,-1,1,0}, {-1,-1,-1,0}};
-
-// At the possible cost of unaligned access, we use char instead of
-// int here to try to ensure that this table fits in L1 cache
-const unsigned char PERM[] = {
- 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140,
- 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120,
- 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33,
- 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71,
- 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133,
- 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161,
- 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130,
- 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250,
- 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227,
- 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44,
- 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98,
- 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34,
- 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14,
- 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121,
- 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243,
- 141, 128, 195, 78, 66, 215, 61, 156, 180, 151, 160, 137, 91, 90, 15, 131,
- 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37,
- 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252,
- 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125,
- 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158,
- 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245,
- 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187,
- 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198,
- 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126,
- 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223,
- 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167,
- 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185,
- 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179,
- 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199,
- 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236,
- 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156,
- 180};
-
-const unsigned char SIMPLEX[][4] = {
- {0,1,2,3},{0,1,3,2},{0,0,0,0},{0,2,3,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},
- {1,2,3,0},{0,2,1,3},{0,0,0,0},{0,3,1,2},{0,3,2,1},{0,0,0,0},{0,0,0,0},
- {0,0,0,0},{1,3,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},{1,2,0,3},{0,0,0,0},{1,3,0,2},{0,0,0,0},
- {0,0,0,0},{0,0,0,0},{2,3,0,1},{2,3,1,0},{1,0,2,3},{1,0,3,2},{0,0,0,0},
- {0,0,0,0},{0,0,0,0},{2,0,3,1},{0,0,0,0},{2,1,3,0},{0,0,0,0},{0,0,0,0},
- {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,0,1,3},
- {0,0,0,0},{0,0,0,0},{0,0,0,0},{3,0,1,2},{3,0,2,1},{0,0,0,0},{3,1,2,0},
- {2,1,0,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,1,0,2},{0,0,0,0},{3,2,0,1},
- {3,2,1,0}};
-
-#define fastfloor(n) (int)(n) - (((n) < 0.0f) & ((n) != (int)(n)))
-
-// Fast sine/cosine functions from
-// http://devmaster.net/forums/topic/4648-fast-and-accurate-sinecosine/page__st__80
-// Note the input to these functions is not radians
-// instead x = [0, 2] for r = [0, 2*PI]
-
-inline float fast_sin(float x)
-{
- // Convert the input value to a range of -1 to 1
- // x = x * (1.0f / PI);
-
- // Wrap around
- volatile float z = (x + 25165824.0f);
- x = x - (z - 25165824.0f);
-
- #if LOW_SINE_PRECISION
- return 4.0f * (x - x * fabsf(x));
- #else
- {
- float y = x - x * fabsf(x);
- const float Q = 3.1f;
- const float P = 3.6f;
- return y * (Q + P * fabsf(y));
- }
- #endif
-}
-
-inline float fast_cos(float x)
-{
- return fast_sin(x + 0.5f);
-}
-
-// 2D simplex skew factors
-#define F2 0.3660254037844386f // 0.5 * (sqrt(3.0) - 1.0)
-#define G2 0.21132486540518713f // (3.0 - sqrt(3.0)) / 6.0
-
-float
-noise2(float x, float y)
-{
- int i1, j1, II, JJ, c;
- float s = (x + y) * F2;
- float i = floorf(x + s);
- float j = floorf(y + s);
- float t = (i + j) * G2;
-
- float xx[3], yy[3], f[3];
- float noise[3] = {0.0f, 0.0f, 0.0f};
- int g[3];
-
- xx[0] = x - (i - t);
- yy[0] = y - (j - t);
-
- i1 = xx[0] > yy[0];
- j1 = xx[0] <= yy[0];
-
- xx[2] = xx[0] + G2 * 2.0f - 1.0f;
- yy[2] = yy[0] + G2 * 2.0f - 1.0f;
- xx[1] = xx[0] - i1 + G2;
- yy[1] = yy[0] - j1 + G2;
-
- II = (int) i & 255;
- JJ = (int) j & 255;
- g[0] = PERM[II + PERM[JJ]] % 12;
- g[1] = PERM[II + i1 + PERM[JJ + j1]] % 12;
- g[2] = PERM[II + 1 + PERM[JJ + 1]] % 12;
-
- for (c = 0; c <= 2; c++)
- f[c] = 0.5f - xx[c]*xx[c] - yy[c]*yy[c];
-
- for (c = 0; c <= 2; c++)
- if (f[c] > 0)
- noise[c] = f[c]*f[c]*f[c]*f[c] * (GRAD3[g[c]][0]*xx[c] + GRAD3[g[c]][1]*yy[c]);
-
- return (noise[0] + noise[1] + noise[2]) * 70.0f;
-}
diff --git a/pufferlib/ocean/benchmark/README.md b/pufferlib/ocean/benchmark/README.md
new file mode 100644
index 000000000..2e08295f4
--- /dev/null
+++ b/pufferlib/ocean/benchmark/README.md
@@ -0,0 +1,68 @@
+# Waymo Open Sim Agent Challenge (WOSAC) benchmark
+
+## Usage
+
+WOSAC evaluation with random policy
+```bash
+puffer eval puffer_drive --eval.wosac-realism-eval True
+```
+
+WOSAC evaluation with your checkpoint
+```bash
+puffer eval puffer_drive --eval.wosac-realism-eval True --load-model-path .pt
+```
+
+## Links
+
+- [Challenge and leaderboard](https://waymo.com/open/challenges/2025/sim-agents/)
+- [Sim agent challenge tutorial](https://github.com/waymo-research/waymo-open-dataset/blob/master/tutorial/tutorial_sim_agents.ipynb)
+- [Reference paper introducing WOSAC](https://arxiv.org/pdf/2305.12032)
+- [Metrics entry point](https://github.com/waymo-research/waymo-open-dataset/blob/master/src/waymo_open_dataset/wdl_limited/sim_agents_metrics/metrics.py)
+- [Log-likelihood estimators](https://github.com/waymo-research/waymo-open-dataset/blob/master/src/waymo_open_dataset/wdl_limited/sim_agents_metrics/estimators.py)
+- Configurations [proto file](https://github.com/waymo-research/waymo-open-dataset/blob/99a4cb3ff07e2fe06c2ce73da001f850f628e45a/src/waymo_open_dataset/protos/sim_agents_metrics.proto#L51) [default sim agent challenge configs](https://github.com/waymo-research/waymo-open-dataset/blob/master/src/waymo_open_dataset/wdl_limited/sim_agents_metrics/challenge_2025_sim_agents_config.textproto)
+
+
+## Implementation
+
+- For the sim agent challenge we compute the log likelihood with `aggregate_objects=False`, which means that we use [`_log_likelihood_estimate_timeseries_agent_level()`](https://github.com/waymo-research/waymo-open-dataset/blob/99a4cb3ff07e2fe06c2ce73da001f850f628e45a/src/waymo_open_dataset/wdl_limited/sim_agents_metrics/estimators.py#L17)
+- As such, the interpretation is as follows:
+
+Steps [for every scene]:
+1. Rollout policy in environment K times → (n_agents, n_rollouts, n_steps)
+2. Obtain log data → (n_agents, 1, n_steps)
+3. Obtain features from (x, y, z, heading tuples)
+4. Compute log-likelihood metrics from features
+ - a. Flatten across time (assume independence) → (n_agents, n_rollouts * n_steps)
+ - b. Use the per-agent simulated features to construct a probability distribution
+ - c. Take the per-agent ground-truth values and find the bin that is closed for each
+ - d. Take log of the probability for each bin → (n_agents, n_steps)
+5. Likelihood score is exp(sum(log_probs)/n_steps) → (n_agents, 1) \in [0, 1]
+
+## Notes
+
+- Currently, only kinematics realism score is implemented. Next steps would be to add the interactive realism score, and the map realism score:
+
+ - Interactive realism score: requires grouping agents per scenario, and computing pairwise distances between agents over time.
+ - Map realism score: requires access to the map and computing offroad status.
+
+ Those two scores might require heavy computations, so we will consider reimplementic all the metrics in torch.
+
+- About the time-independence assumption:
+
+ 1. This is the assumption used in the official WOSAC evaluation, their argument is that it would give more flexibility to the sim agents models:
+
+ > Given the time series nature of simulation data, two choices emerge for how to treat samples over multiple timesteps for a given object for a given run segment: to treat them as time-independent or time-dependent samples. In the latter case, users would be expected to not only reconstruct the general behaviors present in the logged data in one rollout, but also recreate those behaviors over the exact same time intervals. To allow more flexibility in agent behavior, we use the former formulation when computing NLLs, defining each component metric m as an average (in log-space) over the time-axis, masked by validity.
+
+ 2. However this will lead to the score of a perfect logged oracle being inferior to 1.0, and makes it less interpretable. Here are the scores of a logged oracle using the time-independence assumption (setup: 1024 agents, 48 rollouts):
+
+ ```
+ Linear speed: 0.5640
+ Linear acceleration: 0.4658
+ Angular speed: 0.5543
+ Angular acceleration: 0.6589
+
+ Kinematics realism score: 0.5607
+ ```
+ These scores go to 1.0 if we use the time-dependent estimator, execpt for the smoothing factor that is used to avoid bins with 0 probability.
+
+ Using the time-dependent estimator means generating n_steps histograms per agent, using num_rollouts samples per histogram, while time-independence means generating one histogram per agent using n_rollouts * n_steps samples. With the speed of PufferDrive, we might be able to increase n_rollouts to have more samples per histogram.
diff --git a/pufferlib/ocean/cpr/__init__.py b/pufferlib/ocean/benchmark/__init__.py
similarity index 100%
rename from pufferlib/ocean/cpr/__init__.py
rename to pufferlib/ocean/benchmark/__init__.py
diff --git a/pufferlib/ocean/benchmark/estimators.py b/pufferlib/ocean/benchmark/estimators.py
new file mode 100644
index 000000000..7af3592a5
--- /dev/null
+++ b/pufferlib/ocean/benchmark/estimators.py
@@ -0,0 +1,168 @@
+"""Simplified estimators to compute log-likelihood of simulated trajs based on https://github.com/waymo-research/waymo-open-dataset/blob/master/src/waymo_open_dataset/wdl_limited/sim_agents_metrics/estimators.py"""
+
+import numpy as np
+import matplotlib.pyplot as plt
+from typing import Optional
+
+np.set_printoptions(suppress=True)
+
+
+def histogram_estimate(
+ log_samples: np.ndarray,
+ sim_samples: np.ndarray,
+ min_val: float,
+ max_val: float,
+ num_bins: int,
+ additive_smoothing: float = 0.1,
+) -> np.ndarray:
+ """Computes log-likelihoods of samples based on histograms.
+
+ Args:
+ log_samples: Shape (n_agents, sample_size) - samples to evaluate
+ sim_samples: Shape (n_agents, sample_size) - samples to build distribution from
+ min_val: Minimum value for histogram bins
+ max_val: Maximum value for histogram bins
+ num_bins: Number of histogram bins
+ additive_smoothing: Pseudocount for Laplace smoothing (default: 0.1)
+ sanity_check: If True, plot visualization for debugging
+
+ Returns:
+ Shape (n_agents, sample_size) - log-likelihood of each log sample
+ under the corresponding sim distribution
+ """
+
+ n_agents, sample_size = sim_samples.shape
+
+ # Clip samples to valid range
+ log_samples_clipped = np.clip(log_samples, min_val, max_val)
+ sim_samples_clipped = np.clip(sim_samples, min_val, max_val)
+
+ # Create bin edges
+ edges = np.linspace(min_val, max_val, num_bins + 1)
+
+ # Create histogram for each agent from sim samples
+ sim_counts = np.array([np.histogram(sim_samples_clipped[i], bins=edges)[0] for i in range(n_agents)])
+
+ # Apply smoothing and normalize to probabilities
+ sim_counts = sim_counts.astype(float) + additive_smoothing
+ sim_probs = sim_counts / sim_counts.sum(axis=1, keepdims=True)
+
+ # Find which bin each log sample belongs to
+ # digitize returns values in [1, num_bins], so subtract 1 for 0-indexing
+ # right=False means bins are [left, right) except last bin which is [left, right]
+ log_bins = np.digitize(log_samples_clipped, edges, right=False) - 1
+
+ # Clip to valid bin indices (handles edge case where value == max_val)
+ log_bins = np.clip(log_bins, 0, num_bins - 1)
+
+ # Get log probabilities for each sample
+ agent_indices = np.arange(n_agents)[:, None]
+ log_probs = np.log(sim_probs[agent_indices, log_bins])
+
+ return log_probs
+
+
+def log_likelihood_estimate_timeseries(
+ log_values: np.ndarray,
+ sim_values: np.ndarray,
+ min_val: float,
+ max_val: float,
+ num_bins: int,
+ additive_smoothing: float = 0.1,
+ treat_timesteps_independently: bool = True,
+ sanity_check: bool = False,
+ plot_agent_idx: int = 0,
+) -> np.ndarray:
+ """Computes log-likelihood estimates for time-series simulated features on a per-agent basis.
+
+ Args:
+ log_values: Shape (n_agents, 1, n_steps)
+ sim_values: Shape (n_agents, n_rollouts, n_steps)
+ min_val: Minimum value for histogram bins
+ max_val: Maximum value for histogram bins
+ num_bins: Number of histogram bins
+ additive_smoothing: Pseudocount for Laplace smoothing
+ treat_timesteps_independently: If True, treat each timestep independently
+ sanity_check: If True, plot visualizations for debugging
+ plot_agent_idx: Which agent to plot if sanity_check=True
+ plot_rollouts: How many rollouts to show if sanity_check=True
+
+ Returns:
+ A tensor of shape (n_objects, n_steps) containing the log probability
+ estimates of the log features under the simulated distribution of the same
+ feature.
+ """
+ n_agents, n_rollouts, n_steps = sim_values.shape
+
+ if treat_timesteps_independently:
+ # Ignore temporal structure: We end up with (n_agents, n_rollouts * n_steps)
+ log_flat = log_values.reshape(n_agents, n_steps)
+ sim_flat = sim_values.reshape(n_agents, n_rollouts * n_steps)
+
+ else:
+ # If values in time are instead to be compared per-step, reshape:
+ # - `sim_values` as (n_objects * n_steps, n_rollouts)
+ # - `log_values` as (n_objects * n_steps, 1)
+ log_flat = log_values.reshape(n_agents * n_steps, 1)
+ sim_flat = sim_values.transpose(0, 2, 1).reshape(n_agents * n_steps, n_rollouts)
+
+ # Compute log-likelihoods
+ log_probs = histogram_estimate(log_flat, sim_flat, min_val, max_val, num_bins, additive_smoothing)
+
+ # Depending on `independent_timesteps`, the likelihoods might be flattened, so
+ # reshape back to the initial `log_values` shape.
+ log_probs = log_probs.reshape(n_agents, n_steps)
+
+ # Sanity check visualization
+ if sanity_check:
+ _plot_histogram_sanity_check(log_flat, sim_flat, log_probs, plot_agent_idx)
+
+ return log_probs
+
+
+def _plot_histogram_sanity_check(
+ log_samples: np.ndarray,
+ sim_samples: np.ndarray,
+ log_probs: np.ndarray,
+ idx: int,
+):
+ """Plot data as sanity check."""
+
+ for idx in range(log_samples.shape[0]):
+ fig, axes = plt.subplots(1, 3, figsize=(15, 4))
+ fig.suptitle(f"Histogram Log-Likelihood Sanity Check for Agent {idx}")
+
+ # Plot 1: Simulated distribution (histogram)
+ axes[0].hist(sim_samples[idx], density=True, alpha=0.7, color="blue")
+ axes[0].set_xlabel("Value")
+ axes[0].set_ylabel("Density")
+ axes[0].set_title("Simulated distribution")
+ axes[0].grid(alpha=0.3)
+
+ # Plot 2: Ground-truth values overlaid on simulated
+ axes[1].hist(sim_samples[idx], density=True, alpha=0.5, color="blue", label="Simulated")
+ axes[1].scatter(
+ log_samples[idx],
+ np.zeros_like(log_samples[idx]),
+ color="green",
+ marker="|",
+ s=200,
+ linewidths=2,
+ label="Ground-truth",
+ zorder=5,
+ )
+ axes[1].set_xlabel("Value")
+ axes[1].set_ylabel("Density")
+ axes[1].set_title("Ground-truth vs Simulated")
+ axes[1].legend()
+ axes[1].grid(alpha=0.3)
+
+ # Plot 3: Log-likelihood values
+ axes[2].hist(log_samples[idx], alpha=0.7, color="orange")
+ axes[2].set_ylabel("Log-likelihood")
+ axes[2].set_title("Log-likelihood of Ground-truth")
+ axes[2].grid(alpha=0.3)
+ axes[2].axhline(y=0, color="k", linestyle="--", alpha=0.3)
+
+ plt.tight_layout()
+ plt.savefig(f"histogram_sanity_check_agent_{idx}.png")
diff --git a/pufferlib/ocean/benchmark/evaluator.py b/pufferlib/ocean/benchmark/evaluator.py
new file mode 100644
index 000000000..4c50a422a
--- /dev/null
+++ b/pufferlib/ocean/benchmark/evaluator.py
@@ -0,0 +1,492 @@
+"""WOSAC evaluation class for PufferDrive."""
+
+import torch
+import time
+import numpy as np
+import pandas as pd
+from pprint import pprint
+from typing import Dict, Optional
+import matplotlib.pyplot as plt
+import configparser
+import os
+
+import pufferlib
+from pufferlib.ocean.benchmark import metrics
+from pufferlib.ocean.benchmark import estimators
+
+
+_METRIC_FIELD_NAMES = [
+ "linear_speed",
+ "linear_acceleration",
+ "angular_speed",
+ "angular_acceleration",
+]
+
+
+class WOSACEvaluator:
+ """Evaluates policys on the Waymo Open Sim Agent Challenge (WOSAC) in PufferDrive. Info and links in the readme."""
+
+ def __init__(self, config: Dict):
+ self.config = config
+ self.num_steps = 91 # Hardcoded for WOSAC (9.1s at 10Hz)
+ self.init_steps = config.get("eval", {}).get("wosac_init_steps", 0)
+ self.sim_steps = self.num_steps - self.init_steps
+ self.num_rollouts = config.get("eval", {}).get("wosac_num_rollouts", 32)
+
+ wosac_metrics_path = os.path.join(os.path.dirname(__file__), "wosac.ini")
+ self.metrics_config = configparser.ConfigParser()
+ self.metrics_config.read(wosac_metrics_path)
+
+ def _compute_metametric(self, metrics: pd.Series) -> float:
+ metametric = 0.0
+ for field_name in _METRIC_FIELD_NAMES:
+ likelihood_field_name = "likelihood_" + field_name
+ weight = self.metrics_config.getfloat(field_name, "metametric_weight")
+ metric_score = metrics[likelihood_field_name]
+ metametric += weight * metric_score
+
+ weight_sum = sum(self.metrics_config.getfloat(fn, "metametric_weight") for fn in _METRIC_FIELD_NAMES)
+ return metametric / weight_sum
+
+ def _get_histogram_params(self, metric_name: str):
+ return (
+ self.metrics_config.getfloat(metric_name, "histogram.min_val"),
+ self.metrics_config.getfloat(metric_name, "histogram.max_val"),
+ self.metrics_config.getint(metric_name, "histogram.num_bins"),
+ self.metrics_config.getfloat(metric_name, "histogram.additive_smoothing_pseudocount"),
+ self.metrics_config.getboolean(metric_name, "independent_timesteps"),
+ )
+
+ def collect_ground_truth_trajectories(self, puffer_env):
+ """Collect ground truth data for evaluation.
+ Returns:
+ trajectories: dict with keys 'x', 'y', 'z', 'heading', 'id'
+ each of shape (num_agents, 1, num_steps) for trajectory data
+ """
+ return puffer_env.get_ground_truth_trajectories()
+
+ def collect_simulated_trajectories(self, args, puffer_env, policy):
+ """Roll out policy in env and collect trajectories.
+ Returns:
+ trajectories: dict with keys 'x', 'y', 'z', 'heading' each of shape
+ (num_agents, num_rollouts, num_steps)
+ """
+
+ driver = puffer_env.driver_env
+ num_agents = puffer_env.observation_space.shape[0]
+ device = args["train"]["device"]
+
+ trajectories = {
+ "x": np.zeros((num_agents, self.num_rollouts, self.sim_steps), dtype=np.float32),
+ "y": np.zeros((num_agents, self.num_rollouts, self.sim_steps), dtype=np.float32),
+ "z": np.zeros((num_agents, self.num_rollouts, self.sim_steps), dtype=np.float32),
+ "heading": np.zeros((num_agents, self.num_rollouts, self.sim_steps), dtype=np.float32),
+ "id": np.zeros((num_agents, self.num_rollouts, self.sim_steps), dtype=np.int32),
+ }
+
+ for rollout_idx in range(self.num_rollouts):
+ print(f"\rCollecting rollout {rollout_idx + 1}/{self.num_rollouts}...", end="", flush=True)
+ obs, info = puffer_env.reset()
+ state = {}
+ if args["train"]["use_rnn"]:
+ state = dict(
+ lstm_h=torch.zeros(num_agents, policy.hidden_size, device=device),
+ lstm_c=torch.zeros(num_agents, policy.hidden_size, device=device),
+ )
+
+ for time_idx in range(self.sim_steps):
+ # Get global state
+ agent_state = driver.get_global_agent_state()
+ trajectories["x"][:, rollout_idx, time_idx] = agent_state["x"]
+ trajectories["y"][:, rollout_idx, time_idx] = agent_state["y"]
+ trajectories["z"][:, rollout_idx, time_idx] = agent_state["z"]
+ trajectories["heading"][:, rollout_idx, time_idx] = agent_state["heading"]
+ trajectories["id"][:, rollout_idx, time_idx] = agent_state["id"]
+
+ # Step policy
+ with torch.no_grad():
+ ob_tensor = torch.as_tensor(obs).to(device)
+ logits, value = policy.forward_eval(ob_tensor, state)
+ action, logprob, _ = pufferlib.pytorch.sample_logits(logits)
+ action_np = action.cpu().numpy().reshape(puffer_env.action_space.shape)
+
+ if isinstance(logits, torch.distributions.Normal):
+ action_np = np.clip(action_np, puffer_env.action_space.low, puffer_env.action_space.high)
+
+ obs, _, _, _, _ = puffer_env.step(action_np)
+
+ return trajectories
+
+ def compute_metrics(
+ self,
+ ground_truth_trajectories: Dict,
+ simulated_trajectories: Dict,
+ aggregate_results: bool = False,
+ ) -> Dict:
+ """Compute realism metrics comparing simulated and ground truth trajectories.
+
+ Args:
+ ground_truth_trajectories: Dict with keys ['x', 'y', 'z', 'heading', 'id']
+ Each trajectory has shape (n_agents, n_rollouts, n_steps)
+ simulated_trajectories: Dict with same keys plus 'scenario_id'
+ shape (n_agents, n_steps) for trajectories
+ shape (n_agents,) for id
+ list of length n_agents for scenario_id
+
+ Note: z-position currently not used.
+
+ Returns:
+ Dictionary with scores per scenario_id
+ """
+ # Ensure the id order matches exactly for simulated and ground truth
+ assert np.array_equal(simulated_trajectories["id"][:, 0:1, 0], ground_truth_trajectories["id"]), (
+ "Agent IDs don't match between simulated and ground truth trajectories"
+ )
+
+ # Extract trajectories
+ sim_x = simulated_trajectories["x"]
+ sim_y = simulated_trajectories["y"]
+ sim_heading = simulated_trajectories["heading"]
+ ref_x = ground_truth_trajectories["x"]
+ ref_y = ground_truth_trajectories["y"]
+ ref_heading = ground_truth_trajectories["heading"]
+ ref_valid = ground_truth_trajectories["valid"]
+
+ # Compute features
+ # Kinematics-related features
+ sim_linear_speed, sim_linear_accel, sim_angular_speed, sim_angular_accel = metrics.compute_kinematic_features(
+ sim_x, sim_y, sim_heading
+ )
+
+ ref_linear_speed, ref_linear_accel, ref_angular_speed, ref_angular_accel = metrics.compute_kinematic_features(
+ ref_x, ref_y, ref_heading
+ )
+
+ # Get the log speed (linear and angular) validity. Since this is computed by
+ # a delta between steps i-1 and i+1, we verify that both of these are
+ # valid (logical and).
+ speed_validity, acceleration_validity = metrics.compute_kinematic_validity(ref_valid)
+
+ # Compute realism metrics
+ # Average Displacement Error (ADE) and minADE
+ # Note: This metric is not included in the scoring meta-metric, as per WOSAC rules.
+ ade, min_ade = metrics.compute_displacement_error(sim_x, sim_y, ref_x, ref_y, ref_valid)
+
+ # Log-likelihood metrics
+ # Kinematic features log-likelihoods
+ min_val, max_val, num_bins, additive_smoothing, independent_timesteps = self._get_histogram_params(
+ "linear_speed"
+ )
+ linear_speed_log_likelihood = estimators.log_likelihood_estimate_timeseries(
+ log_values=ref_linear_speed,
+ sim_values=sim_linear_speed,
+ treat_timesteps_independently=independent_timesteps,
+ min_val=min_val,
+ max_val=max_val,
+ num_bins=num_bins,
+ additive_smoothing=additive_smoothing,
+ sanity_check=False,
+ )
+
+ min_val, max_val, num_bins, additive_smoothing, independent_timesteps = self._get_histogram_params(
+ "linear_acceleration"
+ )
+ linear_accel_log_likelihood = estimators.log_likelihood_estimate_timeseries(
+ log_values=ref_linear_accel,
+ sim_values=sim_linear_accel,
+ treat_timesteps_independently=independent_timesteps,
+ min_val=min_val,
+ max_val=max_val,
+ num_bins=num_bins,
+ additive_smoothing=additive_smoothing,
+ sanity_check=False,
+ )
+
+ min_val, max_val, num_bins, additive_smoothing, independent_timesteps = self._get_histogram_params(
+ "angular_speed"
+ )
+ angular_speed_log_likelihood = estimators.log_likelihood_estimate_timeseries(
+ log_values=ref_angular_speed,
+ sim_values=sim_angular_speed,
+ treat_timesteps_independently=independent_timesteps,
+ min_val=min_val,
+ max_val=max_val,
+ num_bins=num_bins,
+ additive_smoothing=additive_smoothing,
+ sanity_check=False,
+ )
+
+ min_val, max_val, num_bins, additive_smoothing, independent_timesteps = self._get_histogram_params(
+ "angular_acceleration"
+ )
+ angular_accel_log_likelihood = estimators.log_likelihood_estimate_timeseries(
+ log_values=ref_angular_accel,
+ sim_values=sim_angular_accel,
+ treat_timesteps_independently=independent_timesteps,
+ min_val=min_val,
+ max_val=max_val,
+ num_bins=num_bins,
+ additive_smoothing=additive_smoothing,
+ sanity_check=False,
+ )
+
+ speed_likelihood = np.exp(
+ metrics._reduce_average_with_validity(
+ linear_speed_log_likelihood,
+ speed_validity[:, 0, :],
+ axis=1,
+ )
+ )
+
+ accel_likelihood = np.exp(
+ metrics._reduce_average_with_validity(
+ linear_accel_log_likelihood,
+ acceleration_validity[:, 0, :],
+ axis=1,
+ )
+ )
+
+ angular_speed_likelihood = np.exp(
+ metrics._reduce_average_with_validity(
+ angular_speed_log_likelihood,
+ speed_validity[:, 0, :],
+ axis=1,
+ )
+ )
+
+ angular_accel_likelihood = np.exp(
+ metrics._reduce_average_with_validity(
+ angular_accel_log_likelihood,
+ acceleration_validity[:, 0, :],
+ axis=1,
+ )
+ )
+
+ # Get agent IDs and scenario IDs
+ agent_ids = ground_truth_trajectories["id"]
+ scenario_ids = ground_truth_trajectories["scenario_id"]
+
+ df = pd.DataFrame(
+ {
+ "agent_id": agent_ids.flatten(),
+ "scenario_id": scenario_ids.flatten(),
+ "ade": ade,
+ "min_ade": min_ade,
+ "likelihood_linear_speed": speed_likelihood,
+ "likelihood_linear_acceleration": accel_likelihood,
+ "likelihood_angular_speed": angular_speed_likelihood,
+ "likelihood_angular_acceleration": angular_accel_likelihood,
+ }
+ )
+
+ scene_level_results = df.groupby("scenario_id")[
+ [
+ "ade",
+ "min_ade",
+ "likelihood_linear_speed",
+ "likelihood_linear_acceleration",
+ "likelihood_angular_speed",
+ "likelihood_angular_acceleration",
+ ]
+ ].mean()
+
+ scene_level_results["realism_meta_score"] = scene_level_results.apply(self._compute_metametric, axis=1)
+ scene_level_results["num_agents"] = df.groupby("scenario_id").size()
+ scene_level_results = scene_level_results[
+ ["num_agents"] + [col for col in scene_level_results.columns if col != "num_agents"]
+ ]
+
+ if aggregate_results:
+ aggregate_metrics = scene_level_results.mean().to_dict()
+ aggregate_metrics["total_num_agents"] = scene_level_results["num_agents"].sum()
+ # Convert numpy types to Python native types
+ return {k: v.item() if hasattr(v, "item") else v for k, v in aggregate_metrics.items()}
+ else:
+ print("\n Scene-level results:\n")
+ print(scene_level_results)
+
+ print(f"\n Overall realism meta score: {scene_level_results['realism_meta_score'].mean():.4f}")
+ print(f"\n Overall minADE: {scene_level_results['min_ade'].mean():.4f}")
+ print(f"\n Overall ADE: {scene_level_results['ade'].mean():.4f}")
+
+ # print(f"\n Full agent-level results:\n")
+ # print(df)
+ return scene_level_results
+
+ def _quick_sanity_check(self, gt_trajectories, simulated_trajectories, agent_idx=None, max_agents_to_plot=10):
+ if agent_idx is None:
+ agent_indices = range(np.clip(simulated_trajectories["x"].shape[0], 1, max_agents_to_plot))
+
+ else:
+ agent_indices = [agent_idx]
+
+ for agent_idx in agent_indices:
+ valid_mask = gt_trajectories["valid"][agent_idx, 0, :] == 1
+ invalid_mask = ~valid_mask
+
+ last_valid_idx = np.where(valid_mask)[0][-1] if valid_mask.any() else 0
+ goal_x = gt_trajectories["x"][agent_idx, 0, last_valid_idx]
+ goal_y = gt_trajectories["y"][agent_idx, 0, last_valid_idx]
+ goal_radius = 2.0 # Note: Hardcoded here; ideally pass from config
+
+ fig, axs = plt.subplots(1, 3, figsize=(12, 4))
+
+ axs[0].set_title(f"Simulated rollouts (x, y) for agent id: {simulated_trajectories['id'][agent_idx, 0][0]}")
+
+ for i in range(self.num_rollouts):
+ # Sample random color for each rollout
+ color = plt.cm.tab20(i % 20)
+ axs[0].scatter(
+ simulated_trajectories["x"][agent_idx, i, :],
+ simulated_trajectories["y"][agent_idx, i, :],
+ alpha=0.1,
+ color=color,
+ )
+
+ axs[1].set_title(
+ f"Simulated rollouts (x, y) and GT; agent id: {simulated_trajectories['id'][agent_idx, 0][0]}"
+ )
+
+ axs[1].scatter(
+ simulated_trajectories["x"][agent_idx, :, valid_mask],
+ simulated_trajectories["y"][agent_idx, :, valid_mask],
+ color="b",
+ alpha=0.1,
+ zorder=4,
+ )
+
+ axs[1].scatter(
+ gt_trajectories["x"][agent_idx, 0, valid_mask],
+ gt_trajectories["y"][agent_idx, 0, valid_mask],
+ color="g",
+ label="Ground truth",
+ alpha=0.5,
+ )
+
+ axs[1].scatter(
+ gt_trajectories["x"][agent_idx, 0, 0],
+ gt_trajectories["y"][agent_idx, 0, 0],
+ color="darkgreen",
+ marker="*",
+ s=200,
+ label="Log start",
+ zorder=5,
+ alpha=0.5,
+ )
+ axs[1].scatter(
+ simulated_trajectories["x"][agent_idx, :, 0],
+ simulated_trajectories["y"][agent_idx, :, 0],
+ color="darkblue",
+ marker="*",
+ s=200,
+ label="Agent start",
+ zorder=5,
+ alpha=0.5,
+ )
+
+ circle = plt.Circle(
+ (goal_x, goal_y),
+ goal_radius,
+ color="g",
+ fill=False,
+ linewidth=2,
+ linestyle="--",
+ label=f"Goal radius ({goal_radius}m)",
+ zorder=0,
+ )
+ axs[1].add_patch(circle)
+
+ axs[1].set_xlabel("x")
+ axs[1].set_ylabel("y")
+ axs[1].legend()
+ axs[1].set_aspect("equal", adjustable="datalim")
+
+ axs[2].set_title(f"Heading timeseries for agent ID: {simulated_trajectories['id'][agent_idx, 0][0]}")
+ time_steps = list(range(self.sim_steps))
+ for r in range(self.num_rollouts):
+ axs[2].plot(
+ time_steps,
+ simulated_trajectories["heading"][agent_idx, r, :],
+ color="b",
+ alpha=0.1,
+ label="Simulated" if r == 0 else "",
+ )
+ axs[2].plot(time_steps, gt_trajectories["heading"][agent_idx, 0, :], color="g", label="Ground truth")
+
+ if invalid_mask.any():
+ invalid_timesteps = np.where(invalid_mask)[0]
+ axs[2].scatter(
+ invalid_timesteps,
+ gt_trajectories["heading"][agent_idx, 0, invalid_mask],
+ color="r",
+ marker="^",
+ s=100,
+ label="Invalid",
+ zorder=6,
+ edgecolors="darkred",
+ linewidths=1,
+ )
+
+ axs[2].set_xlabel("Time step")
+ axs[2].legend()
+
+ plt.tight_layout()
+
+ plt.savefig(f"trajectory_comparison_agent_{agent_idx}.png")
+
+
+class HumanReplayEvaluator:
+ """Evaluates policies against human replays in PufferDrive."""
+
+ def __init__(self, config: Dict):
+ self.config = config
+ self.sim_steps = 91 - self.config["env"]["init_steps"]
+
+ def rollout(self, args, puffer_env, policy):
+ """Roll out policy in env with human replays. Store statistics.
+
+ In human replay mode, only the SDC (self-driving car) is controlled by the policy
+ while all other agents replay their human trajectories. This tests how compatible
+ the policy is with (static) human partners.
+
+ Args:
+ args: Config dict with train settings (device, use_rnn, etc.)
+ puffer_env: PufferLib environment wrapper
+ policy: Trained policy to evaluate
+
+ Returns:
+ dict: Aggregated metrics including:
+ - avg_collisions_per_agent: Average collisions per agent
+ - avg_offroad_per_agent: Average offroad events per agent
+ """
+ import numpy as np
+ import torch
+ import pufferlib
+
+ num_agents = puffer_env.observation_space.shape[0]
+ device = args["train"]["device"]
+
+ obs, info = puffer_env.reset()
+ state = {}
+ if args["train"]["use_rnn"]:
+ state = dict(
+ lstm_h=torch.zeros(num_agents, policy.hidden_size, device=device),
+ lstm_c=torch.zeros(num_agents, policy.hidden_size, device=device),
+ )
+
+ for time_idx in range(self.sim_steps):
+ # Step policy
+ with torch.no_grad():
+ ob_tensor = torch.as_tensor(obs).to(device)
+ logits, value = policy.forward_eval(ob_tensor, state)
+ action, logprob, _ = pufferlib.pytorch.sample_logits(logits)
+ action_np = action.cpu().numpy().reshape(puffer_env.action_space.shape)
+
+ if isinstance(logits, torch.distributions.Normal):
+ action_np = np.clip(action_np, puffer_env.action_space.low, puffer_env.action_space.high)
+
+ obs, rewards, dones, truncs, info_list = puffer_env.step(action_np)
+
+ if len(info_list) > 0: # Happens at the end of episode
+ results = info_list[0]
+ return results
diff --git a/pufferlib/ocean/benchmark/metrics.py b/pufferlib/ocean/benchmark/metrics.py
new file mode 100644
index 000000000..bc1f049e0
--- /dev/null
+++ b/pufferlib/ocean/benchmark/metrics.py
@@ -0,0 +1,214 @@
+"""Metrics computation for WOSAC realism evaluation. Adapted from
+https://github.com/waymo-research/waymo-open-dataset/blob/master/src/waymo_open_dataset/wdl_limited/sim_agents_metrics/metrics.py
+"""
+
+import numpy as np
+from typing import Dict, Tuple
+
+
+def compute_displacement_error(
+ pred_x: np.ndarray,
+ pred_y: np.ndarray,
+ ref_x: np.ndarray,
+ ref_y: np.ndarray,
+ ref_valid: np.ndarray,
+) -> np.ndarray:
+ """Compute average displacement error (ADE) between simulated and ground truth trajectories.
+
+ Args:
+ pred_x, pred_y: Simulated positions, shape (n_agents, n_rollouts, n_steps)
+ ref_x, ref_y: Ground truth positions, shape (n_agents, 1, n_steps)
+ ref_valid: Valid timesteps, shape (n_agents, 1, n_steps)
+
+ Returns:
+ Average displacement error per agent per rollout, shape (n_agents, n_rollouts)
+ """
+
+ ref_traj = np.stack([ref_x, ref_y], axis=-1) # (n_agents, 1, n_steps, 2)
+ pred_traj = np.stack([pred_x, pred_y], axis=-1)
+
+ # Compute displacement error for each timestep and every agent and rollout
+ displacement = np.linalg.norm(pred_traj - ref_traj, axis=-1) # (n_agents, n_rollouts, n_steps)
+
+ # Mask invalid timesteps
+ displacement = np.where(ref_valid, displacement, 0.0)
+
+ # Aggregate
+ valid_count = np.sum(ref_valid, axis=2) # (n_agents, 1)
+
+ # Compute ADE
+ ade_per_rollout = np.sum(displacement, axis=2) / np.maximum(valid_count, 1) # (n_agents, n_rollouts)
+
+ ade = ade_per_rollout.mean(axis=-1) # (n_agents,)
+
+ # The rollout with the minimum ADE for each agent
+ min_ade = np.min(ade_per_rollout, axis=1) # (n_agents,)
+
+ return ade, min_ade
+
+
+def central_diff(t: np.ndarray, pad_value: float) -> np.ndarray:
+ """Computes the central difference along the last axis.
+
+ This function is used to compute 1st order derivatives (speeds) when called
+ once. Calling this function twice is used to compute 2nd order derivatives
+ (accelerations) instead.
+ This function returns the central difference as
+ df(x)/dx = [f(x+h)-f(x-h)] / 2h.
+
+ Args:
+ t: A float array of shape [..., steps].
+ pad_value: To maintain the original tensor shape, this value is prepended
+ once and appended once to the difference.
+
+ Returns:
+ An array of shape [..., steps] containing the central differences,
+ appropriately prepended and appended with `pad_value` to maintain the
+ original shape.
+ """
+ # Prepare the array containing the value(s) to pad the result with.
+ pad_shape = (*t.shape[:-1], 1)
+ pad_array = np.full(pad_shape, pad_value)
+ diff_t = (t[..., 2:] - t[..., :-2]) / 2
+ return np.concatenate([pad_array, diff_t, pad_array], axis=-1)
+
+
+def central_logical_and(t: np.ndarray, pad_value: bool) -> np.ndarray:
+ """Computes the central `logical_and` along the last axis.
+
+ This function is used to compute the validity tensor for 1st and 2nd order
+ derivatives using central difference, where element [i] is valid only if
+ both elements [i-1] and [i+1] are valid.
+
+ Args:
+ t: A bool array of shape [..., steps].
+ pad_value: To maintain the original tensor shape, this value is prepended
+ once and appended once to the difference.
+
+ Returns:
+ An array of shape [..., steps] containing the central `logical_and`,
+ appropriately prepended and appended with `pad_value` to maintain the
+ original shape.
+ """
+ # Prepare the array containing the value(s) to pad the result with.
+ pad_shape = (*t.shape[:-1], 1)
+ pad_array = np.full(pad_shape, pad_value)
+ diff_t = np.logical_and(t[..., 2:], t[..., :-2])
+ return np.concatenate([pad_array, diff_t, pad_array], axis=-1)
+
+
+def compute_displacement_error_3d(
+ x: np.ndarray, y: np.ndarray, z: np.ndarray, ref_x: np.ndarray, ref_y: np.ndarray, ref_z: np.ndarray
+) -> np.ndarray:
+ """Computes displacement error (in x,y,z) w.r.t. a reference trajectory.
+
+ Note: This operation doesn't put any constraint on the shape of the arrays,
+ except that they are all consistent with each other, so this can be used
+ with any arbitrary array shape.
+
+ Args:
+ x: The x-component of the predicted trajectories.
+ y: The y-component of the predicted trajectories
+ ref_x: The x-component of the reference trajectories.
+ ref_y: The y-component of the reference trajectories.
+
+ Returns:
+ A float array with the same shape as all the arguments, containing
+ the 3D distance between the predicted trajectories and the reference
+ trajectories.
+ """
+ return np.linalg.norm(np.stack([x, y], axis=-1) - np.stack([ref_x, ref_y], axis=-1), ord=2, axis=-1)
+
+
+def compute_kinematic_features(
+ x: np.ndarray,
+ y: np.ndarray,
+ heading: np.ndarray,
+ seconds_per_step: float = 0.1,
+) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
+ """Computes kinematic features (speeds and accelerations).
+
+ Note: Everything is assumed to be valid, filtering must be done afterwards.
+ To maintain the original tensor length, speeds are prepended and appended
+ with 1 np.nan, while accelerations with 2 np.nan (since central difference
+ invalidated the two extremes).
+
+ Args:
+ x: A float array of shape (..., num_steps) containing x coordinates.
+ y: A float array of shape (..., num_steps) containing y coordinates.
+ heading: A float array of shape (..., num_steps,) containing heading.
+ seconds_per_step: The duration (in seconds) of one step. Defaults to 0.1s.
+
+ Returns:
+ A tuple containing the following 4 arrays:
+ linear_speed: Magnitude of speed in (x, y, z). Shape (..., num_steps).
+ linear_acceleration: Linear signed acceleration (changes in linear speed).
+ Shape (..., num_steps).
+ angular_speed: Angular speed (changes in heading). Shape (..., num_steps).
+ angular_acceleration: Angular acceleration (changes in `angular_speed`).
+ Shape (..., num_steps).
+ """
+ # Linear speed and acceleration.
+ dpos = central_diff(np.stack([x, y], axis=0), pad_value=np.nan)
+ linear_speed = np.linalg.norm(dpos, ord=2, axis=0) / seconds_per_step
+ linear_accel = central_diff(linear_speed, pad_value=np.nan) / seconds_per_step
+ # Angular speed and acceleration.
+ dh_step = _wrap_angle(central_diff(heading, pad_value=np.nan) * 2) / 2
+ dh = dh_step / seconds_per_step
+ d2h_step = _wrap_angle(central_diff(dh_step, pad_value=np.nan) * 2) / 2
+ d2h = d2h_step / (seconds_per_step**2)
+ return linear_speed, linear_accel, dh, d2h
+
+
+def _wrap_angle(angle: np.ndarray) -> np.ndarray:
+ """Wraps angles in the range [-pi, pi]."""
+ return (angle + np.pi) % (2 * np.pi) - np.pi
+
+
+def compute_kinematic_validity(valid: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
+ """Return validity tensors for speeds and accelerations.
+
+ Computes validity using central logical_and: element [i] is valid only if
+ both elements [i-1] and [i+1] are valid. Applied once for speeds and twice
+ for accelerations.
+
+ Args:
+ valid: A boolean array of shape (..., num_steps) containing whether a
+ certain object is valid at that step.
+
+ Returns:
+ speed_validity: A validity array for speed fields (central_and applied once).
+ acceleration_validity: A validity array for acceleration fields (central_and applied twice).
+ """
+ # First application for speeds
+ pad_shape = (*valid.shape[:-1], 1)
+ pad_tensor = np.full(pad_shape, False)
+ speed_validity = np.concatenate([pad_tensor, np.logical_and(valid[..., 2:], valid[..., :-2]), pad_tensor], axis=-1)
+
+ # Second application for accelerations
+ pad_tensor = np.full(pad_shape, False)
+ acceleration_validity = np.concatenate(
+ [pad_tensor, np.logical_and(speed_validity[..., 2:], speed_validity[..., :-2]), pad_tensor], axis=-1
+ )
+
+ return speed_validity, acceleration_validity
+
+
+def _reduce_average_with_validity(tensor: np.ndarray, validity: np.ndarray, axis: int = None) -> np.ndarray:
+ """Returns the tensor's average, only selecting valid items.
+
+ Args:
+ tensor: A float array of any shape.
+ validity: A boolean array of the same shape as `tensor`.
+ axis: The axis or axes along which to average. If None, averages over all axes.
+
+ Returns:
+ A float or array containing the average of the valid elements of `tensor`.
+ """
+ if tensor.shape != validity.shape:
+ raise ValueError(
+ f"Shapes of `tensor` and `validity` must be the same. (Actual: {tensor.shape}, {validity.shape})."
+ )
+ cond_sum = np.sum(np.where(validity, tensor, np.zeros_like(tensor)), axis=axis, keepdims=False)
+ valid_sum = np.sum(validity.astype(np.float32), axis=axis, keepdims=False)
+ return cond_sum / valid_sum
diff --git a/pufferlib/ocean/benchmark/metrics_sanity_check.py b/pufferlib/ocean/benchmark/metrics_sanity_check.py
new file mode 100644
index 000000000..bb0acfbeb
--- /dev/null
+++ b/pufferlib/ocean/benchmark/metrics_sanity_check.py
@@ -0,0 +1,98 @@
+"""
+Validation script for WOSAC log-likelihood metrics.
+
+Idea is to check how the log-likelihood metrics change as we replace
+increasing numbers of random rollouts with ground-truth data.
+"""
+
+import argparse
+import numpy as np
+
+from pufferlib.pufferl import load_config, load_env, load_policy
+from pufferlib.ocean.benchmark.evaluator import WOSACEvaluator
+
+
+def replace_rollouts_with_gt(simulated_traj, gt_traj, num_replacements):
+ """Replace first N rollouts with ground truth."""
+ modified = {}
+ for key in simulated_traj:
+ if key in ["x", "y", "z", "heading"]:
+ modified[key] = simulated_traj[key].copy()
+ modified[key][:, :num_replacements, :] = np.broadcast_to(
+ gt_traj[key], (gt_traj[key].shape[0], num_replacements, gt_traj[key].shape[2])
+ )
+ else:
+ modified[key] = simulated_traj[key].copy()
+ return modified
+
+
+def run_validation_experiment(config, vecenv, policy):
+ evaluator = WOSACEvaluator(config)
+
+ gt_trajectories = evaluator.collect_ground_truth_trajectories(vecenv)
+ simulated_trajectories = evaluator.collect_simulated_trajectories(config, vecenv, policy)
+
+ results = {}
+ for num_gt in [0, 1, 2, 8, 16, 32]:
+ modified_sim = replace_rollouts_with_gt(simulated_trajectories, gt_trajectories, num_gt)
+ scene_results = evaluator.compute_metrics(gt_trajectories, modified_sim)
+
+ results[num_gt] = {
+ "ade": scene_results["ade"].mean(),
+ "min_ade": scene_results["min_ade"].mean(),
+ "likelihood_linear_speed": scene_results["likelihood_linear_speed"].mean(),
+ "likelihood_linear_acceleration": scene_results["likelihood_linear_acceleration"].mean(),
+ "likelihood_angular_speed": scene_results["likelihood_angular_speed"].mean(),
+ "likelihood_angular_acceleration": scene_results["likelihood_angular_acceleration"].mean(),
+ "realism_metametric": scene_results["realism_metametric"].mean(),
+ }
+
+ return results
+
+
+def format_results_table(results):
+ lines = [
+ "## WOSAC Log-Likelihood Validation Results\n",
+ "| GT Rollouts | ADE | minADE | Linear Speed | Linear Accel | Angular Speed | Angular Accel | Realism Metametric |",
+ "|-------------|--------|--------|--------------|--------------|---------------|---------------|--------------------|\n",
+ ]
+
+ for num_gt in sorted(results.keys()):
+ label = f"{num_gt:2d} (random)" if num_gt == 0 else f"{num_gt:2d} (all GT)" if num_gt == 32 else f"{num_gt:2d}"
+ r = results[num_gt]
+ lines.append(
+ f"| {label:11s} | {r['ade']:6.4f} | {r['min_ade']:6.4f} | {r['likelihood_linear_speed']:12.4f} | "
+ f"{r['likelihood_linear_acceleration']:12.4f} | {r['likelihood_angular_speed']:13.4f} | "
+ f"{r['likelihood_angular_acceleration']:13.4f} | {r['realism_metametric']:18.4f} |"
+ )
+
+ return "\n".join(lines)
+
+
+def main():
+ parser = argparse.ArgumentParser(description="Validate WOSAC log-likelihood metrics")
+ parser.add_argument("--env", default="puffer_drive")
+ parser.add_argument("--config", default="config/ocean/drive.ini")
+ args = parser.parse_args()
+
+ config = load_config(args.env)
+ config["vec"]["backend"] = "PufferEnv"
+ config["vec"]["num_envs"] = 1
+ config["eval"]["enabled"] = True
+ config["eval"]["wosac_num_rollouts"] = 32
+
+ config["env"]["num_agents"] = config["eval"]["wosac_num_agents"]
+ config["env"]["init_mode"] = config["eval"]["wosac_init_mode"]
+ config["env"]["control_mode"] = config["eval"]["wosac_control_mode"]
+ config["env"]["init_steps"] = config["eval"]["wosac_init_steps"]
+ config["env"]["goal_behavior"] = config["eval"]["wosac_goal_behavior"]
+
+ vecenv = load_env(args.env, config)
+ policy = load_policy(config, vecenv, args.env)
+
+ results = run_validation_experiment(config, vecenv, policy)
+ print("\n" + format_results_table(results))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/pufferlib/ocean/benchmark/wosac.ini b/pufferlib/ocean/benchmark/wosac.ini
new file mode 100644
index 000000000..a7632e65d
--- /dev/null
+++ b/pufferlib/ocean/benchmark/wosac.ini
@@ -0,0 +1,70 @@
+# Taken from WOSAC 2025 Sim Agents Challenge configuration
+# Link: https://github.com/waymo-research/waymo-open-dataset/blob/master/src/waymo_open_dataset/wdl_limited/sim_agents_metrics/challenge_2025_sim_agents_config.textproto
+
+[linear_speed]
+histogram.min_val = 0.0
+histogram.max_val = 25.0
+histogram.num_bins = 10
+histogram.additive_smoothing_pseudocount = 0.1
+independent_timesteps = true
+metametric_weight = 0.05
+
+[linear_acceleration]
+histogram.min_val = -12.0
+histogram.max_val = 12.0
+histogram.num_bins = 11
+histogram.additive_smoothing_pseudocount = 0.1
+independent_timesteps = true
+metametric_weight = 0.05
+
+[angular_speed]
+histogram.min_val = -0.628
+histogram.max_val = 0.628
+histogram.num_bins = 11
+histogram.additive_smoothing_pseudocount = 0.1
+independent_timesteps = true
+metametric_weight = 0.05
+
+[angular_acceleration]
+histogram.min_val = -3.14
+histogram.max_val = 3.14
+histogram.num_bins = 11
+histogram.additive_smoothing_pseudocount = 0.1
+independent_timesteps = true
+metametric_weight = 0.05
+
+[distance_to_nearest_object]
+histogram.min_val = -5.0
+histogram.max_val = 40.0
+histogram.num_bins = 10
+histogram.additive_smoothing_pseudocount = 0.1
+independent_timesteps = true
+metametric_weight = 0.1
+
+[collision_indication]
+bernoulli = true
+metametric_weight = 0.25
+
+[distance_to_road_edge]
+histogram.min_val = -20.0
+histogram.max_val = 40
+histogram.num_bins = 10
+histogram.additive_smoothing_pseudocount = 0.1
+independent_timesteps = true
+metametric_weight = 0.05
+
+[offroad_indication]
+bernoulli = true
+metametric_weight = 0.25
+
+[time_to_collision]
+histogram.min_val = 0.0
+histogram.max_val = 5.0
+histogram.num_bins = 10
+histogram.additive_smoothing_pseudocount = 0.1
+independent_timesteps = true
+metametric_weight = 0.1
+
+[traffic_light_violation]
+bernoulli = true
+metametric_weight = 0.05
diff --git a/pufferlib/ocean/blastar/binding.c b/pufferlib/ocean/blastar/binding.c
deleted file mode 100644
index 03e318a12..000000000
--- a/pufferlib/ocean/blastar/binding.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "blastar.h"
-#define Env Blastar
-#include "../env_binding.h"
-
-static int my_init(Env* env, PyObject* args, PyObject* kwargs) {
- env->num_obs = unpack(kwargs, "num_obs");
- init(env, env->num_obs);
- return 0;
-}
-
-static int my_log(PyObject* dict, Log* log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "episode_length", log->episode_length);
- assign_to_dict(dict, "lives", log->lives);
- assign_to_dict(dict, "vertical_closeness_rew", log->vertical_closeness_rew);
- assign_to_dict(dict, "fired_bullet_rew", log->fired_bullet_rew);
- assign_to_dict(dict, "kill_streak", log->kill_streak);
- assign_to_dict(dict, "hit_enemy_with_bullet_rew", log->hit_enemy_with_bullet_rew);
- assign_to_dict(dict, "avg_score_difference", log->avg_score_difference);
- return 0;
-}
diff --git a/pufferlib/ocean/blastar/blastar.c b/pufferlib/ocean/blastar/blastar.c
deleted file mode 100644
index a4400288d..000000000
--- a/pufferlib/ocean/blastar/blastar.c
+++ /dev/null
@@ -1,85 +0,0 @@
-#include "blastar.h"
-#include
-#include
-#include
-#include
-#include "puffernet.h"
-
-const char* WEIGHTS_PATH = "resources/blastar/blastar_weights.bin";
-#define OBSERVATIONS_SIZE 10
-#define ACTIONS_SIZE 6
-#define NUM_WEIGHTS 134407
-
-void get_input(Blastar* env) {
- if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) {
- env->actions[0] = 1; // Left
- } else if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) {
- env->actions[0] = 2; // Right
- } else if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)) {
- env->actions[0] = 3; // Up
- } else if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)) {
- env->actions[0] = 4; // Down
- } else if (IsKeyDown(KEY_SPACE)) {
- env->actions[0] = 5; // Fire
- } else {
- env->actions[0] = 0; // Noop
- }
-}
-
-int demo() {
- Weights* weights = load_weights(WEIGHTS_PATH, NUM_WEIGHTS);
- int logit_sizes[1] = {ACTIONS_SIZE};
- LinearLSTM* net = make_linearlstm(weights, 1, OBSERVATIONS_SIZE, logit_sizes, 1);
- Blastar env = {
- .num_obs = OBSERVATIONS_SIZE,
- };
- allocate(&env, env.num_obs);
- Client* client = make_client(&env);
- unsigned int seed = 12345;
- srand(seed);
- c_reset(&env);
- int running = 1;
- while (running) {
- if (IsKeyDown(KEY_LEFT_SHIFT)) {
- get_input(&env); // Human input
- } else {
- forward_linearlstm(net, env.observations, env.actions); // AI input
- }
- c_step(&env);
- c_render(&env);
- if (WindowShouldClose() || env.game_over) {
- running = 0;
- }
- }
- free_linearlstm(net);
- free(weights);
- close_client(client);
- free_allocated(&env);
- return 0;
-}
-
-void perftest(float test_time) {
- Blastar env = {
- .num_obs = OBSERVATIONS_SIZE,
- };
- allocate(&env, env.num_obs);
- unsigned int seed = 12345;
- srand(seed);
- c_reset(&env);
- int start = time(NULL);
- int steps = 0;
- while (time(NULL) - start < test_time) {
- env.actions[0] = rand() % ACTIONS_SIZE; // Random actions
- c_step(&env);
- steps++;
- }
- int end = time(NULL);
- printf("Steps per second: %f\n", steps / (float)(end - start));
- free_allocated(&env);
-}
-
-int main() {
- demo();
- // perftest(10.0f);
- return 0;
-}
diff --git a/pufferlib/ocean/blastar/blastar.h b/pufferlib/ocean/blastar/blastar.h
deleted file mode 100644
index 7020c0c1c..000000000
--- a/pufferlib/ocean/blastar/blastar.h
+++ /dev/null
@@ -1,499 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-
-#include "raylib.h"
-
-#define SCREEN_WIDTH 640
-#define SCREEN_HEIGHT 480
-#define PLAYER_MAX_LIVES 10
-#define ENEMY_SPAWN_Y 50
-#define ENEMY_SPAWN_X -30
-#define INIT_BULLET_SPEED 3.0f
-#define MAX_SCORE (5 * PLAYER_MAX_LIVES)
-#define BULLET_SPEED (INIT_BULLET_SPEED * SPEED_SCALE)
-
-static const float SPEED_SCALE = 4.0f;
-static const int ENEMY_WIDTH = 16;
-static const int ENEMY_HEIGHT = 17;
-static const int PLAYER_WIDTH = 17;
-static const int PLAYER_HEIGHT = 17;
-static const int PLAYER_BULLET_WIDTH = 17;
-static const int PLAYER_BULLET_HEIGHT = 6;
-
-typedef struct Log {
- float perf;
- float score;
- float episode_return;
- float episode_length;
- float lives;
- float vertical_closeness_rew;
- float fired_bullet_rew;
- float kill_streak;
- float hit_enemy_with_bullet_rew;
- float avg_score_difference;
- float n;
-} Log;
-
-typedef struct Bullet {
- float x;
- float y;
- bool active;
-} Bullet;
-
-typedef struct Enemy {
- float x;
- float y;
- float enemy_speed;
- bool active;
- bool attacking;
- int crossed_screen;
- Bullet bullet;
-} Enemy;
-
-typedef struct Player {
- float x;
- float y;
- float player_speed;
- int score;
- int lives;
- Bullet bullet;
- bool bullet_fired;
- bool player_stuck;
-} Player;
-
-typedef struct Client {
- Texture2D player_texture;
- Texture2D enemy_texture;
- Texture2D player_bullet_texture;
- Texture2D enemy_bullet_texture;
- Texture2D explosion_texture;
-} Client;
-
-typedef struct Blastar {
- Client* client;
- int reset_count;
- int num_obs;
- bool game_over;
- int tick;
- int player_explosion_timer;
- int enemy_explosion_timer;
- int kill_streak;
- int enemy_respawns;
- Player player;
- Enemy enemy;
- float* observations;
- int* actions;
- float* rewards;
- unsigned char* terminals;
- Log log;
-} Blastar;
-
-void add_log(Blastar* env) {
- env->log.episode_length += env->tick;
- env->log.lives = env->player.lives;
- env->log.score = env->player.score;
- env->log.perf = env->player.score / MAX_SCORE;
- env->log.kill_streak = env->kill_streak;
- env->log.n += 1;
-}
-
-static inline void scale_speeds(Blastar* env) {
- env->player.player_speed *= SPEED_SCALE;
- env->enemy.enemy_speed *= SPEED_SCALE;
-}
-
-void c_reset(Blastar* env) {
- env->game_over = false;
- env->tick = 0;
- env->player_explosion_timer = 0;
- env->enemy_explosion_timer = 0;
- env->player.player_speed = 2.0f;
- env->enemy.enemy_speed = 1.0f;
- scale_speeds(env);
- env->player.x = (float)(rand() % (SCREEN_WIDTH - PLAYER_WIDTH));
- env->player.y = (float)(rand() % (SCREEN_HEIGHT - PLAYER_HEIGHT));
- env->player.score = 0;
- env->player.lives = PLAYER_MAX_LIVES;
- env->player.bullet_fired = false;
- env->player.player_stuck = false;
- env->player.bullet.active = false;
- env->player.bullet.x = env->player.x;
- env->player.bullet.y = env->player.y;
- env->kill_streak = 0;
- env->enemy.x = ENEMY_SPAWN_X;
- env->enemy.y = ENEMY_SPAWN_Y;
- env->enemy.active = true;
- env->enemy.attacking = false;
- if (env->reset_count < 1) {
- env->enemy_respawns = 0;
- env->enemy.crossed_screen = 0;
- }
- env->enemy.bullet.active = false;
- env->enemy.bullet.x = env->enemy.x;
- env->enemy.bullet.y = env->enemy.y;
- env->reset_count++;
-
- env->log = (Log){0};
-}
-
-void c_close(Blastar* env) {
-}
-
-void init(Blastar* env, int num_obs) {
- env->reset_count = 0;
- env->num_obs = num_obs;
- c_reset(env);
-}
-
-void allocate(Blastar* env, int num_obs) {
- init(env, num_obs);
- env->observations = (float*)calloc(env->num_obs, sizeof(float));
- env->actions = (int*)calloc(1, sizeof(int));
- env->rewards = (float*)calloc(1, sizeof(float));
- env->terminals = (unsigned char*)calloc(1, sizeof(unsigned char));
-}
-
-void free_allocated(Blastar* env) {
- free(env->observations);
- free(env->actions);
- free(env->rewards);
- free(env->terminals);
-}
-
-static inline void calculate_center(float x, float y, int width, int height, float* center_x, float* center_y) {
- *center_x = x + width / 2.0f;
- *center_y = y + height / 2.0f;
-}
-
-void compute_observations(Blastar* env) {
- env->log.lives = env->player.lives;
- env->log.score = env->player.score;
-
- memset(env->observations, 0, env->num_obs * sizeof(float));
- env->observations[0] = env->player.x / SCREEN_WIDTH;
- env->observations[1] = env->player.y / SCREEN_HEIGHT;
- env->observations[2] = env->enemy.x / SCREEN_WIDTH;
- env->observations[3] = env->enemy.y / SCREEN_HEIGHT;
- if (env->player.bullet.active) {
- env->observations[4] = env->player.bullet.x / SCREEN_WIDTH;
- env->observations[5] = env->player.bullet.y / SCREEN_HEIGHT;
- env->observations[6] = 1.0f;
- }
- if (env->enemy.bullet.active) {
- env->observations[7] = env->enemy.bullet.x / SCREEN_WIDTH;
- env->observations[8] = env->enemy.bullet.y / SCREEN_HEIGHT;
- env->observations[9] = 1.0f;
- }
-}
-
-bool check_collision(float x1, float y1, float w1, float h1, float x2, float y2, float w2, float h2) {
- if (x1 < x2 + w2 && x1 + w1 > x2 && y1 < y2 + h2 && y1 + h1 > y2) {
- return true;
- }
- return false;
-}
-
-void c_step(Blastar* env) {
- if (env->game_over) {
- if (env->terminals) env->terminals[0] = 1;
- add_log(env);
- c_reset(env);
- return;
- }
-
- env->tick++;
- env->log.episode_length += 1;
- float rew = 0.0f;
- env->rewards[0] = rew;
- float fired_bullet_rew = 0.0f;
- float vertical_closeness_rew = 0.0f;
- float hit_enemy_with_bullet_rew = 0.0f;
- int crossed_screen = 0;
- int action = env->actions[0];
-
- if (env->player_explosion_timer > 0) {
- env->player_explosion_timer--;
- env->kill_streak = 0;
- if (env->player_explosion_timer == 0) {
- env->player.player_stuck = false;
- env->player.bullet.active = false;
- }
- compute_observations(env);
- add_log(env);
- return;
- }
-
- if (env->enemy_explosion_timer > 0) {
- env->enemy_explosion_timer--;
- if (env->enemy_explosion_timer == 0) {
- env->enemy.crossed_screen = 0;
- float respawn_bias = 0.1f;
- if ((float)rand() / (float)RAND_MAX > respawn_bias) {
- env->enemy.x = -ENEMY_WIDTH;
- env->enemy.y = rand() % (SCREEN_HEIGHT - ENEMY_HEIGHT);
- env->enemy_respawns += 1;
- }
- env->enemy.active = true;
- env->enemy.attacking = false;
- }
- compute_observations(env);
- add_log(env);
- return;
- }
-
- if (env->enemy.y > (SCREEN_HEIGHT - (ENEMY_HEIGHT * 3.5f))) {
- env->enemy.y = (SCREEN_HEIGHT - (ENEMY_HEIGHT * 3.5f));
- }
-
- if (!env->player.player_stuck) {
- if (action == 1 && env->player.x > 0) env->player.x -= env->player.player_speed;
- if (action == 2 && env->player.x < SCREEN_WIDTH - PLAYER_WIDTH) env->player.x += env->player.player_speed;
- if (action == 3 && env->player.y > 0) env->player.y -= env->player.player_speed;
- if (action == 4 && env->player.y < SCREEN_HEIGHT - PLAYER_HEIGHT) env->player.y += env->player.player_speed;
- }
-
- if (action == 5 && (!env->enemy.bullet.active)) {
- if (env->player.bullet.active) {
- env->player.bullet.active = false;
- } else {
- fired_bullet_rew += 0.0005f;
- }
- env->player.bullet.active = true;
- env->player.bullet.x = env->player.x + PLAYER_WIDTH / 2 - PLAYER_BULLET_WIDTH / 2;
- env->player.bullet.y = env->player.y;
- }
-
- if (env->player.bullet.active) {
- env->player.bullet.y -= BULLET_SPEED;
- if (env->player.bullet.y < 0) {
- env->player.bullet.active = false;
- }
- }
-
- float player_center_x;
- float enemy_center_x;
- float dummy;
- calculate_center(env->player.x, env->player.y, PLAYER_WIDTH, PLAYER_HEIGHT, &player_center_x, &dummy);
- calculate_center(env->enemy.x, env->enemy.y, ENEMY_WIDTH, ENEMY_HEIGHT, &enemy_center_x, &dummy);
-
- if (!env->enemy.attacking) {
- env->enemy.x += env->enemy.enemy_speed;
- if (env->enemy.x > SCREEN_WIDTH) {
- env->enemy.x = -ENEMY_WIDTH;
- crossed_screen += 1;
- }
- }
-
- if (fabs(player_center_x - enemy_center_x) < SPEED_SCALE &&
- !env->enemy.attacking && env->enemy.active &&
- env->enemy.y < env->player.y - (ENEMY_HEIGHT / 2)) {
- if (rand() % 2 == 0) {
- env->enemy.attacking = true;
- if (!env->enemy.bullet.active) {
- env->enemy.bullet.active = true;
- calculate_center(env->enemy.x, env->enemy.y, ENEMY_WIDTH, ENEMY_HEIGHT, &enemy_center_x, &dummy);
- env->enemy.bullet.x = enemy_center_x - 5.0f;
- env->enemy.bullet.y = env->enemy.y + ENEMY_HEIGHT;
- env->player.bullet.active = false;
- env->player.player_stuck = true;
- }
- } else {
- env->enemy.attacking = false;
- env->enemy.x += env->enemy.enemy_speed;
- }
- }
-
- if (env->enemy.bullet.active) {
- env->enemy.bullet.y += BULLET_SPEED;
- if (env->enemy.bullet.y > SCREEN_HEIGHT) {
- env->enemy.bullet.active = false;
- env->player.player_stuck = false;
- env->enemy.attacking = false;
- }
- }
-
- if (check_collision(env->player.x, env->player.y, PLAYER_WIDTH, PLAYER_HEIGHT,
- env->enemy.x, env->enemy.y, ENEMY_WIDTH, ENEMY_HEIGHT)) {
- env->player.lives--;
- env->enemy.active = false;
- env->enemy_explosion_timer = 30;
- env->enemy.x = -ENEMY_WIDTH;
- env->enemy.y = rand() % (SCREEN_HEIGHT - ENEMY_HEIGHT);
- env->player_explosion_timer = 30;
- env->player.player_stuck = false;
-
- if (env->player.lives <= 0) {
- env->player.lives = 0;
- env->game_over = true;
- if (env->terminals) env->terminals[0] = 1;
- add_log(env);
- compute_observations(env);
- c_reset(env);
- }
- compute_observations(env);
- add_log(env);
- return;
- }
-
- if (env->player.bullet.active && env->player.y > env->enemy.y + ENEMY_HEIGHT &&
- check_collision(env->player.bullet.x, env->player.bullet.y, PLAYER_BULLET_WIDTH, PLAYER_BULLET_HEIGHT,
- env->enemy.x, env->enemy.y, ENEMY_WIDTH, ENEMY_HEIGHT) &&
- env->enemy.active) {
- env->player.bullet.active = false;
- env->enemy.active = false;
- env->kill_streak += 1;
- fired_bullet_rew += 1.5f;
- env->player.score += 1;
- env->log.score += 1.0f;
- env->enemy_explosion_timer = 30;
- float enemy_x_normalized = 1.0f - (env->enemy.x / SCREEN_WIDTH);
- hit_enemy_with_bullet_rew += (crossed_screen == 0) ? (4.5f * enemy_x_normalized)
- : (3.5f * enemy_x_normalized);
- }
-
- if (env->enemy.bullet.active &&
- check_collision(env->enemy.bullet.x, env->enemy.bullet.y, 10, 12,
- env->player.x, env->player.y, PLAYER_WIDTH, PLAYER_HEIGHT)) {
- env->enemy.bullet.active = false;
- env->player.lives--;
- env->player_explosion_timer = 30;
- env->player.player_stuck = false;
- env->enemy.attacking = false;
- env->enemy.x = -ENEMY_WIDTH;
- env->enemy.y = rand() % (SCREEN_HEIGHT - ENEMY_HEIGHT);
-
- if (env->player.lives <= 0) {
- env->player.lives = 0;
- env->game_over = true;
- if (env->terminals) {
- env->terminals[0] = 1;
- }
- compute_observations(env);
- add_log(env);
- c_reset(env);
- }
- }
-
- if (!(env->player.y > env->enemy.y + ENEMY_HEIGHT)) {
- vertical_closeness_rew = 0.0f;
- fired_bullet_rew = 0.0f;
- hit_enemy_with_bullet_rew = 0.0f;
- } else {
- float v_delta_distance = env->player.y - env->enemy.y;
- v_delta_distance = 2.0f - (v_delta_distance / SCREEN_HEIGHT);
- vertical_closeness_rew = 0.01f * v_delta_distance;
- }
-
- float avg_score_difference = 0.0f;
- if (env->player.score > 0) {
- avg_score_difference = (float)env->player.score / (env->tick + 1);
- }
-
- env->log.avg_score_difference = avg_score_difference;
- env->log.fired_bullet_rew = fired_bullet_rew;
- env->log.kill_streak = env->kill_streak;
- env->log.hit_enemy_with_bullet_rew = hit_enemy_with_bullet_rew;
- env->log.vertical_closeness_rew = vertical_closeness_rew;
- env->enemy.crossed_screen = crossed_screen;
-
- rew += fired_bullet_rew + vertical_closeness_rew + hit_enemy_with_bullet_rew + avg_score_difference;
- rew *= (1.0f + env->kill_streak * 0.1f);
-
- if (!(env->player.y > env->enemy.y + ENEMY_HEIGHT && fabs(player_center_x - enemy_center_x) > ENEMY_WIDTH * 0.3f)) {
- rew = fminf(rew, 0.0f);
- }
-
- if (env->player.x > SCREEN_WIDTH / 2.0f) {
- env->log.episode_return = 0;
- rew = 0.0f;
- }
-
- env->rewards[0] = rew;
- env->log.episode_return += rew;
-
- if (env->player.score > MAX_SCORE) {
- env->game_over = true;
- env->terminals[0] = 1;
- compute_observations(env);
- add_log(env);
- c_reset(env);
- }
-
- compute_observations(env);
-}
-
-const Color PUFF_RED = (Color){187, 0, 0, 255};
-const Color PUFF_CYAN = (Color){0, 187, 187, 255};
-const Color PUFF_WHITE = (Color){241, 241, 241, 241};
-const Color PUFF_BACKGROUND = (Color){6, 24, 24, 255};
-
-Client* make_client(Blastar* env) {
- InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Blastar");
- Client* client = (Client*)malloc(sizeof(Client));
- SetTargetFPS(60);
- client->player_texture = LoadTexture("resources/blastar/player_ship.png");
- client->enemy_texture = LoadTexture("resources/blastar/enemy_ship.png");
- client->player_bullet_texture = LoadTexture("resources/blastar/player_bullet.png");
- client->enemy_bullet_texture = LoadTexture("resources/blastar/enemy_bullet.png");
- client->explosion_texture = LoadTexture("resources/blastar/player_death_explosion.png");
- env->client = client;
- return client;
-}
-
-void close_client(Client* client) {
- CloseWindow();
- free(client);
-}
-
-void c_render(Blastar* env) {
- if (env->client == NULL) {
- make_client(env);
- }
-
- if (IsKeyDown(KEY_ESCAPE)) {
- exit(0);
- }
-
- Client* client = env->client;
-
- if (WindowShouldClose()) {
- env->game_over = true;
- close_client(client);
- env->client = NULL;
- exit(0);
- }
-
- BeginDrawing();
- ClearBackground(PUFF_BACKGROUND);
-
- if (env->game_over && env->player.lives <=0) {
- DrawText("GAME OVER", SCREEN_WIDTH / 2 - MeasureText("GAME OVER", 30) / 2, SCREEN_HEIGHT / 2 - 15, 30, PUFF_RED);
- DrawText(TextFormat("FINAL SCORE: %d", env->player.score), SCREEN_WIDTH / 2 - MeasureText(TextFormat("FINAL SCORE: %d", env->player.score), 20)/2, SCREEN_HEIGHT / 2 + 25, 20, PUFF_CYAN);
- } else {
- if (env->player_explosion_timer > 0) {
- DrawTexture(client->explosion_texture, env->player.x, env->player.y, WHITE);
- } else if (env->player.lives > 0) {
- DrawTexture(client->player_texture, env->player.x, env->player.y, WHITE);
- }
- if (env->enemy_explosion_timer > 0) {
- DrawTexture(client->explosion_texture, env->enemy.x, env->enemy.y, WHITE);
- } else if (env->enemy.active) {
- DrawTexture(client->enemy_texture, env->enemy.x, env->enemy.y, WHITE);
- }
- if (env->player.bullet.active) {
- DrawTexture(client->player_bullet_texture, env->player.bullet.x, env->player.bullet.y, WHITE);
- }
- if (env->enemy.bullet.active) {
- DrawTexture(client->enemy_bullet_texture, env->enemy.bullet.x, env->enemy.bullet.y, WHITE);
- }
- if (env->player.player_stuck) {
- DrawText("Status Beam", SCREEN_WIDTH - MeasureText("Status Beam", 20) - 10, SCREEN_HEIGHT / 3, 20, PUFF_RED);
- }
- DrawText(TextFormat("SCORE: %d", env->player.score), 10, 10, 20, PUFF_CYAN);
- DrawText(TextFormat("LIVES: %d", env->player.lives), SCREEN_WIDTH - MeasureText(TextFormat("LIVES: %d", env->player.lives), 20) - 10, 10, 20, PUFF_CYAN);
- }
- EndDrawing();
-}
diff --git a/pufferlib/ocean/blastar/blastar.py b/pufferlib/ocean/blastar/blastar.py
deleted file mode 100644
index e93b3067e..000000000
--- a/pufferlib/ocean/blastar/blastar.py
+++ /dev/null
@@ -1,71 +0,0 @@
-import numpy as np
-import gymnasium
-import pufferlib
-from pufferlib.ocean.blastar import binding
-
-class Blastar(pufferlib.PufferEnv):
- def __init__(self, num_envs=1, render_mode=None, buf=None, seed=0):
- self.single_observation_space = gymnasium.spaces.Box(
- low=0, high=1, shape=(10,), dtype=np.float32
- )
- self.single_action_space = gymnasium.spaces.Discrete(6)
- self.render_mode = render_mode
- self.num_agents = num_envs
- self.num_obs = self.single_observation_space.shape[0]
- self.tick = 0
- self.log_interval = 1
-
- super().__init__(buf)
- self.c_envs = binding.vec_init(
- self.observations,
- self.actions,
- self.rewards,
- self.terminals,
- self.truncations,
- num_envs,
- seed,
- num_obs=self.num_obs
- )
-
- def reset(self, seed=None):
- self.tick = 0
- binding.vec_reset(self.c_envs, seed)
- return self.observations, []
-
- def step(self, actions):
- self.actions[:] = actions
- self.tick += 1
- binding.vec_step(self.c_envs)
-
- info = []
- if self.tick % self.log_interval == 0:
- info.append(binding.vec_log(self.c_envs))
-
- return (self.observations, self.rewards,
- self.terminals, self.truncations, info)
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-def test_performance(timeout=10, atn_cache=1024):
- env = Blastar(num_envs=1000)
- env.reset(0)
- tick = 0
-
- rng = np.random.default_rng()
- actions = rng.integers(0, 6, (atn_cache, env.num_agents))
-
- import time
- start = time.time()
- while time.time() - start < timeout:
- atn = actions[tick % atn_cache]
- env.step(atn)
- tick += 1
-
- print('SPS:', env.num_agents * tick / (time.time() - start))
-
-if __name__ == '__main__':
- test_performance()
diff --git a/pufferlib/ocean/boids/binding.c b/pufferlib/ocean/boids/binding.c
deleted file mode 100644
index a3483d652..000000000
--- a/pufferlib/ocean/boids/binding.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "boids.h"
-
-#define Env Boids
-#include "../env_binding.h"
-
-static int my_init(Env* env, PyObject* args, PyObject* kwargs) {
- env->num_boids = unpack(kwargs, "num_boids");
- env->report_interval = unpack(kwargs, "report_interval");
- env->margin_turn_factor = unpack(kwargs, "margin_turn_factor");
- env->centering_factor = unpack(kwargs, "centering_factor");
- env->avoid_factor = unpack(kwargs, "avoid_factor");
- env->matching_factor = unpack(kwargs, "matching_factor");
- init(env);
- return 0;
-}
-
-static int my_log(PyObject* dict, Log* log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "episode_length", log->episode_length);
- assign_to_dict(dict, "n", log->n);
- return 0;
-}
diff --git a/pufferlib/ocean/boids/boids.c b/pufferlib/ocean/boids/boids.c
deleted file mode 100644
index 735f8e8c9..000000000
--- a/pufferlib/ocean/boids/boids.c
+++ /dev/null
@@ -1,80 +0,0 @@
-// Standalone C demo for Boids environment
-// Compile using: ./scripts/build_ocean.sh boids [local|fast]
-// Run with: ./boids
-
-#include
-#include "boids.h"
-
-// --- Demo Configuration ---
-#define NUM_BOIDS_DEMO 20 // Number of boids for the standalone demo
-#define MAX_STEPS_DEMO 500 // Max steps per episode in the demo
-#define ACTION_SCALE 3.0f // Corresponds to action space [-3.0, 3.0]
-
-// Dummy action generation: random velocity changes for each boid
-void generate_dummy_actions(Boids* env) {
- for (unsigned int i = 0; i < env->num_boids; ++i) {
- // Generate random floats in [-1, 1] range
- float rand_vx = ((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f;
- float rand_vy = ((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f;
-
- // Scale to the action space [-ACTION_SCALE, ACTION_SCALE]
- env->actions[i * 2 + 0] = rand_vx * ACTION_SCALE;
- env->actions[i * 2 + 1] = rand_vy * ACTION_SCALE;
- }
-}
-
-void demo() {
- // Initialize Boids environment struct
- Boids env = {0};
- env.num_boids = NUM_BOIDS_DEMO;
-
- // In the Python binding, these pointers are assigned from NumPy arrays.
- // Here, we need to allocate them explicitly.
- size_t obs_size = env.num_boids * 4; // num_boids * (x, y, vx, vy)
- size_t act_size = env.num_boids * 2; // num_boids * (dvx, dvy)
- env.observations = (float*)calloc(obs_size, sizeof(float));
- env.actions = (float*)calloc(act_size, sizeof(float));
- env.rewards = (float*)calloc(env.num_boids, sizeof(float)); // Env-level reward
-
- if (!env.observations || !env.actions || !env.rewards) {
- fprintf(stderr, "ERROR: Failed to allocate memory for demo buffers.\n");
- free(env.observations); free(env.actions); free(env.rewards);
- return;
- }
-
- init(&env);
- Client* client = make_client(&env);
-
- if (client == NULL) {
- fprintf(stderr, "ERROR: Failed to create rendering client during initial setup.\n");
- c_close(&env);
- free(env.observations); free(env.actions); free(env.rewards);
- return;
- }
- env.client = client;
-
- // Initial reset
- c_reset(&env);
- int total_steps = 0;
-
- printf("Starting Boids demo with %d boids. Press ESC to exit.\n", env.num_boids);
-
- while (!WindowShouldClose() && total_steps < MAX_STEPS_DEMO) { // Raylib function to check if ESC is pressed or window closed
- generate_dummy_actions(&env);
- c_step(&env);
- c_render(&env);
- total_steps++;
- }
-
- c_close(&env);
- free(env.observations);
- free(env.actions);
- free(env.rewards);
- // ----------------------------------------
-}
-
-int main() {
- srand(time(NULL)); // Seed random number generator
- demo();
- return 0;
-}
diff --git a/pufferlib/ocean/boids/boids.h b/pufferlib/ocean/boids/boids.h
deleted file mode 100644
index bf2bf6331..000000000
--- a/pufferlib/ocean/boids/boids.h
+++ /dev/null
@@ -1,296 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "raylib.h"
-
-#define TOP_MARGIN 50
-#define BOTTOM_MARGIN 50
-#define LEFT_MARGIN 50
-#define RIGHT_MARGIN 50
-#define VELOCITY_CAP 5
-#define VISUAL_RANGE 20
-#define PROTECTED_RANGE 100
-#define WIDTH 1080
-#define HEIGHT 720
-#define BOID_WIDTH 32
-#define BOID_HEIGHT 32
-#define BOID_TEXTURE_PATH "./resources/puffers_128.png"
-
-typedef struct {
- float perf;
- float score;
- float episode_return;
- float episode_length;
- float n;
-} Log;
-
-typedef struct {
- float x;
- float y;
-} Velocity;
-
-typedef struct {
- float x;
- float y;
- Velocity velocity;
-} Boid;
-
-typedef struct Client Client;
-typedef struct {
- // an array of shape (num_boids, 4) with the 4 values correspoinding to (x, y, velocity x, velocity y)
- float* observations;
- // an array of shape (num_boids, 2) with the 2 values correspoinding to (velocity x, velocity y)
- float* actions;
- // an array of shape (1) with the summed up reward for all boids
- float* rewards;
- unsigned char* terminals; // Not being used but is required by env_binding.h
- Boid* boids;
- unsigned int num_boids;
- float margin_turn_factor;
- float centering_factor;
- float avoid_factor;
- float matching_factor;
- unsigned tick;
- Log log;
- Log* boid_logs;
- unsigned report_interval;
- Client* client;
-
-} Boids;
-
-static inline float flmax(float a, float b) { return a > b ? a : b; }
-static inline float flmin(float a, float b) { return a > b ? b : a; }
-static inline float flclip(float x,float lo,float hi) { return flmin(hi,flmax(lo,x)); }
-static inline float rndf(float lo,float hi) { return lo + (float)rand()/(float)RAND_MAX*(hi-lo); }
-
-static void respawn_boid(Boids *env, unsigned int i) {
- env->boids[i].x = rndf(LEFT_MARGIN, WIDTH - RIGHT_MARGIN);
- env->boids[i].y = rndf(BOTTOM_MARGIN, HEIGHT - TOP_MARGIN);
- env->boids[i].velocity.x = 0;
- env->boids[i].velocity.y = 0;
- env->boid_logs[i] = (Log){0};
-}
-
-void init(Boids *env) {
- env->boids = (Boid*)calloc(env->num_boids, sizeof(Boid));
- env->boid_logs = (Log*)calloc(env->num_boids, sizeof(Log));
- env->log = (Log){0};
- env->tick = 0;
-
- for (unsigned current_indx = 0; current_indx < env->num_boids; current_indx++) {
- env->boids[current_indx].x = rndf(LEFT_MARGIN, WIDTH - RIGHT_MARGIN);
- env->boids[current_indx].y = rndf(BOTTOM_MARGIN, HEIGHT - TOP_MARGIN);
- env->boids[current_indx].velocity.x = 0;
- env->boids[current_indx].velocity.y = 0;
- }
-}
-
-
-static void compute_observations(Boids *env) {
- unsigned base_indx;
-
- int idx = 0;
- for (unsigned i=0; inum_boids; i++) {
- for (unsigned j=0; jnum_boids; j++) {
- env->observations[idx++] = (env->boids[j].x - env->boids[i].x) / WIDTH;
- env->observations[idx++] = (env->boids[j].y - env->boids[i].y) / HEIGHT;
- env->observations[idx++] = (env->boids[j].velocity.x - env->boids[i].velocity.x) / VELOCITY_CAP;
- env->observations[idx++] = (env->boids[j].velocity.y - env->boids[i].velocity.y) / VELOCITY_CAP;
- }
- }
-}
-
-void c_reset(Boids *env) {
- env->log = (Log){0};
- env->tick = 0;
- for (unsigned boid_indx = 0; boid_indx < env->num_boids; boid_indx++) {
- respawn_boid(env, boid_indx);
- }
- compute_observations(env);
-}
-
-void c_step(Boids *env) {
- Boid* current_boid;
- Boid observed_boid;
- float vis_vx_sum, vis_vy_sum, vis_x_sum, vis_y_sum, vis_x_avg, vis_y_avg, vis_vx_avg, vis_vy_avg;
- float diff_x, diff_y, dist, protected_dist_sum, current_boid_reward;
- unsigned visual_count, protected_count;
- bool manual_control = IsKeyDown(KEY_LEFT_SHIFT);
- float mouse_x = (float)GetMouseX();
- float mouse_y = (float)GetMouseY();
-
- env->tick++;
- env->rewards[0] = 0;
- env->log.score = 0;
- for (unsigned current_indx = 0; current_indx < env->num_boids; current_indx++) {
- // apply action
- current_boid = &env->boids[current_indx];
- if (manual_control) {
- current_boid->velocity.x = flclip(current_boid->velocity.x + (mouse_x - current_boid->x), -VELOCITY_CAP, VELOCITY_CAP);
- current_boid->velocity.y = flclip(current_boid->velocity.y + (mouse_y - current_boid->y), -VELOCITY_CAP, VELOCITY_CAP);
- } else {
- current_boid->velocity.x = flclip(current_boid->velocity.x + 2*env->actions[current_indx * 2 + 0], -VELOCITY_CAP, VELOCITY_CAP);
- current_boid->velocity.y = flclip(current_boid->velocity.y + 2*env->actions[current_indx * 2 + 1], -VELOCITY_CAP, VELOCITY_CAP);
- }
- current_boid->x = flclip(current_boid->x + current_boid->velocity.x, 0, WIDTH - BOID_WIDTH);
- current_boid->y = flclip(current_boid->y + current_boid->velocity.y, 0, HEIGHT - BOID_HEIGHT);
-
- // reward calculation
- current_boid_reward = 0.0f, protected_dist_sum = 0.0f, protected_count = 0.0f;
- visual_count = 0.0f, vis_vx_sum = 0.0f, vis_vy_sum = 0.0f, vis_x_sum = 0.0f, vis_y_sum = 0.0f;
- for (unsigned observed_indx = 0; observed_indx < env->num_boids; observed_indx++) {
- if (current_indx == observed_indx) continue;
- observed_boid = env->boids[observed_indx];
- diff_x = current_boid->x - observed_boid.x;
- diff_y = current_boid->y - observed_boid.y;
- dist = sqrtf(diff_x*diff_x + diff_y*diff_y);
- if (dist < PROTECTED_RANGE) {
- protected_dist_sum += (PROTECTED_RANGE - dist);
- protected_count++;
- } else if (dist < VISUAL_RANGE) {
- vis_x_sum += observed_boid.x;
- vis_y_sum += observed_boid.y;
- vis_vx_sum += observed_boid.velocity.x;
- vis_vy_sum += observed_boid.velocity.y;
- visual_count++;
- }
- }
- if (protected_count > 0) {
- //current_boid_reward -= fabsf(protected_dist_sum / protected_count) * env->avoid_factor;
- current_boid_reward -= flclip(protected_count/5.0, 0.0f, 1.0f) * env->avoid_factor;
- }
- if (visual_count) {
- vis_x_avg = vis_x_sum / visual_count;
- vis_y_avg = vis_y_sum / visual_count;
- vis_vx_avg = vis_vx_sum / visual_count;
- vis_vy_avg = vis_vy_sum / visual_count;
-
- current_boid_reward -= fabsf(vis_vx_avg - current_boid->velocity.x) * env->matching_factor;
- current_boid_reward -= fabsf(vis_vy_avg - current_boid->velocity.y) * env->matching_factor;
- current_boid_reward -= fabsf(vis_x_avg - current_boid->x) * env->centering_factor;
- current_boid_reward -= fabsf(vis_y_avg - current_boid->y) * env->centering_factor;
- }
- if (current_boid->y < TOP_MARGIN || current_boid->y > HEIGHT - BOTTOM_MARGIN) {
- current_boid_reward -= env->margin_turn_factor;
- } else {
- current_boid_reward += env->margin_turn_factor;
- }
- if (current_boid->x < LEFT_MARGIN || current_boid->x > WIDTH - RIGHT_MARGIN) {
- current_boid_reward -= env->margin_turn_factor;
- } else {
- current_boid_reward += env->margin_turn_factor;
- }
- // Normalization
- // env->rewards[current_indx] = current_boid_reward / 15.0f;
- // printf("current_boid_reward: %f\n", current_boid_reward);
- env->rewards[current_indx] = current_boid_reward / 2.0f;
-
- //log updates
- if (env->tick == env->report_interval) {
- env->log.score += env->rewards[current_indx];
- env->log.n += 1.0f;
-
- /* clear per-boid log for next episode */
- // env->boid_logs[boid_indx] = (Log){0};
- env->tick = 0;
- }
- }
- //env->log.score /= env->num_boids;
-
- compute_observations(env);
-}
-
-typedef struct Client Client;
-struct Client {
- float width;
- float height;
- Texture2D boid_texture;
-};
-
-void c_close_client(Client* client) {
- UnloadTexture(client->boid_texture);
- CloseWindow();
- free(client);
-}
-
-void c_close(Boids* env) {
- free(env->boids);
- free(env->boid_logs);
- if (env->client != NULL) {
- c_close_client(env->client);
- }
-}
-
-Client* make_client(Boids* env) {
- Client* client = (Client*)calloc(1, sizeof(Client));
-
- client->width = WIDTH;
- client->height = HEIGHT;
-
- InitWindow(WIDTH, HEIGHT, "PufferLib Boids");
- SetTargetFPS(60);
-
- if (!IsWindowReady()) {
- TraceLog(LOG_ERROR, "Window failed to initialize\n");
- free(client);
- return NULL;
- }
-
- client->boid_texture = LoadTexture(BOID_TEXTURE_PATH);
- if (client->boid_texture.id == 0) {
- TraceLog(LOG_ERROR, "Failed to load texture: %s", BOID_TEXTURE_PATH);
- c_close_client(client);
- return NULL;
- }
-
- return client;
-}
-
-void c_render(Boids* env) {
- if (env->client == NULL) {
- env->client = make_client(env);
- if (env->client == NULL) {
- TraceLog(LOG_ERROR, "Failed to initialize client for rendering\n");
- return;
- }
- }
-
- if (!WindowShouldClose() && IsWindowReady()) {
- if (IsKeyDown(KEY_ESCAPE)) {
- exit(0);
- }
-
- BeginDrawing();
- ClearBackground((Color){6, 24, 24, 255});
-
- for (unsigned boid_indx = 0; boid_indx < env->num_boids; boid_indx++) {
- DrawTexturePro(
- env->client->boid_texture,
- (Rectangle){
- (env->boids[boid_indx].velocity.x > 0) ? 0 : 128,
- 0,
- 128,
- 128,
- },
- (Rectangle){
- env->boids[boid_indx].x,
- env->boids[boid_indx].y,
- BOID_WIDTH,
- BOID_HEIGHT
- },
- (Vector2){0, 0},
- 0,
- WHITE
- );
- }
-
- EndDrawing();
- } else {
- TraceLog(LOG_WARNING, "Window is not ready or should close");
- }
-}
diff --git a/pufferlib/ocean/boids/boids.py b/pufferlib/ocean/boids/boids.py
deleted file mode 100644
index 329b36dea..000000000
--- a/pufferlib/ocean/boids/boids.py
+++ /dev/null
@@ -1,126 +0,0 @@
-'''
-High-perf Boids
-Inspired by https://people.ece.cornell.edu/land/courses/ece4760/labs/s2021/Boids/Boids.html
-'''
-
-import numpy as np
-import gymnasium
-
-import pufferlib
-from pufferlib.ocean.boids import binding
-
-class Boids(pufferlib.PufferEnv):
- def __init__(
- self,
- num_envs=1,
- buf=None,
- render_mode=None,
- seed=0,
- report_interval=1,
- num_boids=1,
- margin_turn_factor=1.0,
- centering_factor=0.0,
- avoid_factor=0.0,
- matching_factor=0.0
- ):
- ACTION_SPACE_SIZE = 2
- self.num_agents = num_envs * num_boids
- self.num_boids = num_boids
-
- self.single_observation_space = gymnasium.spaces.Box(
- -1000.0, 1000.0, shape=(num_boids*4,), dtype=np.float32
- )
-
- #self.single_action_space = gymnasium.spaces.Box(
- # -np.inf, np.inf, shape=(ACTION_SPACE_SIZE,), dtype=np.float32
- #)
- self.single_action_space = gymnasium.spaces.MultiDiscrete([5, 5])
-
- self.render_mode = render_mode
- self.report_interval = report_interval
-
- super().__init__(buf)
- self.actions = self.actions.astype(np.float32)
-
- # Create C binding with flattened action buffer
- # We need to manually create a flattened action buffer to pass to C
- #self.flat_actions = np.zeros((self.num_agents * ACTION_SPACE_SIZE), dtype=np.float32)
-
- c_envs = []
- for env_num in range(num_envs):
- c_envs.append(binding.env_init(
- self.observations[env_num*num_boids:(env_num+1)*num_boids],
- #self.flat_actions[env_num*num_boids*ACTION_SPACE_SIZE:(env_num+1)*num_boids*ACTION_SPACE_SIZE],
- self.actions[env_num*num_boids:(env_num+1)*num_boids],
- self.rewards[env_num*num_boids:(env_num+1)*num_boids],
- self.terminals[env_num*num_boids:(env_num+1)*num_boids],
- self.truncations[env_num*num_boids:(env_num+1)*num_boids],
- seed,
- num_boids=num_boids,
- report_interval=self.report_interval,
- margin_turn_factor=margin_turn_factor,
- centering_factor=centering_factor,
- avoid_factor=avoid_factor,
- matching_factor=matching_factor,
- ))
-
- self.c_envs = binding.vectorize(*c_envs)
-
- def reset(self, seed=0):
- self.tick = 0
- binding.vec_reset(self.c_envs, seed)
- return self.observations, []
-
- def step(self, actions):
- # Clip actions to valid range
- clipped_actions = (actions.astype(np.float32) - 2.0) / 4.0
- #clipped_actions = np.clip(actions, -1.0, 1.0)
-
- # Copy the clipped actions to our flat actions buffer for C binding
- # Flatten from [num_agents, num_boids, 2] to a 1D array for C
- # TODO: Check if I even need this? its not like I'm using the actions anywhere else
- #self.flat_actions[:] = clipped_actions.reshape(-1)
-
- # Save the original actions for the experience buffer
- # TODO: Same thing with this
- self.actions[:] = clipped_actions
-
- self.tick += 1
- binding.vec_step(self.c_envs)
-
- info = []
- if self.tick % self.report_interval == 0:
- log_data = binding.vec_log(self.c_envs)
- if log_data:
- info.append(log_data)
-
- # print(f"OBSERVATIONS: {self.observations}")
- return (self.observations, self.rewards,
- self.terminals, self.truncations, info)
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-def test_performance(timeout=10, atn_cache=1024):
- env = Boids(num_envs=1000)
- env.reset()
- tick = 0
-
- # Generate random actions with proper shape: [cache_size, num_agents, action_dim]
- actions = np.random.uniform(-3.0, 3.0, (atn_cache, env.num_agents, 2))
-
- import time
- start = time.time()
- while time.time() - start < timeout:
- atn = actions[tick % atn_cache]
- env.step(atn)
- tick += 1
-
- print(f'SPS: {env.num_agents * tick / (time.time() - start)}')
-
-
-if __name__ == '__main__':
- test_performance()
diff --git a/pufferlib/ocean/breakout/binding.c b/pufferlib/ocean/breakout/binding.c
deleted file mode 100644
index e5fb3d02c..000000000
--- a/pufferlib/ocean/breakout/binding.c
+++ /dev/null
@@ -1,29 +0,0 @@
-#include "breakout.h"
-
-#define Env Breakout
-#include "../env_binding.h"
-
-static int my_init(Env* env, PyObject* args, PyObject* kwargs) {
- env->frameskip = unpack(kwargs, "frameskip");
- env->width = unpack(kwargs, "width");
- env->height = unpack(kwargs, "height");
- env->paddle_width = unpack(kwargs, "paddle_width");
- env->paddle_height = unpack(kwargs, "paddle_height");
- env->ball_width = unpack(kwargs, "ball_width");
- env->ball_height = unpack(kwargs, "ball_height");
- env->brick_width = unpack(kwargs, "brick_width");
- env->brick_height = unpack(kwargs, "brick_height");
- env->brick_rows = unpack(kwargs, "brick_rows");
- env->brick_cols = unpack(kwargs, "brick_cols");
- env->continuous = unpack(kwargs, "continuous");
- init(env);
- return 0;
-}
-
-static int my_log(PyObject* dict, Log* log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "episode_length", log->episode_length);
- return 0;
-}
diff --git a/pufferlib/ocean/breakout/breakout.c b/pufferlib/ocean/breakout/breakout.c
deleted file mode 100644
index e74f66a45..000000000
--- a/pufferlib/ocean/breakout/breakout.c
+++ /dev/null
@@ -1,94 +0,0 @@
-#include
-#include "breakout.h"
-#include "puffernet.h"
-
-void demo() {
- Weights* weights = load_weights("resources/breakout/breakout_weights.bin", 147844);
- int logit_sizes[1] = {3};
- LinearLSTM* net = make_linearlstm(weights, 1, 118, logit_sizes, 1);
-
- Breakout env = {
- .frameskip = 1,
- .width = 576,
- .height = 330,
- .paddle_width = 62,
- .paddle_height = 8,
- .ball_width = 32,
- .ball_height = 32,
- .brick_width = 32,
- .brick_height = 12,
- .brick_rows = 6,
- .brick_cols = 18,
- .continuous = 0,
- };
- allocate(&env);
-
- env.client = make_client(&env);
-
- c_reset(&env);
- int frame = 0;
- SetTargetFPS(60);
- while (!WindowShouldClose()) {
- // User can take control of the paddle
- if (IsKeyDown(KEY_LEFT_SHIFT)) {
- if(env.continuous) {
- float move = GetMouseWheelMove();
- float clamped_wheel = fmaxf(-1.0f, fminf(1.0f, move));
- env.actions[0] = clamped_wheel;
- } else {
- env.actions[0] = 0.0;
- if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) env.actions[0] = 1;
- if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) env.actions[0] = 2;
- }
- } else if (frame % 4 == 0) {
- // Apply frameskip outside the env for smoother rendering
- int* actions = (int*)env.actions;
- forward_linearlstm(net, env.observations, actions);
- env.actions[0] = actions[0];
- }
-
- frame = (frame + 1) % 4;
- c_step(&env);
- c_render(&env);
- }
- free_linearlstm(net);
- free(weights);
- free_allocated(&env);
- close_client(env.client);
-}
-
-void test_performance(int timeout) {
- Breakout env = {
- .width = 512,
- .height = 512,
- .paddle_width = 20,
- .paddle_height = 70,
- .ball_width = 10,
- .ball_height = 15,
- .brick_width = 10,
- .brick_height = 10,
- .brick_rows = 5,
- .brick_cols = 10,
- .continuous = 0,
- };
- allocate(&env);
- c_reset(&env);
-
- int start = time(NULL);
- int num_steps = 0;
- while (time(NULL) - start < timeout) {
- env.actions[0] = rand() % 3;
- c_step(&env);
- num_steps++;
- }
-
- int end = time(NULL);
- float sps = num_steps / (end - start);
- printf("Test Environment SPS: %f\n", sps);
- free_allocated(&env);
-}
-
-int main() {
- demo();
- //test_performance(10);
-}
diff --git a/pufferlib/ocean/breakout/breakout.h b/pufferlib/ocean/breakout/breakout.h
deleted file mode 100644
index c63f8e2ab..000000000
--- a/pufferlib/ocean/breakout/breakout.h
+++ /dev/null
@@ -1,557 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include "raylib.h"
-
-#define NOOP 0
-#define LEFT 1
-#define RIGHT 2
-#define MAX_BALL_SPEED 448
-#define HALF_PADDLE_WIDTH 31
-#define Y_OFFSET 50
-#define TICK_RATE 1.0f/60.0f
-
-#define BRICK_INDEX_NO_COLLISION -4
-#define BRICK_INDEX_SIDEWALL_COLLISION -3
-#define BRICK_INDEX_BACKWALL_COLLISION -2
-#define BRICK_INDEX_PADDLE_COLLISION -1
-
-typedef struct Log {
- float perf;
- float score;
- float episode_return;
- float episode_length;
- float n;
-} Log;
-
-typedef struct Client {
- float width;
- float height;
- float paddle_width;
- float paddle_height;
- float ball_width;
- float ball_height;
- Texture2D ball;
-} Client;
-
-typedef struct Breakout {
- Client* client;
- Log log;
- float* observations;
- float* actions;
- float* rewards;
- unsigned char* terminals;
- int score;
- float paddle_x;
- float paddle_y;
- float ball_x;
- float ball_y;
- float ball_vx;
- float ball_vy;
- float* brick_x;
- float* brick_y;
- float* brick_states;
- int balls_fired;
- float paddle_width;
- float paddle_height;
- float ball_speed;
- int hits;
- int width;
- int height;
- int num_bricks;
- int brick_rows;
- int brick_cols;
- int ball_width;
- int ball_height;
- int brick_width;
- int brick_height;
- int num_balls;
- int max_score;
- int half_max_score;
- int tick;
- int frameskip;
- unsigned char hit_brick;
- int continuous;
-} Breakout;
-
-typedef struct CollisionInfo CollisionInfo;
-struct CollisionInfo {
- float t;
- float overlap;
- float x;
- float y;
- float vx;
- float vy;
- int brick_index;
-};
-
-void generate_brick_positions(Breakout* env) {
- env->half_max_score=0;
- for (int row = 0; row < env->brick_rows; row++) {
- for (int col = 0; col < env->brick_cols; col++) {
- int idx = row * env->brick_cols + col;
- env->brick_x[idx] = col*env->brick_width;
- env->brick_y[idx] = row*env->brick_height + Y_OFFSET;
- env->half_max_score += 7 - 3 * (idx / env->brick_cols / 2);
- }
- }
- env->max_score=2*env->half_max_score;
-}
-
-void init(Breakout* env) {
- env->tick = 0;
- env->num_bricks = env->brick_rows * env->brick_cols;
- assert(env->num_bricks > 0);
-
- env->brick_x = (float*)calloc(env->num_bricks, sizeof(float));
- env->brick_y = (float*)calloc(env->num_bricks, sizeof(float));
- env->brick_states = (float*)calloc(env->num_bricks, sizeof(float));
- env->num_balls = -1;
- generate_brick_positions(env);
-}
-
-void allocate(Breakout* env) {
- init(env);
- env->observations = (float*)calloc(11 + env->num_bricks, sizeof(float));
- env->actions = (float*)calloc(1, sizeof(float));
- env->rewards = (float*)calloc(1, sizeof(float));
- env->terminals = (unsigned char*)calloc(1, sizeof(unsigned char));
-}
-
-void c_close(Breakout* env) {
- free(env->brick_x);
- free(env->brick_y);
- free(env->brick_states);
-}
-
-void free_allocated(Breakout* env) {
- free(env->actions);
- free(env->observations);
- free(env->terminals);
- free(env->rewards);
- c_close(env);
-}
-
-void add_log(Breakout* env) {
- env->log.episode_length += env->tick;
- env->log.episode_return += env->score;
- env->log.score += env->score;
- env->log.perf += env->score / (float)env->max_score;
- env->log.n += 1;
-}
-
-void compute_observations(Breakout* env) {
- env->observations[0] = env->paddle_x / env->width;
- env->observations[1] = env->paddle_y / env->height;
- env->observations[2] = env->ball_x / env->width;
- env->observations[3] = env->ball_y / env->height;
- env->observations[4] = env->ball_vx / 512.0f;
- env->observations[5] = env->ball_vy / 512.0f;
- env->observations[6] = env->balls_fired / 5.0f;
- env->observations[7] = env->score / 864.0f;
- env->observations[8] = env->num_balls / 5.0f;
- env->observations[9] = env->paddle_width / (2.0f * HALF_PADDLE_WIDTH);
- for (int i = 0; i < env->num_bricks; i++) {
- env->observations[10 + i] = env->brick_states[i];
- }
-}
-
-// Collision of a stationary vertical line segment (xw,yw) to (xw,yw+hw)
-// with a moving line segment (x+vx*t,y+vy*t) to (x+vx*t,y+vy*t+h).
-static inline bool calc_vline_collision(float xw, float yw, float hw, float x,
- float y, float vx, float vy, float h, CollisionInfo* col) {
- float t_new = (xw - x) / vx;
- float topmost = fmin(yw + hw, y + h + vy * t_new);
- float botmost = fmax(yw, y + vy * t_new);
- float overlap_new = topmost - botmost;
-
- // Collision finds the smallest time of collision with the greatest overlap
- // between the ball and the wall.
- if (overlap_new > 0.0f && t_new > 0.0f && t_new <= 1.0f &&
- (t_new < col->t || (t_new == col->t && overlap_new > col->overlap))) {
- col->t = t_new;
- col->overlap = overlap_new;
- col->x = xw;
- col->y = y + vy * t_new;
- col->vx = -vx;
- col->vy = vy;
- return true;
- }
- return false;
-}
-static inline bool calc_hline_collision(float xw, float yw, float ww,
- float x, float y, float vx, float vy, float w, CollisionInfo* col) {
- float t_new = (yw - y) / vy;
- float rightmost = fminf(xw + ww, x + w + vx * t_new);
- float leftmost = fmaxf(xw, x + vx * t_new);
- float overlap_new = rightmost - leftmost;
-
- // Collision finds the smallest time of collision with the greatest overlap between the ball and the wall.
- if (overlap_new > 0.0f && t_new > 0.0f && t_new <= 1.0f &&
- (t_new < col->t || (t_new == col->t && overlap_new > col->overlap))) {
- col->t = t_new;
- col->overlap = overlap_new;
- col->x = x + vx * t_new;
- col->y = yw;
- col->vx = vx;
- col->vy = -vy;
- return true;
- }
- return false;
-}
-static inline void calc_brick_collision(Breakout* env, int idx,
- CollisionInfo* collision_info) {
- bool collision = false;
- // Brick left wall collides with ball right side
- if (env->ball_vx > 0) {
- if (calc_vline_collision(env->brick_x[idx], env->brick_y[idx], env->brick_height,
- env->ball_x + env->ball_width, env->ball_y, env->ball_vx, env->ball_vy, env->ball_height, collision_info)) {
- collision = true;
- collision_info->x -= env->ball_width;
- }
- }
-
- // Brick right wall collides with ball left side
- if (env->ball_vx < 0) {
- if (calc_vline_collision(env->brick_x[idx] + env->brick_width, env->brick_y[idx], env->brick_height,
- env->ball_x, env->ball_y, env->ball_vx, env->ball_vy, env->ball_height, collision_info)) {
- collision = true;
- }
- }
-
- // Brick top wall collides with ball bottom side
- if (env->ball_vy > 0) {
- if (calc_hline_collision(env->brick_x[idx], env->brick_y[idx], env->brick_width,
- env->ball_x, env->ball_y + env->ball_height, env->ball_vx, env->ball_vy, env->ball_width, collision_info)) {
- collision = true;
- collision_info->y -= env->ball_height;
- }
- }
-
- // Brick bottom wall collides with ball top side
- if (env->ball_vy < 0) {
- if (calc_hline_collision(env->brick_x[idx], env->brick_y[idx] + env->brick_height, env->brick_width,
- env->ball_x, env->ball_y, env->ball_vx, env->ball_vy, env->ball_width, collision_info)) {
- collision = true;
- }
- }
- if (collision) {
- collision_info->brick_index = idx;
- }
-}
-static inline int column_index(Breakout* env, float x) {
- return (int)(floorf(x / env->brick_width));
-}
-static inline int row_index(Breakout* env, float y) {
- return (int)(floorf((y - Y_OFFSET) / env->brick_height));
-}
-
-void calc_all_brick_collisions(Breakout* env, CollisionInfo* collision_info) {
- int column_from = column_index(env, fminf(env->ball_x + env->ball_vx, env->ball_x));
- column_from = fmaxf(column_from, 0);
- int column_to = column_index(env, fmaxf(env->ball_x + env->ball_width + env->ball_vx, env->ball_x + env->ball_width));
- column_to = fminf(column_to, env->brick_cols - 1);
- int row_from = row_index(env, fminf(env->ball_y + env->ball_vy, env->ball_y));
- row_from = fmaxf(row_from, 0);
- int row_to = row_index(env, fmaxf(env->ball_y + env->ball_height + env->ball_vy, env->ball_y + env->ball_height));
- row_to = fminf(row_to, env->brick_rows - 1);
-
- for (int row = row_from; row <= row_to; row++) {
- for (int column = column_from; column <= column_to; column++) {
- int brick_index = row * env->brick_cols + column;
- if (env->brick_states[brick_index] == 0.0)
- calc_brick_collision(env, brick_index, collision_info);
- }
- }
-}
-
-bool calc_paddle_ball_collisions(Breakout* env, CollisionInfo* collision_info) {
- float base_angle = M_PI / 4.0f;
-
- // Check if ball is above the paddle
- if (env->ball_y + env->ball_height + env->ball_vy < env->paddle_y) {
- return false;
- }
-
- // Check for collision
- // If we've found another collision (eg the ball hits the wall before the paddle)
- // this correctly skips the paddle collision.
- if (!calc_hline_collision(env->paddle_x, env->paddle_y, env->paddle_width,
- env->ball_x, env->ball_y + env->ball_height, env->ball_vx, env->ball_vy, env->ball_width,
- collision_info) || collision_info->t > 1.0f) {
- return false;
- }
-
- collision_info->y -= env->ball_height;
- collision_info->brick_index = BRICK_INDEX_PADDLE_COLLISION;
-
- env->hit_brick = false;
- float relative_intersection = ((env->ball_x +
- env->ball_width / 2) -
- env->paddle_x) /
- env->paddle_width;
- float angle = -base_angle + relative_intersection * 2 * base_angle;
- env->ball_vx = sin(angle) * env->ball_speed * TICK_RATE;
- env->ball_vy = -cos(angle) * env->ball_speed * TICK_RATE;
- env->hits += 1;
- if (env->hits % 4 == 0 && env->ball_speed < MAX_BALL_SPEED) {
- env->ball_speed += 64;
- }
- if (env->score == env->half_max_score) {
- for (int i = 0; i < env->num_bricks; i++) {
- env->brick_states[i] = 0.0;
- }
- }
- return true;
-}
-
-void calc_all_wall_collisions(Breakout* env, CollisionInfo* collision_info) {
- if (env->ball_vx < 0) {
- if (calc_vline_collision(0, 0, env->height,
- env->ball_x, env->ball_y, env->ball_vx, env->ball_vy, env->ball_height,
- collision_info)) {
- collision_info->brick_index = BRICK_INDEX_SIDEWALL_COLLISION;
- }
- }
- if (env->ball_vx > 0) {
- if (calc_vline_collision(env->width, 0, env->height,
- env->ball_x + env->ball_width, env->ball_y, env->ball_vx, env->ball_vy, env->ball_height,
- collision_info)) {
- collision_info->x -= env->ball_width;
- collision_info->brick_index = BRICK_INDEX_SIDEWALL_COLLISION;
- }
- }
- if (env->ball_vy < 0) {
- if (calc_hline_collision(0, 0, env->width,
- env->ball_x, env->ball_y, env->ball_vx, env->ball_vy, env->ball_width,
- collision_info)) {
- collision_info->brick_index = BRICK_INDEX_BACKWALL_COLLISION;
- }
- }
-}
-
-// With rare floating point conditions, the ball could escape the bounds.
-// Let's handle that explicitly.
-void check_wall_bounds(Breakout* env) {
- if (env->ball_x < 0)
- env->ball_x += MAX_BALL_SPEED * 1.1f * TICK_RATE;
- if (env->ball_x > env->width)
- env->ball_x -= MAX_BALL_SPEED * 1.1f * TICK_RATE;
- if (env->ball_y < 0)
- env->ball_y += MAX_BALL_SPEED * 1.1f * TICK_RATE;
-}
-
-void destroy_brick(Breakout* env, int brick_idx) {
- float gained_points = 7 - 3 * ((brick_idx / env->brick_cols) / 2);
-
- env->score += gained_points;
- env->brick_states[brick_idx] = 1.0;
-
- env->rewards[0] += gained_points;
-
- if (brick_idx / env->brick_cols < 3) {
- env->ball_speed = MAX_BALL_SPEED;
- }
-}
-
-bool handle_collisions(Breakout* env) {
- CollisionInfo collision_info = {
- .t = 2.0f,
- .overlap = -1.0f,
- .x = 0.0f,
- .y = 0.0f,
- .vx = 0.0f,
- .vy = 0.0f,
- .brick_index = BRICK_INDEX_NO_COLLISION,
- };
-
- check_wall_bounds(env);
-
- calc_all_brick_collisions(env, &collision_info);
- calc_all_wall_collisions(env, &collision_info);
- calc_paddle_ball_collisions(env, &collision_info);
- if (collision_info.brick_index != BRICK_INDEX_PADDLE_COLLISION
- && collision_info.t <= 1.0f) {
- env->ball_x = collision_info.x;
- env->ball_y = collision_info.y;
- env->ball_vx = collision_info.vx;
- env->ball_vy = collision_info.vy;
- if (collision_info.brick_index >= 0) {
- destroy_brick(env, collision_info.brick_index);
- }
- if (collision_info.brick_index == BRICK_INDEX_BACKWALL_COLLISION) {
- env->paddle_width = HALF_PADDLE_WIDTH;
- }
- }
- return collision_info.brick_index != BRICK_INDEX_NO_COLLISION;
-}
-
-void reset_round(Breakout* env) {
- env->balls_fired = 0;
- env->hit_brick = false;
- env->hits = 0;
- env->ball_speed = 256;
- env->paddle_width = 2 * HALF_PADDLE_WIDTH;
-
- env->paddle_x = env->width / 2.0 - env->paddle_width / 2;
- env->paddle_y = env->height - env->paddle_height - 10;
-
- env->ball_x = env->paddle_x + (env->paddle_width / 2 - env->ball_width / 2);
- env->ball_y = env->height / 2 - 30;
-
- env->ball_vx = 0.0;
- env->ball_vy = 0.0;
-}
-
-void c_reset(Breakout* env) {
- env->score = 0;
- env->num_balls = 5;
- for (int i = 0; i < env->num_bricks; i++) {
- env->brick_states[i] = 0.0;
- }
- reset_round(env);
- env->tick = 0;
- compute_observations(env);
-}
-
-void step_frame(Breakout* env, float action) {
- float act = 0.0;
- if (env->balls_fired == 0) {
- env->balls_fired = 1;
- float direction = M_PI / 3.25f;
-
- env->ball_vy = cos(direction) * env->ball_speed * TICK_RATE;
- env->ball_vx = sin(direction) * env->ball_speed * TICK_RATE;
- if (rand() % 2 == 0) {
- env->ball_vx = -env->ball_vx;
- }
- }
- else if (action == LEFT) {
- act = -1.0;
- } else if (action == RIGHT) {
- act = 1.0;
- }
- if (env->continuous){
- act = action;
- }
- env->paddle_x += act * 620 * TICK_RATE;
- if (env->paddle_x <= 0){
- env->paddle_x = fmaxf(0, env->paddle_x);
- } else {
- env->paddle_x = fminf(env->width - env->paddle_width, env->paddle_x);
- }
-
- //Handle collisions.
- //Regular timestepping is done only if there are no collisions.
- if(!handle_collisions(env)){
- env->ball_x += env->ball_vx;
- env->ball_y += env->ball_vy;
- }
-
- if (env->ball_y >= env->paddle_y + env->paddle_height) {
- env->num_balls -= 1;
- reset_round(env);
- }
- if (env->num_balls < 0 || env->score == env->max_score) {
- env->terminals[0] = 1;
- add_log(env);
- c_reset(env);
- }
-}
-
-void c_step(Breakout* env) {
- env->terminals[0] = 0;
- env->rewards[0] = 0.0;
-
- float action = env->actions[0];
- for (int i = 0; i < env->frameskip; i++) {
- env->tick += 1;
- step_frame(env, action);
- }
-
- compute_observations(env);
-}
-
-Color BRICK_COLORS[6] = {RED, ORANGE, YELLOW, GREEN, SKYBLUE, BLUE};
-
-Client* make_client(Breakout* env) {
- Client* client = (Client*)calloc(1, sizeof(Client));
- client->width = env->width;
- client->height = env->height;
- client->paddle_width = env->paddle_width;
- client->paddle_height = env->paddle_height;
- client->ball_width = env->ball_width;
- client->ball_height = env->ball_height;
-
- InitWindow(env->width, env->height, "PufferLib Breakout");
- SetTargetFPS(60 / env->frameskip);
-
- client->ball = LoadTexture("resources/shared/puffers_128.png");
- return client;
-}
-
-void close_client(Client* client) {
- CloseWindow();
- free(client);
-}
-
-void c_render(Breakout* env) {
- if (env->client == NULL) {
- env->client = make_client(env);
- }
-
- Client* client = env->client;
-
- if (IsKeyDown(KEY_ESCAPE)) {
- exit(0);
- }
- if (IsKeyPressed(KEY_TAB)) {
- ToggleFullscreen();
- }
-
- BeginDrawing();
- ClearBackground((Color){6, 24, 24, 255});
-
- DrawRectangle(env->paddle_x, env->paddle_y,
- env->paddle_width, env->paddle_height, (Color){0, 255, 255, 255});
-
- // Draw ball
- DrawTexturePro(
- client->ball,
- (Rectangle){
- (env->ball_vx > 0) ? 0 : 128,
- 0, 128, 128,
- },
- (Rectangle){
- env->ball_x,
- env->ball_y,
- env->ball_width,
- env->ball_height
- },
- (Vector2){0, 0},
- 0,
- WHITE
- );
-
- for (int row = 0; row < env->brick_rows; row++) {
- for (int col = 0; col < env->brick_cols; col++) {
- int brick_idx = row * env->brick_cols + col;
- if (env->brick_states[brick_idx] == 1) {
- continue;
- }
- int x = env->brick_x[brick_idx];
- int y = env->brick_y[brick_idx];
- Color brick_color = BRICK_COLORS[row];
- DrawRectangle(x, y, env->brick_width, env->brick_height, brick_color);
- }
- }
-
- DrawText(TextFormat("Score: %i", env->score), 10, 10, 20, WHITE);
- DrawText(TextFormat("Balls: %i", env->num_balls), client->width - 80, 10, 20, WHITE);
- EndDrawing();
-
- //PlaySound(client->sound);
-}
diff --git a/pufferlib/ocean/breakout/breakout.py b/pufferlib/ocean/breakout/breakout.py
deleted file mode 100644
index f482701a8..000000000
--- a/pufferlib/ocean/breakout/breakout.py
+++ /dev/null
@@ -1,93 +0,0 @@
-'''High-perf Pong
-
-Inspired from https://gist.github.com/Yttrmin/18ecc3d2d68b407b4be1
-& https://jair.org/index.php/jair/article/view/10819/25823
-& https://www.youtube.com/watch?v=PSQt5KGv7Vk
-'''
-
-import numpy as np
-import gymnasium
-
-import pufferlib
-from pufferlib.ocean.breakout import binding
-
-class Breakout(pufferlib.PufferEnv):
- def __init__(self, num_envs=1, render_mode=None,
- frameskip=4, width=576, height=330,
- paddle_width=62, paddle_height=8,
- ball_width=32, ball_height=32,
- brick_width=32, brick_height=12,
- brick_rows=6, brick_cols=18, continuous=False, log_interval=128,
- buf=None, seed=0):
- self.single_observation_space = gymnasium.spaces.Box(low=0, high=1,
- shape=(10 + brick_rows*brick_cols,), dtype=np.float32)
- self.render_mode = render_mode
- self.num_agents = num_envs
- self.continuous = continuous
- self.log_interval = log_interval
- self.tick = 0
-
- if continuous:
- self.single_action_space = gymnasium.spaces.Box(low=-1, high=1,
- shape=(1,), dtype=np.float32)
- else:
- self.single_action_space = gymnasium.spaces.Discrete(3)
-
- super().__init__(buf)
- if continuous:
- self.actions = self.actions.flatten()
- else:
- self.actions = self.actions.astype(np.float32)
-
- self.c_envs = binding.vec_init(self.observations, self.actions, self.rewards,
- self.terminals, self.truncations, num_envs, seed, frameskip=frameskip, width=width, height=height,
- paddle_width=paddle_width, paddle_height=paddle_height, ball_width=ball_width, ball_height=ball_height,
- brick_width=brick_width, brick_height=brick_height, brick_rows=brick_rows,
- brick_cols=brick_cols, continuous=continuous
- )
-
- def reset(self, seed=0):
- binding.vec_reset(self.c_envs, seed)
- self.tick = 0
- return self.observations, []
-
- def step(self, actions):
- if self.continuous:
- self.actions[:] = np.clip(actions.flatten(), -1.0, 1.0)
- else:
- self.actions[:] = actions
-
- self.tick += 1
- binding.vec_step(self.c_envs)
-
- info = []
- if self.tick % self.log_interval == 0:
- info.append(binding.vec_log(self.c_envs))
-
- return (self.observations, self.rewards,
- self.terminals, self.truncations, info)
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-def test_performance(timeout=10, atn_cache=1024):
- env = Breakout(num_envs=1000)
- env.reset()
- tick = 0
-
- actions = np.random.randint(0, 2, (atn_cache, env.num_agents))
-
- import time
- start = time.time()
- while time.time() - start < timeout:
- atn = actions[tick % atn_cache]
- env.step(atn)
- tick += 1
-
- print(f'SPS: %f', env.num_agents * tick / (time.time() - start))
-
-if __name__ == '__main__':
- test_performance()
diff --git a/pufferlib/ocean/cartpole/binding.c b/pufferlib/ocean/cartpole/binding.c
deleted file mode 100644
index 8bda2cfd1..000000000
--- a/pufferlib/ocean/cartpole/binding.c
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "cartpole.h"
-#define Env Cartpole
-#include "../env_binding.h"
-
-static int my_init(Env* env, PyObject* args, PyObject* kwargs) {
- env->continuous = unpack(kwargs, "continuous");
- init(env);
- return 0;
-}
-
-static int my_log(PyObject* dict, Log* log) {
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "episode_length", log->episode_length);
- assign_to_dict(dict, "x_threshold_termination", log->x_threshold_termination);
- assign_to_dict(dict, "pole_angle_termination", log->pole_angle_termination);
- assign_to_dict(dict, "max_steps_termination", log->max_steps_termination);
- assign_to_dict(dict, "n", log->n);
- return 0;
-}
diff --git a/pufferlib/ocean/cartpole/cartpole.c b/pufferlib/ocean/cartpole/cartpole.c
deleted file mode 100644
index 20e834b37..000000000
--- a/pufferlib/ocean/cartpole/cartpole.c
+++ /dev/null
@@ -1,72 +0,0 @@
-// local compile/eval implemented for discrete actions only
-// eval with python demo.py --mode eval --env puffer_cartpole --eval-mode-path
-
-#include
-#include
-#include
-#include
-#include "cartpole.h"
-#include "puffernet.h"
-
-#define NUM_WEIGHTS 133123
-#define OBSERVATIONS_SIZE 4
-#define ACTIONS_SIZE 2
-#define CONTINUOUS 0
-
-const char* WEIGHTS_PATH = "resources/cartpole/cartpole_weights.bin";
-
-float movement(int discrete_action, int userControlMode) {
- if (userControlMode) {
- return (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) ? 1.0f : -1.0f;
- } else {
- return (discrete_action == 1) ? 1.0f : -1.0f;
- }
-}
-
-void demo() {
- Weights* weights = load_weights(WEIGHTS_PATH, NUM_WEIGHTS);
- LinearLSTM* net;
-
- int logit_sizes[1] = {ACTIONS_SIZE};
- net = make_linearlstm(weights, 1, OBSERVATIONS_SIZE, logit_sizes, 1);
- Cartpole env = {0};
- env.continuous = CONTINUOUS;
- allocate(&env);
- c_reset(&env);
- c_render(&env);
-
- SetTargetFPS(60);
-
- while (!WindowShouldClose()) {
- int userControlMode = IsKeyDown(KEY_LEFT_SHIFT);
-
- if (!userControlMode) {
- int action_value;
- forward_linearlstm(net, env.observations, &action_value);
- env.actions[0] = movement(action_value, 0);
- } else {
- env.actions[0] = movement(env.actions[0], userControlMode);
- }
-
- c_step(&env);
-
- BeginDrawing();
- ClearBackground(RAYWHITE);
- c_render(&env);
- EndDrawing();
-
- if (env.terminals[0]) {
- c_reset(&env);
- }
- }
-
- free_linearlstm(net);
- free(weights);
- free_allocated(&env);
-}
-
-int main() {
- srand(time(NULL));
- demo();
- return 0;
-}
diff --git a/pufferlib/ocean/cartpole/cartpole.h b/pufferlib/ocean/cartpole/cartpole.h
deleted file mode 100644
index d3d00d581..000000000
--- a/pufferlib/ocean/cartpole/cartpole.h
+++ /dev/null
@@ -1,212 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include "raylib.h"
-
-#define GRAVITY 9.8f
-#define MASSCART 1.0f
-#define MASSPOLE 0.1f
-#define TOTAL_MASS (MASSPOLE + MASSCART)
-#define LENGTH 0.5f // half pole length
-#define POLEMASS_LENGTH (MASSPOLE * LENGTH)
-#define FORCE_MAG 10.0f
-#define TAU 0.02f // timestep duration
-
-#define X_THRESHOLD 2.4f
-#define THETA_THRESHOLD_RADIANS (12 * 2 * M_PI / 360)
-#define MAX_STEPS 200
-#define WIDTH 600
-#define HEIGHT 200
-#define SCALE 100
-
-typedef struct Log Log;
-struct Log {
- float perf;
- float episode_length;
- float x_threshold_termination;
- float pole_angle_termination;
- float max_steps_termination;
- float n;
- float score;
-};
-
-typedef struct Client Client;
-struct Client {
-};
-
-typedef struct Cartpole Cartpole;
-struct Cartpole {
- float* observations;
- float* actions;
- float* rewards;
- unsigned char* terminals;
- unsigned char* truncations;
- Log log;
- Client* client;
- float x;
- float x_dot;
- float theta;
- float theta_dot;
- int tick;
- int continuous;
- float episode_return;
-};
-
-void add_log(Cartpole* env) {
- if (env->episode_return > 0) {
- env->log.perf = env->episode_return / MAX_STEPS;
- } else {
- env->log.perf = 0.0f;
- }
- env->log.episode_length += env->tick;
- env->log.score += env->tick;
- env->log.x_threshold_termination += (env->x < -X_THRESHOLD || env->x > X_THRESHOLD);
- env->log.pole_angle_termination += (env->theta < -THETA_THRESHOLD_RADIANS || env->theta > THETA_THRESHOLD_RADIANS);
- env->log.max_steps_termination += (env->tick >= MAX_STEPS);
- env->log.n += 1;
-}
-
-void init(Cartpole* env) {
- env->tick = 0;
- memset(&env->log, 0, sizeof(Log));
-}
-
-void allocate(Cartpole* env) {
- init(env);
- env->observations = (float*)calloc(4, sizeof(float));
- env->actions = (float*)calloc(1, sizeof(float));
- env->rewards = (float*)calloc(1, sizeof(float));
- env->terminals = (unsigned char*)calloc(1, sizeof(unsigned char));
-}
-
-void free_allocated(Cartpole* env) {
- free(env->observations);
- free(env->actions);
- free(env->rewards);
- free(env->terminals);
-}
-
-void c_close(Cartpole* env) {
-}
-
-const Color PUFF_RED = (Color){187, 0, 0, 255};
-const Color PUFF_CYAN = (Color){0, 187, 187, 255};
-const Color PUFF_WHITE = (Color){241, 241, 241, 241};
-const Color PUFF_BACKGROUND = (Color){6, 24, 24, 255};
-
-Client* make_client(Cartpole* env) {
- Client* client = (Client*)calloc(1, sizeof(Client));
- InitWindow(WIDTH, HEIGHT, "puffer Cartpole");
- SetTargetFPS(60);
- return client;
-}
-
-void close_client(Client* client) {
- CloseWindow();
- free(client);
-}
-
-void c_render(Cartpole* env) {
- if (IsKeyDown(KEY_ESCAPE))
- exit(0);
- if (IsKeyPressed(KEY_TAB))
- ToggleFullscreen();
-
- if (env->client == NULL) {
- env->client = make_client(env);
- }
-
- BeginDrawing();
- ClearBackground(PUFF_BACKGROUND);
- DrawLine(0, HEIGHT / 1.5, WIDTH, HEIGHT / 1.5, PUFF_CYAN);
- float cart_x = WIDTH / 2 + env->x * SCALE;
- float cart_y = HEIGHT / 1.6;
- DrawRectangle((int)(cart_x - 20), (int)(cart_y - 10), 40, 20, PUFF_CYAN);
- float pole_length = 2.0f * 0.5f * SCALE;
- float pole_x2 = cart_x + sinf(env->theta) * pole_length;
- float pole_y2 = cart_y - cosf(env->theta) * pole_length;
- DrawLineEx((Vector2){cart_x, cart_y}, (Vector2){pole_x2, pole_y2}, 5, PUFF_RED);
- DrawText(TextFormat("Steps: %i", env->tick), 10, 10, 20, PUFF_WHITE);
- DrawText(TextFormat("Cart Position: %.2f", env->x), 10, 40, 20, PUFF_WHITE);
- DrawText(TextFormat("Pole Angle: %.2f", env->theta * 180.0f / M_PI), 10, 70, 20, PUFF_WHITE);
- EndDrawing();
-}
-
-void compute_observations(Cartpole* env) {
- env->observations[0] = env->x;
- env->observations[1] = env->x_dot;
- env->observations[2] = env->theta;
- env->observations[3] = env->theta_dot;
-}
-
-void c_reset(Cartpole* env) {
- env->episode_return = 0.0f;
- env->x = ((float)rand() / (float)RAND_MAX) * 0.08f - 0.04f;
- env->x_dot = ((float)rand() / (float)RAND_MAX) * 0.08f - 0.04f;
- env->theta = ((float)rand() / (float)RAND_MAX) * 0.08f - 0.04f;
- env->theta_dot = ((float)rand() / (float)RAND_MAX) * 0.08f - 0.04f;
- env->tick = 0;
-
- compute_observations(env);
-}
-
-void c_step(Cartpole* env) {
- // float force = 0.0;
- // if (env->continuous) {
- // force = env->actions[0] * FORCE_MAG;
- // } else {
- // force = (env->actions[0] > 0.5f) ? FORCE_MAG : -FORCE_MAG;
- // }
-
- float a = env->actions[0];
-
- /* ===== runtime sanity check –– delete after debugging ===== */
- if (!isfinite(a) || a < -1.0001f || a > 1.0001f) {
- fprintf(stderr,
- "[BAD ACTION] tick=%d raw=%.6f\n",
- env->tick, a);
- fflush(stderr);
- }
- /* ========================================================== */
-
- if (!isfinite(a)) a = 0.0f;
- a = fminf(fmaxf(a, -1.0f), 1.0f);
- env->actions[0] = a;
-
- float force = env->continuous ? a * FORCE_MAG
- : (a > 0.5f ? FORCE_MAG : -FORCE_MAG);
-
- float costheta = cosf(env->theta);
- float sintheta = sinf(env->theta);
-
- float temp = (force + POLEMASS_LENGTH * env->theta_dot * env->theta_dot * sintheta) / TOTAL_MASS;
- float thetaacc = (GRAVITY * sintheta - costheta * temp) /
- (LENGTH * (4.0f / 3.0f - MASSPOLE * costheta * costheta / TOTAL_MASS));
- float xacc = temp - POLEMASS_LENGTH * thetaacc * costheta / TOTAL_MASS;
-
- env->x += TAU * env->x_dot;
- env->x_dot += TAU * xacc;
- env->theta += TAU * env->theta_dot;
- env->theta_dot += TAU * thetaacc;
-
- env->tick += 1;
-
- bool terminated = env->x < -X_THRESHOLD || env->x > X_THRESHOLD ||
- env->theta < -THETA_THRESHOLD_RADIANS || env->theta > THETA_THRESHOLD_RADIANS;
- bool truncated = env->tick >= MAX_STEPS;
- bool done = terminated || truncated;
-
- env->rewards[0] = done ? 0.0f : 1.0f;
- env->episode_return += env->rewards[0];
- env->terminals[0] = terminated ? 1 : 0;
-
- if (done) {
- add_log(env);
- c_reset(env);
- }
-
- compute_observations(env);
-}
diff --git a/pufferlib/ocean/cartpole/cartpole.py b/pufferlib/ocean/cartpole/cartpole.py
deleted file mode 100644
index 735a669a6..000000000
--- a/pufferlib/ocean/cartpole/cartpole.py
+++ /dev/null
@@ -1,99 +0,0 @@
-import numpy as np
-import gymnasium
-import pufferlib
-from pufferlib.ocean.cartpole import binding
-
-class Cartpole(pufferlib.PufferEnv):
- def __init__(self, num_envs=1, render_mode='human', report_interval=1, continuous=False, buf=None, seed=0):
- self.render_mode = render_mode
- self.num_agents = num_envs
- self.report_interval = report_interval
- self.tick = 0
- self.continuous = continuous
- self.human_action = None
-
- self.num_obs = 4
- self.single_observation_space = gymnasium.spaces.Box(
- low=-np.inf, high=np.inf, shape=(self.num_obs,), dtype=np.float32
- )
- if self.continuous:
- self.single_action_space = gymnasium.spaces.Box(
- low=-1.0, high=1.0, shape=(1,)
- )
-
- else:
- self.single_action_space = gymnasium.spaces.Discrete(2)
-
- super().__init__(buf)
- self.actions = np.zeros(num_envs, dtype=np.float32)
-
- self.c_envs = binding.vec_init(
- self.observations,
- self.actions,
- self.rewards,
- self.terminals,
- self.truncations,
- num_envs,
- seed,
- continuous=int(self.continuous),
- )
-
- def reset(self, seed=None):
- self.tick = 0
- if seed is None:
- binding.vec_reset(self.c_envs, 0)
- else:
- binding.vec_reset(self.c_envs, seed)
- return self.observations, []
-
- def step(self, actions):
- if self.continuous:
- self.actions[:] = np.clip(actions.flatten(), -1.0, 1.0)
- else:
- self.actions[:] = actions
-
- self.tick += 1
- binding.vec_step(self.c_envs)
-
- info = []
- if self.tick % self.report_interval == 0:
- info.append(binding.vec_log(self.c_envs))
-
- return (
- self.observations,
- self.rewards,
- self.terminals,
- self.truncations,
- info
- )
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-def test_performance(timeout=10, atn_cache=8192, continuous=True):
- """Benchmark environment performance."""
- num_envs = 4096
- env = Cartpole(num_envs=num_envs, continuous=continuous)
- env.reset()
- tick = 0
-
- if env.continuous:
- actions = np.random.uniform(-1, 1, (atn_cache, num_envs, 1)).astype(np.float32)
- else:
- actions = np.random.randint(0, env.single_action_space.n, (atn_cache, num_envs)).astype(np.int8)
-
- import time
- start = time.time()
- while time.time() - start < timeout:
- atn = actions[tick % atn_cache]
- env.step(atn)
- tick += 1
- sps = num_envs * tick / (time.time() - start)
- print(f'SPS: {sps:,}')
-
-if __name__ == '__main__':
- test_performance()
-
diff --git a/pufferlib/ocean/checkers/binding.c b/pufferlib/ocean/checkers/binding.c
deleted file mode 100644
index b53f1dc6b..000000000
--- a/pufferlib/ocean/checkers/binding.c
+++ /dev/null
@@ -1,18 +0,0 @@
-#include "checkers.h"
-
-#define Env Checkers
-#include "../env_binding.h"
-
-static int my_init(Env *env, PyObject *args, PyObject *kwargs) {
- env->size = unpack(kwargs, "size");
- return 0;
-}
-
-static int my_log(PyObject *dict, Log *log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "episode_length", log->episode_length);
- assign_to_dict(dict, "winrate", log->winrate);
- return 0;
-}
diff --git a/pufferlib/ocean/checkers/checkers.c b/pufferlib/ocean/checkers/checkers.c
deleted file mode 100644
index c232d56a8..000000000
--- a/pufferlib/ocean/checkers/checkers.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#include "checkers.h"
-
-int main() {
- Checkers env = {.size = 8};
- env.observations =
- (unsigned char *)calloc(env.size * env.size, sizeof(unsigned char));
- env.actions = (int *)calloc(1, sizeof(int));
- env.rewards = (float *)calloc(1, sizeof(float));
- env.terminals = (unsigned char *)calloc(1, sizeof(unsigned char));
-
- c_reset(&env);
- c_render(&env);
- while (!WindowShouldClose()) {
- if (IsKeyDown(KEY_LEFT_SHIFT)) {
- env.actions[0] = 0;
- if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W))
- env.actions[0] = 1;
- if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S))
- env.actions[0] = 2;
- if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A))
- env.actions[0] = 3;
- if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D))
- env.actions[0] = 4;
- } else {
- env.actions[0] = rand() % 5;
- }
- c_step(&env);
- c_render(&env);
- }
- free(env.observations);
- free(env.actions);
- free(env.rewards);
- free(env.terminals);
- c_close(&env);
-}
diff --git a/pufferlib/ocean/checkers/checkers.h b/pufferlib/ocean/checkers/checkers.h
deleted file mode 100644
index 8976ecf2c..000000000
--- a/pufferlib/ocean/checkers/checkers.h
+++ /dev/null
@@ -1,825 +0,0 @@
-#pragma once
-
-#include "raylib.h"
-#include
-#include
-#include
-#include
-#include
-
-#define EMPTY 0
-#define AGENT 1
-#define OPPONENT 3
-#define AGENT_PAWN 1
-#define AGENT_KING 2
-#define OPPONENT_PAWN 3
-#define OPPONENT_KING 4
-
-// Required struct. Only use floats!
-typedef struct {
- float perf;
- float score;
- float episode_return;
- float episode_length;
- float winrate;
- float n;
-} Log;
-
-// Required that you have some struct for your env
-// Recommended that you name it the same as the env file
-typedef struct {
- Log log;
- unsigned char *observations;
- int *actions;
- float *rewards;
- unsigned char *terminals;
- int size;
- int tick;
- int current_player;
- int agent_pieces;
- int opponent_pieces;
- int capture_available_cache;
- int capture_available_valid;
- int game_over_cache;
- int game_over_valid;
-} Checkers;
-
-typedef struct {
- int r;
- int c;
-} Position;
-
-typedef struct {
- Position from;
- Position to;
-} Move;
-
-float clamp(float val, float low, float high) {
- return fmin(fmax(val, low), high);
-}
-
-Move decode_action(Checkers *env, int action) {
- int num_move_types = 8;
- int pos = action / num_move_types;
- int move_type = action % num_move_types;
-
- Move m;
- m.from.r = pos / env->size;
- m.from.c = pos % env->size;
- m.to.r = m.from.r;
- m.to.c = m.from.c;
-
- switch (move_type) {
- case 0:
- m.to.r = m.from.r - 1;
- m.to.c = m.from.c - 1;
- break;
- case 1:
- m.to.r = m.from.r - 1;
- m.to.c = m.from.c + 1;
- break;
- case 2:
- m.to.r = m.from.r + 1;
- m.to.c = m.from.c - 1;
- break;
- case 3:
- m.to.r = m.from.r + 1;
- m.to.c = m.from.c + 1;
- break;
- case 4:
- m.to.r = m.from.r - 2;
- m.to.c = m.from.c - 2;
- break;
- case 5:
- m.to.r = m.from.r - 2;
- m.to.c = m.from.c + 2;
- break;
- case 6:
- m.to.r = m.from.r + 2;
- m.to.c = m.from.c - 2;
- break;
- case 7:
- m.to.r = m.from.r + 2;
- m.to.c = m.from.c + 2;
- break;
- }
-
- return m;
-}
-
-int p2i(Checkers *env, Position p) { return p.r * env->size + p.c; }
-
-int check_in_bounds(Checkers *env, Position p) {
- return 0 <= p.r && p.r < env->size && 0 <= p.c && p.c < env->size;
-}
-
-int get_piece(Checkers *env, Position p) {
- if (!check_in_bounds(env, p)) {
- return EMPTY;
- }
- return env->observations[p2i(env, p)];
-}
-
-int get_piece_type(Checkers *env, Position p) {
- int piece = get_piece(env, p);
- if (piece == AGENT_PAWN || piece == AGENT_KING)
- return AGENT;
- if (piece == OPPONENT_PAWN || piece == OPPONENT_KING)
- return OPPONENT;
- return EMPTY;
-}
-
-int get_move_direction(Checkers *env, Move m) {
- return m.to.r > m.from.r ? 1 : -1;
-}
-
-int valid_move_direction(Checkers *env, Move m) {
- int piece = get_piece(env, m.from);
- if (piece == AGENT_PAWN)
- return get_move_direction(env, m) == 1 ? 1 : 0;
- if (piece == OPPONENT_PAWN)
- return get_move_direction(env, m) == -1 ? 1 : 0;
- return 1;
-}
-
-int is_diagonal_move(Move m) {
- int dr = m.to.r - m.from.r;
- int dc = m.to.c - m.from.c;
- return (dr == dc) || (dr == -dc);
-}
-int move_size(Move m) { return abs(m.from.r - m.to.r); }
-
-int is_valid_move_no_capture(Checkers *env, Move m) {
- if (!check_in_bounds(env, m.from) || !check_in_bounds(env, m.to))
- return 0;
-
- if (get_piece_type(env, m.from) != env->current_player)
- return 0;
-
- if (get_piece(env, m.to) != EMPTY)
- return 0;
-
- if (!valid_move_direction(env, m))
- return 0;
-
- if (!is_diagonal_move(m))
- return 0;
-
- if (move_size(m) != 1 && move_size(m) != 2)
- return 0;
-
- if (move_size(m) == 2) {
- int other_player = env->current_player == AGENT ? OPPONENT : AGENT;
- Position between_pos =
- (Position){(m.from.r + m.to.r) / 2, (m.from.c + m.to.c) / 2};
- if (get_piece_type(env, between_pos) != other_player)
- return 0;
- }
-
- return 1;
-}
-
-int capture_available(Checkers *env) {
- if (env->capture_available_valid) {
- return env->capture_available_cache;
- }
-
- int current_pawn = env->current_player == AGENT ? AGENT_PAWN : OPPONENT_PAWN;
- int current_king = env->current_player == AGENT ? AGENT_KING : OPPONENT_KING;
-
- for (int i = 0; i < env->size * env->size; i++) {
- int piece = env->observations[i];
- if (piece != current_pawn && piece != current_king)
- continue;
-
- int r = i / env->size;
- int c = i % env->size;
-
- int directions[4][2] = {{-2, -2}, {-2, 2}, {2, -2}, {2, 2}};
- for (int d = 0; d < 4; d++) {
- int new_r = r + directions[d][0];
- int new_c = c + directions[d][1];
-
- if (new_r < 0 || new_r >= env->size || new_c < 0 || new_c >= env->size)
- continue;
-
- if (env->observations[new_r * env->size + new_c] != EMPTY)
- continue;
-
- int mid_r = r + directions[d][0] / 2;
- int mid_c = c + directions[d][1] / 2;
- int mid_piece = env->observations[mid_r * env->size + mid_c];
-
- int opponent_pawn =
- env->current_player == AGENT ? OPPONENT_PAWN : AGENT_PAWN;
- int opponent_king =
- env->current_player == AGENT ? OPPONENT_KING : AGENT_KING;
-
- if (mid_piece == opponent_pawn || mid_piece == opponent_king) {
- int move_dir = directions[d][0] > 0 ? 1 : -1;
- int valid_dir = env->current_player == AGENT ? 1 : -1;
- if (move_dir != valid_dir)
- continue;
-
- env->capture_available_cache = 1;
- env->capture_available_valid = 1;
- return 1;
- }
- }
- }
-
- env->capture_available_cache = 0;
- env->capture_available_valid = 1;
- return 0;
-}
-
-int is_valid_move(Checkers *env, Move m) {
- if (capture_available(env) && move_size(m) != 2)
- return 0;
- return is_valid_move_no_capture(env, m);
-}
-
-int num_legal_moves(Checkers *env) {
- int res = 0;
- int current_pawn = env->current_player == AGENT ? AGENT_PAWN : OPPONENT_PAWN;
- int current_king = env->current_player == AGENT ? AGENT_KING : OPPONENT_KING;
- int has_captures = capture_available(env);
-
- for (int i = 0; i < env->size * env->size; i++) {
- int piece = env->observations[i];
- if (piece != current_pawn && piece != current_king)
- continue;
-
- int r = i / env->size;
- int c = i % env->size;
-
- int directions[8][2] = {{-1, -1}, {-1, 1}, {1, -1}, {1, 1},
- {-2, -2}, {-2, 2}, {2, -2}, {2, 2}};
-
- for (int d = 0; d < 8; d++) {
- int new_r = r + directions[d][0];
- int new_c = c + directions[d][1];
-
- if (new_r < 0 || new_r >= env->size || new_c < 0 || new_c >= env->size)
- continue;
-
- if (env->observations[new_r * env->size + new_c] != EMPTY)
- continue;
-
- int move_size = abs(directions[d][0]);
-
- if (has_captures && move_size != 2)
- continue;
-
- if (piece == current_pawn) {
- int move_dir = directions[d][0] > 0 ? 1 : -1;
- int valid_dir = env->current_player == AGENT ? 1 : -1;
- if (move_dir != valid_dir)
- continue;
- }
-
- if (move_size == 2) {
- int mid_r = r + directions[d][0] / 2;
- int mid_c = c + directions[d][1] / 2;
- int mid_piece = env->observations[mid_r * env->size + mid_c];
-
- int opponent_pawn =
- env->current_player == AGENT ? OPPONENT_PAWN : AGENT_PAWN;
- int opponent_king =
- env->current_player == AGENT ? OPPONENT_KING : AGENT_KING;
-
- if (mid_piece != opponent_pawn && mid_piece != opponent_king)
- continue;
- }
-
- res++;
- }
- }
-
- return res;
-}
-
-int num_pieces_by_player(Checkers *env, int player) {
- if (player == AGENT) {
- return env->agent_pieces;
- } else {
- return env->opponent_pieces;
- }
-}
-
-int try_make_king(Checkers *env) {
- int promoted = 0;
-
- for (int i = 0; i < env->size; i++) {
- if (env->observations[i] == OPPONENT_PAWN) {
- env->observations[i] = OPPONENT_KING;
- promoted = 1;
- }
- }
- for (int i = 0; i < env->size; i++) {
- if (env->observations[env->size * (env->size - 1) + i] == AGENT_PAWN) {
- env->observations[env->size * (env->size - 1) + i] = AGENT_KING;
- promoted = 1;
- }
- }
-
- if (promoted) {
- env->capture_available_valid = 0;
- env->game_over_valid = 0;
- }
-
- return promoted;
-}
-
-int is_game_over(Checkers *env) {
- if (env->game_over_valid) {
- return env->game_over_cache;
- }
-
- int current_player_pieces = num_pieces_by_player(env, env->current_player);
- int other_player = env->current_player == AGENT ? OPPONENT : AGENT;
- int other_player_pieces = num_pieces_by_player(env, other_player);
-
- if (current_player_pieces == 0 || other_player_pieces == 0) {
- env->game_over_cache = 1;
- env->game_over_valid = 1;
- return 1;
- }
-
- int has_captures = capture_available(env);
- if (has_captures) {
- env->game_over_cache = 0;
- env->game_over_valid = 1;
- return 0;
- }
-
- int current_pawn = env->current_player == AGENT ? AGENT_PAWN : OPPONENT_PAWN;
- int current_king = env->current_player == AGENT ? AGENT_KING : OPPONENT_KING;
-
- for (int i = 0; i < env->size * env->size; i++) {
- int piece = env->observations[i];
- if (piece != current_pawn && piece != current_king)
- continue;
-
- int r = i / env->size;
- int c = i % env->size;
-
- int directions[4][2] = {{-1, -1}, {-1, 1}, {1, -1}, {1, 1}};
- for (int d = 0; d < 4; d++) {
- int new_r = r + directions[d][0];
- int new_c = c + directions[d][1];
-
- if (new_r < 0 || new_r >= env->size || new_c < 0 || new_c >= env->size)
- continue;
- if (env->observations[new_r * env->size + new_c] != EMPTY)
- continue;
-
- if (piece == current_pawn) {
- int move_dir = directions[d][0] > 0 ? 1 : -1;
- int valid_dir = env->current_player == AGENT ? 1 : -1;
- if (move_dir != valid_dir)
- continue;
- }
-
- env->game_over_cache = 0;
- env->game_over_valid = 1;
- return 0;
- }
- }
-
- env->game_over_cache = 1;
- env->game_over_valid = 1;
- return 1;
-}
-
-int get_winner(Checkers *env) {
- if (env->agent_pieces == 0) {
- return OPPONENT;
- }
-
- if (env->opponent_pieces == 0) {
- return AGENT;
- }
-
- if (is_game_over(env)) {
- return env->current_player == AGENT ? OPPONENT : AGENT;
- }
-
- return EMPTY;
-}
-
-void make_move(Checkers *env, int action) {
- Move m = decode_action(env, action);
- if (!is_valid_move(env, m)) {
- env->rewards[0] = -1.0f; // reward for invalid move
- return;
- }
-
- int moving_piece = get_piece(env, m.from);
- env->observations[p2i(env, m.from)] = EMPTY;
- env->observations[p2i(env, m.to)] = moving_piece;
-
- int capture_occurred = 0;
- float reward = 0.0f;
-
- if (move_size(m) == 2) {
- Position between_pos =
- (Position){(m.from.r + m.to.r) / 2, (m.from.c + m.to.c) / 2};
- int captured_piece = env->observations[p2i(env, between_pos)];
- env->observations[p2i(env, between_pos)] = EMPTY;
- capture_occurred = 1;
-
- if (captured_piece == AGENT_PAWN || captured_piece == AGENT_KING) {
- env->agent_pieces--;
- reward -= 0.05f; // reward for losing pieces
- } else if (captured_piece == OPPONENT_PAWN ||
- captured_piece == OPPONENT_KING) {
- env->opponent_pieces--;
- }
- }
-
- env->capture_available_valid = 0;
- env->game_over_valid = 0;
-
- int promotion_occurred = try_make_king(env);
-
- if (capture_occurred && env->current_player == OPPONENT) {
- reward += 0.1f; // reward for capturing
- } else if (env->current_player == AGENT) {
- reward += 0.01f; // reward for successful moves
- }
-
- if (move_size(m) == 1 || !capture_available(env)) {
- int other_player = env->current_player == AGENT ? OPPONENT : AGENT;
- env->current_player = other_player;
- }
-
- if (promotion_occurred) {
- for (int i = 0; i < env->size; i++) {
- if (env->observations[env->size * (env->size - 1) + i] == AGENT_KING) {
- reward += 0.05f; // reward for promotion
- break;
- }
- }
- }
-
- if (is_game_over(env)) {
- env->terminals[0] = 1;
- int winner = get_winner(env);
- reward = winner == AGENT ? 1.0f : -1.0f;
- }
-
- env->rewards[0] = clamp(reward, -1.0f, 1.0f);
-}
-
-void scripted_first_move(Checkers *env) {
- int current_pawn = env->current_player == AGENT ? AGENT_PAWN : OPPONENT_PAWN;
- int current_king = env->current_player == AGENT ? AGENT_KING : OPPONENT_KING;
- int has_captures = capture_available(env);
-
- for (int i = 0; i < env->size * env->size; i++) {
- int piece = env->observations[i];
- if (piece != current_pawn && piece != current_king)
- continue;
-
- int r = i / env->size;
- int c = i % env->size;
-
- int directions[8][2] = {{-1, -1}, {-1, 1}, {1, -1}, {1, 1},
- {-2, -2}, {-2, 2}, {2, -2}, {2, 2}};
-
- for (int d = 0; d < 8; d++) {
- int new_r = r + directions[d][0];
- int new_c = c + directions[d][1];
-
- if (new_r < 0 || new_r >= env->size || new_c < 0 || new_c >= env->size)
- continue;
- if (env->observations[new_r * env->size + new_c] != EMPTY)
- continue;
-
- int move_size = abs(directions[d][0]);
-
- if (has_captures && move_size != 2)
- continue;
-
- if (piece == current_pawn) {
- int move_dir = directions[d][0] > 0 ? 1 : -1;
- int valid_dir = env->current_player == AGENT ? 1 : -1;
- if (move_dir != valid_dir)
- continue;
- }
-
- if (move_size == 2) {
- int mid_r = r + directions[d][0] / 2;
- int mid_c = c + directions[d][1] / 2;
- int mid_piece = env->observations[mid_r * env->size + mid_c];
-
- int opponent_pawn =
- env->current_player == AGENT ? OPPONENT_PAWN : AGENT_PAWN;
- int opponent_king =
- env->current_player == AGENT ? OPPONENT_KING : AGENT_KING;
-
- if (mid_piece != opponent_pawn && mid_piece != opponent_king)
- continue;
- }
-
- int action = i * 8 + d;
- make_move(env, action);
- return;
- }
- }
-}
-
-// Helper function to evaluate position value
-float evaluate_position(Checkers *env) {
- float score = 0.0f;
-
- for (int i = 0; i < env->size * env->size; i++) {
- int piece = env->observations[i];
- int r = i / env->size;
-
- if (piece == AGENT_PAWN) {
- score += 1.0f + (r * 0.1f); // Pawns are worth more as they advance
- } else if (piece == AGENT_KING) {
- score += 2.0f;
- } else if (piece == OPPONENT_PAWN) {
- score -= 1.0f + ((env->size - 1 - r) * 0.1f);
- } else if (piece == OPPONENT_KING) {
- score -= 2.0f;
- }
- }
-
- return score;
-}
-
-void scripted_random_move(Checkers *env) {
- int current_pawn = env->current_player == AGENT ? AGENT_PAWN : OPPONENT_PAWN;
- int current_king = env->current_player == AGENT ? AGENT_KING : OPPONENT_KING;
- int has_captures = capture_available(env);
-
- srand(time(NULL));
- int i;
- int num_positions = env->size * env->size;
- while (1) {
- i = random() % num_positions;
- int piece = env->observations[i];
- if (piece != current_pawn && piece != current_king)
- continue;
-
- int r = i / env->size;
- int c = i % env->size;
-
- int directions[8][2] = {{-1, -1}, {-1, 1}, {1, -1}, {1, 1},
- {-2, -2}, {-2, 2}, {2, -2}, {2, 2}};
-
- for (int d = 0; d < 8; d++) {
- int new_r = r + directions[d][0];
- int new_c = c + directions[d][1];
-
- if (new_r < 0 || new_r >= env->size || new_c < 0 || new_c >= env->size)
- continue;
- if (env->observations[new_r * env->size + new_c] != EMPTY)
- continue;
-
- int move_size = abs(directions[d][0]);
-
- if (has_captures && move_size != 2)
- continue;
-
- if (piece == current_pawn) {
- int move_dir = directions[d][0] > 0 ? 1 : -1;
- int valid_dir = env->current_player == AGENT ? 1 : -1;
- if (move_dir != valid_dir)
- continue;
- }
-
- if (move_size == 2) {
- int mid_r = r + directions[d][0] / 2;
- int mid_c = c + directions[d][1] / 2;
- int mid_piece = env->observations[mid_r * env->size + mid_c];
-
- int opponent_pawn =
- env->current_player == AGENT ? OPPONENT_PAWN : AGENT_PAWN;
- int opponent_king =
- env->current_player == AGENT ? OPPONENT_KING : AGENT_KING;
-
- if (mid_piece != opponent_pawn && mid_piece != opponent_king)
- continue;
- }
-
- int action = i * 8 + d;
- make_move(env, action);
- return;
- }
- }
-}
-
-void scripted_step(Checkers *env, int difficulty) {
- switch (difficulty) {
- case 0:
- scripted_first_move(env);
- break;
- case 1:
- scripted_random_move(env);
- break;
- default:
- scripted_random_move(env);
- break;
- }
-}
-
-void update_piece_counts(Checkers *env) {
- env->agent_pieces = 0;
- env->opponent_pieces = 0;
-
- for (int i = 0; i < env->size * env->size; i++) {
- int piece = env->observations[i];
- if (piece == AGENT_PAWN || piece == AGENT_KING) {
- env->agent_pieces++;
- } else if (piece == OPPONENT_PAWN || piece == OPPONENT_KING) {
- env->opponent_pieces++;
- }
- }
-
- env->capture_available_valid = 0;
- env->game_over_valid = 0;
-}
-
-void add_log(Checkers *env) {
- env->log.perf += (env->rewards[0] > 0) ? 1 : 0;
- env->log.score += evaluate_position(env);
- env->log.episode_length += env->tick;
- env->log.episode_return += env->rewards[0];
- if (env->terminals[0] == 1)
- env->log.winrate += get_winner(env) == AGENT ? 1.0f : 0.0f;
- env->log.n += 1;
-}
-
-// Required function
-void c_reset(Checkers *env) {
- env->tick = 0;
- env->terminals[0] = 0;
- env->rewards[0] = 0.0f;
-
- int tiles = env->size * env->size;
- for (int i = 0; i < tiles; i++)
- env->observations[i] = EMPTY;
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < env->size; j++) {
- if ((i + j) % 2)
- env->observations[i * env->size + j] = AGENT_PAWN;
- }
- }
- for (int i = env->size - 3; i < env->size; i++) {
- for (int j = 0; j < env->size; j++) {
- if ((i + j) % 2)
- env->observations[i * env->size + j] = OPPONENT_PAWN;
- }
- }
-
- env->current_player = AGENT;
-
- update_piece_counts(env);
-}
-
-// Required function
-void c_step(Checkers *env) {
- env->tick += 1;
- int action = env->actions[0];
- env->rewards[0] = 0.0f;
- env->terminals[0] = 0;
-
- make_move(env, action);
-
- env->rewards[0] = clamp(env->rewards[0], -1.0f, 1.0f);
- if (env->terminals[0] == 1) {
- add_log(env);
- c_reset(env);
- return;
- }
-
- scripted_step(env, 1);
- if (env->terminals[0] == 1) {
- add_log(env);
- c_reset(env);
- return;
- }
-}
-
-// Required function. Should handle creating the client on first call
-void c_render(Checkers *env) {
- const Color BG1 = (Color){27, 27, 27, 255};
- const Color BG2 = (Color){13, 13, 13, 255};
-
- int cell_size = 64;
- int window_width = cell_size * env->size;
- int window_height = cell_size * env->size;
- int radius = cell_size / 3;
- int king_offset = 14;
-
- if (!IsWindowReady()) {
- SetConfigFlags(FLAG_MSAA_4X_HINT);
- InitWindow(window_width, window_height, "Puffer Checkers");
- SetTargetFPS(30);
- } else if (GetScreenWidth() != window_width ||
- GetScreenHeight() != window_height) {
- SetWindowSize(window_width, window_height);
- }
-
- if (IsKeyDown(KEY_ESCAPE)) {
- CloseWindow();
- exit(0);
- return;
- }
-
- BeginDrawing();
- ClearBackground(BG1);
-
- Color piece_color;
- for (int i = 0; i < env->size; i++) {
- for (int j = 0; j < env->size; j++) {
- int piece = env->observations[i * env->size + j];
- if ((i + j) % 2 == 0)
- DrawRectangle(j * cell_size - 1, i * cell_size - 1, cell_size + 1,
- cell_size + 1, BG2);
- if (piece == EMPTY)
- continue;
-
- int center_x = j * cell_size + cell_size / 2;
- int center_y = i * cell_size + cell_size / 2;
-
- switch (piece) {
- case AGENT_PAWN:
- piece_color = BLUE;
- DrawCircle(center_x, center_y, radius, piece_color);
- DrawCircleGradient(center_x - radius / 3, center_y - radius / 3,
- radius / 3, (Color){255, 255, 255, 80},
- (Color){255, 255, 255, 10});
- DrawCircleGradient(center_x, center_y, radius,
- (Color){255, 255, 255, 50},
- (Color){255, 255, 255, 5});
- break;
-
- case AGENT_KING:
- piece_color = BLUE;
- DrawCircle(center_x, center_y, radius, piece_color);
- DrawCircleGradient(center_x, center_y, radius,
- (Color){255, 255, 255, 50},
- (Color){255, 255, 255, 5});
-
- DrawCircleGradient(center_x, center_y - king_offset / 2, radius,
- (Color){20, 20, 20, 60}, (Color){20, 20, 20, 30});
- DrawCircle(center_x, center_y - king_offset, radius, piece_color);
- DrawCircleGradient(
- center_x - radius / 3, center_y - radius / 3 - king_offset,
- radius / 3, (Color){255, 255, 255, 80}, (Color){255, 255, 255, 10});
- DrawCircleGradient(center_x, center_y - king_offset, radius,
- (Color){255, 255, 255, 50},
- (Color){255, 255, 255, 5});
- break;
-
- case OPPONENT_PAWN:
- piece_color = RED;
- DrawCircle(center_x, center_y, radius, piece_color);
- DrawCircleGradient(center_x - radius / 3, center_y - radius / 3,
- radius / 3, (Color){255, 255, 255, 80},
- (Color){255, 255, 255, 10});
- DrawCircleGradient(center_x, center_y, radius,
- (Color){255, 255, 255, 50},
- (Color){255, 255, 255, 5});
- break;
-
- case OPPONENT_KING:
- piece_color = RED;
- DrawCircle(center_x, center_y, radius, piece_color);
- DrawCircleGradient(center_x, center_y, radius,
- (Color){255, 255, 255, 50},
- (Color){255, 255, 255, 5});
-
- DrawCircleGradient(center_x, center_y - king_offset / 2, radius,
- (Color){20, 20, 20, 60}, (Color){20, 20, 20, 30});
- DrawCircle(center_x, center_y - king_offset, radius, piece_color);
- DrawCircleGradient(
- center_x - radius / 3, center_y - radius / 3 - king_offset,
- radius / 3, (Color){255, 255, 255, 80}, (Color){255, 255, 255, 10});
- DrawCircleGradient(center_x, center_y - king_offset, radius,
- (Color){255, 255, 255, 50},
- (Color){255, 255, 255, 5});
- break;
-
- default:
- break;
- }
- }
- }
-
- EndDrawing();
-}
-
-// Required function. Should clean up anything you allocated
-// Do not free env->observations, actions, rewards, terminals
-void c_close(Checkers *env) {
- if (IsWindowReady()) {
- CloseWindow();
- }
-}
diff --git a/pufferlib/ocean/checkers/checkers.py b/pufferlib/ocean/checkers/checkers.py
deleted file mode 100644
index 8c2195cfa..000000000
--- a/pufferlib/ocean/checkers/checkers.py
+++ /dev/null
@@ -1,65 +0,0 @@
-import gymnasium
-import numpy as np
-
-import pufferlib
-from pufferlib.ocean.checkers import binding
-
-class Checkers(pufferlib.PufferEnv):
- def __init__(self, num_envs=1, render_mode=None, log_interval=128, size=8, buf=None, seed=0):
- self.single_observation_space = gymnasium.spaces.Box(low=0, high=1,
- shape=(size*size,), dtype=np.uint8)
- num_move_types = 8 # Move types are: NW, NE, SW, SE, 2*NW, 2*NE, 2*SW, 2*SE,
- action_space_size = size * size * num_move_types
- self.single_action_space = gymnasium.spaces.Discrete(action_space_size)
- self.render_mode = render_mode
- self.num_agents = num_envs
- self.log_interval = log_interval
-
- super().__init__(buf)
- self.c_envs = binding.vec_init(self.observations, self.actions, self.rewards,
- self.terminals, self.truncations, num_envs, seed, size=size)
-
- def reset(self, seed=0):
- binding.vec_reset(self.c_envs, seed)
- self.tick = 0
- return self.observations, []
-
- def step(self, actions):
- self.tick += 1
-
- self.actions[:] = actions
- binding.vec_step(self.c_envs)
-
- info = []
- if self.tick % self.log_interval == 0:
- info.append(binding.vec_log(self.c_envs))
-
- return (self.observations, self.rewards,
- self.terminals, self.truncations, info)
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-if __name__ == '__main__':
- N = 4096
- size = 3
-
- env = Checkers(num_envs=N, size=size)
- env.reset()
- steps = 0
-
- CACHE = 1024
- actions = np.random.randint(0, size * size * 6, (CACHE, N))
-
- i = 0
- import time
- start = time.time()
- while time.time() - start < 10:
- env.step(actions[i % CACHE])
- steps += N
- i += 1
-
- print('Checkers SPS:', int(steps / (time.time() - start)))
diff --git a/pufferlib/ocean/connect4/binding.c b/pufferlib/ocean/connect4/binding.c
deleted file mode 100644
index de8d7877a..000000000
--- a/pufferlib/ocean/connect4/binding.c
+++ /dev/null
@@ -1,17 +0,0 @@
-#include "connect4.h"
-#define Env CConnect4
-#include "../env_binding.h"
-
-static int my_init(Env* env, PyObject* args, PyObject* kwargs) {
- init(env);
- return 0;
-}
-
-static int my_log(PyObject* dict, Log* log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "episode_length", log->episode_length);
- assign_to_dict(dict, "n", log->n);
- return 0;
-}
diff --git a/pufferlib/ocean/connect4/connect4.c b/pufferlib/ocean/connect4/connect4.c
deleted file mode 100644
index cf617b7af..000000000
--- a/pufferlib/ocean/connect4/connect4.c
+++ /dev/null
@@ -1,77 +0,0 @@
-#include "connect4.h"
-#include "puffernet.h"
-#include "time.h"
-
-const unsigned char NOOP = 8;
-
-void interactive() {
- Weights* weights = load_weights("resources/connect4/connect4_weights.bin", 138632);
- int logit_sizes[] = {7};
- LinearLSTM* net = make_linearlstm(weights, 1, 42, logit_sizes, 1);
-
- CConnect4 env = {
- };
- allocate_cconnect4(&env);
- c_reset(&env);
-
- env.client = make_client();
- float observations[42] = {0};
- int actions[1] = {0};
-
- int tick = 0;
- while (!WindowShouldClose()) {
- env.actions[0] = NOOP;
- // user inputs 1 - 7 key pressed
- if (IsKeyDown(KEY_LEFT_SHIFT)) {
- if(IsKeyPressed(KEY_ONE)) env.actions[0] = 0;
- if(IsKeyPressed(KEY_TWO)) env.actions[0] = 1;
- if(IsKeyPressed(KEY_THREE)) env.actions[0] = 2;
- if(IsKeyPressed(KEY_FOUR)) env.actions[0] = 3;
- if(IsKeyPressed(KEY_FIVE)) env.actions[0] = 4;
- if(IsKeyPressed(KEY_SIX)) env.actions[0] = 5;
- if(IsKeyPressed(KEY_SEVEN)) env.actions[0] = 6;
- } else if (tick % 30 == 0) {
- for (int i = 0; i < 42; i++) {
- observations[i] = env.observations[i];
- }
- forward_linearlstm(net, (float*)&observations, (int*)&actions);
- env.actions[0] = actions[0];
- }
-
- tick = (tick + 1) % 60;
- if (env.actions[0] >= 0 && env.actions[0] <= 6) {
- c_step(&env);
- }
-
- c_render(&env);
- }
- free_linearlstm(net);
- free(weights);
- close_client(env.client);
- free_allocated_cconnect4(&env);
-}
-
-void performance_test() {
- long test_time = 10;
- CConnect4 env = {
- };
- allocate_cconnect4(&env);
- c_reset(&env);
-
- long start = time(NULL);
- int i = 0;
- while (time(NULL) - start < test_time) {
- env.actions[0] = rand() % 7;
- c_step(&env);
- i++;
- }
- long end = time(NULL);
- printf("SPS: %ld\n", i / (end - start));
- free_allocated_cconnect4(&env);
-}
-
-int main() {
- // performance_test();
- interactive();
- return 0;
-}
diff --git a/pufferlib/ocean/connect4/connect4.h b/pufferlib/ocean/connect4/connect4.h
deleted file mode 100644
index dde12a4a1..000000000
--- a/pufferlib/ocean/connect4/connect4.h
+++ /dev/null
@@ -1,392 +0,0 @@
-#include
-#include
-#include
-#include
-#include "raylib.h"
-
-#define WIN_CONDITION 4
-const int PLAYER_WIN = 1.0;
-const int ENV_WIN = -1.0;
-const unsigned char DONE = 1;
-const unsigned char NOT_DONE = 0;
-const int ROWS = 6;
-const int COLUMNS = 7;
-const int WIDTH = 672;
-const int HEIGHT = 576;
-const int PIECE_WIDTH = 96;
-const int PIECE_HEIGHT = 96;
-
-const float MAX_VALUE = 31;
-const float WIN_VALUE = 30;
-const float DRAW_VALUE = 0;
-
-typedef struct Log Log;
-struct Log {
- float perf;
- float score;
- float episode_return;
- float episode_length;
- float n;
-};
-
-typedef struct Client Client;
-typedef struct CConnect4 CConnect4;
-struct CConnect4 {
- // Pufferlib inputs / outputs
- float* observations;
- int* actions;
- float* rewards;
- unsigned char* terminals;
- Log log;
- Client* client;
-
- // Bit string representation from:
- // https://towardsdatascience.com/creating-the-perfect-connect-four-ai-bot-c165115557b0
- // & http://blog.gamesolver.org/solving-connect-four/01-introduction/
- uint64_t player_pieces;
- uint64_t env_pieces;
-
- int tick;
-};
-
-void allocate_cconnect4(CConnect4* env) {
- env->observations = (float*)calloc(42, sizeof(float));
- env->actions = (int*)calloc(1, sizeof(int));
- env->terminals = (unsigned char*)calloc(1, sizeof(unsigned char));
- env->rewards = (float*)calloc(1, sizeof(float));
-}
-
-void free_allocated_cconnect4(CConnect4* env) {
- free(env->actions);
- free(env->observations);
- free(env->terminals);
- free(env->rewards);
-}
-
-void c_close(CConnect4* env) {
-}
-
-void add_log(CConnect4* env) {
- env->log.perf += (float)(env->rewards[0] == PLAYER_WIN);
- env->log.score += env->rewards[0];
- env->log.episode_return += env->rewards[0];
- env->log.episode_length += env->log.episode_length;
- env->log.n += 1;
-}
-
-void init(CConnect4* env) {
- env->log = (Log){0};
- env->tick = 0;
-}
-
-// Get the bit at the top of 'column'. Column can be played if bit is 0
-uint64_t top_mask(uint64_t column) {
- return (UINT64_C(1) << (ROWS - 1)) << column * (ROWS + 1);
-}
-
-// Get a bit mask for where a piece played at 'column' would end up.
-uint64_t bottom_mask(uint64_t column) {
- return UINT64_C(1) << column * (ROWS + 1);
-}
-
-// A bit mask used to create unique representation of the game state.
-uint64_t c_bottom() {
- return UINT64_C(1) << (COLUMNS - 1) * (ROWS + 1);
-}
-
-bool invalid_move(int column, uint64_t mask) {
- return (mask & top_mask(column)) != 0;
-}
-
-uint64_t play(int column, uint64_t mask, uint64_t other_pieces) {
- mask |= mask + bottom_mask(column); // Somehow faster than |= bottom_mask(column)
- return other_pieces ^ mask;
-}
-
-// A full board has this specifc value
-bool draw(uint64_t mask) {
- return mask == 4432406249472;
-}
-
-// Determine if 'pieces' contains at least one line of connected pieces.
-bool won(uint64_t pieces) {
- // Horizontal
- uint64_t m = pieces & (pieces >> (ROWS + 1));
- if(m & (m >> (2 * (ROWS + 1)))) {
- return true;
- }
-
- // Diagonal 1
- m = pieces & (pieces >> ROWS);
- if(m & (m >> (2 * ROWS))) {
- return true;
- }
-
- // Diagonal 2
- m = pieces & (pieces >> (ROWS + 2));
- if(m & (m >> (2 * (ROWS + 2)))) {
- return true;
- }
-
- // Vertical;
- m = pieces & (pieces >> 1);
- if(m & (m >> 2)) {
- return true;
- }
-
- return false;
-}
-
-// https://en.wikipedia.org/wiki/Negamax#Negamax_variant_with_no_color_parameter
-float negamax(uint64_t pieces, uint64_t other_pieces, int depth) {
- uint64_t piece_mask = pieces | other_pieces;
- if (won(other_pieces)) {
- return pow(10, depth);
- }
- if (won(pieces)) {
- return 0;
- }
-
- if (depth == 0 || draw(piece_mask)) {
- return 0;
- }
-
- float value = 0;
- for (uint64_t column = 0; column < 7; column ++) {
- if (invalid_move(column, piece_mask)) {
- continue;
- }
- uint64_t child_pieces = play(column, piece_mask, other_pieces);
- value -= negamax(other_pieces, child_pieces, depth - 1);
- }
- return value;
-}
-
-int compute_env_move(CConnect4* env) {
- uint64_t piece_mask = env->player_pieces | env->env_pieces;
- uint64_t hash = env->player_pieces + piece_mask + c_bottom();
-
- // Hard coded opening book to handle some early game traps
- // TODO: Add more opening book moves
- switch (hash) {
- case 4398050705408:
- // Respond to _ _ _ o _ _ _
- // with _ _ x o _ _ _
- return 2;
- case 4398583382016:
- // Respond to _ _ _ _ o _ _
- // with _ _ _ x o _ _
- return 3;
- }
-
- float best_value = 9999;
- float values[7];
- for (int i = 0; i < 7; i++) {
- values[i] = 9999;
- }
- for (uint64_t column = 0; column < 7; column ++) {
- if (invalid_move(column, piece_mask)) {
- continue;
- }
- uint64_t child_env_pieces = play(column, piece_mask, env->player_pieces);
- if (won(child_env_pieces)) {
- return column;
- }
- float val = -negamax(env->player_pieces, child_env_pieces, 3);
- values[column] = val;
- if (val < best_value) {
- best_value = val;
- }
- }
- int num_ties = 0;
- for (uint64_t column = 0; column < 7; column ++) {
- if (values[column] == best_value) {
- num_ties++;
- }
- }
- //printf("Values: %f, %f, %f, %f, %f, %f, %f\n", values[0], values[1], values[2], values[3], values[4], values[5], values[6]);
- int best_tie = rand() % num_ties;
- for (uint64_t column = 0; column < 7; column ++) {
- if (values[column] == best_value) {
- if (best_tie == 0) {
- return column;
-
- }
- best_tie--;
- }
- }
- return 0;
-}
-
-void compute_observation(CConnect4* env) {
- // Populate observations from bitstring game representation
- // http://blog.gamesolver.org/solving-connect-four/06-bitboard/
- uint64_t player_pieces = env->player_pieces;
- uint64_t env_pieces = env->env_pieces;
-
- int obs_idx = 0;
- for (int i = 0; i < 49; i++) {
- // Skip the sentinel row
- if ((i + 1) % 7 == 0) {
- continue;
- }
-
- int p0_bit = (player_pieces >> i) & 1;
- if (p0_bit == 1) {
- env->observations[obs_idx] = PLAYER_WIN;
- }
- int p1_bit = (env_pieces >> i) & 1;
- if (p1_bit == 1) {
- env->observations[obs_idx] = ENV_WIN;
- }
- obs_idx += 1;
- }
-}
-
-void c_reset(CConnect4* env) {
- env->log = (Log){0};
- env->terminals[0] = NOT_DONE;
- env->player_pieces = 0;
- env->env_pieces = 0;
- for (int i = 0; i < 42; i ++) {
- env->observations[i] = 0.0;
- }
-}
-
-void finish_game(CConnect4* env, float reward) {
- env->rewards[0] = reward;
- env->terminals[0] = DONE;
- add_log(env);
- compute_observation(env);
-}
-
-void c_step(CConnect4* env) {
- env->log.episode_length += 1;
- env->rewards[0] = 0.0;
-
- if (env->terminals[0] == DONE) {
- c_reset(env);
- return;
- }
-
- // Player action (PLAYER_WIN)
- uint64_t column = env->actions[0];
- uint64_t piece_mask = env->player_pieces | env->env_pieces;
- if (invalid_move(column, piece_mask)) {
- finish_game(env, ENV_WIN);
- return;
- }
-
- env->player_pieces = play(column, piece_mask, env->env_pieces);
- if (won(env->player_pieces)) {
- finish_game(env, PLAYER_WIN);
- return;
- }
-
- // Environment action (ENV_WIN)
- column = compute_env_move(env);
- piece_mask = env->player_pieces | env->env_pieces;
- if (invalid_move(column, piece_mask)) {
- finish_game(env, PLAYER_WIN);
- return;
- }
-
- env->env_pieces = play(column, piece_mask, env->player_pieces);
- if (won(env->env_pieces)) {
- finish_game(env, ENV_WIN);
- return;
- }
-
- compute_observation(env);
-}
-
-const Color PUFF_RED = (Color){187, 0, 0, 255};
-const Color PUFF_CYAN = (Color){0, 187, 187, 255};
-const Color PUFF_WHITE = (Color){241, 241, 241, 241};
-const Color PUFF_BACKGROUND = (Color){6, 24, 24, 255};
-
-typedef struct Client Client;
-struct Client {
- float width;
- float height;
- Texture2D puffers;
-};
-
-Client* make_client() {
- Client* client = (Client*)calloc(1, sizeof(Client));
- client->width = WIDTH;
- client->height = HEIGHT;
-
- InitWindow(WIDTH, HEIGHT, "PufferLib Ray Connect4");
- SetTargetFPS(60);
-
- client->puffers = LoadTexture("resources/shared/puffers_128.png");
- return client;
-}
-
-void c_render(CConnect4* env) {
- if (IsKeyDown(KEY_ESCAPE)) {
- exit(0);
- }
-
- if (env->client == NULL) {
- env->client = make_client();
- }
-
- Client* client = env->client;
-
- BeginDrawing();
- ClearBackground(PUFF_BACKGROUND);
-
- int y_offset = client->height - PIECE_HEIGHT;
- int obs_idx = 0;
- for (int i = 0; i < 49; i++) {
- // TODO: Simplify this by iterating over the observation more directly
- if ((i + 1) % 7 == 0) {
- continue;
- }
-
- int row = i % (ROWS + 1);
- int column = i / (ROWS + 1);
- int y = y_offset - row * PIECE_HEIGHT;
- int x = column * PIECE_WIDTH;
-
- Color piece_color=PURPLE;
- int color_idx = 0;
- if (env->observations[obs_idx] == 0.0) {
- piece_color = BLACK;
- } else if (env->observations[obs_idx] == PLAYER_WIN) {
- piece_color = PUFF_CYAN;
- color_idx = 1;
- } else if (env->observations[obs_idx] == ENV_WIN) {
- piece_color = PUFF_RED;
- color_idx = 2;
- }
-
- obs_idx += 1;
- Color board_color = (Color){0, 80, 80, 255};
- DrawRectangle(x , y , PIECE_WIDTH, PIECE_WIDTH, board_color);
- DrawCircle(x + PIECE_WIDTH/2, y + PIECE_WIDTH/2, PIECE_WIDTH/2, piece_color);
- if (color_idx == 0) {
- continue;
- }
-
- DrawTexturePro(
- client->puffers,
- (Rectangle){
- (color_idx == 1) ? 0 : 128,
- 0, 128, 128,
- },
- (Rectangle){x+16, y+16, PIECE_WIDTH-32, PIECE_WIDTH-32},
- (Vector2){0, 0},
- 0,
- WHITE
- );
- }
- EndDrawing();
-}
-
-void close_client(Client* client) {
- CloseWindow();
- free(client);
-}
diff --git a/pufferlib/ocean/connect4/connect4.py b/pufferlib/ocean/connect4/connect4.py
deleted file mode 100644
index 27cdffb25..000000000
--- a/pufferlib/ocean/connect4/connect4.py
+++ /dev/null
@@ -1,82 +0,0 @@
-'''High-perf Pong
-
-Inspired from https://gist.github.com/Yttrmin/18ecc3d2d68b407b4be1
-& https://jair.org/index.php/jair/article/view/10819/25823
-& https://www.youtube.com/watch?v=PSQt5KGv7Vk
-'''
-
-import numpy as np
-import gymnasium
-
-import pufferlib
-from pufferlib.ocean.connect4 import binding
-
-
-class Connect4(pufferlib.PufferEnv):
- def __init__(self, num_envs=1, render_mode=None, report_interval=128,
- buf=None, seed=0):
-
- self.single_observation_space = gymnasium.spaces.Box(low=0, high=1,
- shape=(42,), dtype=np.float32)
- self.single_action_space = gymnasium.spaces.Discrete(7)
- self.report_interval = report_interval
- self.render_mode = render_mode
- self.num_agents = num_envs
-
- super().__init__(buf=buf)
- self.c_envs = binding.vec_init(self.observations, self.actions, self.rewards,
- self.terminals, self.truncations, num_envs, seed)
-
- def reset(self, seed=None):
- self.tick = 0
- if seed is None:
- binding.vec_reset(self.c_envs, 0)
- else:
- binding.vec_reset(self.c_envs, seed)
- return self.observations, []
-
- def step(self, actions):
- self.actions[:] = actions
- binding.vec_step(self.c_envs)
- self.tick += 1
-
- info = []
- if self.tick % self.report_interval == 0:
- log = binding.vec_log(self.c_envs)
- if log['episode_length'] > 0:
- info.append(log)
-
- return (self.observations, self.rewards,
- self.terminals, self.truncations, info)
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-
-def test_performance(timeout=10, atn_cache=1024, num_envs=1024):
- import time
-
- env = Connect4(num_envs=num_envs)
- env.reset()
- tick = 0
-
- actions = np.random.randint(
- 0,
- env.single_action_space.n + 1,
- (atn_cache, num_envs),
- )
-
- start = time.time()
- while time.time() - start < timeout:
- atn = actions[tick % atn_cache]
- env.step(atn)
- tick += 1
-
- print(f'SPS: {num_envs * tick / (time.time() - start)}')
-
-
-if __name__ == '__main__':
- test_performance()
diff --git a/pufferlib/ocean/connect4/connect4game b/pufferlib/ocean/connect4/connect4game
deleted file mode 100755
index d2677ee4f..000000000
Binary files a/pufferlib/ocean/connect4/connect4game and /dev/null differ
diff --git a/pufferlib/ocean/convert/binding.c b/pufferlib/ocean/convert/binding.c
deleted file mode 100644
index e53f6e943..000000000
--- a/pufferlib/ocean/convert/binding.c
+++ /dev/null
@@ -1,22 +0,0 @@
-#include "convert.h"
-
-#define Env Convert
-#include "../env_binding.h"
-
-static int my_init(Env* env, PyObject* args, PyObject* kwargs) {
- env->width = unpack(kwargs, "width");
- env->height = unpack(kwargs, "height");
- env->num_agents = unpack(kwargs, "num_agents");
- env->num_factories = unpack(kwargs, "num_factories");
- env->num_resources = unpack(kwargs, "num_resources");
- init(env);
- return 0;
-}
-
-static int my_log(PyObject* dict, Log* log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "episode_length", log->episode_length);
- return 0;
-}
diff --git a/pufferlib/ocean/convert/convert.c b/pufferlib/ocean/convert/convert.c
deleted file mode 100644
index 09f0d41f4..000000000
--- a/pufferlib/ocean/convert/convert.c
+++ /dev/null
@@ -1,46 +0,0 @@
-#include "convert.h"
-#include "puffernet.h"
-
-int main() {
- Convert env = {
- .width = 1920,
- .height = 1080,
- .num_agents = 1024,
- .num_factories = 32,
- .num_resources = 8,
- };
- init(&env);
-
- int num_obs = 2*env.num_resources + 4 + env.num_resources;
- env.observations = calloc(env.num_agents*num_obs, sizeof(float));
- env.actions = calloc(2*env.num_agents, sizeof(int));
- env.rewards = calloc(env.num_agents, sizeof(float));
- env.terminals = calloc(env.num_agents, sizeof(unsigned char));
-
- Weights* weights = load_weights("resources/convert/convert_weights.bin", 137743);
- int logit_sizes[2] = {9, 5};
- LinearLSTM* net = make_linearlstm(weights, env.num_agents, num_obs, logit_sizes, 2);
-
- c_reset(&env);
- c_render(&env);
-
- while (!WindowShouldClose()) {
- for (int i=0; i
-#include
-#include
-#include "raylib.h"
-
-typedef struct {
- float perf;
- float score;
- float episode_return;
- float episode_length;
- float n;
-} Log;
-
-typedef struct {
- Texture2D sprites;
-} Client;
-
-typedef struct {
- float x;
- float y;
- float heading;
- float speed;
- int item;
- int episode_length;
-} Agent;
-
-typedef struct {
- float x;
- float y;
- float heading;
- int item;
-} Factory;
-
-typedef struct {
- Log log;
- Client* client;
- Agent* agents;
- Factory* factories;
- float* observations;
- int* actions;
- float* rewards;
- unsigned char* terminals;
- int width;
- int height;
- int num_agents;
- int num_factories;
- int num_resources;
-} Convert;
-
-void init(Convert* env) {
- env->agents = calloc(env->num_agents, sizeof(Agent));
- env->factories = calloc(env->num_factories, sizeof(Factory));
-}
-
-int compare_floats(const void* a, const void* b) {
- return (*(float*)a - *(float*)b) > 0;
-}
-
-void compute_observations(Convert* env) {
- int obs_idx = 0;
- for (int a=0; anum_agents; a++) {
- Agent* agent = &env->agents[a];
- float dists[env->num_resources];
- for (int i=0; inum_resources; i++) {
- dists[i] = 999999;
- }
- for (int f=0; fnum_factories; f++) {
- Factory* factory = &env->factories[f];
- float dx = factory->x - agent->x;
- float dy = factory->y - agent->y;
- float dd = dx*dx + dy*dy;
- int type = f % env->num_resources;
- if (dd < dists[type]) {
- dists[type] = dd;
- env->observations[obs_idx + 2*type] = dx/env->width;
- env->observations[obs_idx + 2*type + 1] = dy/env->height;
- }
- }
- obs_idx += 2*env->num_resources;
- env->observations[obs_idx++] = agent->heading/(2*PI);
- env->observations[obs_idx++] = env->rewards[a];
- env->observations[obs_idx++] = agent->x/env->width;
- env->observations[obs_idx++] = agent->y/env->height;
- memset(&env->observations[obs_idx], 0, env->num_resources*sizeof(float));
- env->observations[obs_idx + agent->item] = 1.0f;
- obs_idx += env->num_resources;
- }
-}
-
-void c_reset(Convert* env) {
- for (int i=0; inum_agents; i++) {
- env->agents[i].x = 16 + rand()%(env->width-16);
- env->agents[i].y = 16 + rand()%(env->height-16);
- env->agents[i].item = rand() % env->num_resources;
- env->agents[i].episode_length = 0;
- }
- for (int i=0; inum_factories; i++) {
- env->factories[i].x = 16 + rand()%(env->width-16);
- env->factories[i].y = 16 + rand()%(env->height-16);
- env->factories[i].item = i % env->num_resources;
- env->factories[i].heading = (rand() % 360)*PI/180.0f;
- }
- compute_observations(env);
-}
-
-float clip(float val, float min, float max) {
- if (val < min) {
- return min;
- } else if (val > max) {
- return max;
- }
- return val;
-}
-
-void c_step(Convert* env) {
- for (int i=0; inum_agents; i++) {
- env->terminals[i] = 0;
- env->rewards[i] = 0;
- Agent* agent = &env->agents[i];
- agent->episode_length += 1;
-
- agent->heading += ((float)env->actions[2*i] - 4.0f)/12.0f;
- agent->heading = clip(agent->heading, 0, 2*PI);
-
- agent->speed += 1.0f*((float)env->actions[2*i + 1] - 2.0f);
- agent->speed = clip(agent->speed, -20.0f, 20.0f);
-
- agent->x += agent->speed*cosf(agent->heading);
- agent->x = clip(agent->x, 16, env->width-16);
-
- agent->y += agent->speed*sinf(agent->heading);
- agent->y = clip(agent->y, 16, env->height-16);
-
- if (rand() % env->num_agents == 0) {
- env->agents[i].x = rand() % env->width;
- env->agents[i].y = rand() % env->height;
- }
-
- for (int f=0; fnum_factories; f++) {
- Factory* factory = &env->factories[f];
- float dx = (factory->x - agent->x);
- float dy = (factory->y - agent->y);
- float dist = sqrt(dx*dx + dy*dy);
- if (dist > 32) {
- continue;
- }
- if (factory->item == agent->item) {
- agent->item = (agent->item + 1) % env->num_resources;
- env->log.perf += 1.0f;
- env->log.score += 1.0f;
- env->log.episode_length += agent->episode_length;
- env->log.n++;
- env->rewards[i] = 1.0f;
- agent->episode_length = 0;
- }
- }
- }
- for (int f=0; fnum_factories; f++) {
- Factory* factory = &env->factories[f];
- factory->x += 2.0f*cosf(factory->heading);
- factory->y += 2.0f*sinf(factory->heading);
-
- float factory_x = clip(factory->x, 16, env->width-16);
- float factory_y = clip(factory->y, 16, env->height-16);
-
- if (factory_x != factory->x || factory_y != factory->y) {
- factory->heading = (rand() % 360)*PI/180.0f;
- factory->x = factory_x;
- factory->y = factory_y;
- }
- }
- compute_observations(env);
-}
-
-void c_render(Convert* env) {
- if (env->client == NULL) {
- InitWindow(env->width, env->height, "PufferLib Convert");
- SetTargetFPS(30);
- env->client = (Client*)calloc(1, sizeof(Client));
- env->client->sprites = LoadTexture("resources/shared/puffers.png");
- }
-
- if (IsKeyDown(KEY_ESCAPE)) {
- exit(0);
- }
-
- BeginDrawing();
- ClearBackground((Color){6, 24, 24, 255});
-
- for (int f=0; fnum_factories; f++) {
- Factory* factory = &env->factories[f];
- DrawTexturePro(
- env->client->sprites,
- (Rectangle){
- 64*factory->item, 512, 64, 64,
- },
- (Rectangle){
- factory->x - 32,
- factory->y - 32,
- 64,
- 64
- },
- (Vector2){0, 0},
- 0,
- WHITE
- );
- }
-
- for (int i=0; inum_agents; i++) {
- Agent* agent = &env->agents[i];
- float heading = agent->heading;
- int y = 576;
- if (heading < PI/2 || heading > 3*PI/2) {
- y += 32;
- }
- DrawTexturePro(
- env->client->sprites,
- (Rectangle){
- 32*agent->item, y, 32, 32,
- },
- (Rectangle){
- agent->x - 16,
- agent->y - 16,
- 32,
- 32
- },
- (Vector2){0, 0},
- 0,
- WHITE
- );
- }
-
- EndDrawing();
-}
-
-void c_close(Convert* env) {
- free(env->agents);
- free(env->factories);
- if (env->client != NULL) {
- Client* client = env->client;
- UnloadTexture(client->sprites);
- CloseWindow();
- free(client);
- }
-}
diff --git a/pufferlib/ocean/convert/convert.py b/pufferlib/ocean/convert/convert.py
deleted file mode 100644
index 1f57cead8..000000000
--- a/pufferlib/ocean/convert/convert.py
+++ /dev/null
@@ -1,82 +0,0 @@
-'''A simple sample environment. Use this as a template for your own envs.'''
-
-import gymnasium
-import numpy as np
-
-import pufferlib
-from pufferlib.ocean.convert import binding
-
-class Convert(pufferlib.PufferEnv):
- def __init__(self, num_envs=1, width=1920, height=1080, num_agents=1024, num_factories=32,
- num_resources=8, render_mode=None, log_interval=128, buf=None, seed=0):
- self.single_observation_space = gymnasium.spaces.Box(low=0, high=1,
- shape=(2*num_resources + 4 + num_resources,), dtype=np.float32)
- self.single_action_space = gymnasium.spaces.MultiDiscrete([9, 5])
-
- self.render_mode = render_mode
- self.num_agents = num_envs*num_agents
- self.log_interval = log_interval
-
- if num_resources < 1 or num_resources > 8:
- raise pufferlib.APIUsageError('num_resources must be in [1, 8]')
-
- super().__init__(buf)
- c_envs = []
- for i in range(num_envs):
- c_env = binding.env_init(
- self.observations[i*num_agents:(i+1)*num_agents],
- self.actions[i*num_agents:(i+1)*num_agents],
- self.rewards[i*num_agents:(i+1)*num_agents],
- self.terminals[i*num_agents:(i+1)*num_agents],
- self.truncations[i*num_agents:(i+1)*num_agents],
- seed, width=width, height=height,
- num_agents=num_agents, num_factories=num_factories,
- num_resources=num_resources)
- c_envs.append(c_env)
-
- self.c_envs = binding.vectorize(*c_envs)
-
- def reset(self, seed=0):
- binding.vec_reset(self.c_envs, seed)
- self.tick = 0
- return self.observations, []
-
- def step(self, actions):
- self.tick += 1
- self.actions[:] = actions
- binding.vec_step(self.c_envs)
-
- info = []
- if self.tick % self.log_interval == 0:
- log = binding.vec_log(self.c_envs)
- if log:
- info.append(log)
-
- return (self.observations, self.rewards,
- self.terminals, self.truncations, info)
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-if __name__ == '__main__':
- N = 512
-
- env = Convert(num_envs=N)
- env.reset()
- steps = 0
-
- CACHE = 1024
- actions = np.random.randint(env.single_action_space.nvec, size=(CACHE, 2))
-
- i = 0
- import time
- start = time.time()
- while time.time() - start < 10:
- env.step(actions[i % CACHE])
- steps += env.num_agents
- i += 1
-
- print('Convert SPS:', int(steps / (time.time() - start)))
diff --git a/pufferlib/ocean/convert_circle/binding.c b/pufferlib/ocean/convert_circle/binding.c
deleted file mode 100644
index ae91dedfd..000000000
--- a/pufferlib/ocean/convert_circle/binding.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "convert_circle.h"
-
-#define Env ConvertCircle
-#include "../env_binding.h"
-
-static int my_init(Env *env, PyObject *args, PyObject *kwargs) {
- env->width = unpack(kwargs, "width");
- env->height = unpack(kwargs, "height");
- env->num_agents = unpack(kwargs, "num_agents");
- env->num_factories = unpack(kwargs, "num_factories");
- env->num_resources = unpack(kwargs, "num_resources");
- env->equidistant = unpack(kwargs, "equidistant");
- env->radius = unpack(kwargs, "radius");
- init(env);
- return 0;
-}
-
-static int my_log(PyObject *dict, Log *log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "episode_length", log->episode_length);
- return 0;
-}
diff --git a/pufferlib/ocean/convert_circle/convert_circle.c b/pufferlib/ocean/convert_circle/convert_circle.c
deleted file mode 100644
index d88936108..000000000
--- a/pufferlib/ocean/convert_circle/convert_circle.c
+++ /dev/null
@@ -1,52 +0,0 @@
-#include "convert_circle.h"
-#include "puffernet.h"
-#include
-#include
-
-int main() {
- ConvertCircle env = {
- .width = 1920,
- .height = 1080,
- .num_agents = 128,
- .num_factories = 16,
- .num_resources = 6,
- .equidistant = 1,
- .radius = 400,
- };
- srand(time(NULL));
- init(&env);
-
- int num_obs = 2 * env.num_resources + 4 + env.num_resources;
- env.observations = calloc(env.num_agents * num_obs, sizeof(float));
- env.actions = calloc(2 * env.num_agents, sizeof(int));
- env.rewards = calloc(env.num_agents, sizeof(float));
- env.terminals = calloc(env.num_agents, sizeof(unsigned char));
-
- Weights *weights =
- load_weights("resources/convert/convert_weights.bin", 137743);
- int logit_sizes[2] = {9, 5};
- LinearLSTM *net =
- make_linearlstm(weights, env.num_agents, num_obs, logit_sizes, 2);
-
- c_reset(&env);
- c_render(&env);
-
- while (!WindowShouldClose()) {
- for (int i = 0; i < env.num_agents; i++) {
- env.actions[2 * i] = rand() % 9;
- env.actions[2 * i + 1] = rand() % 5;
- }
-
- forward_linearlstm(net, env.observations, env.actions);
- compute_observations(&env);
- c_step(&env);
- c_render(&env);
- }
-
- free_linearlstm(net);
- free(env.observations);
- free(env.actions);
- free(env.rewards);
- free(env.terminals);
- c_close(&env);
-}
diff --git a/pufferlib/ocean/convert_circle/convert_circle.h b/pufferlib/ocean/convert_circle/convert_circle.h
deleted file mode 100644
index 00a4b772a..000000000
--- a/pufferlib/ocean/convert_circle/convert_circle.h
+++ /dev/null
@@ -1,252 +0,0 @@
-/* ConvertCircle: a sample multiagent env about puffers eating stars.
- * Use this as a tutorial and template for your own multiagent envs.
- * We suggest starting with the Squared env for a simpler intro.
- * Star PufferLib on GitHub to support. It really, really helps!
- */
-
-#include "raylib.h"
-#include
-#include
-#include
-
-typedef struct {
- float perf;
- float score;
- float episode_return;
- float episode_length;
- float n;
-} Log;
-
-typedef struct {
- Texture2D sprites;
-} Client;
-
-typedef struct {
- float x;
- float y;
- float heading;
- float speed;
- int item;
- int episode_length;
-} Agent;
-
-typedef struct {
- float x;
- float y;
- float heading;
- int item;
-} Factory;
-
-typedef struct {
- Log log;
- Client *client;
- Agent *agents;
- Factory *factories;
- float *observations;
- int *actions;
- float *rewards;
- unsigned char *terminals;
- int width;
- int height;
- int num_agents;
- int num_factories;
- int num_resources;
- int equidistant;
- int radius;
-} ConvertCircle;
-
-static inline float random_float(float low, float high) {
- return low + (high - low) * ((float)rand() / (float)RAND_MAX);
-}
-
-void init(ConvertCircle *env) {
- env->agents = calloc(env->num_agents, sizeof(Agent));
- env->factories = calloc(env->num_factories, sizeof(Factory));
-}
-
-int compare_floats(const void *a, const void *b) {
- return (*(float *)a - *(float *)b) > 0;
-}
-
-void compute_observations(ConvertCircle *env) {
- int obs_idx = 0;
- for (int a = 0; a < env->num_agents; a++) {
- Agent *agent = &env->agents[a];
- float dists[env->num_resources];
- for (int i = 0; i < env->num_resources; i++) {
- dists[i] = 999999;
- }
- for (int f = 0; f < env->num_factories; f++) {
- Factory *factory = &env->factories[f];
- float dx = factory->x - agent->x;
- float dy = factory->y - agent->y;
- float dd = dx * dx + dy * dy;
- int type = f % env->num_resources;
- if (dd < dists[type]) {
- dists[type] = dd;
- env->observations[obs_idx + 2 * type] = dx / env->width;
- env->observations[obs_idx + 2 * type + 1] = dy / env->height;
- }
- }
- obs_idx += 2 * env->num_resources;
- env->observations[obs_idx++] = agent->heading / (2 * PI);
- env->observations[obs_idx++] = env->rewards[a];
- env->observations[obs_idx++] = agent->x / env->width;
- env->observations[obs_idx++] = agent->y / env->height;
- memset(&env->observations[obs_idx], 0, env->num_resources * sizeof(float));
- env->observations[obs_idx + agent->item] = 1.0f;
- obs_idx += env->num_resources;
- }
-}
-
-void c_reset(ConvertCircle *env) {
- for (int i = 0; i < env->num_agents; i++) {
- env->agents[i].x = env->width / 2.0f + random_float(-10.0f, 10.0f);
- env->agents[i].y = env->height / 2.0f + random_float(-10.0f, 10.0f);
- env->agents[i].item = rand() % env->num_resources;
- env->agents[i].episode_length = 0;
- }
- float angle;
- float delta_angle = 2.0f * PI / env->num_factories;
- for (int i = 0; i < env->num_factories; i++) {
- if (env->equidistant) {
- angle = i * delta_angle;
- } else {
- angle = random_float(0, 2.0f * PI);
- }
- env->factories[i].x = env->width / 2.0f + env->radius * cosf(angle);
- env->factories[i].y = env->height / 2.0f + env->radius * sinf(angle);
- env->factories[i].item = i % env->num_resources;
- env->factories[i].heading = (rand() % 360) * PI / 180.0f;
- }
- compute_observations(env);
-}
-
-float clip(float val, float min, float max) {
- if (val < min) {
- return min;
- } else if (val > max) {
- return max;
- }
- return val;
-}
-
-void c_step(ConvertCircle *env) {
- for (int i = 0; i < env->num_agents; i++) {
- env->terminals[i] = 0;
- env->rewards[i] = 0;
- Agent *agent = &env->agents[i];
- agent->episode_length += 1;
-
- agent->heading += ((float)env->actions[2 * i] - 4.0f) / 12.0f;
- agent->heading = clip(agent->heading, 0, 2 * PI);
-
- agent->speed += 1.0f * ((float)env->actions[2 * i + 1] - 2.0f);
- agent->speed = clip(agent->speed, -20.0f, 20.0f);
-
- agent->x += agent->speed * cosf(agent->heading);
- agent->x = clip(agent->x, 16, env->width - 16);
-
- agent->y += agent->speed * sinf(agent->heading);
- agent->y = clip(agent->y, 16, env->height - 16);
-
- if (rand() % env->num_agents == 0) {
- env->agents[i].x = env->width / 2.0f + random_float(-10.0f, 10.0f);
- env->agents[i].y = env->height / 2.0f + random_float(-10.0f, 10.0f);
- }
-
- for (int f = 0; f < env->num_factories; f++) {
- Factory *factory = &env->factories[f];
- float dx = (factory->x - agent->x);
- float dy = (factory->y - agent->y);
- float dist = sqrt(dx * dx + dy * dy);
- if (dist > 32) {
- continue;
- }
- if (factory->item == agent->item) {
- agent->item = (agent->item + 1) % env->num_resources;
- env->log.perf += 1.0f;
- env->log.score += 1.0f;
- env->log.episode_length += agent->episode_length;
- env->log.n++;
- env->rewards[i] = 1.0f;
- agent->episode_length = 0;
- }
- }
- }
- for (int f = 0; f < env->num_factories; f++) {
- Factory *factory = &env->factories[f];
- factory->x += 0.0f * cosf(factory->heading);
- factory->y += 0.0f * sinf(factory->heading);
-
- float factory_x = clip(factory->x, 16, env->width - 16);
- float factory_y = clip(factory->y, 16, env->height - 16);
-
- if (factory_x != factory->x || factory_y != factory->y) {
- factory->heading = (rand() % 360) * PI / 180.0f;
- factory->x = factory_x;
- factory->y = factory_y;
- }
- }
- compute_observations(env);
-}
-
-void c_render(ConvertCircle *env) {
- if (env->client == NULL) {
- InitWindow(env->width, env->height, "PufferLib ConvertCircle");
- SetTargetFPS(30);
- env->client = (Client *)calloc(1, sizeof(Client));
- env->client->sprites = LoadTexture("resources/shared/puffers.png");
- }
-
- if (IsKeyDown(KEY_ESCAPE)) {
- exit(0);
- }
-
- BeginDrawing();
- ClearBackground((Color){6, 24, 24, 255});
-
- for (int f = 0; f < env->num_factories; f++) {
- Factory *factory = &env->factories[f];
- DrawTexturePro(env->client->sprites,
- (Rectangle){
- 64 * factory->item,
- 512,
- 64,
- 64,
- },
- (Rectangle){factory->x - 32, factory->y - 32, 64, 64},
- (Vector2){0, 0}, 0, WHITE);
- }
-
- for (int i = 0; i < env->num_agents; i++) {
- Agent *agent = &env->agents[i];
- float heading = agent->heading;
- int y = 576;
- if (heading < PI / 2 || heading > 3 * PI / 2) {
- y += 32;
- }
- DrawTexturePro(env->client->sprites,
- (Rectangle){
- 32 * agent->item,
- y,
- 32,
- 32,
- },
- (Rectangle){agent->x - 16, agent->y - 16, 32, 32},
- (Vector2){0, 0}, 0, WHITE);
- }
-
- EndDrawing();
-}
-
-void c_close(ConvertCircle *env) {
- free(env->agents);
- free(env->factories);
- if (env->client != NULL) {
- Client *client = env->client;
- UnloadTexture(client->sprites);
- CloseWindow();
- free(client);
- }
-}
diff --git a/pufferlib/ocean/convert_circle/convert_circle.py b/pufferlib/ocean/convert_circle/convert_circle.py
deleted file mode 100644
index f8682535b..000000000
--- a/pufferlib/ocean/convert_circle/convert_circle.py
+++ /dev/null
@@ -1,83 +0,0 @@
-'''A simple sample environment. Use this as a template for your own envs.'''
-
-import gymnasium
-import numpy as np
-
-import pufferlib
-from pufferlib.ocean.convert_circle import binding
-
-class ConvertCircle(pufferlib.PufferEnv):
- def __init__(self, num_envs=1, width=1920, height=1080, num_agents=1024, num_factories=32,
- num_resources=8, equidistant=0, radius=30, render_mode=None, log_interval=128, buf=None, seed=0):
- self.single_observation_space = gymnasium.spaces.Box(low=0, high=1,
- shape=(2*num_resources + 4 + num_resources,), dtype=np.float32)
- self.single_action_space = gymnasium.spaces.MultiDiscrete([9, 5])
-
- self.render_mode = render_mode
- self.num_agents = num_envs*num_agents
- self.log_interval = log_interval
-
- if num_resources < 1 or num_resources > 8:
- raise pufferlib.APIUsageError('num_resources must be in [1, 8]')
-
- super().__init__(buf)
- c_envs = []
- for i in range(num_envs):
- c_env = binding.env_init(
- self.observations[i*num_agents:(i+1)*num_agents],
- self.actions[i*num_agents:(i+1)*num_agents],
- self.rewards[i*num_agents:(i+1)*num_agents],
- self.terminals[i*num_agents:(i+1)*num_agents],
- self.truncations[i*num_agents:(i+1)*num_agents],
- seed, width=width, height=height,
- num_agents=num_agents, num_factories=num_factories,
- num_resources=num_resources, equidistant=equidistant,
- radius=radius)
- c_envs.append(c_env)
-
- self.c_envs = binding.vectorize(*c_envs)
-
- def reset(self, seed=0):
- binding.vec_reset(self.c_envs, seed)
- self.tick = 0
- return self.observations, []
-
- def step(self, actions):
- self.tick += 1
- self.actions[:] = actions
- binding.vec_step(self.c_envs)
-
- info = []
- if self.tick % self.log_interval == 0:
- log = binding.vec_log(self.c_envs)
- if log:
- info.append(log)
-
- return (self.observations, self.rewards,
- self.terminals, self.truncations, info)
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-if __name__ == '__main__':
- N = 512
-
- env = ConvertCircle(num_envs=N)
- env.reset()
- steps = 0
-
- CACHE = 1024
- actions = np.random.randint(env.single_action_space.nvec, size=(CACHE, 2))
-
- i = 0
- import time
- start = time.time()
- while time.time() - start < 10:
- env.step(actions[i % CACHE])
- steps += env.num_agents
- i += 1
-
- print('ConvertCircle SPS:', int(steps / (time.time() - start)))
diff --git a/pufferlib/ocean/cpr/binding.c b/pufferlib/ocean/cpr/binding.c
deleted file mode 100644
index 751165185..000000000
--- a/pufferlib/ocean/cpr/binding.c
+++ /dev/null
@@ -1,27 +0,0 @@
-#include "cpr.h"
-
-#define Env CCpr
-#include "../env_binding.h"
-
-static int my_init(Env* env, PyObject* args, PyObject* kwargs) {
- env->width = unpack(kwargs, "width");
- env->height = unpack(kwargs, "height");
- env->num_agents = unpack(kwargs, "num_agents");
- env->vision = unpack(kwargs, "vision");
- env->reward_food = unpack(kwargs, "reward_food");
- env->interactive_food_reward = unpack(kwargs, "interactive_food_reward");
- env->reward_move = unpack(kwargs, "reward_move");
- env->food_base_spawn_rate = unpack(kwargs, "food_base_spawn_rate");
- init_ccpr(env);
- return 0;
-}
-
-static int my_log(PyObject* dict, Log* log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "moves", log->moves);
- assign_to_dict(dict, "food_nb", log->food_nb);
- assign_to_dict(dict, "alive_steps", log->alive_steps);
- return 0;
-}
diff --git a/pufferlib/ocean/cpr/cpr.c b/pufferlib/ocean/cpr/cpr.c
deleted file mode 100644
index c70026474..000000000
--- a/pufferlib/ocean/cpr/cpr.c
+++ /dev/null
@@ -1,52 +0,0 @@
-#include
-#include
-#include "cpr.h"
-#include "puffernet.h"
-
-int main() {
- CCpr env = {
- .num_agents = 4,
- .width = 32,
- .height = 32,
- .vision = 3,
- .reward_food = 1.0f,
- .interactive_food_reward = 5.0f,
- .food_base_spawn_rate = 2e-3,
- };
- allocate_ccpr(&env);
- c_reset(&env);
- c_render(&env);
-
- Weights* weights = load_weights("resources/cpr/cpr_weights.bin", 139270);
- int logit_sizes[] = {5};
- LinearLSTM* net = make_linearlstm(weights, env.num_agents, 49, logit_sizes, 1);
-
- while (!WindowShouldClose()) {
- // User can take control of the first puffer
- if (IsKeyDown(KEY_LEFT_SHIFT)) {
- if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W))
- env.actions[0] = 0;
- if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S))
- env.actions[0] = 1;
- if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A))
- env.actions[0] = 2;
- if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D))
- env.actions[0] = 3;
-
- printf("Getting user input %d\n", env.actions[0]);
- sleep(2);
- } else {
- for (int i = 0; i < env.num_agents*49; i++) {
- net->obs[i] = env.observations[i];
- }
- forward_linearlstm(net, net->obs, env.actions);
- }
-
- c_step(&env);
- c_render(&env);
- }
- //close_renderer(renderer);
- free_CCpr(&env);
-
- return 0;
-}
diff --git a/pufferlib/ocean/cpr/cpr.h b/pufferlib/ocean/cpr/cpr.h
deleted file mode 100644
index 110b01e62..000000000
--- a/pufferlib/ocean/cpr/cpr.h
+++ /dev/null
@@ -1,691 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "raylib.h"
-
-#include "grid.h"
-
-#define EMPTY 0
-#define NORMAL_FOOD 1
-#define INTERACTIVE_FOOD 2
-// Anything above Wall should be obstacles
-#define WALL 3
-#define AGENTS 4
-
-#define LOG_BUFFER_SIZE 8192
-
-#define SET_BIT(arr, i) (arr[(i) / 8] |= (1 << ((i) % 8)))
-#define CLEAR_BIT(arr, i) (arr[(i) / 8] &= ~(1 << ((i) % 8)))
-#define CHECK_BIT(arr, i) (arr[(i) / 8] & (1 << ((i) % 8)))
-#define min(a, b) ((a) < (b) ? (a) : (b))
-
-#define REWARD_20_HP -0
-#define REWARD_80_HP 0
-#define REWARD_DEATH -1.0f
-
-
-#define LOG_SCORE_REWARD_SMALL 0.1f
-#define LOG_SCORE_REWARD_MEDIUM 0.2f
-#define LOG_SCORE_REWARD_MOVE - 0.0
-#define LOG_SCORE_REWARD_DEATH -1
-
-#define HP_REWARD_FOOD_MEDIUM 50
-#define HP_REWARD_FOOD_SMALL 20
-#define HP_LOSS_PER_STEP 1
-#define MAX_HP 100
-
-typedef struct Log Log;
-struct Log {
- float perf;
- float score;
- float episode_return;
- float moves;
- float food_nb;
- float alive_steps;
- float n;
-};
-
-typedef struct Agent Agent;
-struct Agent {
- int r;
- int c;
- int id;
- float hp;
- int direction;
-};
-
-typedef struct FoodList FoodList;
-struct FoodList {
- int *indexes; // Grid flattened index positions
- int size;
-};
-
-FoodList *allocate_foodlist(int size) {
- FoodList *foods = (FoodList *)calloc(1, sizeof(FoodList));
- foods->indexes = (int *)calloc(size, sizeof(int));
- foods->size = 0;
- return foods;
-}
-
-void free_foodlist(FoodList *foods) {
- free(foods->indexes);
- free(foods);
-}
-
-typedef struct Renderer Renderer;
-typedef struct CCpr CCpr;
-struct CCpr {
- Renderer* client;
- int width;
- int height;
- int num_agents;
-
- int vision;
- int vision_window;
- int obs_size;
-
- int tick;
-
- float reward_food;
- float reward_move;
- float interactive_food_reward;
-
- unsigned char *grid;
- unsigned char *observations;
- int *actions;
- float *rewards;
- unsigned char *terminals;
- unsigned char *truncations;
- unsigned char *masks;
-
- Agent *agents;
-
- Log log;
- Log* agent_logs;
-
- uint8_t *interactive_food_agent_count;
-
- FoodList *foods;
- float food_base_spawn_rate;
-};
-
-void add_log(CCpr *env, Log *log) {
- env->log.perf = fmaxf(0, 1.0 - 0.01*log->alive_steps);
- env->log.episode_return += log->episode_return;
- env->log.score += log->score;
- env->log.moves += log->moves / log->alive_steps;
- env->log.alive_steps += log->alive_steps;
- env->log.n += 1;
-}
-
-void init_ccpr(CCpr *env) {
- env->grid =
- (unsigned char *)calloc(env->width * env->height, sizeof(unsigned char));
- env->agents = (Agent *)calloc(env->num_agents, sizeof(Agent));
- env->vision_window = 2 * env->vision + 1;
- env->obs_size = env->vision_window * env->vision_window;// + 1;
- env->interactive_food_agent_count =
- (uint8_t *)calloc((env->width * env->height + 7) / 8, sizeof(uint8_t));
- env->foods = allocate_foodlist(env->width * env->height);
- env->agent_logs = (Log *)calloc(env->num_agents, sizeof(Log));
- env->masks = (unsigned char *)calloc(env->num_agents, sizeof(unsigned char));
-}
-
-void allocate_ccpr(CCpr *env) {
- // Called by C stuff
- int obs_size = (2 * env->vision + 1) * (2 * env->vision + 1); //+ 1;
- env->observations = (unsigned char *)calloc(env->num_agents * obs_size,
- sizeof(unsigned char));
- env->actions = (int *)calloc(env->num_agents, sizeof(unsigned int));
- env->rewards = (float *)calloc(env->num_agents, sizeof(float));
- env->terminals =
- (unsigned char *)calloc(env->num_agents, sizeof(unsigned char));
- env->truncations = (unsigned char*)calloc(env->num_agents, sizeof(unsigned char));
- init_ccpr(env);
-}
-
-void c_close(CCpr *env) {
- free(env->grid);
- free(env->agents);
- free(env->interactive_food_agent_count);
- free_foodlist(env->foods);
- free(env->masks);
- free(env->agent_logs);
-}
-
-void free_CCpr(CCpr *env) {
- free(env->observations);
- free(env->actions);
- free(env->rewards);
- free(env->terminals);
- free(env->truncations);
- c_close(env);
-}
-
-int grid_index(CCpr *env, int r, int c) { return r * env->width + c; }
-int get_agent_tile_from_id(int agent_id) { return AGENTS + agent_id; }
-
-int get_agent_id_from_tile(int tile) { return tile - AGENTS; }
-
-void add_food(CCpr *env, int grid_idx, int food_type) {
- // Add food to the grid and the food_list at grid_idx
- assert(env->grid[grid_idx] == EMPTY);
- env->grid[grid_idx] = food_type;
- FoodList *foods = env->foods;
- foods->indexes[foods->size++] = grid_idx;
-}
-
-void reward_agent(CCpr *env, int agent_id, float reward) {
- // We don't reward if agent is full life
- // Agent *agent = &env->agents[agent_id];
- // if (agent->hp >= MAX_HP) {
- // return;
- // }
- env->rewards[agent_id] += reward;
- env->agent_logs[agent_id].episode_return += reward;
-}
-
-void spawn_food(CCpr *env, int food_type) {
- // Randomly spawns such food in the grid
- int idx, tile;
- do {
- int r = rand() % (env->height - 1);
- int c = rand() % (env->width - 1);
- idx = r * env->width + c;
- tile = env->grid[idx];
- } while (tile != EMPTY);
- add_food(env, idx, food_type);
-}
-
-void remove_food(CCpr *env, int grid_idx) {
- // Removes food from the grid and food_list
- env->grid[grid_idx] = EMPTY;
- FoodList *foods = env->foods;
- for (int i = 0; i < foods->size; i++) {
- if (foods->indexes[i] == grid_idx) {
- foods->indexes[i] = foods->indexes[foods->size - 1];
- foods->size--;
- return;
- }
- }
-}
-
-void init_foods(CCpr *env) {
- // On reset spawns x number of each food randomly.
- int available_tiles = (env->width * env->height) -
- (2 * env->vision * env->width +
- 2 * env->vision * (env->height - 2 * env->vision));
- int normalizer = (env->width * env->height) / 576;
- int normal = available_tiles / (20 * normalizer);
- int interactive = available_tiles / (50 * normalizer);
- for (int i = 0; i < normal; i++) {
- spawn_food(env, NORMAL_FOOD);
- }
- for (int i = 0; i < interactive; i++) {
- spawn_food(env, INTERACTIVE_FOOD);
- }
-}
-
-void spawn_foods(CCpr *env) {
- // After each step, check existing foods and spawns new food in the
- // neighborhood Iterates over food_list for efficiency instead of the entire
- // grid.
- FoodList *foods = env->foods;
- int original_size = foods->size;
- for (int i = 0; i < original_size; i++) {
- int idx = foods->indexes[i];
- int offset = idx - env->width - 1; // Food spawn in 1 radius
- int r = offset / env->width;
- int c = offset % env->width;
- for (int ri = 0; ri < 3; ri++) {
- for (int ci = 0; ci < 3; ci++) {
- int grid_idx = grid_index(env, (r + ri), (c + ci));
- if (env->grid[grid_idx] != EMPTY) {
- continue;
- }
- switch (env->grid[idx]) {
- // %Chance spawning new food
- case NORMAL_FOOD:
- if ((rand() / (double)RAND_MAX) < env->food_base_spawn_rate) {
- add_food(env, grid_idx, env->grid[idx]);
- }
- break;
- case INTERACTIVE_FOOD:
- if ((rand() / (double)RAND_MAX) <
- (env->food_base_spawn_rate / 10.0)) {
- add_food(env, grid_idx, env->grid[idx]);
- }
- break;
- }
- }
- }
- }
-
- // // Each turn there is random probability for a food to spawn at a random
- // // location To cope with resource depletion
- // int normalizer = (env->width * env->height) / 576;
- // if ((rand() / (double)RAND_MAX) <
- // min((env->food_base_spawn_rate * 2 * normalizer), 1e-2)) {
- // spawn_food(env, NORMAL_FOOD);
- // }
- // if ((rand() / (double)RAND_MAX) <
- // min((env->food_base_spawn_rate / 5.0 * normalizer), 5e-3)) {
- // spawn_food(env, INTERACTIVE_FOOD);
- // }
-}
-
-void compute_observations(CCpr *env) {
- // For full obs
- // memcpy(env->observations, env->grid,
- // env->width * env->height * sizeof(unsigned char));
- // return;
-
- // For partial obs
- for (int i = 0; i < env->num_agents; i++) {
- Agent *agent = &env->agents[i];
- // env->observations[env->vision_window*env->vision_window + i*env->obs_size] = agent->hp;
- if (agent->hp == 0) {
- continue;
- }
- int obs_offset = i * env->obs_size;
- int r_offset = agent->r - env->vision;
- int c_offset = agent->c - env->vision;
- for (int r = 0; r < 2 * env->vision + 1; r++) {
- for (int c = 0; c < 2 * env->vision + 1; c++) {
- int grid_idx = (r_offset + r) * env->width + c_offset + c;
- int obs_idx = obs_offset + r * env->vision_window + c;
- env->observations[obs_idx] = env->grid[grid_idx];
- }
- }
-
-
- }
-}
-
-void add_hp(CCpr *env, int agent_id, float hp) {
- Agent *agent = &env->agents[agent_id];
- agent->hp += hp;
- if (agent->hp > MAX_HP) {
- agent->hp = MAX_HP;
- } else if (agent->hp <= 0) {
- agent->hp = 0;
- env->agent_logs[agent->id].score += LOG_SCORE_REWARD_DEATH;
- reward_agent(env, agent_id, REWARD_DEATH);
- env->terminals[agent->id] = 1;
- add_log(env, &env->agent_logs[agent_id]);
- }
-}
-
-void remove_hp(CCpr *env, int agent_id, float hp) {
- add_hp(env, agent_id, -hp);
-}
-
-void save_grid_to_file(CCpr *env, const char *filename) {
- FILE *file = fopen(filename, "w");
- if (!file) {
- perror("Failed to open file");
- return;
- }
- fprintf(file, "#ifndef GRID_H\n#define GRID_H\n\n");
- fprintf(file, "#define GRID_HEIGHT %d\n", env->height);
- fprintf(file, "#define GRID_WIDTH %d\n\n", env->width);
- fprintf(file, "static const unsigned char grid[GRID_HEIGHT][GRID_WIDTH] = {\n");
-
- for (int r = 0; r < env->height; r++) {
- fprintf(file, " {");
- for (int c = 0; c < env->width; c++) {
- unsigned char val = env->grid[r * env->width + c];
- fprintf(file, "0x%02X%s", val, (c == env->width - 1) ? "" : ", ");
- }
- fprintf(file, "}%s\n", (r == env->height - 1) ? "" : ",");
- }
- fprintf(file, "};\n\n#endif // GRID_H\n");
- fclose(file);
-}
-
-void make_grid_from_scratch(CCpr *env){
- memset(env->grid, EMPTY, (env->height * env->width) * sizeof(env->grid[0]));
- // top walling
- for (int r = 0; r < env->vision; r++) {
- memset(env->grid + (r * env->width), WALL,
- env->width * sizeof(env->grid[0]));
- }
- // left side walling
- for (int r = 0; r < env->height; r++) {
- memset(env->grid + (r * env->width), WALL,
- env->vision * sizeof(env->grid[0]));
- }
- // bottom walling
- for (int r = env->height - env->vision; r < env->height; r++) {
- memset(env->grid + (r * env->width), WALL,
- env->width * sizeof(env->grid[0]));
- }
-
- // right side walling
- for (int r = 0; r < env->height; r++) {
- memset(env->grid + (r * env->width) + (env->width - env->vision), WALL,
- env->vision * sizeof(env->grid[0]));
- }
- save_grid_to_file(env, "grid.h");
-}
-
-void spawn_agent(CCpr *env, int i){
- Agent *agent = &env->agents[i];
- agent->id = i;
- agent->hp = 80;
- int adr = 0;
-
- bool allocated = false;
- while (!allocated) {
- adr = rand() % (env->height * env->width);
- if (env->grid[adr] == EMPTY) {
- int r = adr / env->width;
- int c = adr % env->width;
- agent->r = r;
- agent->c = c;
- allocated = true;
- }
- }
- assert(env->grid[adr] == EMPTY);
- env->grid[adr] = get_agent_tile_from_id(agent->id);
- env->agent_logs[i] = (Log){0};
-}
-void c_reset(CCpr *env) {
- env->tick = 0;
- memset(env->agent_logs, 0, env->num_agents * sizeof(Log));
- env->log = (Log){0};
- env->foods->size = 0;
- memset(env->foods->indexes, 0, env->width * env->height * sizeof(int));
- // make_grid_from_scratch(env);
- memcpy(env->grid, grid_32_32_3v, env->width * env->height * sizeof(unsigned char));
-
- for (int i = 0; i < env->num_agents; i++) {
- spawn_agent(env, i);
- }
-
- init_foods(env);
- memset(env->observations, 0, env->num_agents * env->obs_size * sizeof(unsigned char));
- //memset(env->truncations, 0, env->num_agents * sizeof(unsigned char));
- memset(env->terminals, 0, env->num_agents * sizeof(unsigned char));
- memset(env->masks, 1, env->num_agents * sizeof(unsigned char));
- compute_observations(env);
-}
-
-void reward_agents_near(CCpr *env, int food_index) {
- int food_r = food_index / env->width;
- int food_c = food_index % env->width;
-
- // TODO: could iterate over neighbors of food index and check if is agent
- // (remove iteration cost)
- for (int i = 0; i < env->num_agents; i++) {
- int ac = env->agents[i].c;
- int ar = env->agents[i].r;
-
- if ((ac == food_c && (ar == food_r - 1 || ar == food_r + 1)) ||
- (ar == food_r && (ac == food_c - 1 || ac == food_c + 1))) {
- reward_agent(env, i, env->interactive_food_reward);
- env->agent_logs[i].score += LOG_SCORE_REWARD_MEDIUM;
- add_hp(env, i, HP_REWARD_FOOD_MEDIUM);
- }
- }
- remove_food(env, food_index);
-}
-
-void step_agent(CCpr *env, int i) {
-
- Agent *agent = &env->agents[i];
-
- int action = env->actions[i];
-
- int dr = 0;
- int dc = 0;
-
- switch (action) {
- case 0:
- dr = -1;
- agent->direction = 3;
- break; // UP
- case 1:
- dr = 1;
- agent->direction = 1;
- break; // DOWN
- case 2:
- dc = -1;
- agent->direction = 2;
- break; // LEFT
- case 3:
- dc = 1;
- agent->direction = 0;
- break; // RIGHT
- case 4:
- return; // No moves
- }
- env->agent_logs[i].moves += 1;
-
- // Get next row and column
-
- int next_r = agent->r + dr;
- int next_c = agent->c + dc;
-
- int prev_grid_idx = grid_index(env, agent->r, agent->c);
- int next_grid_idx = env->width * next_r + next_c;
- int tile = env->grid[next_grid_idx];
-
- // Anything above should be obstacle
- // In this case the agent position does not change
- // We still have some checks to perform
- if (tile >= INTERACTIVE_FOOD) {
- env->agent_logs[i].score += LOG_SCORE_REWARD_MOVE;
- reward_agent(env, i, env->reward_move);
- next_r = agent->r;
- next_c = agent->c;
- next_grid_idx = env->width * next_r + next_c;
- tile = env->grid[next_grid_idx];
- }
- switch (tile) {
- case NORMAL_FOOD:
- reward_agent(env, i, env->reward_food);
- env->agent_logs[i].score += LOG_SCORE_REWARD_SMALL;
- add_hp(env, i, HP_REWARD_FOOD_SMALL);
- remove_food(env, next_grid_idx);
- break;
- case EMPTY:
- env->agent_logs[i].score += LOG_SCORE_REWARD_MOVE;
- reward_agent(env, i, env->reward_move);
- break;
- }
-
- // Interactive food logic
- int neighboors[4] = {
- grid_index(env, next_r - 1, next_c), // Up
- grid_index(env, next_r + 1, next_c), // Down
- grid_index(env, next_r, next_c + 1), // Right
- grid_index(env, next_r, next_c - 1) // Left
- };
-
- for (int j = 0; j < 4; j++) {
- int grid_idx = neighboors[j];
- // If neighbooring grid tile is interactive food
- if (env->grid[grid_idx] == INTERACTIVE_FOOD) {
- // If was already marked as "ready to collect"
- if (CHECK_BIT(env->interactive_food_agent_count, grid_idx)) {
- reward_agents_near(env, grid_idx);
- } else {
- // First agent detected
- SET_BIT(env->interactive_food_agent_count, grid_idx);
- }
- }
- }
-
- // update the grid tiles values
- int agent_tile = get_agent_tile_from_id(agent->id);
- env->grid[prev_grid_idx] = EMPTY;
- env->grid[next_grid_idx] = agent_tile;
- agent->r = next_r;
- agent->c = next_c;
-
- return;
-}
-
-void clear_agent(CCpr *env, int agent_id) {
- Agent *agent = &env->agents[agent_id];
- if (agent->r < 0 || agent->c < 0) {
- return;
- }
- int grid_idx = grid_index(env, agent->r, agent->c);
- env->grid[grid_idx] = EMPTY;
- agent->r = -1;
- agent->c = -1;
-}
-
-void c_step(CCpr *env) {
- env->tick++;
-
- memset(env->rewards, 0, env->num_agents * sizeof(float));
- memset(env->interactive_food_agent_count, 0,
- (env->width * env->height + 7) / 8);
-
- for (int i = 0; i < env->num_agents; i++) {
- if (env->agents[i].hp == 0) {
- env->masks[i] = 0;
- clear_agent(env, i);
- continue;
- }
- step_agent(env, i);
- remove_hp(env, i, HP_LOSS_PER_STEP);
- }
-
- spawn_foods(env);
-
- //We loop again here because in the future an entity might have attacked an agent in the process
- int alive_agents = 0;
- for (int i = 0; i < env->num_agents; i++) {
- if (env->agents[i].hp > 0) {
- env->agent_logs[i].alive_steps += 1;
- alive_agents += 1;
- if (env->agents[i].hp < 20) {
- reward_agent(env, i, REWARD_20_HP);
- env->agent_logs[i].score += REWARD_20_HP;
- } else if (env->agents[i].hp > 80) {
- reward_agent(env, i, REWARD_80_HP);
- env->agent_logs[i].score += REWARD_80_HP;
- }
- }
- // else {
- // int grid_idx = grid_index(env, env->agents[i].r, env->agents[i].c);
- // env->grid[grid_idx] = EMPTY;
- // spawn_agent(env, i);
- // }
- }
- /*
- if (alive_agents == 0) {
- env->agent_logs[i].moves = 0;
- }else{
- env->agent_logs[i].moves /= alive_agents;
- }
- env->agent_logs[i].food_nb = env->foods->size;
- env->agent_logs[i].alive_steps = env->tick;
- */
- env->log.food_nb = env->foods->size;
- compute_observations(env);
- if (alive_agents == 0 || env->tick > 1000) {
- c_reset(env);
- if (alive_agents == 0) {
- memset(env->terminals, 1, env->num_agents * sizeof(unsigned char));
- }
- }
-}
-
-// Raylib client
-Color COLORS[] = {
- (Color){255, 0, 0, 255}, (Color){170, 170, 170, 255},
- (Color){255, 255, 0, 255}, (Color){0, 255, 0, 255},
- (Color){0, 255, 255, 255}, (Color){0, 128, 255, 255},
- (Color){128, 128, 128, 255}, (Color){255, 0, 0, 255},
- (Color){255, 255, 255, 255}, (Color){255, 85, 85, 255},
- (Color){170, 170, 170, 255}, (Color){0, 255, 255, 255},
- (Color){0, 0, 255, 255}, (Color){6, 24, 24, 255},
-};
-
-Rectangle UV_COORDS[7] = {
- (Rectangle){0, 0, 0, 0}, (Rectangle){512, 0, 128, 128},
- (Rectangle){0, 0, 0, 0}, (Rectangle){0, 0, 128, 128},
- (Rectangle){128, 0, 128, 128}, (Rectangle){256, 0, 128, 128},
- (Rectangle){384, 0, 128, 128},
-};
-
-struct Renderer {
- int cell_size;
- int width;
- int height;
- Texture2D puffer;
-};
-
-Renderer *init_renderer(int cell_size, int width, int height) {
- Renderer *renderer = (Renderer *)calloc(1, sizeof(Renderer));
- renderer->cell_size = cell_size;
- renderer->width = width;
- renderer->height = height;
-
- InitWindow(width * cell_size, height * cell_size, "CPR");
- SetTargetFPS(10);
-
- renderer->puffer = LoadTexture("resources/shared/puffers_128.png");
- return renderer;
-}
-
-void close_renderer(Renderer *renderer) {
- CloseWindow();
- free(renderer);
-}
-
-void c_render(CCpr *env) {
- if (env->client == NULL) {
- env->client = init_renderer(32, env->width, env->height);
- };
- Renderer *renderer = env->client;
-
- if (IsKeyDown(KEY_ESCAPE)) {
- exit(0);
- }
-
- BeginDrawing();
- ClearBackground((Color){6, 24, 24, 255});
-
- int ts = renderer->cell_size;
- for (int r = 0; r < env->height; r++) {
- for (int c = 0; c < env->width; c++) {
- int adr = grid_index(env, r, c);
- int tile = env->grid[adr];
- if (tile == EMPTY) {
- continue;
- } else if (tile == WALL) {
- DrawRectangle(c * ts, r * ts, ts, ts, (Color){227, 227, 227, 255});
- } else if (tile == NORMAL_FOOD || tile == INTERACTIVE_FOOD) {
- DrawRectangle(c * ts, r * ts, ts, ts, COLORS[tile]);
- } else {
-
- int agent_id = get_agent_id_from_tile(tile);
- int col_id = agent_id % (sizeof(COLORS) / sizeof(COLORS[0]));
- Color color = COLORS[col_id];
- int starting_sprite_x = 0;
- float rotation = env->agents[agent_id].direction * 90.0f;
- if (rotation == 180) {
- starting_sprite_x = 128;
- rotation = 0;
- }
- Rectangle source_rect = (Rectangle){starting_sprite_x, 0, 128, 128};
- Rectangle dest_rect = (Rectangle){c * ts + ts/2, r * ts + ts/2, ts, ts};
- DrawTexturePro(renderer->puffer, source_rect, dest_rect,
- (Vector2){ts/2, ts/2}, rotation, color);
- }
- }
- }
- EndDrawing();
-}
diff --git a/pufferlib/ocean/cpr/cpr.py b/pufferlib/ocean/cpr/cpr.py
deleted file mode 100644
index bd2c78d77..000000000
--- a/pufferlib/ocean/cpr/cpr.py
+++ /dev/null
@@ -1,109 +0,0 @@
-import gymnasium
-import numpy as np
-
-import pufferlib
-from pufferlib.ocean.cpr import binding
-
-class PyCPR(pufferlib.PufferEnv):
- def __init__(self,
- num_envs=1,
- widths=[32],
- heights=[32],
- num_agents=[8],
- vision=3,
- reward_food=1.0,
- interactive_food_reward=5.0,
- reward_move=-0.01,
- food_base_spawn_rate=2e-3,
- report_interval=1,
- render_mode=None,
- buf=None,
- seed=0,
- ):
- widths = num_envs*widths
- heights = num_envs*heights
- num_agents = num_envs*num_agents
-
- self.single_observation_space = gymnasium.spaces.Box(low=0, high=255, shape=((2*vision+1)*(2*vision+1),), dtype=np.uint8)
- self.single_action_space = gymnasium.spaces.Discrete(5)
- self.render_mode = render_mode
- self.num_agents = sum(num_agents)
-
- self.tick = 0
- self.report_interval = report_interval
-
- super().__init__(buf)
- c_envs = []
- for i in range(num_envs):
- n = num_agents[i]
- env_id = binding.env_init(
- self.observations[i*n:(i+1)*n],
- self.actions[i*n:(i+1)*n],
- self.rewards[i*n:(i+1)*n],
- self.terminals[i*n:(i+1)*n],
- self.truncations[i*n:(i+1)*n],
- i + seed * num_envs,
- width=widths[i],
- height=heights[i],
- num_agents=num_agents[i],
- vision=vision,
- reward_food=reward_food,
- interactive_food_reward=interactive_food_reward,
- reward_move=reward_move,
- food_base_spawn_rate=food_base_spawn_rate,
- )
- c_envs.append(env_id)
-
- self.c_envs = binding.vectorize(*c_envs)
-
- def reset(self, seed=None):
- self.tick = 0
- binding.vec_reset(self.c_envs, seed)
- return self.observations, []
-
- def step(self, actions):
- self.actions[:] = actions
- binding.vec_step(self.c_envs)
- self.tick += 1
-
- info = []
- if self.tick % self.report_interval == 0:
- log = binding.vec_log(self.c_envs)
- if log:
- info.append(log)
-
- return (self.observations, self.rewards, self.terminals, self.truncations, info)
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-if __name__ == "__main__":
- env = PyCPR()
- env.reset()
- tick = 0
- timeout=30
-
- tot_agents = env.num_agents
- actions = np.random.randint(0,5,(1024,tot_agents))
-
- import time
- start = time.time()
- # while time.time() - start < timeout:
- while tick < 500:
- atns = actions[tick % 1024]
- env.step(atns)
- if -1 in env.rewards:
- breakpoint()
- # env.render()
- tick += 1
-
- print(f'SPS: {int(tot_agents * tick / (time.time() - start)):_}')
-
- env.close()
-
-
-
-
diff --git a/pufferlib/ocean/cpr/grid.h b/pufferlib/ocean/cpr/grid.h
deleted file mode 100644
index 768299966..000000000
--- a/pufferlib/ocean/cpr/grid.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef GRID_H
-#define GRID_H
-
-#define GRID_HEIGHT 32
-#define GRID_WIDTH 32
-
-static const unsigned char grid_32_32_3v[GRID_HEIGHT][GRID_WIDTH] = {
- {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03},
- {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03}
-};
-
-#endif // GRID_H
diff --git a/pufferlib/ocean/drive/README.md b/pufferlib/ocean/drive/README.md
new file mode 100644
index 000000000..a37907b20
--- /dev/null
+++ b/pufferlib/ocean/drive/README.md
@@ -0,0 +1,108 @@
+# PufferDrive
+
+This readme contains several important assumptions and definions about the `PufferDrive` environment.
+
+## Agent initialization and control
+
+### `init_mode`
+
+Determines which agents are **created** in the environment.
+
+| Option | Description |
+| ------------------------ | ---------------------------------------------------------------------------- |
+| `create_all_valid` | Create all entities valid at initialization (`traj_valid[init_steps] == 1`). |
+| `create_only_controlled` | Create only those agents that are controlled by the policy. |
+
+### `control_mode`
+
+Determines which created agents are **controlled** by the policy.
+
+| Option | Description |
+| ----------------------------------------- | ------------------------------------------------------------------------------------------------- |
+| `control_vehicles` (default) | Control only valid **vehicles** (not experts, beyond `MIN_DISTANCE_TO_GOAL`, under `MAX_AGENTS`). |
+| `control_agents` | Control all valid **agent types** (vehicles, cyclists, pedestrians). |
+| `control_tracks_to_predict` *(WOMD only)* | Control agents listed in the `tracks_to_predict` metadata. |
+
+
+## Termination conditions (`done`)
+
+Episodes are never truncated before reaching `episode_len`. The `goal_behavior` argument controls agent behavior after reaching a goal early:
+
+* **`goal_behavior=0` (default):** Agents respawn at their initial position after reaching their goal (last valid log position).
+* **`goal_behavior=1`:** Agents receive new goals indefinitely after reaching each goal.
+* **`goal_behavior=2`:** Agents stop after reaching their goal.
+
+## Logged performance metrics
+
+We record multiple performance metrics during training, aggregated over all *active agents* (alive and controlled). Key metrics include:
+
+- `score`: Goals reached cleanly (goal was achieved without collision or going off-road)
+- `collision_rate`: Binary flag (0 or 1) if agent hit another vehicle.
+- `offroad_rate`: Binary flag (0 or 1) if agent left road bounds.
+- `completion_rate`: Whether the agent reached its goal in this episode (even if it collided or went off-road).
+
+
+### Metric aggregation
+
+The `num_agents` parameter in `drive.ini` defines the total number of agents used to collect experience.
+At runtime, **Puffer** uses `num_maps` to create enough environments to populate the buffer with `num_agents`, distributing them evenly across `num_envs`.
+
+Because agents are respawned immediately after reaching their goal, they remain active throughout the episode.
+
+At the end of each episode (i.e., when `timestep == TRAJECTORY_LENGTH`), metrics are logged once via:
+
+```C
+if (env->timestep == TRAJECTORY_LENGTH) {
+ add_log(env);
+ c_reset(env);
+ return;
+}
+```
+
+Metrics are normalized and aggregated in `vec_log` (`pufferlib/ocean/env_binding.h`). They are averaged over all active agents across all environments. For example, the aggregated collision rate is computed as:
+
+$$
+r^{agg}_{\text{collision}} = \frac{\mathbb{I}[\text{collided in episode}]}{N}
+$$
+
+where $N$ is the number of controlled agents.
+This value represents the fraction of agents that collided at least once during the episode. So, cases **A** and **B** below would yield identical off-road and collision rates:
+
+
+
+Since these metrics do not capture *multiple* events per agent, we additionally log the **average number of collision and off-road events per episode**. This is computed as:
+
+$$
+c^{avg}_{\text{collision}} = \frac{\text{total number of collision events across all agents and environments}}{N}
+$$
+
+where $N$ is the total number of controlled agents.
+For example, an `avg_collisions_per_agent` value of 4 indicates that, on average, each agent collides four times per episode.
+
+### Effect of respawning on metrics
+
+By default, agents are reset to their initial position when they reach their goal before the episode ends. Upon respawn, `respawn_timestep` is updated from `-1` to the current step index.
+
+This raises the question: **how does repeated respawning affect aggregated metrics?**
+
+To begin, note that the environment is a bit different before and after respawn. After an agent respawns, all other agents are "removed" from the environment. As a result, collisions with other agents cannot occur post-respawn.
+
+This effectively transforms the scenario into a single-agent environment, simplifying the task since the agent no longer needs to coordinate with others.
+
+
+
+#### `score`
+
+Consider an episode of 91 steps where an agent is initialized relatively close to the goal position and reaches its goal three times:
+
+1. **First attempt:** reaches the goal without collisions
+2. **Second attempt:** reaches the goal without collisions
+3. **Third attempt:** reaches the goal but goes off-road along the way
+
+
+
+The highlighted trajectory shows the first attempt. In this case, the recorded score is `0.0` — a single off-road event invalidates the score for the entire episode. This behavior is desired: the score metric is unforgiving.
+
+#### `offroad_rate` and `collision_rate`
+
+Same logic holds as above.
diff --git a/pufferlib/ocean/drive/binding.c b/pufferlib/ocean/drive/binding.c
index 45fed372e..1edd05bc4 100644
--- a/pufferlib/ocean/drive/binding.c
+++ b/pufferlib/ocean/drive/binding.c
@@ -70,11 +70,16 @@ static int my_put(Env* env, PyObject* args, PyObject* kwargs) {
static PyObject* my_shared(PyObject* self, PyObject* args, PyObject* kwargs) {
int num_agents = unpack(kwargs, "num_agents");
int num_maps = unpack(kwargs, "num_maps");
+ int init_mode = unpack(kwargs, "init_mode");
+ int control_mode = unpack(kwargs, "control_mode");
+ int init_steps = unpack(kwargs, "init_steps");
+ int goal_behavior = unpack(kwargs, "goal_behavior");
clock_gettime(CLOCK_REALTIME, &ts);
srand(ts.tv_nsec);
int total_agent_count = 0;
int env_count = 0;
int max_envs = num_agents;
+ int maps_checked = 0;
PyObject* agent_offsets = PyList_New(max_envs+1);
PyObject* map_ids = PyList_New(max_envs);
// getting env count
@@ -82,9 +87,96 @@ static PyObject* my_shared(PyObject* self, PyObject* args, PyObject* kwargs) {
char map_file[100];
int map_id = rand() % num_maps;
Drive* env = calloc(1, sizeof(Drive));
+ env->init_mode = init_mode;
+ env->control_mode = control_mode;
+ env->init_steps = init_steps;
+ env->goal_behavior = goal_behavior;
sprintf(map_file, "resources/drive/binaries/map_%03d.bin", map_id);
load_map_binary(map_file, env);
+
+ // Skip map if it contains traffic lights
+ bool has_traffic_light = false;
+ for(int j=0; jnum_traffic_elements; j++) {
+ if(env->traffic_elements[j].type == TRAFFIC_LIGHT) {
+ has_traffic_light = true;
+ break;
+ }
+ }
+ if(has_traffic_light) {
+ maps_checked++;
+
+ // Safeguard: if we've checked all available maps and all have traffic lights, raise an error
+ if(maps_checked >= num_maps) {
+ for(int j=0;jnum_total_agents;j++) free_agent(&env->agents[j]);
+ for (int j=0;jnum_road_elements;j++) free_road_element(&env->road_elements[j]);
+ for (int j=0;jnum_traffic_elements;j++) free_traffic_element(&env->traffic_elements[j]);
+ free(env->agents);
+ free(env->road_elements);
+ free(env->traffic_elements);
+ free(env->active_agent_indices);
+ free(env->static_agent_indices);
+ free(env->expert_static_agent_indices);
+ free(env);
+ Py_DECREF(agent_offsets);
+ Py_DECREF(map_ids);
+ char error_msg[256];
+ sprintf(error_msg, "All %d available maps contain traffic lights which are not supported", num_maps);
+ PyErr_SetString(PyExc_ValueError, error_msg);
+ return NULL;
+ }
+
+ for(int j=0;jnum_total_agents;j++) free_agent(&env->agents[j]);
+ for (int j=0;jnum_road_elements;j++) free_road_element(&env->road_elements[j]);
+ for (int j=0;jnum_traffic_elements;j++) free_traffic_element(&env->traffic_elements[j]);
+ free(env->agents);
+ free(env->road_elements);
+ free(env->traffic_elements);
+ free(env->active_agent_indices);
+ free(env->static_agent_indices);
+ free(env->expert_static_agent_indices);
+ free(env);
+ continue;
+ }
+
set_active_agents(env);
+
+ // Skip map if it doesn't contain any controllable agents
+ if(env->active_agent_count == 0) {
+ maps_checked++;
+
+ // Safeguard: if we've checked all available maps and found no active agents, raise an error
+ if(maps_checked >= num_maps) {
+ for(int j=0;jnum_total_agents;j++) free_agent(&env->agents[j]);
+ for (int j=0;jnum_road_elements;j++) free_road_element(&env->road_elements[j]);
+ for (int j=0;jnum_traffic_elements;j++) free_traffic_element(&env->traffic_elements[j]);
+ free(env->agents);
+ free(env->road_elements);
+ free(env->traffic_elements);
+ free(env->active_agent_indices);
+ free(env->static_agent_indices);
+ free(env->expert_static_agent_indices);
+ free(env);
+ Py_DECREF(agent_offsets);
+ Py_DECREF(map_ids);
+ char error_msg[256];
+ sprintf(error_msg, "No controllable agents found in any of the %d available maps", num_maps);
+ PyErr_SetString(PyExc_ValueError, error_msg);
+ return NULL;
+ }
+
+ for(int j=0;jnum_total_agents;j++) free_agent(&env->agents[j]);
+ for (int j=0;jnum_road_elements;j++) free_road_element(&env->road_elements[j]);
+ for (int j=0;jnum_traffic_elements;j++) free_traffic_element(&env->traffic_elements[j]);
+ free(env->agents);
+ free(env->road_elements);
+ free(env->traffic_elements);
+ free(env->active_agent_indices);
+ free(env->static_agent_indices);
+ free(env->expert_static_agent_indices);
+ free(env);
+ continue;
+ }
+
// Store map_id
PyObject* map_id_obj = PyLong_FromLong(map_id);
PyList_SetItem(map_ids, env_count, map_id_obj);
@@ -93,19 +185,18 @@ static PyObject* my_shared(PyObject* self, PyObject* args, PyObject* kwargs) {
PyList_SetItem(agent_offsets, env_count, offset);
total_agent_count += env->active_agent_count;
env_count++;
- for(int i = 0; i < env->num_objects; i++){
- free_entity(&env->entities[i]);
- }
- free(env->entities);
- for(int i = 0; i < env->num_roads; i++){
- free_map_entity(&env->map_entities[i]);
- }
- free(env->map_entities);
+ for(int j=0;jnum_total_agents;j++) free_agent(&env->agents[j]);
+ for (int j=0;jnum_road_elements;j++) free_road_element(&env->road_elements[j]);
+ for (int j=0;jnum_traffic_elements;j++) free_traffic_element(&env->traffic_elements[j]);
+ free(env->agents);
+ free(env->road_elements);
+ free(env->traffic_elements);
free(env->active_agent_indices);
- free(env->static_car_indices);
- free(env->expert_static_car_indices);
+ free(env->static_agent_indices);
+ free(env->expert_static_agent_indices);
free(env);
}
+ //printf("Generated %d environments to cover %d agents (requested %d agents)\n", env_count, total_agent_count, num_agents);
if(total_agent_count >= num_agents){
total_agent_count = num_agents;
}
@@ -115,59 +206,68 @@ static PyObject* my_shared(PyObject* self, PyObject* args, PyObject* kwargs) {
// resize lists
PyObject* resized_agent_offsets = PyList_GetSlice(agent_offsets, 0, env_count + 1);
PyObject* resized_map_ids = PyList_GetSlice(map_ids, 0, env_count);
- //
- //Py_DECREF(agent_offsets);
- //Py_DECREF(map_ids);
- // create a tuple
PyObject* tuple = PyTuple_New(3);
PyTuple_SetItem(tuple, 0, resized_agent_offsets);
PyTuple_SetItem(tuple, 1, resized_map_ids);
PyTuple_SetItem(tuple, 2, final_env_count);
return tuple;
-
- //Py_DECREF(num);
- /*
- for(int i = 0;ihuman_agent_idx = unpack(kwargs, "human_agent_idx");
- env->reward_vehicle_collision = unpack(kwargs, "reward_vehicle_collision");
- env->reward_offroad_collision = unpack(kwargs, "reward_offroad_collision");
- env->reward_goal_post_respawn = unpack(kwargs, "reward_goal_post_respawn");
- env->reward_vehicle_collision_post_respawn = unpack(kwargs, "reward_vehicle_collision_post_respawn");
- env->spawn_immunity_timer = unpack(kwargs, "spawn_immunity_timer");
+ env->ini_file = unpack_str(kwargs, "ini_file");
+ env_init_config conf = {0};
+ if(ini_parse(env->ini_file, handler, &conf) < 0) {
+ printf("Error while loading %s", env->ini_file);
+ }
+ if (kwargs && PyDict_GetItemString(kwargs, "scenario_length")) {
+ conf.scenario_length = (int)unpack(kwargs, "scenario_length");
+ }
+ if (conf.scenario_length <= 0) {
+ PyErr_SetString(PyExc_ValueError, "scenario_length must be > 0 (set in INI or kwargs)");
+ return -1;
+ }
+ env->action_type = conf.action_type;
+ env->dynamics_model = conf.dynamics_model;
+ env->reward_vehicle_collision = conf.reward_vehicle_collision;
+ env->reward_offroad_collision = conf.reward_offroad_collision;
+ env->reward_goal = conf.reward_goal;
+ env->reward_goal_post_respawn = conf.reward_goal_post_respawn;
+ env->reward_ade = conf.reward_ade;
+ env->scenario_length = conf.scenario_length;
+ env->collision_behavior = conf.collision_behavior;
+ env->offroad_behavior = conf.offroad_behavior;
+ env->max_controlled_agents = unpack(kwargs, "max_controlled_agents");
+ env->dt = conf.dt;
+ env->init_mode = (int)unpack(kwargs, "init_mode");
+ env->control_mode = (int)unpack(kwargs, "control_mode");
+ env->goal_behavior = (int)unpack(kwargs, "goal_behavior");
+ env->goal_radius = (float)unpack(kwargs, "goal_radius");
int map_id = unpack(kwargs, "map_id");
int max_agents = unpack(kwargs, "max_agents");
-
+ int init_steps = unpack(kwargs, "init_steps");
char map_file[100];
sprintf(map_file, "resources/drive/binaries/map_%03d.bin", map_id);
- env->num_agents = max_agents;
+ env->num_max_agents = max_agents;
env->map_name = strdup(map_file);
+ env->init_steps = init_steps;
+ env->timestep = init_steps;
init(env);
return 0;
}
static int my_log(PyObject* dict, Log* log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "episode_length", log->episode_length);
+ assign_to_dict(dict, "n", log->n);
assign_to_dict(dict, "offroad_rate", log->offroad_rate);
+ assign_to_dict(dict, "episode_length", log->episode_length);
assign_to_dict(dict, "collision_rate", log->collision_rate);
+ assign_to_dict(dict, "episode_return", log->episode_return);
assign_to_dict(dict, "dnf_rate", log->dnf_rate);
- assign_to_dict(dict, "n", log->n);
+ assign_to_dict(dict, "avg_displacement_error", log->avg_displacement_error);
assign_to_dict(dict, "completion_rate", log->completion_rate);
- assign_to_dict(dict, "clean_collision_rate", log->clean_collision_rate);
+ assign_to_dict(dict, "lane_alignment_rate", log->lane_alignment_rate);
+ assign_to_dict(dict, "score", log->score);
+ assign_to_dict(dict, "avg_offroad_per_agent", log->avg_offroad_per_agent);
+ assign_to_dict(dict, "avg_collisions_per_agent", log->avg_collisions_per_agent);
return 0;
}
diff --git a/pufferlib/ocean/drive/datatypes.h b/pufferlib/ocean/drive/datatypes.h
new file mode 100644
index 000000000..ff9b37e5d
--- /dev/null
+++ b/pufferlib/ocean/drive/datatypes.h
@@ -0,0 +1,212 @@
+#define UNKNOWN 0
+
+// -- AGENT TYPE
+#define VEHICLE 1
+#define PEDESTRIAN 2
+#define CYCLIST 3
+#define OTHER 4
+
+// -- ROAD TYPE
+#define LANE_FREEWAY 1
+#define LANE_SURFACE_STREET 2
+#define LANE_BIKE_LANE 3
+
+#define ROAD_LINE_UNKNOWN 10
+#define ROAD_LINE_BROKEN_SINGLE_WHITE 11
+#define ROAD_LINE_SOLID_SINGLE_WHITE 12
+#define ROAD_LINE_SOLID_DOUBLE_WHITE 13
+#define ROAD_LINE_BROKEN_SINGLE_YELLOW 14
+#define ROAD_LINE_BROKEN_DOUBLE_YELLOW 15
+#define ROAD_LINE_SOLID_SINGLE_YELLOW 16
+#define ROAD_LINE_SOLID_DOUBLE_YELLOW 17
+#define ROAD_LINE_PASSING_DOUBLE_YELLOW 18
+
+#define ROAD_EDGE_UNKNOWN 20
+#define ROAD_EDGE_BOUNDARY 21
+#define ROAD_EDGE_MEDIAN 22
+#define ROAD_EDGE_SIDEWALK 23
+
+#define CROSSWALK 31
+#define SPEED_BUMP 32
+#define DRIVEWAY 33
+
+// -- TRAFFIC CONTROL TYPE
+#define TRAFFIC_LIGHT 1
+#define STOP_SIGN 2
+#define YIELD_SIGN 3
+#define SPEED_LIMIT_SIGN 4
+
+
+int is_road_lane(int type){
+ return (type >= 0 && type <= 9);
+}
+
+int is_drivable_road_lane(int type){
+ return (type == LANE_FREEWAY || type == LANE_SURFACE_STREET);
+}
+
+int is_road_line(int type){
+ return (type >= 10 && type <= 19);
+}
+
+int is_road_edge(int type){
+ return (type >= 20 && type <= 29);
+}
+
+int is_road(int type){
+ return is_road_lane(type) || is_road_line(type) || is_road_edge(type);
+}
+
+int is_controllable_agent(int type){
+ return (type == VEHICLE || type == PEDESTRIAN || type == CYCLIST);
+}
+
+int normalize_road_type(int type){
+ if(is_road_lane(type)){
+ return 0;
+ } else if(is_road_line(type)){
+ return 1;
+ } else if(is_road_edge(type)){
+ return 2;
+ } else {
+ return -1;
+ }
+}
+
+int unnormalize_road_type(int norm_type){
+ if(norm_type == 0){
+ return LANE_SURFACE_STREET;
+ } else if(norm_type == 1){
+ return ROAD_LINE_BROKEN_SINGLE_WHITE;
+ } else if(norm_type == 2){
+ return ROAD_EDGE_BOUNDARY;
+ } else {
+ return -1; // Invalid
+ }
+}
+
+
+
+struct Agent {
+ int id;
+ int type;
+
+ // Log trajectory
+ int trajectory_length;
+ float* log_trajectory_x;
+ float* log_trajectory_y;
+ float* log_trajectory_z;
+ float* log_heading;
+ float* log_velocity_x;
+ float* log_velocity_y;
+ float* log_length;
+ float* log_width;
+ float* log_height;
+ int* log_valid;
+
+ // Simulation state
+ float sim_x;
+ float sim_y;
+ float sim_z;
+ float sim_heading;
+ float sim_vx;
+ float sim_vy;
+ float sim_length;
+ float sim_width;
+ float sim_height;
+ int sim_valid;
+
+ // Route information
+ int route_length;
+ int* route;
+
+ // Metrics and status tracking
+ int collision_state;
+ float metrics_array[5]; // [collision, offroad, reached_goal, lane_aligned, avg_displacement_error]
+ int current_lane_idx;
+ int collided_before_goal;
+ int sampled_new_goal;
+ int reached_goal_this_episode;
+ int num_goals_reached;
+ int active_agent;
+ int mark_as_expert;
+ float cumulative_displacement;
+ int displacement_sample_count;
+
+ // Goal positions
+ float goal_position_x;
+ float goal_position_y;
+ float goal_position_z;
+ float init_goal_x; // Initialized from goal_position
+ float init_goal_y; // Initialized from goal_position
+
+ // Respawn tracking
+ int respawn_timestep;
+ int respawn_count;
+
+ int stopped; // 0/1 -> freeze if set
+ int removed; //0/1 -> remove from sim if set
+
+ // Jerk dynamics
+ float a_long;
+ float a_lat;
+ float jerk_long;
+ float jerk_lat;
+ float steering_angle;
+ float wheelbase;
+};
+
+struct RoadMapElement {
+ int id;
+ int type;
+
+ int segment_length;
+ float* x;
+ float* y;
+ float* z;
+
+ // Lane specific info
+ int num_entries;
+ int* entry_lanes;
+ int num_exits;
+ int* exit_lanes;
+ float speed_limit;
+};
+
+struct TrafficControlElement {
+ int id;
+ int type;
+
+ int state_length;
+ int* states;
+ float x;
+ float y;
+ float z;
+ int controlled_lane;
+};
+
+void free_agent(struct Agent* agent){
+ free(agent->log_trajectory_x);
+ free(agent->log_trajectory_y);
+ free(agent->log_trajectory_z);
+ free(agent->log_heading);
+ free(agent->log_velocity_x);
+ free(agent->log_velocity_y);
+ free(agent->log_length);
+ free(agent->log_width);
+ free(agent->log_height);
+ free(agent->log_valid);
+ free(agent->route);
+}
+
+void free_road_element(struct RoadMapElement* element){
+ free(element->x);
+ free(element->y);
+ free(element->z);
+ free(element->entry_lanes);
+ free(element->exit_lanes);
+}
+
+void free_traffic_element(struct TrafficControlElement* element){
+ free(element->states);
+}
diff --git a/pufferlib/ocean/drive/docs/imgs/available_launch_configs.png b/pufferlib/ocean/drive/docs/imgs/available_launch_configs.png
new file mode 100644
index 000000000..632dba19d
Binary files /dev/null and b/pufferlib/ocean/drive/docs/imgs/available_launch_configs.png differ
diff --git a/pufferlib/ocean/drive/docs/imgs/breakpoint_list.png b/pufferlib/ocean/drive/docs/imgs/breakpoint_list.png
new file mode 100644
index 000000000..fb31b3190
Binary files /dev/null and b/pufferlib/ocean/drive/docs/imgs/breakpoint_list.png differ
diff --git a/pufferlib/ocean/drive/docs/imgs/debugger_output.png b/pufferlib/ocean/drive/docs/imgs/debugger_output.png
new file mode 100644
index 000000000..67802c621
Binary files /dev/null and b/pufferlib/ocean/drive/docs/imgs/debugger_output.png differ
diff --git a/pufferlib/ocean/drive/docs/imgs/find_the_debugger_interface.png b/pufferlib/ocean/drive/docs/imgs/find_the_debugger_interface.png
new file mode 100644
index 000000000..313722ffb
Binary files /dev/null and b/pufferlib/ocean/drive/docs/imgs/find_the_debugger_interface.png differ
diff --git a/pufferlib/ocean/drive/docs/setup_your_debugger.md b/pufferlib/ocean/drive/docs/setup_your_debugger.md
new file mode 100644
index 000000000..f465099e1
--- /dev/null
+++ b/pufferlib/ocean/drive/docs/setup_your_debugger.md
@@ -0,0 +1,149 @@
+# Setting Up a C/Python Debugger for PufferAI
+
+Debuggers are extremely useful tools. They let you step through code
+instruction by instruction and observe how variables change over time.
+This makes it much easier to understand confusing parts of the codebase
+and avoids relying solely on your internal "world model" of what the
+code *should* do. Debuggers also eliminate the need for excessive
+`print` statements, which are tedious to manage and clean up afterward.
+
+If you want a general introduction to debuggers, I recommend watching a
+beginner-friendly [vscode debugger tutorial video](https://www.youtube.com/watch?v=3HiLLByBWkg) on YouTube.
+
+> **Disclaimer:**\
+> This guide was written by a beginner who tried this setup and
+> succeeded. If you know better methods or improvements, please feel
+> free to contribute!
+
+------------------------------------------------------------------------
+
+## Overview
+
+Setting up a Python debugger is straightforward, and plenty of guides
+exist online.\
+However, debugging a Python application that spawns **multiple C/C++
+threads**, such as PufferAI environments, requires a bit more care.
+
+This guide is for **Unix-based systems (e.g., Ubuntu)** using
+**VSCode**, which seems to be the default in the lab.
+
+At a high level, our goal is to:
+
+1. Install the tools needed to trace C/C++ code.
+2. Set up VSCode to launch Python under `gdb`.
+3. Tell VSCode which Python module to run.
+4. Configure `gdb` to follow the child C++ processes spawned by Python.
+
+------------------------------------------------------------------------
+
+## 1. Install `gdb`
+
+We'll start by installing the GNU Debugger:
+
+``` bash
+sudo apt update && sudo apt install -y gdb
+which gdb # expect: /usr/bin/gdb
+gdb --version
+```
+
+------------------------------------------------------------------------
+
+## 2. Configure VSCode
+
+Inside your **PufferDrive** directory, create a `.vscode` folder:
+
+``` bash
+mkdir PufferDrive/.vscode
+```
+
+Now create a file called **`launch.json`** with the following content:
+
+``` jsonc
+{
+ "configurations": [
+ // --- Python debugger only ---
+ {
+ "name": "Python: Debug puffer train puffer_drive",
+ "type": "python",
+ "request": "launch",
+ "module": "pufferlib.pufferl",
+ "args": ["train", "puffer_drive"],
+ "cwd": "${workspaceFolder}",
+ "python": "/home/ricky/git/PufferDrive/.venv/bin/python", // <- TODO: point to your python interpreter
+ "justMyCode": false,
+ "env": {
+ "PYTHONPATH": "${workspaceFolder}"
+ }
+ },
+
+ // --- Python running under gdb (C/C++ breakpoints work) ---
+ {
+ "name": "C (gdb): Debug C inside puffer_drive",
+ "type": "cppdbg",
+ "request": "launch",
+ "program": "/home/ricky/git/PufferDrive/.venv/bin/python", // <- TODO: point to your python interpreter
+ "args": ["-m", "pufferlib.pufferl", "train", "puffer_drive"],
+ "cwd": "${workspaceFolder}",
+ "MIMode": "gdb",
+
+ "miDebuggerPath": "/usr/bin/gdb", // <- TODO: point to your gdb path (see previous step to check the path)
+
+ "externalConsole": false,
+ "stopAtEntry": false,
+ "env": { "PYTHONPATH": "${workspaceFolder}" },
+
+ "setupCommands": [
+ { "text": "set breakpoint pending on" },
+ { "text": "set follow-fork-mode child" }
+ ]
+ }
+ ]
+}
+```
+
+**Notes**
+
+- The first configuration is the standard Python debugger.
+- The second runs Python **inside `gdb`**, enabling C/C++
+ breakpoints.
+- The `"follow-fork-mode child"` line is crucial---PufferAI
+ environments spawn child processes that must be traced.
+
+------------------------------------------------------------------------
+
+## 3. Using the Debugger
+
+### Setting Breakpoints
+
+Open the C/C++ file you want to inspect in VSCode.\
+Click to the left of any line to place a breakpoint (a red dot).\
+VSCode will pause execution when that line is reached.
+
+### Opening the Debug Panel
+
+Open the debugger sidebar in VSCode:
+
+
+
+### Selecting the Debugger Configuration
+
+Use the dropdown to select: **"C (gdb): Debug C inside puffer_drive"**
+
+
+
+At the lower left, you should now see your list of breakpoints.\
+You can check/uncheck each one to enable or disable it:
+
+
+
+### Example Debugger Output
+
+Here is an example of what a debug session may look like:
+
+
+
+- The yellow arrow around the red dot on the left of the code editor highlights the point at which the code paused.
+- On the top left you have a "Variables" tab that allows you to explore all existing variables and their values.
+- Underneath, the "Watch" section lets you write simple code expression that manipulate the existing variables and print the output.
+
+For more information on how to then move forward to the next breakpoint, step only the next code instruction etc. I refer you to the [vscode debugger tutorial video](https://www.youtube.com/watch?v=3HiLLByBWkg).
diff --git a/pufferlib/ocean/drive/drive.c b/pufferlib/ocean/drive/drive.c
index f2537d265..4b2645836 100644
--- a/pufferlib/ocean/drive/drive.c
+++ b/pufferlib/ocean/drive/drive.c
@@ -1,244 +1,65 @@
-#include
-#include
#include "drive.h"
-#include "puffernet.h"
+#include "drivenet.h"
+#include
+#include "../env_config.h"
-typedef struct DriveNet DriveNet;
-struct DriveNet {
- int num_agents;
- float* obs_self;
- float* obs_partner;
- float* obs_road;
- float* partner_linear_output;
- float* road_linear_output;
- float* partner_layernorm_output;
- float* road_layernorm_output;
- float* partner_linear_output_two;
- float* road_linear_output_two;
- Linear* ego_encoder;
- Linear* road_encoder;
- Linear* partner_encoder;
- LayerNorm* ego_layernorm;
- LayerNorm* road_layernorm;
- LayerNorm* partner_layernorm;
- Linear* ego_encoder_two;
- Linear* road_encoder_two;
- Linear* partner_encoder_two;
- MaxDim1* partner_max;
- MaxDim1* road_max;
- CatDim1* cat1;
- CatDim1* cat2;
- GELU* gelu;
- Linear* shared_embedding;
- ReLU* relu;
- LSTM* lstm;
- Linear* actor;
- Linear* value_fn;
- Multidiscrete* multidiscrete;
-};
+// Use this test if the network changes to ensure that the forward pass
+// matches the torch implementation to the 3rd or ideally 4th decimal place
+void test_drivenet() {
+ int num_obs = 1848;
+ int num_actions = 2;
+ int num_agents = 4;
-DriveNet* init_drivenet(Weights* weights, int num_agents) {
- DriveNet* net = calloc(1, sizeof(DriveNet));
- int hidden_size = 256;
- int input_size = 64;
-
- net->num_agents = num_agents;
- net->obs_self = calloc(num_agents*7, sizeof(float)); // 7 features
- net->obs_partner = calloc(num_agents*63*7, sizeof(float)); // 63 objects, 7 features
- net->obs_road = calloc(num_agents*200*13, sizeof(float)); // 200 objects, 13 features
- net->partner_linear_output = calloc(num_agents*63*input_size, sizeof(float));
- net->road_linear_output = calloc(num_agents*200*input_size, sizeof(float));
- net->partner_linear_output_two = calloc(num_agents*63*input_size, sizeof(float));
- net->road_linear_output_two = calloc(num_agents*200*input_size, sizeof(float));
- net->partner_layernorm_output = calloc(num_agents*63*input_size, sizeof(float));
- net->road_layernorm_output = calloc(num_agents*200*input_size, sizeof(float));
- net->ego_encoder = make_linear(weights, num_agents, 7, input_size);
- net->ego_layernorm = make_layernorm(weights, num_agents, input_size);
- net->ego_encoder_two = make_linear(weights, num_agents, input_size, input_size);
- net->road_encoder = make_linear(weights, num_agents, 13, input_size);
- net->road_layernorm = make_layernorm(weights, num_agents, input_size);
- net->road_encoder_two = make_linear(weights, num_agents, input_size, input_size);
- net->partner_encoder = make_linear(weights, num_agents, 7, input_size);
- net->partner_layernorm = make_layernorm(weights, num_agents, input_size);
- net->partner_encoder_two = make_linear(weights, num_agents, input_size, input_size);
- net->partner_max = make_max_dim1(num_agents, 63, input_size);
- net->road_max = make_max_dim1(num_agents, 200, input_size);
- net->cat1 = make_cat_dim1(num_agents, input_size, input_size);
- net->cat2 = make_cat_dim1(num_agents, input_size + input_size, input_size);
- net->gelu = make_gelu(num_agents, 3*input_size);
- net->shared_embedding = make_linear(weights, num_agents, input_size*3, hidden_size);
- net->relu = make_relu(num_agents, hidden_size);
- net->actor = make_linear(weights, num_agents, hidden_size, 20);
- net->value_fn = make_linear(weights, num_agents, hidden_size, 1);
- net->lstm = make_lstm(weights, num_agents, hidden_size, 256);
- memset(net->lstm->state_h, 0, num_agents*256*sizeof(float));
- memset(net->lstm->state_c, 0, num_agents*256*sizeof(float));
- int logit_sizes[2] = {7, 13};
- net->multidiscrete = make_multidiscrete(num_agents, logit_sizes, 2);
- return net;
-}
-
-void free_drivenet(DriveNet* net) {
- free(net->obs_self);
- free(net->obs_partner);
- free(net->obs_road);
- free(net->partner_linear_output);
- free(net->road_linear_output);
- free(net->partner_linear_output_two);
- free(net->road_linear_output_two);
- free(net->ego_encoder);
- free(net->road_encoder);
- free(net->partner_encoder);
- free(net->ego_layernorm);
- free(net->road_layernorm);
- free(net->partner_layernorm);
- free(net->ego_encoder_two);
- free(net->road_encoder_two);
- free(net->partner_encoder_two);
- free(net->partner_max);
- free(net->road_max);
- free(net->cat1);
- free(net->cat2);
- free(net->gelu);
- free(net->shared_embedding);
- free(net->relu);
- free(net->multidiscrete);
- free(net->actor);
- free(net->value_fn);
- free(net->lstm);
- free(net);
-}
-
-void forward(DriveNet* net, float* observations, int* actions) {
- // Clear previous observations
- memset(net->obs_self, 0, net->num_agents * 7 * sizeof(float));
- memset(net->obs_partner, 0, net->num_agents * 63 * 7 * sizeof(float));
- memset(net->obs_road, 0, net->num_agents * 200 * 13 * sizeof(float));
-
- // Reshape observations into 2D boards and additional features
- float (*obs_self)[7] = (float (*)[7])net->obs_self;
- float (*obs_partner)[63][7] = (float (*)[63][7])net->obs_partner;
- float (*obs_road)[200][13] = (float (*)[200][13])net->obs_road;
-
- for (int b = 0; b < net->num_agents; b++) {
- int b_offset = b * (7 + 63*7 + 200*7); // offset for each batch
- int partner_offset = b_offset + 7;
- int road_offset = b_offset + 7 + 63*7;
- // Process self observation
- for(int i = 0; i < 7; i++) {
- obs_self[b][i] = observations[b_offset + i];
- }
-
- // Process partner observation
- for(int i = 0; i < 63; i++) {
- for(int j = 0; j < 7; j++) {
- obs_partner[b][i][j] = observations[partner_offset + i*7 + j];
- }
- }
-
- // Process road observation
- for(int i = 0; i < 200; i++) {
- for(int j = 0; j < 7; j++) {
- obs_road[b][i][j] = observations[road_offset + i*7 + j];
- }
- for(int j = 0; j < 7; j++) {
- if(j == observations[road_offset+i*7 + 6]) {
- obs_road[b][i][6 + j] = 1.0f;
- } else {
- obs_road[b][i][6 + j] = 0.0f;
- }
- }
- }
+ float* observations = calloc(num_agents*num_obs, sizeof(float));
+ for (int i = 0; i < num_obs*num_agents; i++) {
+ observations[i] = i % 7;
}
- // Forward pass through the network
- linear(net->ego_encoder, net->obs_self);
- layernorm(net->ego_layernorm, net->ego_encoder->output);
- linear(net->ego_encoder_two, net->ego_layernorm->output);
- for (int b = 0; b < net->num_agents; b++) {
- for (int obj = 0; obj < 63; obj++) {
- // Get the 7 features for this object
- float* obj_features = &net->obs_partner[b*63*7 + obj*7];
- // Apply linear layer to this object
- _linear(obj_features, net->partner_encoder->weights, net->partner_encoder->bias,
- &net->partner_linear_output[b*63*64 + obj*64], 1, 7, 64);
- }
- }
+ int* actions = calloc(num_agents*num_actions, sizeof(int));
- for (int b = 0; b < net->num_agents; b++) {
- for (int obj = 0; obj < 63; obj++) {
- float* after_first = &net->partner_linear_output[b*63*64 + obj*64];
- _layernorm(after_first, net->partner_layernorm->weights, net->partner_layernorm->bias,
- &net->partner_layernorm_output[b*63*64 + obj*64], 1, 64);
- }
- }
- for (int b = 0; b < net->num_agents; b++) {
- for (int obj = 0; obj < 63; obj++) {
- // Get the 7 features for this object
- float* obj_features = &net->partner_layernorm_output[b*63*64 + obj*64];
- // Apply linear layer to this object
- _linear(obj_features, net->partner_encoder_two->weights, net->partner_encoder_two->bias,
- &net->partner_linear_output_two[b*63*64 + obj*64], 1, 64, 64);
-
- }
- }
-
- // Process road objects: apply linear to each object individually
- for (int b = 0; b < net->num_agents; b++) {
- for (int obj = 0; obj < 200; obj++) {
- // Get the 13 features for this object
- float* obj_features = &net->obs_road[b*200*13 + obj*13];
- // Apply linear layer to this object
- _linear(obj_features, net->road_encoder->weights, net->road_encoder->bias,
- &net->road_linear_output[b*200*64 + obj*64], 1, 13, 64);
- }
- }
-
- // Apply layer norm and second linear to each road object
- for (int b = 0; b < net->num_agents; b++) {
- for (int obj = 0; obj < 200; obj++) {
- float* after_first = &net->road_linear_output[b*200*64 + obj*64];
- _layernorm(after_first, net->road_layernorm->weights, net->road_layernorm->bias,
- &net->road_layernorm_output[b*200*64 + obj*64], 1, 64);
- }
- }
- for (int b = 0; b < net->num_agents; b++) {
- for (int obj = 0; obj < 200; obj++) {
- float* after_first = &net->road_layernorm_output[b*200*64 + obj*64];
- _linear(after_first, net->road_encoder_two->weights, net->road_encoder_two->bias,
- &net->road_linear_output_two[b*200*64 + obj*64], 1, 64, 64);
+ //Weights* weights = load_weights("resources/drive/puffer_drive_weights.bin");
+ Weights* weights = load_weights("puffer_drive_weights.bin");
+ DriveNet* net = init_drivenet(weights, num_agents);
+
+ forward(net, observations, actions);
+ for (int i = 0; i < num_agents*num_actions; i++) {
+ printf("idx: %d, action: %d, logits:", i, actions[i]);
+ for (int j = 0; j < num_actions; j++) {
+ printf(" %.6f", net->actor->output[i*num_actions + j]);
}
+ printf("\n");
}
-
- max_dim1(net->partner_max, net->partner_linear_output_two);
- max_dim1(net->road_max, net->road_linear_output_two);
- cat_dim1(net->cat1, net->ego_encoder_two->output, net->road_max->output);
- cat_dim1(net->cat2, net->cat1->output, net->partner_max->output);
- gelu(net->gelu, net->cat2->output);
- linear(net->shared_embedding, net->gelu->output);
- relu(net->relu, net->shared_embedding->output);
- lstm(net->lstm, net->relu->output);
- linear(net->actor, net->lstm->state_h);
- linear(net->value_fn, net->lstm->state_h);
-
- // Get action by taking argmax of actor output
- softmax_multidiscrete(net->multidiscrete, net->actor->output, actions);
+ free_drivenet(net);
+ free(weights);
}
+
void demo() {
+ // Read configuration from INI file
+ env_init_config conf = {0};
+ const char* ini_file = "pufferlib/config/ocean/drive.ini";
+ if(ini_parse(ini_file, handler, &conf) < 0) {
+ fprintf(stderr, "Error: Could not load %s. Cannot determine environment configuration.\n", ini_file);
+ exit(1);
+ }
Drive env = {
- .dynamics_model = CLASSIC,
.human_agent_idx = 0,
- .reward_vehicle_collision = -0.1f,
- .reward_offroad_collision = -0.1f,
- .map_name = "resources/drive/binaries/map_942.bin",
- .spawn_immunity_timer = 50
+ .dynamics_model = conf.dynamics_model,
+ .reward_vehicle_collision = conf.reward_vehicle_collision,
+ .reward_offroad_collision = conf.reward_offroad_collision,
+ .reward_ade = conf.reward_ade,
+ .goal_radius = conf.goal_radius,
+ .dt = conf.dt,
+ .map_name = "resources/drive/binaries/map_000.bin",
+ .init_steps = conf.init_steps,
+ .collision_behavior = conf.collision_behavior,
+ .offroad_behavior = conf.offroad_behavior,
};
allocate(&env);
c_reset(&env);
c_render(&env);
- Weights* weights = load_weights("resources/drive/puffer_drive_weights.bin", 595925);
- DriveNet* net = init_drivenet(weights, env.active_agent_count);
+ Weights* weights = load_weights("resources/drive/puffer_drive_weights.bin");
+ DriveNet* net = init_drivenet(weights, env.active_agent_count, env.dynamics_model);
//Client* client = make_client(&env);
int accel_delta = 2;
int steer_delta = 4;
@@ -276,7 +97,7 @@ void demo() {
if(actions[env.human_agent_idx][1] > 12) {
actions[env.human_agent_idx][1] = 12;
}
- }
+ }
if(IsKeyPressed(KEY_TAB)){
env.human_agent_idx = (env.human_agent_idx + 1) % env.active_agent_count;
}
@@ -292,11 +113,25 @@ void demo() {
}
void performance_test() {
+ // Read configuration from INI file
+ env_init_config conf = {0};
+ const char* ini_file = "pufferlib/config/ocean/drive.ini";
+ if(ini_parse(ini_file, handler, &conf) < 0) {
+ fprintf(stderr, "Error: Could not load %s. Cannot determine environment configuration.\n", ini_file);
+ exit(1);
+ }
+
long test_time = 10;
Drive env = {
- .dynamics_model = CLASSIC,
.human_agent_idx = 0,
- .map_name = "resources/drive/binaries/map_942.bin"
+ .dynamics_model = conf.dynamics_model,
+ .reward_vehicle_collision = conf.reward_vehicle_collision,
+ .reward_offroad_collision = conf.reward_offroad_collision,
+ .reward_ade = conf.reward_ade,
+ .goal_radius = conf.goal_radius,
+ .dt = conf.dt,
+ .map_name = "resources/drive/binaries/map_000.bin",
+ .init_steps = conf.init_steps,
};
clock_t start_time, end_time;
double cpu_time_used;
@@ -310,7 +145,7 @@ void performance_test() {
long start = time(NULL);
int i = 0;
int (*actions)[2] = (int(*)[2])env.actions;
-
+
while (time(NULL) - start < test_time) {
// Set random actions for all agents
for(int j = 0; j < env.active_agent_count; j++) {
@@ -319,7 +154,7 @@ void performance_test() {
actions[j][0] = accel; // -1, 0, or 1
actions[j][1] = steer; // Random steering
}
-
+
c_step(&env);
i++;
}
@@ -329,7 +164,8 @@ void performance_test() {
}
int main() {
+ //performance_test();
demo();
- // performance_test();
+ //test_drivenet();
return 0;
}
diff --git a/pufferlib/ocean/drive/drive.h b/pufferlib/ocean/drive/drive.h
index 9001d063a..d88b2803e 100644
--- a/pufferlib/ocean/drive/drive.h
+++ b/pufferlib/ocean/drive/drive.h
@@ -10,33 +10,55 @@
#include "raymath.h"
#include "rlgl.h"
#include
+#include "error.h"
+#include "datatypes.h"
+// GridMapEntity types
+#define ENTITY_TYPE_DYNAMIC_AGENT 1
+#define ENTITY_TYPE_ROAD_ELEMENT 2
+#define ENTITY_TYPE_TRAFFIC_CONTROL 3
-// Trajectory Length
-#define TRAJECTORY_LENGTH 91
+#define INVALID_POSITION -10000.0f
+
+// Initialization modes
+#define INIT_ALL_VALID 0
+#define INIT_ONLY_CONTROLLABLE_AGENTS 1
+
+// Control modes
+#define CONTROL_VEHICLES 0
+#define CONTROL_AGENTS 1
+#define CONTROL_TRACKS_TO_PREDICT 2
+#define CONTROL_SDC_ONLY 3
+
+// Minimum distance to goal position
+#define MIN_DISTANCE_TO_GOAL 2.0f
// Actions
#define NOOP 0
// Dynamics Models
#define CLASSIC 0
-#define INVERTIBLE_BICYLE 1
-#define DELTA_LOCAL 2
-#define STATE_DYNAMICS 3
+#define JERK 1
-// collision state
+// Collision state
#define NO_COLLISION 0
#define VEHICLE_COLLISION 1
#define OFFROAD 2
-// grid cell size
+// Metrics array indices
+#define COLLISION_IDX 0
+#define OFFROAD_IDX 1
+#define REACHED_GOAL_IDX 2
+#define LANE_ALIGNED_IDX 3
+#define AVG_DISPLACEMENT_ERROR_IDX 4
+
+// Grid cell size
#define GRID_CELL_SIZE 5.0f
-#define MAX_ENTITIES_PER_CELL 10
-#define SLOTS_PER_CELL (MAX_ENTITIES_PER_CELL*2 + 1)
+#define MAX_ENTITIES_PER_CELL 30 // Depends on resolution of data Formula: 3 * (2 + GRID_CELL_SIZE*sqrt(2)/resolution) => For each entity type in gridmap, diagonal poly-lines -> sqrt(2), include diagonal ends -> 2
// Max road segment observation entities
#define MAX_ROAD_SEGMENT_OBSERVATIONS 200
-#define MAX_CARS 64
+#define MAX_AGENTS 64
// Observation Space Constants
#define MAX_SPEED 100.0f
#define MAX_VEH_LEN 30.0f
@@ -51,12 +73,22 @@
#define MAX_RG_COORD 1000.0f
#define MAX_ROAD_SCALE 100.0f
#define MAX_ROAD_SEGMENT_LENGTH 100.0f
+#define STOP_AGENT 1
+#define REMOVE_AGENT 2
-// Acceleration Values
-static const float ACCELERATION_VALUES[7] = {-4.0000f, -2.6670f, -1.3330f, -0.0000f, 1.3330f, 2.6670f, 4.0000f};
-// static const float STEERING_VALUES[13] = {-3.1420f, -2.6180f, -2.0940f, -1.5710f, -1.0470f, -0.5240f, 0.0000f, 0.5240f,
-// 1.0470f, 1.5710f, 2.0940f, 2.6180f, 3.1420f};
+//GOAL BEHAVIOUR
+#define GOAL_RESPAWN 0
+#define GOAL_GENERATE_NEW 1
+#define GOAL_STOP 2
+
+// Jerk action space (for JERK dynamics model)
+static const float JERK_LONG[4] = {-15.0f, -4.0f, 0.0f, 4.0f};
+static const float JERK_LAT[3] = {-4.0f, 0.0f, 4.0f};
+
+// Classic action space (for CLASSIC dynamics model)
+static const float ACCELERATION_VALUES[7] = {-4.0000f, -2.6670f, -1.3330f, -0.0000f, 1.3330f, 2.6670f, 4.0000f};
static const float STEERING_VALUES[13] = {-1.000f, -0.833f, -0.667f, -0.500f, -0.333f, -0.167f, 0.000f, 0.167f, 0.333f, 0.500f, 0.667f, 0.833f, 1.000f};
+
static const float offsets[4][2] = {
{-1, 1}, // top-left
{1, 1}, // top-right
@@ -77,104 +109,32 @@ struct timespec ts;
typedef struct Drive Drive;
typedef struct Client Client;
typedef struct Log Log;
+typedef struct Graph Graph;
+typedef struct AdjListNode AdjListNode;
+typedef struct Agent Agent;
+typedef struct RoadMapElement RoadMapElement;
+typedef struct TrafficControlElement TrafficControlElement;
struct Log {
float episode_return;
float episode_length;
- float perf;
float score;
float offroad_rate;
float collision_rate;
- float clean_collision_rate;
+ float num_goals_reached;
float completion_rate;
float dnf_rate;
float n;
+ float lane_alignment_rate;
+ float avg_displacement_error;
+ float active_agent_count;
+ float expert_static_agent_count;
+ float static_agent_count;
+ float avg_offroad_per_agent;
+ float avg_collisions_per_agent;
};
-typedef struct Entity Entity;
-struct Entity {
- int type;
- int array_size;
- float* traj_x;
- float* traj_y;
- float* traj_z;
- float* traj_vx;
- float* traj_vy;
- float* traj_vz;
- float* traj_heading;
- int* traj_valid;
- float width;
- float length;
- float height;
- float goal_position_x;
- float goal_position_y;
- float goal_position_z;
- int mark_as_expert;
- int collision_state;
- float x;
- float y;
- float z;
- float vx;
- float vy;
- float vz;
- float heading;
- float heading_x;
- float heading_y;
- int valid;
- int reached_goal;
- int respawn_timestep;
- int collided_before_goal;
- int reached_goal_this_episode;
- int active_agent;
-};
-
-// Based on the original GPUDrive MapType(WOMD)
-typedef enum MapEntityType MapEntityType;
-enum MapEntityType{
- NONE = 0,
- VEHICLE = 1,
- PEDESTRIAN = 2,
- CYCLIST = 3,
- ROAD_LANE = 4,
- ROAD_LINE = 5,
- ROAD_EDGE = 6,
- STOP_SIGN = 7,
- CROSSWALK = 8,
- SPEED_BUMP = 9,
- DRIVEWAY = 10,
- NUM_TYPES = 11,
-};
-
-typedef struct MapEntity MapEntity;
-struct MapEntity {
- int id;
- int type;
- MapEntityType map_type;
- int array_size;
- float* traj_x;
- float* traj_y;
- float* traj_z;
-};
-
-void free_map_entity(MapEntity* map_entity){
- // free trajectory arrays
- if(map_entity->traj_x) free(map_entity->traj_x);
- if(map_entity->traj_y) free(map_entity->traj_y);
- if(map_entity->traj_z) free(map_entity->traj_z);
-}
-
-void free_entity(Entity* entity){
- // free trajectory arrays only if they're not NULL
- if (entity->traj_x) free(entity->traj_x);
- if (entity->traj_y) free(entity->traj_y);
- if (entity->traj_z) free(entity->traj_z);
- if (entity->traj_vx) free(entity->traj_vx);
- if (entity->traj_vy) free(entity->traj_vy);
- if (entity->traj_vz) free(entity->traj_vz);
- if (entity->traj_heading) free(entity->traj_heading);
- if (entity->traj_valid) free(entity->traj_valid);
-}
-
+// Utility functions
float relative_distance(float a, float b){
float distance = sqrtf(powf(a - b, 2));
return distance;
@@ -187,156 +147,400 @@ float relative_distance_2d(float x1, float y1, float x2, float y2){
return distance;
}
+float clip(float value, float min, float max) {
+ if (value < min) return min;
+ if (value > max) return max;
+ return value;
+}
+
+float compute_displacement_error(Agent* agent, int timestep) {
+ // Check if timestep is within valid range
+ if (timestep < 0 || timestep >= agent->trajectory_length) {
+ return 0.0f;
+ }
+
+ // Check if reference trajectory is valid at this timestep
+ if (!agent->log_valid[timestep]) {
+ return 0.0f;
+ }
+
+ // Get reference position from logged trajectory at current timestep
+ float ref_x = agent->log_trajectory_x[timestep];
+ float ref_y = agent->log_trajectory_y[timestep];
+
+ if (ref_x == INVALID_POSITION || ref_y == INVALID_POSITION) {
+ return 0.0f;
+ }
+
+ // Compute deltas: Euclidean distance between simulated and reference position
+ float dx = agent->sim_x - ref_x;
+ float dy = agent->sim_y - ref_y;
+ float displacement = sqrtf(dx*dx + dy*dy);
+
+ return displacement;
+}
+
+typedef struct GridMapEntity GridMapEntity;
+struct GridMapEntity {
+ int entity_type; // Entity type: 1=Agent, 2=RoadMapElement, 3=TrafficControlElement
+ int entity_idx; // Index into the corresponding typed array
+ int geometry_idx; // Index into entity's trajectory/geometry array
+};
+
+typedef struct GridMap GridMap;
+struct GridMap {
+ float top_left_x;
+ float top_left_y;
+ float bottom_right_x;
+ float bottom_right_y;
+ int grid_cols;
+ int grid_rows;
+ int cell_size_x;
+ int cell_size_y;
+ int* cell_entities_count; // number of entities in each cell of the GridMap
+ GridMapEntity** cells; // list of gridEntities in each cell of the GridMap
+
+ // Extras/Optimizations
+ int vision_range;
+ int* neighbor_cache_count; // number of entities in each cells neighbor cache
+ GridMapEntity** neighbor_cache_entities; // preallocated array to hold neighbor entities
+};
+
struct Drive {
Client* client;
float* observations;
- int* actions;
+ float* actions;
float* rewards;
unsigned char* terminals;
Log log;
Log* logs;
- int num_agents;
+ int num_max_agents;
int active_agent_count;
int* active_agent_indices;
+ int action_type;
int human_agent_idx;
- Entity* entities;
- MapEntity* map_entities;
- int num_entities;
- int num_cars;
- int num_objects;
- int num_roads;
- int static_car_count;
- int* static_car_indices;
- int expert_static_car_count;
- int* expert_static_car_indices;
+ Agent* agents;
+ RoadMapElement* road_elements;
+ TrafficControlElement* traffic_elements;
+ Graph* topology_graph;
+ int num_total_agents;
+ int num_road_elements;
+ int num_traffic_elements;
+ int num_actors;
+ int static_agent_count;
+ int* static_agent_indices;
+ int expert_static_agent_count;
+ int* expert_static_agent_indices;
int timestep;
+ int init_steps;
int dynamics_model;
- float* map_corners;
- int* grid_cells; // holds entity ids and geometry index per cell
- int grid_cols;
- int grid_rows;
- int vision_range;
+ GridMap* grid_map;
int* neighbor_offsets;
- int* neighbor_cache_entities;
- int* neighbor_cache_indices;
+ int scenario_length;
float reward_vehicle_collision;
float reward_offroad_collision;
+ float reward_ade;
char* map_name;
float world_mean_x;
float world_mean_y;
- int spawn_immunity_timer;
+ float dt;
+ float reward_goal;
float reward_goal_post_respawn;
- float reward_vehicle_collision_post_respawn;
+ float goal_radius;
+ int max_controlled_agents;
+ int logs_capacity;
+ int goal_behavior;
+ char* ini_file;
+ int collision_behavior;
+ int offroad_behavior;
+ int control_non_vehicles;
+ // Metadata fields
+ char scenario_id[128];
+ int map_index;
+ char dataset_name[64];
+ int log_length;
+ int sdc_index;
+ int num_objects_of_interest;
+ int* objects_of_interest;
+ int num_tracks_to_predict;
+ int* tracks_to_predict;
+ int init_mode;
+ int control_mode;
};
void add_log(Drive* env) {
for(int i = 0; i < env->active_agent_count; i++){
- Entity* e = &env->entities[env->active_agent_indices[i]];
- if(e->reached_goal_this_episode){
+ Agent* agent = &env->agents[env->active_agent_indices[i]];
+
+ if(agent->reached_goal_this_episode){
env->log.completion_rate += 1.0f;
}
int offroad = env->logs[i].offroad_rate;
env->log.offroad_rate += offroad;
int collided = env->logs[i].collision_rate;
env->log.collision_rate += collided;
- int clean_collided = env->logs[i].clean_collision_rate;
- env->log.clean_collision_rate += clean_collided;
- if(e->reached_goal_this_episode && !e->collided_before_goal){
+ float avg_offroad_per_agent = env->logs[i].avg_offroad_per_agent;
+ env->log.avg_offroad_per_agent += avg_offroad_per_agent;
+ float avg_collisions_per_agent = env->logs[i].avg_collisions_per_agent;
+ env->log.avg_collisions_per_agent += avg_collisions_per_agent;
+ int num_goals_reached = env->logs[i].num_goals_reached;
+ env->log.num_goals_reached += num_goals_reached;
+ if(agent->reached_goal_this_episode && !agent->collided_before_goal){
env->log.score += 1.0f;
- env->log.perf += 1.0f;
}
- if(!offroad && !collided && !e->reached_goal_this_episode){
+ if(!offroad && !collided && !agent->reached_goal_this_episode){
env->log.dnf_rate += 1.0f;
}
+ int lane_aligned = env->logs[i].lane_alignment_rate;
+ env->log.lane_alignment_rate += lane_aligned;
+ float displacement_error = env->logs[i].avg_displacement_error;
+ env->log.avg_displacement_error += displacement_error;
env->log.episode_length += env->logs[i].episode_length;
env->log.episode_return += env->logs[i].episode_return;
+ // Log composition counts per agent so vec_log averaging recovers the per-env value
+ env->log.active_agent_count += env->active_agent_count;
+ env->log.expert_static_agent_count += env->expert_static_agent_count;
+ env->log.static_agent_count += env->static_agent_count;
env->log.n += 1;
}
}
-void load_map_binary(const char* filename, Drive* env) {
+
+struct AdjListNode {
+ int dest;
+ struct AdjListNode* next;
+};
+
+struct Graph {
+ int V;
+ struct AdjListNode** array;
+};
+
+// Function to create a new adjacency list node
+struct AdjListNode* newAdjListNode(int dest) {
+ struct AdjListNode* newNode = malloc(sizeof(struct AdjListNode));
+ newNode->dest = dest;
+ newNode->next = NULL;
+ return newNode;
+}
+
+// Function to create a graph of V vertices
+struct Graph* createGraph(int V) {
+ struct Graph* graph = malloc(sizeof(struct Graph));
+ graph->V = V;
+ graph->array = calloc(V, sizeof(struct AdjListNode*));
+ return graph;
+}
+
+// Function to get next lanes from a given lane entity index
+// Returns the number of next lanes found, fills next_lanes array with entity indices
+int getNextLanes(struct Graph* graph, int entity_idx, int* next_lanes, int max_lanes) {
+ if (!graph || entity_idx < 0 || entity_idx >= graph->V) {
+ return 0;
+ }
+
+ int count = 0;
+ struct AdjListNode* node = graph->array[entity_idx];
+
+ while (node && count < max_lanes) {
+ next_lanes[count] = node->dest;
+ count++;
+ node = node->next;
+ }
+
+ return count;
+}
+
+// Function to free the topology graph
+void freeTopologyGraph(struct Graph* graph) {
+ if (!graph) return;
+
+ for (int i = 0; i < graph->V; i++) {
+ struct AdjListNode* node = graph->array[i];
+ while (node) {
+ struct AdjListNode* temp = node;
+ node = node->next;
+ free(temp);
+ }
+ }
+
+ free(graph->array);
+ free(graph);
+}
+
+
+int load_map_binary(const char* filename, Drive* drive) {
FILE* file = fopen(filename, "rb");
- if (!file) return;
- fread(&env->num_objects, sizeof(int), 1, file);
- fread(&env->num_roads, sizeof(int), 1, file);
- env->num_entities = env->num_objects + env->num_roads;
- Entity* entities = (Entity*)malloc(env->num_objects * sizeof(Entity));
- for (int i = 0; i < env->num_objects; i++) {
- // Read base entity data
- fread(&entities[i].type, sizeof(int), 1, file);
- fread(&entities[i].array_size, sizeof(int), 1, file);
- if(entities[i].type == 0)
- {
- printf("Warning: Entity %d has type 0 (NONE)\n", i);
- }
- // Allocate arrays based on type
- int size = entities[i].array_size;
- entities[i].traj_x = (float*)malloc(size * sizeof(float));
- entities[i].traj_y = (float*)malloc(size * sizeof(float));
- entities[i].traj_z = (float*)malloc(size * sizeof(float));
- if (entities[i].type == 1 || entities[i].type == 2 || entities[i].type == 3) {
- entities[i].traj_vx = (float*)malloc(size * sizeof(float));
- entities[i].traj_vy = (float*)malloc(size * sizeof(float));
- entities[i].traj_vz = (float*)malloc(size * sizeof(float));
- entities[i].traj_heading = (float*)malloc(size * sizeof(float));
- entities[i].traj_valid = (int*)malloc(size * sizeof(int));
- }
- // Read array data
- fread(entities[i].traj_x, sizeof(float), size, file);
- fread(entities[i].traj_y, sizeof(float), size, file);
- fread(entities[i].traj_z, sizeof(float), size, file);
- if (entities[i].type == 1 || entities[i].type == 2 || entities[i].type == 3) {
- fread(entities[i].traj_vx, sizeof(float), size, file);
- fread(entities[i].traj_vy, sizeof(float), size, file);
- fread(entities[i].traj_vz, sizeof(float), size, file);
- fread(entities[i].traj_heading, sizeof(float), size, file);
- fread(entities[i].traj_valid, sizeof(int), size, file);
- }
- // Read remaining scalar fields
- fread(&entities[i].width, sizeof(float), 1, file);
- fread(&entities[i].length, sizeof(float), 1, file);
- fread(&entities[i].height, sizeof(float), 1, file);
- fread(&entities[i].goal_position_x, sizeof(float), 1, file);
- fread(&entities[i].goal_position_y, sizeof(float), 1, file);
- fread(&entities[i].goal_position_z, sizeof(float), 1, file);
- fread(&entities[i].mark_as_expert, sizeof(int), 1, file);
- }
-
- MapEntity* map_entities = (MapEntity*)malloc(env->num_roads * sizeof(MapEntity));
- // Read road entities
- for (int i = 0; i < env->num_roads; i++) {
- // Read base entity data
- fread(&map_entities[i].type, sizeof(int), 1, file);
- fread(&map_entities[i].array_size, sizeof(int), 1, file);
- if(map_entities[i].type == 0)
- {
- printf("Warning: Map Entity %d has type 0 (NONE)\n", i);
- }
- // Type Handling
- if (map_entities[i].type < 4 || map_entities[i].type > (int)NUM_TYPES) {
- map_entities[i].map_type = (MapEntityType)(map_entities[i].type);
- }
-
- // Allocate arrays based on type
- int size = map_entities[i].array_size;
- map_entities[i].traj_x = (float*)malloc(size * sizeof(float));
- map_entities[i].traj_y = (float*)malloc(size * sizeof(float));
- map_entities[i].traj_z = (float*)malloc(size * sizeof(float));
- // Read array data
- fread(map_entities[i].traj_x, sizeof(float), size, file);
- fread(map_entities[i].traj_y, sizeof(float), size, file);
- fread(map_entities[i].traj_z, sizeof(float), size, file);
- }
-
+ if (!file) return -1;
+
+ int num_total_agents, num_roads, num_traffic;
+ fread(&num_total_agents, sizeof(int), 1, file);
+ fread(&num_roads, sizeof(int), 1, file);
+ fread(&num_traffic, sizeof(int), 1, file);
+
+ drive->num_total_agents = num_total_agents;
+ drive->num_road_elements = num_roads;
+ drive->num_traffic_elements = num_traffic;
+
+ if (num_total_agents > 0) {
+ drive->agents = (Agent*)calloc(num_total_agents, sizeof(Agent));
+ }
+
+ if (num_roads > 0) {
+ drive->road_elements = (RoadMapElement*)calloc(num_roads, sizeof(RoadMapElement));
+ }
+
+ if (num_traffic > 0) {
+ drive->traffic_elements = (TrafficControlElement*)calloc(num_traffic, sizeof(TrafficControlElement));
+ }
+
+ for (int i = 0; i < num_total_agents; i++) {
+ Agent* agent = &drive->agents[i];
+
+ fread(&agent->id, sizeof(int), 1, file);
+ fread(&agent->type, sizeof(int), 1, file);
+ fread(&agent->trajectory_length, sizeof(int), 1, file);
+
+ int tlen = agent->trajectory_length;
+
+ agent->log_trajectory_x = (float*)malloc(tlen * sizeof(float));
+ agent->log_trajectory_y = (float*)malloc(tlen * sizeof(float));
+ agent->log_trajectory_z = (float*)malloc(tlen * sizeof(float));
+ agent->log_heading = (float*)malloc(tlen * sizeof(float));
+ agent->log_velocity_x = (float*)malloc(tlen * sizeof(float));
+ agent->log_velocity_y = (float*)malloc(tlen * sizeof(float));
+ agent->log_length = (float*)malloc(tlen * sizeof(float));
+ agent->log_width = (float*)malloc(tlen * sizeof(float));
+ agent->log_height = (float*)malloc(tlen * sizeof(float));
+ agent->log_valid = (int*)malloc(tlen * sizeof(int));
+
+ fread(agent->log_trajectory_x, sizeof(float), tlen, file);
+ fread(agent->log_trajectory_y, sizeof(float), tlen, file);
+ fread(agent->log_trajectory_z, sizeof(float), tlen, file);
+ fread(agent->log_heading, sizeof(float), tlen, file);
+ fread(agent->log_velocity_x, sizeof(float), tlen, file);
+ fread(agent->log_velocity_y, sizeof(float), tlen, file);
+ fread(agent->log_length, sizeof(float), tlen, file);
+ fread(agent->log_width, sizeof(float), tlen, file);
+ fread(agent->log_height, sizeof(float), tlen, file);
+ fread(agent->log_valid, sizeof(int), tlen, file);
+
+ fread(&agent->route_length, sizeof(int), 1, file);
+
+ if (agent->route_length > 0) {
+ agent->route = (int*)malloc(agent->route_length * sizeof(int));
+ fread(agent->route, sizeof(int), agent->route_length, file);
+ } else {
+ agent->route = NULL;
+ }
+
+ fread(&agent->goal_position_x, sizeof(float), 1, file);
+ fread(&agent->goal_position_y, sizeof(float), 1, file);
+ fread(&agent->goal_position_z, sizeof(float), 1, file);
+ fread(&agent->mark_as_expert, sizeof(int), 1, file);
+ }
+
+ for (int i = 0; i < num_roads; i++) {
+ RoadMapElement* road = &drive->road_elements[i];
+
+ fread(&road->id, sizeof(int), 1, file);
+ fread(&road->type, sizeof(int), 1, file);
+ fread(&road->segment_length, sizeof(int), 1, file);
+
+ int slen = road->segment_length;
+
+ road->x = (float*)malloc(slen * sizeof(float));
+ road->y = (float*)malloc(slen * sizeof(float));
+ road->z = (float*)malloc(slen * sizeof(float));
+
+ fread(road->x, sizeof(float), slen, file);
+ fread(road->y, sizeof(float), slen, file);
+ fread(road->z, sizeof(float), slen, file);
+
+ if (is_road_lane(road->type)) {
+ fread(&road->num_entries, sizeof(int), 1, file);
+ if (road->num_entries > 0) {
+ road->entry_lanes = (int*)malloc(road->num_entries * sizeof(int));
+ fread(road->entry_lanes, sizeof(int), road->num_entries, file);
+ } else {
+ road->entry_lanes = NULL;
+ }
+
+ fread(&road->num_exits, sizeof(int), 1, file);
+ if (road->num_exits > 0) {
+ road->exit_lanes = (int*)malloc(road->num_exits * sizeof(int));
+ fread(road->exit_lanes, sizeof(int), road->num_exits, file);
+ } else {
+ road->exit_lanes = NULL;
+ }
+
+ fread(&road->speed_limit, sizeof(float), 1, file);
+ } else {
+ road->entry_lanes = NULL;
+ road->exit_lanes = NULL;
+ road->speed_limit = 0.0f;
+ }
+ }
+
+ for (int i = 0; i < num_traffic; i++) {
+ TrafficControlElement* traffic = &drive->traffic_elements[i];
+
+ fread(&traffic->id, sizeof(int), 1, file);
+ fread(&traffic->type, sizeof(int), 1, file);
+ fread(&traffic->x, sizeof(float), 1, file);
+ fread(&traffic->y, sizeof(float), 1, file);
+ fread(&traffic->z, sizeof(float), 1, file);
+ fread(&traffic->state_length, sizeof(int), 1, file);
+
+ int state_len = traffic->state_length;
+
+ traffic->states = (int*)malloc(state_len * sizeof(int));
+ fread(traffic->states, sizeof(int), state_len, file);
+
+ // Read controlled_lanes array (but only store first one in single controlled_lane field)
+ int num_controlled_lanes;
+ fread(&num_controlled_lanes, sizeof(int), 1, file);
+ if (num_controlled_lanes > 0) {
+ fread(&traffic->controlled_lane, sizeof(int), 1, file);
+ // Skip remaining controlled lanes if any
+ for (int j = 1; j < num_controlled_lanes; j++) {
+ int dummy;
+ fread(&dummy, sizeof(int), 1, file);
+ }
+ } else {
+ traffic->controlled_lane = -1;
+ }
+ }
+
+ fread(drive->scenario_id, sizeof(char), 128, file);
+ fread(&drive->map_index, sizeof(int), 1, file);
+ fread(drive->dataset_name, sizeof(char), 64, file);
+ fread(&drive->log_length, sizeof(int), 1, file);
+ fread(&drive->sdc_index, sizeof(int), 1, file);
+ fread(&drive->num_objects_of_interest, sizeof(int), 1, file);
+
+ if (drive->num_objects_of_interest > 0) {
+ drive->objects_of_interest = (int*)malloc(drive->num_objects_of_interest * sizeof(int));
+ fread(drive->objects_of_interest, sizeof(int), drive->num_objects_of_interest, file);
+ } else {
+ drive->objects_of_interest = NULL;
+ }
+
+ fread(&drive->num_tracks_to_predict, sizeof(int), 1, file);
+
+ if (drive->num_tracks_to_predict > 0) {
+ drive->tracks_to_predict = (int*)malloc(drive->num_tracks_to_predict * sizeof(int));
+ fread(drive->tracks_to_predict, sizeof(int), drive->num_tracks_to_predict, file);
+ } else {
+ drive->tracks_to_predict = NULL;
+ }
+
fclose(file);
- env->entities = entities;
- env->map_entities = map_entities;
+ return 0;
}
void set_start_position(Drive* env){
- //InitWindow(800, 600, "GPU Drive");
- //BeginDrawing();
- for(int i = 0; i < env->num_objects; i++){
+ for(int i = 0; i < env->num_total_agents; i++){
int is_active = 0;
for(int j = 0; j < env->active_agent_count; j++){
if(env->active_agent_indices[j] == i){
@@ -344,127 +548,244 @@ void set_start_position(Drive* env){
break;
}
}
- Entity* e = &env->entities[i];
- e->x = e->traj_x[0];
- e->y = e->traj_y[0];
- e->z = e->traj_z[0];
- //printf("Entity %d is at (%f, %f, %f)\n", i, e->x, e->y, e->z);
- //if (e->type < 4) {
- // DrawRectangle(200+2*e->x, 200+2*e->y, 2.0, 2.0, RED);
- //}
- if(e->type >3 || e->type == 0){
- continue;
- }
+ Agent* agent = &env->agents[i];
+
+ // Clamp init_steps to ensure we don't go out of bounds
+ int step = env->init_steps;
+ if (step >= agent->trajectory_length) step = agent->trajectory_length - 1;
+ if (step < 0) step = 0;
+
+ // Initialize simulation trajectory from logged trajectory at init_steps
+ agent->sim_x = agent->log_trajectory_x[step];
+ agent->sim_y = agent->log_trajectory_y[step];
+ agent->sim_z = agent->log_trajectory_z[step];
+ agent->sim_heading = agent->log_heading[step];
+ agent->sim_valid = agent->log_valid[step];
+ agent->sim_length = agent->log_length[step];
+ agent->sim_width = agent->log_width[step];
+ agent->sim_height = agent->log_height[step];
+
+ if(agent->type == UNKNOWN) continue;
+
if(is_active == 0){
- e->vx = 0;
- e->vy = 0;
- e->vz = 0;
- e->reached_goal = 0;
- e->collided_before_goal = 0;
- } else{
- e->vx = e->traj_vx[0];
- e->vy = e->traj_vy[0];
- e->vz = e->traj_vz[0];
- }
- e->heading = e->traj_heading[0];
- e->heading_x = cosf(e->heading);
- e->heading_y = sinf(e->heading);
- e->valid = e->traj_valid[0];
- e->collision_state = 0;
- e->respawn_timestep = -1;
+ agent->sim_vx = 0.0f;
+ agent->sim_vy = 0.0f;
+ agent->collided_before_goal = 0;
+ } else {
+ agent->sim_vx = agent->log_velocity_x[step];
+ agent->sim_vy = agent->log_velocity_y[step];
+ }
+
+ // Shrink width and length slightly to avoid initial collisions
+ agent->sim_length *= 0.7f;
+ agent->sim_width *= 0.7f;
+
+ // Initialize metrics and state
+ agent->collision_state = 0;
+ agent->metrics_array[COLLISION_IDX] = 0.0f;
+ agent->metrics_array[OFFROAD_IDX] = 0.0f;
+ agent->metrics_array[REACHED_GOAL_IDX] = 0.0f;
+ agent->metrics_array[LANE_ALIGNED_IDX] = 0.0f;
+ agent->metrics_array[AVG_DISPLACEMENT_ERROR_IDX] = 0.0f;
+ agent->cumulative_displacement = 0.0f;
+ agent->displacement_sample_count = 0;
+ agent->respawn_timestep = -1;
+ agent->stopped = 0;
+ agent->removed = 0;
+ agent->respawn_count = 0;
+
+ // Dynamics
+ agent->a_long = 0.0f;
+ agent->a_lat = 0.0f;
+ agent->jerk_long = 0.0f;
+ agent->jerk_lat = 0.0f;
+ agent->steering_angle = 0.0f;
+ agent->wheelbase = 0.6f * agent->sim_length;
}
}
int getGridIndex(Drive* env, float x1, float y1) {
- if (env->map_corners[0] >= env->map_corners[2] || env->map_corners[1] >= env->map_corners[3]) {
- printf("Invalid grid coordinates\n");
+ if (env->grid_map->top_left_x >= env->grid_map->bottom_right_x || env->grid_map->bottom_right_y >= env->grid_map->top_left_y) {
return -1; // Invalid grid coordinates
}
- float worldWidth = env->map_corners[2] - env->map_corners[0]; // Positive value
- float worldHeight = env->map_corners[3] - env->map_corners[1]; // Positive value
- int cellsX = (int)ceil(worldWidth / GRID_CELL_SIZE); // Number of columns
- int cellsY = (int)ceil(worldHeight / GRID_CELL_SIZE); // Number of rows
- float relativeX = x1 - env->map_corners[0]; // Distance from left
- float relativeY = y1 - env->map_corners[1]; // Distance from top
+
+ float relativeX = x1 - env->grid_map->top_left_x; // Distance from left
+ float relativeY = y1 - env->grid_map->bottom_right_y; // Distance from bottom
int gridX = (int)(relativeX / GRID_CELL_SIZE); // Column index
int gridY = (int)(relativeY / GRID_CELL_SIZE); // Row index
- if (gridX < 0 || gridX >= cellsX || gridY < 0 || gridY >= cellsY) {
+ if (gridX < 0 || gridX >= env->grid_map->grid_cols || gridY < 0 || gridY >= env->grid_map->grid_rows) {
return -1; // Return -1 for out of bounds
}
- int index = (gridY*cellsX) + gridX;
+ int index = (gridY*env->grid_map->grid_cols) + gridX;
return index;
}
-void add_entity_to_grid(Drive* env, int grid_index, int entity_idx, int geometry_idx){
+void add_entity_to_grid(Drive* env, int grid_index, int entity_type, int entity_idx, int geometry_idx, int* cell_entities_insert_index){
if(grid_index == -1){
return;
}
- int base_index = grid_index * SLOTS_PER_CELL;
- int count = env->grid_cells[base_index];
- if(count>= MAX_ENTITIES_PER_CELL) return;
- env->grid_cells[base_index + count*2 + 1] = entity_idx;
- env->grid_cells[base_index + count*2 + 2] = geometry_idx;
- env->grid_cells[base_index] = count + 1;
-
+
+ int count = cell_entities_insert_index[grid_index];
+ if(count >= env->grid_map->cell_entities_count[grid_index]) {
+ printf("Error: Exceeded precomputed entity count for grid cell %d. Current count: %d, Max count(Precomputed): %d\n", grid_index, count, env->grid_map->cell_entities_count[grid_index]);
+ return;
+ }
+
+ env->grid_map->cells[grid_index][count].entity_type = entity_type;
+ env->grid_map->cells[grid_index][count].entity_idx = entity_idx;
+ env->grid_map->cells[grid_index][count].geometry_idx = geometry_idx;
+ cell_entities_insert_index[grid_index] = count + 1;
+}
+
+
+void init_topology_graph(Drive* env){
+ // Count ROAD_LANE entities in road_elements
+ int road_lane_count = 0;
+ for(int i = 0; i < env->num_road_elements; i++){
+ if(is_drivable_road_lane(env->road_elements[i].type)){
+ road_lane_count++;
+ }
+ }
+
+ if(road_lane_count == 0){
+ env->topology_graph = NULL;
+ return;
+ }
+
+ // Create graph with road_elements as vertices
+ env->topology_graph = createGraph(env->num_road_elements);
+
+ // Connect ROAD_LANE entities based on geometric connectivity
+ for(int i = 0; i < env->num_road_elements; i++){
+ if(!is_drivable_road_lane(env->road_elements[i].type)) continue;
+
+ RoadMapElement* lane_i = &env->road_elements[i];
+ if(lane_i->segment_length < 2) continue; // Need at least 2 points
+
+ // Get end point of current lane
+ float end_x = lane_i->x[lane_i->segment_length - 1];
+ float end_y = lane_i->y[lane_i->segment_length - 1];
+ float end_vector_x = lane_i->x[lane_i->segment_length - 1] - lane_i->x[lane_i->segment_length - 2];
+ float end_vector_y = lane_i->y[lane_i->segment_length - 1] - lane_i->y[lane_i->segment_length - 2];
+ float end_heading = atan2f(end_vector_y, end_vector_x);
+
+ // Find lanes that start near this lane's end
+ for(int j = 0; j < env->num_road_elements; j++){
+ if(i == j || !is_drivable_road_lane(env->road_elements[j].type)) continue;
+
+ RoadMapElement* lane_j = &env->road_elements[j];
+ if(lane_j->segment_length < 2) continue;
+
+ // Get start point of potential next lane
+ float start_x = lane_j->x[0];
+ float start_y = lane_j->y[0];
+ float start_vector_x = lane_j->x[1] - lane_j->x[0];
+ float start_vector_y = lane_j->y[1] - lane_j->y[0];
+ float start_heading = atan2f(start_vector_y, start_vector_x);
+
+ // Check if end of lane_i is close to start of lane_j
+ float distance = relative_distance_2d(end_x, end_y, start_x, start_y);
+ float heading_diff = fabsf(end_heading - start_heading);
+
+ // Lane connectivity thresholds:
+ // - 0.01m distance: lanes must connect within 1cm (very strict for clean topology)
+ // - 0.1 (~5.7 degrees) heading difference: allow slight curves
+ if(distance < 0.01f && heading_diff < 0.1f){
+ // Add directed edge from i to j (lane i connects to lane j)
+ struct AdjListNode* node = newAdjListNode(j);
+ node->next = env->topology_graph->array[i];
+ env->topology_graph->array[i] = node;
+ }
+ }
+ }
}
void init_grid_map(Drive* env){
+ // Allocate memory for the grid map structure
+ env->grid_map = (GridMap*)malloc(sizeof(GridMap));
+
// Find top left and bottom right points of the map
float top_left_x;
float top_left_y;
float bottom_right_x;
float bottom_right_y;
int first_valid_point = 0;
- for(int i = 0; i < env->num_roads; i++){
- if(env->map_entities[i].type > 3 && env->map_entities[i].type < 7){
- // Check all points in the trajectory for road elements
- MapEntity* e = &env->map_entities[i];
- for(int j = 0; j < e->array_size; j++){
- if(e->traj_x[j] == -10000) continue;
- if(e->traj_y[j] == -10000) continue;
- if(!first_valid_point) {
- top_left_x = bottom_right_x = e->traj_x[j];
- top_left_y = bottom_right_y = e->traj_y[j];
- first_valid_point = true;
- continue;
- }
- if(e->traj_x[j] < top_left_x) top_left_x = e->traj_x[j];
- if(e->traj_x[j] > bottom_right_x) bottom_right_x = e->traj_x[j];
- if(e->traj_y[j] < top_left_y) top_left_y = e->traj_y[j];
- if(e->traj_y[j] > bottom_right_y) bottom_right_y = e->traj_y[j];
+ for(int i = 0; i < env->num_road_elements; i++){
+ // Check all points in the geometry for road elements (ROAD_LANE, ROAD_LINE, ROAD_EDGE)
+ if (!is_road(env->road_elements[i].type)) continue;
+ RoadMapElement* element = &env->road_elements[i];
+ for(int j = 0; j < element->segment_length; j++){
+ if(element->x[j] == INVALID_POSITION) continue;
+ if(element->y[j] == INVALID_POSITION) continue;
+ if(!first_valid_point) {
+ top_left_x = bottom_right_x = element->x[j];
+ top_left_y = bottom_right_y = element->y[j];
+ first_valid_point = true;
+ continue;
}
+ if(element->x[j] < top_left_x) top_left_x = element->x[j];
+ if(element->x[j] > bottom_right_x) bottom_right_x = element->x[j];
+ if(element->y[j] > top_left_y) top_left_y = element->y[j];
+ if(element->y[j] < bottom_right_y) bottom_right_y = element->y[j];
}
}
- env->map_corners = (float*)calloc(4, sizeof(float));
- env->map_corners[0] = top_left_x;
- env->map_corners[1] = top_left_y;
- env->map_corners[2] = bottom_right_x;
- env->map_corners[3] = bottom_right_y;
-
+ env->grid_map->top_left_x = top_left_x;
+ env->grid_map->top_left_y = top_left_y;
+ env->grid_map->bottom_right_x = bottom_right_x;
+ env->grid_map->bottom_right_y = bottom_right_y;
+ env->grid_map->cell_size_x = GRID_CELL_SIZE;
+ env->grid_map->cell_size_y = GRID_CELL_SIZE;
+
// Calculate grid dimensions
float grid_width = bottom_right_x - top_left_x;
- float grid_height = bottom_right_y - top_left_y;
- env->grid_cols = ceil(grid_width / GRID_CELL_SIZE);
- env->grid_rows = ceil(grid_height / GRID_CELL_SIZE);
- int grid_cell_count = env->grid_cols*env->grid_rows;
- env->grid_cells = (int*)calloc(grid_cell_count*SLOTS_PER_CELL, sizeof(int));
+ float grid_height = top_left_y - bottom_right_y;
+ env->grid_map->grid_cols = ceil(grid_width / GRID_CELL_SIZE);
+ env->grid_map->grid_rows = ceil(grid_height / GRID_CELL_SIZE);
+ int grid_cell_count = env->grid_map->grid_cols*env->grid_map->grid_rows;
+ env->grid_map->cells = (GridMapEntity**)calloc(grid_cell_count, sizeof(GridMapEntity*));
+ env->grid_map->cell_entities_count = (int*)calloc(grid_cell_count, sizeof(int));
+
+ // Calculate number of entities in each grid cell
+ for(int i = 0; i < env->num_road_elements; i++){
+ for(int j = 0; j < env->road_elements[i].segment_length - 1; j++){
+ float x_center = (env->road_elements[i].x[j] + env->road_elements[i].x[j+1]) / 2;
+ float y_center = (env->road_elements[i].y[j] + env->road_elements[i].y[j+1]) / 2;
+ int grid_index = getGridIndex(env, x_center, y_center);
+ if (grid_index == -1) continue; // Skip out-of-bounds entities
+ env->grid_map->cell_entities_count[grid_index]++;
+ }
+ }
+
+ int cell_entities_insert_index[grid_cell_count]; // Helper array for insertion index
+ memset(cell_entities_insert_index, 0, grid_cell_count * sizeof(int));
+
+ // Initialize grid cells
+ for(int grid_index = 0; grid_index < grid_cell_count; grid_index++){
+ env->grid_map->cells[grid_index] = (GridMapEntity*)calloc(env->grid_map->cell_entities_count[grid_index], sizeof(GridMapEntity));
+ }
+ for(int i = 0;inum_roads; i++){
- if(env->map_entities[i].type > 3 && env->map_entities[i].type < 7){
- for(int j = 0; j < env->map_entities[i].array_size - 1; j++){
- float x_center = (env->map_entities[i].traj_x[j] + env->map_entities[i].traj_x[j+1]) / 2;
- float y_center = (env->map_entities[i].traj_y[j] + env->map_entities[i].traj_y[j+1]) / 2;
- int grid_index = getGridIndex(env, x_center, y_center);
- add_entity_to_grid(env, grid_index, i, j);
- }
+ for(int i = 0; i < env->num_road_elements; i++){
+ for(int j = 0; j < env->road_elements[i].segment_length - 1; j++){
+ float x_center = (env->road_elements[i].x[j] + env->road_elements[i].x[j+1]) / 2;
+ float y_center = (env->road_elements[i].y[j] + env->road_elements[i].y[j+1]) / 2;
+ int grid_index = getGridIndex(env, x_center, y_center);
+ if (grid_index == -1) continue; // Skip out-of-bounds entities
+ add_entity_to_grid(env, grid_index, ENTITY_TYPE_ROAD_ELEMENT, i, j, cell_entities_insert_index);
}
- }
+ }
}
void init_neighbor_offsets(Drive* env) {
// Allocate memory for the offsets
- env->neighbor_offsets = (int*)calloc(env->vision_range*env->vision_range*2, sizeof(int));
+ env->neighbor_offsets = (int*)calloc(env->grid_map->vision_range*env->grid_map->vision_range*2, sizeof(int));
// neighbor offsets in a spiral pattern
int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};
@@ -475,7 +796,7 @@ void init_neighbor_offsets(Drive* env) {
int steps_taken = 0; // Steps taken in current direction
int segments_completed = 0; // Count of direction segments completed
int total = 0; // Total offsets added
- int max_offsets = env->vision_range*env->vision_range;
+ int max_offsets = env->grid_map->vision_range*env->grid_map->vision_range;
// Start at center (0,0)
int curr_idx = 0;
env->neighbor_offsets[curr_idx++] = 0; // x offset
@@ -487,7 +808,7 @@ void init_neighbor_offsets(Drive* env) {
x += dx[dir];
y += dy[dir];
// Only add if within vision range bounds
- if (abs(x) <= env->vision_range/2 && abs(y) <= env->vision_range/2) {
+ if (abs(x) <= env->grid_map->vision_range/2 && abs(y) <= env->grid_map->vision_range/2) {
env->neighbor_offsets[curr_idx++] = x;
env->neighbor_offsets[curr_idx++] = y;
total++;
@@ -507,61 +828,74 @@ void init_neighbor_offsets(Drive* env) {
void cache_neighbor_offsets(Drive* env){
int count = 0;
- int cell_count = env->grid_cols*env->grid_rows;
+ int cell_count = env->grid_map->grid_cols*env->grid_map->grid_rows;
+ env->grid_map->neighbor_cache_entities = (GridMapEntity**)calloc(cell_count, sizeof(GridMapEntity*));
+ env->grid_map->neighbor_cache_count = (int*)calloc(cell_count + 1, sizeof(int));
for(int i = 0; i < cell_count; i++){
- int cell_x = i % env->grid_cols; // Convert to 2D coordinates
- int cell_y = i / env->grid_cols;
- env->neighbor_cache_indices[i] = count;
- for(int j = 0; j< env->vision_range*env->vision_range; j++){
+ int cell_x = i % env->grid_map->grid_cols; // Convert to 2D coordinates
+ int cell_y = i / env->grid_map->grid_cols;
+ int current_cell_neighbor_count = 0;
+ for(int j = 0; j < env->grid_map->vision_range*env->grid_map->vision_range; j++){
int x = cell_x + env->neighbor_offsets[j*2];
int y = cell_y + env->neighbor_offsets[j*2+1];
- int grid_index = env->grid_cols*y + x;
- if(x < 0 || x >= env->grid_cols || y < 0 || y >= env->grid_rows) continue;
- int grid_count = env->grid_cells[grid_index*SLOTS_PER_CELL];
- count += grid_count * 2;
+ int grid_index = env->grid_map->grid_cols*y + x;
+ if(x < 0 || x >= env->grid_map->grid_cols || y < 0 || y >= env->grid_map->grid_rows) continue;
+ int grid_count = env->grid_map->cell_entities_count[grid_index];
+ current_cell_neighbor_count += grid_count;
+ }
+ env->grid_map->neighbor_cache_count[i] = current_cell_neighbor_count;
+ count += current_cell_neighbor_count;
+ if(current_cell_neighbor_count == 0) {
+ env->grid_map->neighbor_cache_entities[i] = NULL;
+ continue;
}
+ env->grid_map->neighbor_cache_entities[i] = (GridMapEntity*)calloc(current_cell_neighbor_count, sizeof(GridMapEntity));
}
- env->neighbor_cache_indices[cell_count] = count;
- env->neighbor_cache_entities = (int*)calloc(count, sizeof(int));
+
+ env->grid_map->neighbor_cache_count[cell_count] = count;
for(int i = 0; i < cell_count; i ++){
- int neighbor_cache_base_index = 0;
- int cell_x = i % env->grid_cols; // Convert to 2D coordinates
- int cell_y = i / env->grid_cols;
- for(int j = 0; jvision_range*env->vision_range; j++){
+ int cell_x = i % env->grid_map->grid_cols; // Convert to 2D coordinates
+ int cell_y = i / env->grid_map->grid_cols;
+ int base_index = 0;
+ for(int j = 0; j < env->grid_map->vision_range*env->grid_map->vision_range; j++){
int x = cell_x + env->neighbor_offsets[j*2];
int y = cell_y + env->neighbor_offsets[j*2+1];
- int grid_index = env->grid_cols*y + x;
- if(x < 0 || x >= env->grid_cols || y < 0 || y >= env->grid_rows) continue;
- int grid_count = env->grid_cells[grid_index*SLOTS_PER_CELL];
- int base_index = env->neighbor_cache_indices[i];
- int src_idx = grid_index*SLOTS_PER_CELL + 1;
- int dst_idx = base_index + neighbor_cache_base_index;
- // Copy grid_count pairs (entity_idx, geometry_idx) at once
- memcpy(&env->neighbor_cache_entities[dst_idx],
- &env->grid_cells[src_idx],
- grid_count * 2 * sizeof(int));
+ int grid_index = env->grid_map->grid_cols*y + x;
+ if(x < 0 || x >= env->grid_map->grid_cols || y < 0 || y >= env->grid_map->grid_rows) continue;
+ int grid_count = env->grid_map->cell_entities_count[grid_index];
+
+ // Skip if no entities or source is NULL
+ if(grid_count == 0 || env->grid_map->cells[grid_index] == NULL) {
+ continue;
+ }
- // Update index outside the loop
- neighbor_cache_base_index += grid_count * 2;
+ int src_idx = grid_index;
+ int dst_idx = base_index;
+ // Copy grid_count pairs (entity_idx, geometry_idx) at once
+ memcpy(&env->grid_map->neighbor_cache_entities[i][dst_idx],
+ env->grid_map->cells[src_idx],
+ grid_count * sizeof(GridMapEntity));
+ // for(int k = 0; k < grid_count; k++){
+ // env->grid_map->neighbor_cache_entities[i][dst_idx + k] = env->grid_map->cells[src_idx][k];
+ // }
+ base_index += grid_count;
}
}
}
-int get_neighbor_cache_entities(Drive* env, int cell_idx, int* entities, int max_entities) {
- if (cell_idx < 0 || cell_idx >= (env->grid_cols * env->grid_rows)) {
+int get_neighbor_cache_entities(Drive* env, int cell_idx, GridMapEntity* entities, int max_entities) {
+ GridMap* grid_map = env->grid_map;
+ if (cell_idx < 0 || cell_idx >= (grid_map->grid_cols * grid_map->grid_rows)) {
return 0; // Invalid cell index
}
- int base_index = env->neighbor_cache_indices[cell_idx];
- int end_index = env->neighbor_cache_indices[cell_idx + 1];
- int count = end_index - base_index;
- int pairs = count / 2; // Entity ID and geometry ID pairs
+
+ int count = grid_map->neighbor_cache_count[cell_idx];
// Limit to available space
- if (pairs > max_entities) {
- pairs = max_entities;
- count = pairs * 2;
+ if (count > max_entities) {
+ count = max_entities;
}
- memcpy(entities, env->neighbor_cache_entities + base_index, count * sizeof(int));
- return pairs;
+ memcpy(entities, grid_map->neighbor_cache_entities[cell_idx], count * sizeof(GridMapEntity));
+ return count;
}
void set_means(Drive* env) {
@@ -569,57 +903,106 @@ void set_means(Drive* env) {
float mean_y = 0.0f;
int64_t point_count = 0;
- // Compute single mean for all entities (vehicles and roads)
- for (int i = 0; i < env->num_objects; i++) {
- if (env->entities[i].type == VEHICLE) {
- for (int j = 0; j < env->entities[i].array_size; j++) {
- // Assume a validity flag exists (e.g., valid[j]); adjust if not available
- if (env->entities[i].traj_valid[j]) { // Add validity check if applicable
- point_count++;
- mean_x += (env->entities[i].traj_x[j] - mean_x) / point_count;
- mean_y += (env->entities[i].traj_y[j] - mean_y) / point_count;
- }
+ // Compute mean from dynamic agents
+ for (int i = 0; i < env->num_total_agents; i++) {
+ Agent* agent = &env->agents[i];
+ for (int j = 0; j < agent->trajectory_length; j++) {
+ if (agent->log_valid[j]) {
+ point_count++;
+ mean_x += (agent->log_trajectory_x[j] - mean_x) / point_count;
+ mean_y += (agent->log_trajectory_y[j] - mean_y) / point_count;
}
}
}
- for (int i = 0; i < env->num_roads; i++) {
- for (int j = 0; j < env->map_entities[i].array_size; j++) {
+
+ // Compute mean from road elements
+ for (int i = 0; i < env->num_road_elements; i++) {
+ RoadMapElement* element = &env->road_elements[i];
+ for (int j = 0; j < element->segment_length; j++) {
+ if(element->x[j] == INVALID_POSITION) continue;
point_count++;
- mean_x += (env->map_entities[i].traj_x[j] - mean_x) / point_count;
- mean_y += (env->map_entities[i].traj_y[j] - mean_y) / point_count;
+ mean_x += (element->x[j] - mean_x) / point_count;
+ mean_y += (element->y[j] - mean_y) / point_count;
}
}
+
env->world_mean_x = mean_x;
env->world_mean_y = mean_y;
- for (int i = 0; i < env->num_objects; i++) {
- if (env->entities[i].type == VEHICLE) {
- for (int j = 0; j < env->entities[i].array_size; j++) {
- if(env->entities[i].traj_x[j] == -10000) continue;
- env->entities[i].traj_x[j] -= mean_x;
- env->entities[i].traj_y[j] -= mean_y;
- }
- env->entities[i].goal_position_x -= mean_x;
- env->entities[i].goal_position_y -= mean_y;
+ // Subtract mean from dynamic agents
+ for (int i = 0; i < env->num_total_agents; i++) {
+ Agent* agent = &env->agents[i];
+ for (int j = 0; j < agent->trajectory_length; j++) {
+ if(agent->log_trajectory_x[j] == INVALID_POSITION) continue;
+ agent->log_trajectory_x[j] -= mean_x;
+ agent->log_trajectory_y[j] -= mean_y;
+ }
+ // Normalize current sim position (scalars)
+ if(agent->sim_x != INVALID_POSITION) {
+ agent->sim_x -= mean_x;
+ agent->sim_y -= mean_y;
}
+ agent->goal_position_x -= mean_x;
+ agent->goal_position_y -= mean_y;
+ agent->init_goal_x -= mean_x;
+ agent->init_goal_y -= mean_y;
}
- for (int i = 0; i < env->num_roads; i++) {
- for (int j = 0; j < env->map_entities[i].array_size; j++) {
- if(env->map_entities[i].traj_x[j] == -10000) continue;
- env->map_entities[i].traj_x[j] -= mean_x;
- env->map_entities[i].traj_y[j] -= mean_y;
+
+ // Subtract mean from road elements
+ for (int i = 0; i < env->num_road_elements; i++) {
+ RoadMapElement* element = &env->road_elements[i];
+ for (int j = 0; j < element->segment_length; j++) {
+ if(element->x[j] == INVALID_POSITION) continue;
+ element->x[j] -= mean_x;
+ element->y[j] -= mean_y;
}
}
}
-void move_expert(Drive* env, int* actions, int agent_idx){
- Entity* agent = &env->entities[agent_idx];
- agent->x = agent->traj_x[env->timestep];
- agent->y = agent->traj_y[env->timestep];
- agent->z = agent->traj_z[env->timestep];
- agent->heading = agent->traj_heading[env->timestep];
- agent->heading_x = cosf(agent->heading);
- agent->heading_y = sinf(agent->heading);
+void move_expert(Drive* env, float* actions, int agent_idx){
+ Agent* agent = &env->agents[agent_idx];
+ int t = env->timestep;
+
+ // Timestep out of bounds
+ if (t < 0 || t >= agent->trajectory_length) {
+ agent->sim_x = INVALID_POSITION;
+ agent->sim_y = INVALID_POSITION;
+ agent->sim_z = 0.0f;
+ agent->sim_heading = 0.0f;
+ agent->sim_vx = 0.0f;
+ agent->sim_vy = 0.0f;
+ agent->sim_valid = 0;
+ // agent->sim_length = 0.0f;
+ // agent->sim_width = 0.0f;
+ // agent->sim_height = 0.0f;
+ return;
+ }
+ // Invalid log entry
+ if (agent->log_valid && agent->log_valid[t] == 0) {
+ agent->sim_x = INVALID_POSITION;
+ agent->sim_y = INVALID_POSITION;
+ agent->sim_z = 0.0f;
+ agent->sim_heading = 0.0f;
+ agent->sim_vx = 0.0f;
+ agent->sim_vy = 0.0f;
+ agent->sim_valid = 0;
+ // agent->sim_length = 0.0f;
+ // agent->sim_width = 0.0f;
+ // agent->sim_height = 0.0f;
+ return;
+ }
+
+ // Copy from logged trajectory to simulated state
+ agent->sim_x = agent->log_trajectory_x[t];
+ agent->sim_y = agent->log_trajectory_y[t];
+ agent->sim_z = agent->log_trajectory_z[t];
+ agent->sim_heading = agent->log_heading[t];
+ agent->sim_vx = agent->log_velocity_x[t];
+ agent->sim_vy = agent->log_velocity_y[t];
+ // agent->sim_length = agent->log_length[t];
+ // agent->sim_width = agent->log_width[t];
+ // agent->sim_height = agent->log_height[t];
+ agent->sim_valid = agent->log_valid[t];
}
bool check_line_intersection(float p1[2], float p2[2], float q1[2], float q2[2]) {
@@ -632,31 +1015,31 @@ bool check_line_intersection(float p1[2], float p2[2], float q1[2], float q2[2])
float dy1 = p2[1] - p1[1];
float dx2 = q2[0] - q1[0];
float dy2 = q2[1] - q1[1];
-
+
// Calculate cross products
float cross = dx1 * dy2 - dy1 * dx2;
-
+
// If lines are parallel
if (cross == 0) return false;
-
+
// Calculate relative vectors between start points
float dx3 = p1[0] - q1[0];
float dy3 = p1[1] - q1[1];
-
+
// Calculate parameters for intersection point
float s = (dx1 * dy3 - dy1 * dx3) / cross;
float t = (dx2 * dy3 - dy2 * dx3) / cross;
-
+
// Check if intersection point lies within both line segments
return (s >= 0 && s <= 1 && t >= 0 && t <= 1);
}
-int checkNeighbors(Drive* env, float x, float y, int* entity_list, int max_size, const int (*local_offsets)[2], int offset_size) {
+int checkNeighbors(Drive* env, float x, float y, GridMapEntity* entity_list, int max_size, const int (*local_offsets)[2], int offset_size) {
// Get the grid index for the given position (x, y)
int index = getGridIndex(env, x, y);
if (index == -1) return 0; // Return 0 size if position invalid
// Calculate 2D grid coordinates
- int cellsX = env->grid_cols;
+ int cellsX = env->grid_map->grid_cols;
int gridX = index % cellsX;
int gridY = index / cellsX;
int entity_list_count = 0;
@@ -665,48 +1048,53 @@ int checkNeighbors(Drive* env, float x, float y, int* entity_list, int max_size,
int nx = gridX + local_offsets[i][0];
int ny = gridY + local_offsets[i][1];
// Ensure the neighbor is within grid bounds
- if(nx < 0 || nx >= env->grid_cols || ny < 0 || ny >= env->grid_rows) continue;
- int neighborIndex = (ny * env->grid_cols + nx) * SLOTS_PER_CELL;
- int count = env->grid_cells[neighborIndex];
+ if(nx < 0 || nx >= env->grid_map->grid_cols || ny < 0 || ny >= env->grid_map->grid_rows) continue;
+ int neighborIndex = ny * env->grid_map->grid_cols + nx;
+ int count = env->grid_map->cell_entities_count[neighborIndex];
// Add entities from this cell to the list
for (int j = 0; j < count && entity_list_count < max_size; j++) {
- int entityId = env->grid_cells[neighborIndex + 1 + j*2];
- int geometry_idx = env->grid_cells[neighborIndex + 2 + j*2];
- entity_list[entity_list_count] = entityId;
- entity_list[entity_list_count + 1] = geometry_idx;
- entity_list_count += 2;
+ int entityId = env->grid_map->cells[neighborIndex][j].entity_idx;
+ int geometry_idx = env->grid_map->cells[neighborIndex][j].geometry_idx;
+ int entity_type = env->grid_map->cells[neighborIndex][j].entity_type;
+ entity_list[entity_list_count].entity_idx = entityId;
+ entity_list[entity_list_count].geometry_idx = geometry_idx;
+ entity_list[entity_list_count].entity_type = entity_type;
+ entity_list_count += 1;
}
}
return entity_list_count;
}
-int check_aabb_collision(Entity* car1, Entity* car2) {
+int check_aabb_collision(Agent* car1, Agent* car2) {
// Get car corners in world space
- float cos1 = car1->heading_x;
- float sin1 = car1->heading_y;
- float cos2 = car2->heading_x;
- float sin2 = car2->heading_y;
-
+ float heading1 = car1->sim_heading;
+ float cos1 = cosf(heading1);
+ float sin1 = sinf(heading1);
+
+ float heading2 = car2->sim_heading;
+ float cos2 = cosf(heading2);
+ float sin2 = sinf(heading2);
+
// Calculate half dimensions
- float half_len1 = car1->length * 0.5f;
- float half_width1 = car1->width * 0.5f;
- float half_len2 = car2->length * 0.5f;
- float half_width2 = car2->width * 0.5f;
-
+ float half_len1 = car1->sim_length * 0.5f;
+ float half_width1 = car1->sim_width * 0.5f;
+ float half_len2 = car2->sim_length * 0.5f;
+ float half_width2 = car2->sim_width * 0.5f;
+
// Calculate car1's corners in world space
float car1_corners[4][2] = {
- {car1->x + (half_len1 * cos1 - half_width1 * sin1), car1->y + (half_len1 * sin1 + half_width1 * cos1)},
- {car1->x + (half_len1 * cos1 + half_width1 * sin1), car1->y + (half_len1 * sin1 - half_width1 * cos1)},
- {car1->x + (-half_len1 * cos1 - half_width1 * sin1), car1->y + (-half_len1 * sin1 + half_width1 * cos1)},
- {car1->x + (-half_len1 * cos1 + half_width1 * sin1), car1->y + (-half_len1 * sin1 - half_width1 * cos1)}
+ {car1->sim_x + (half_len1 * cos1 - half_width1 * sin1), car1->sim_y + (half_len1 * sin1 + half_width1 * cos1)},
+ {car1->sim_x + (half_len1 * cos1 + half_width1 * sin1), car1->sim_y + (half_len1 * sin1 - half_width1 * cos1)},
+ {car1->sim_x + (-half_len1 * cos1 - half_width1 * sin1), car1->sim_y + (-half_len1 * sin1 + half_width1 * cos1)},
+ {car1->sim_x + (-half_len1 * cos1 + half_width1 * sin1), car1->sim_y + (-half_len1 * sin1 - half_width1 * cos1)}
};
-
+
// Calculate car2's corners in world space
float car2_corners[4][2] = {
- {car2->x + (half_len2 * cos2 - half_width2 * sin2), car2->y + (half_len2 * sin2 + half_width2 * cos2)},
- {car2->x + (half_len2 * cos2 + half_width2 * sin2), car2->y + (half_len2 * sin2 - half_width2 * cos2)},
- {car2->x + (-half_len2 * cos2 - half_width2 * sin2), car2->y + (-half_len2 * sin2 + half_width2 * cos2)},
- {car2->x + (-half_len2 * cos2 + half_width2 * sin2), car2->y + (-half_len2 * sin2 - half_width2 * cos2)}
+ {car2->sim_x + (half_len2 * cos2 - half_width2 * sin2), car2->sim_y + (half_len2 * sin2 + half_width2 * cos2)},
+ {car2->sim_x + (half_len2 * cos2 + half_width2 * sin2), car2->sim_y + (half_len2 * sin2 - half_width2 * cos2)},
+ {car2->sim_x + (-half_len2 * cos2 - half_width2 * sin2), car2->sim_y + (-half_len2 * sin2 + half_width2 * cos2)},
+ {car2->sim_x + (-half_len2 * cos2 + half_width2 * sin2), car2->sim_y + (-half_len2 * sin2 - half_width2 * cos2)}
};
// Get the axes to check (normalized vectors perpendicular to each edge)
@@ -721,206 +1109,398 @@ int check_aabb_collision(Entity* car1, Entity* car2) {
for(int i = 0; i < 4; i++) {
float min1 = INFINITY, max1 = -INFINITY;
float min2 = INFINITY, max2 = -INFINITY;
-
+
// Project car1's corners onto the axis
for(int j = 0; j < 4; j++) {
float proj = car1_corners[j][0] * axes[i][0] + car1_corners[j][1] * axes[i][1];
min1 = fminf(min1, proj);
max1 = fmaxf(max1, proj);
}
-
+
// Project car2's corners onto the axis
for(int j = 0; j < 4; j++) {
float proj = car2_corners[j][0] * axes[i][0] + car2_corners[j][1] * axes[i][1];
min2 = fminf(min2, proj);
max2 = fmaxf(max2, proj);
}
-
+
// If there's a gap on this axis, the boxes don't intersect
if(max1 < min2 || min1 > max2) {
return 0; // No collision
}
}
-
+
// If we get here, there's no separating axis, so the boxes intersect
return 1; // Collision
}
int collision_check(Drive* env, int agent_idx) {
- Entity* agent = &env->entities[agent_idx];
- if(agent->x == -10000.0f ) return -1;
- float half_length = agent->length/2.0f;
- float half_width = agent->width/2.0f;
- float cos_heading = cosf(agent->heading);
- float sin_heading = sinf(agent->heading);
- float corners[4][2];
- for (int i = 0; i < 4; i++) {
- corners[i][0] = agent->x + (offsets[i][0]*half_length*cos_heading - offsets[i][1]*half_width*sin_heading);
- corners[i][1] = agent->y + (offsets[i][0]*half_length*sin_heading + offsets[i][1]*half_width*cos_heading);
- }
- int collided = 0;
+ Agent* agent = &env->agents[agent_idx];
+
+ if(agent->sim_x == INVALID_POSITION) return -1;
+
int car_collided_with_index = -1;
- int entity_list[MAX_ENTITIES_PER_CELL*2*25]; // Array big enough for all neighboring cells
- int list_size = checkNeighbors(env, agent->x, agent->y, entity_list, MAX_ENTITIES_PER_CELL*2*25, collision_offsets, 25);
- for (int i = 0; i < list_size ; i+=2) {
- if(entity_list[i] == -1) continue;
- if(entity_list[i] == agent_idx) continue;
- MapEntity* map_entity = &env->map_entities[entity_list[i]];
- if(map_entity->type != ROAD_EDGE) continue;
- int geometry_idx = entity_list[i + 1];
- float start[2] = {map_entity->traj_x[geometry_idx], map_entity->traj_y[geometry_idx]};
- float end[2] = {map_entity->traj_x[geometry_idx + 1], map_entity->traj_y[geometry_idx + 1]};
- for (int k = 0; k < 4; k++) { // Check each edge of the bounding box
- int next = (k + 1) % 4;
- if (check_line_intersection(corners[k], corners[next], start, end)) {
- collided = OFFROAD;
- break;
- }
- }
- if (collided == OFFROAD) break;
- }
- for(int i = 0; i < MAX_CARS; i++){
+
+ if (agent->respawn_timestep != -1) return car_collided_with_index; // Skip respawning entities
+
+ for(int i = 0; i < MAX_AGENTS; i++){
int index = -1;
if(i < env->active_agent_count){
index = env->active_agent_indices[i];
- } else if (i < env->num_cars){
- index = env->static_car_indices[i - env->active_agent_count];
+ } else if (i < env->num_actors){
+ index = env->static_agent_indices[i - env->active_agent_count];
}
if(index == -1) continue;
if(index == agent_idx) continue;
- Entity* entity = &env->entities[index];
- float x1 = entity->x;
- float y1 = entity->y;
- float dist = ((x1 - agent->x)*(x1 - agent->x) + (y1 - agent->y)*(y1 - agent->y));
+
+ Agent* other_agent = &env->agents[index];
+ if (other_agent->respawn_timestep != -1) continue; // Skip respawning entities
+
+ float dist = ((other_agent->sim_x - agent->sim_x)*(other_agent->sim_x - agent->sim_x) + (other_agent->sim_y - agent->sim_y)*(other_agent->sim_y - agent->sim_y));
if(dist > 225.0f) continue;
- if(check_aabb_collision(agent, entity)) {
- collided = VEHICLE_COLLISION;
+ if(check_aabb_collision(agent, other_agent)) {
car_collided_with_index = index;
break;
}
}
- agent->collision_state = collided;
- // spawn immunity for collisions with other agent cars as agent_idx respawns
- int is_active_agent = env->entities[agent_idx].active_agent;
- int respawned = env->entities[agent_idx].respawn_timestep != -1;
- int exceeded_spawn_immunity_agent = (env->timestep - env->entities[agent_idx].respawn_timestep) >= env->spawn_immunity_timer;
- if(collided == VEHICLE_COLLISION && is_active_agent == 1 && respawned){
- agent->collision_state = 0;
- }
- // spawn immunity for collisions with other cars who just respawned
- if(collided == OFFROAD) return -1;
- if(car_collided_with_index ==-1) return -1;
+ return car_collided_with_index;
+}
- int respawned_collided_with_car = env->entities[car_collided_with_index].respawn_timestep != -1;
- int exceeded_spawn_immunity_collided_with_car = (env->timestep - env->entities[car_collided_with_index].respawn_timestep) >= env->spawn_immunity_timer;
- int within_spawn_immunity_collided_with_car = (env->timestep - env->entities[car_collided_with_index].respawn_timestep) < env->spawn_immunity_timer;
- if (respawned_collided_with_car) {
- agent->collision_state = 0;
+int check_lane_aligned(Agent* car, RoadMapElement* lane, int geometry_idx, int timestep) {
+ // Validate lane geometry length
+ if (!lane || lane->segment_length < 2) return 0;
+
+ // Clamp geometry index to valid segment range [0, segment_length-2]
+ if (geometry_idx < 0) geometry_idx = 0;
+ if (geometry_idx >= lane->segment_length - 1) geometry_idx = lane->segment_length - 2;
+
+ // Compute local lane segment heading
+ float heading_x1, heading_y1;
+ if (geometry_idx > 0) {
+ heading_x1 = lane->x[geometry_idx] - lane->x[geometry_idx - 1];
+ heading_y1 = lane->y[geometry_idx] - lane->y[geometry_idx - 1];
+ } else {
+ // For first segment, just use the forward direction
+ heading_x1 = lane->x[geometry_idx + 1] - lane->x[geometry_idx];
+ heading_y1 = lane->y[geometry_idx + 1] - lane->y[geometry_idx];
}
- return car_collided_with_index;
+ float heading_x2 = lane->x[geometry_idx + 1] - lane->x[geometry_idx];
+ float heading_y2 = lane->y[geometry_idx + 1] - lane->y[geometry_idx];
+
+ float heading_1 = atan2f(heading_y1, heading_x1);
+ float heading_2 = atan2f(heading_y2, heading_x2);
+ float heading = (heading_1 + heading_2) / 2.0f;
+
+ // Normalize to [-pi, pi]
+ if (heading > M_PI) heading -= 2.0f * M_PI;
+ if (heading < -M_PI) heading += 2.0f * M_PI;
+
+ // Compute heading difference
+ float car_heading = car->sim_heading; // radians
+ float heading_diff = fabsf(car_heading - heading);
+
+ if (heading_diff > M_PI) heading_diff = 2.0f * M_PI - heading_diff;
+
+ // within 15 degrees
+ return (heading_diff < (M_PI / 12.0f)) ? 1 : 0;
}
-int valid_active_agent(Drive* env, int agent_idx){
- float cos_heading = cosf(env->entities[agent_idx].traj_heading[0]);
- float sin_heading = sinf(env->entities[agent_idx].traj_heading[0]);
- float goal_x = env->entities[agent_idx].goal_position_x - env->entities[agent_idx].traj_x[0];
- float goal_y = env->entities[agent_idx].goal_position_y - env->entities[agent_idx].traj_y[0];
- // Rotate to ego vehicle's frame
- float rel_goal_x = goal_x*cos_heading + goal_y*sin_heading;
- float rel_goal_y = -goal_x*sin_heading + goal_y*cos_heading;
- float distance_to_goal = relative_distance_2d(0, 0, rel_goal_x, rel_goal_y);
- env->entities[agent_idx].width *= 0.7f;
- env->entities[agent_idx].length *= 0.7f;
- if(distance_to_goal >= 2.0f && env->entities[agent_idx].mark_as_expert == 0 && env->active_agent_count < env->num_agents){
- return distance_to_goal;
- }
- return 0;
+void reset_agent_metrics(Drive* env, int agent_idx){
+ Agent* agent = &env->agents[agent_idx];
+ agent->metrics_array[COLLISION_IDX] = 0.0f; // vehicle collision
+ agent->metrics_array[OFFROAD_IDX] = 0.0f; // offroad
+ agent->metrics_array[LANE_ALIGNED_IDX] = 0.0f; // lane aligned
+ agent->metrics_array[AVG_DISPLACEMENT_ERROR_IDX] = 0.0f;
+ agent->collision_state = 0;
}
-void set_active_agents(Drive* env){
- env->active_agent_count = 0;
- env->static_car_count = 0;
- env->num_cars = 1;
- env->expert_static_car_count = 0;
- int active_agent_indices[MAX_CARS];
- int static_car_indices[MAX_CARS];
- int expert_static_car_indices[MAX_CARS];
-
- if(env->num_agents ==0){
- env->num_agents = MAX_CARS;
- }
- int first_agent_id = env->num_objects-1;
- float distance_to_goal = valid_active_agent(env, first_agent_id);
- if(distance_to_goal){
- env->active_agent_count = 1;
- active_agent_indices[0] = first_agent_id;
- env->entities[first_agent_id].active_agent = 1;
- env->num_cars = 1;
- } else {
- env->active_agent_count = 0;
- env->num_cars = 0;
- }
- for(int i = 0; i < env->num_objects-1 && env->num_cars < MAX_CARS; i++){
- if(env->entities[i].type != 1) continue;
- if(env->entities[i].traj_valid[0] != 1) continue;
- env->num_cars++;
- float distance_to_goal = valid_active_agent(env, i);
- if(distance_to_goal > 0){
- active_agent_indices[env->active_agent_count] = i;
- env->active_agent_count++;
- env->entities[i].active_agent = 1;
- } else {
- static_car_indices[env->static_car_count] = i;
- env->static_car_count++;
- env->entities[i].active_agent = 0;
- if(env->entities[i].mark_as_expert == 1 || (distance_to_goal >=2.0f && env->active_agent_count == env->num_agents)){
- expert_static_car_indices[env->expert_static_car_count] = i;
- env->expert_static_car_count++;
- env->entities[i].mark_as_expert = 1;
- }
- }
+float point_to_segment_distance_2d(float px, float py, float x1, float y1, float x2, float y2) {
+ float dx = x2 - x1;
+ float dy = y2 - y1;
+
+ if (dx == 0 && dy == 0) {
+ // The segment is a point
+ return sqrtf((px - x1) * (px - x1) + (py - y1) * (py - y1));
}
- // set up initial active agents
- env->active_agent_indices = (int*)malloc(env->active_agent_count * sizeof(int));
- env->static_car_indices = (int*)malloc(env->static_car_count * sizeof(int));
- env->expert_static_car_indices = (int*)malloc(env->expert_static_car_count * sizeof(int));
- for(int i=0;iactive_agent_count;i++){
- env->active_agent_indices[i] = active_agent_indices[i];
- };
- for(int i=0;istatic_car_count;i++){
- env->static_car_indices[i] = static_car_indices[i];
-
+
+ // Calculate the t that minimizes the distance
+ float t = ((px - x1) * dx + (py - y1) * dy) / (dx * dx + dy * dy);
+
+ // Clamp t to the segment
+ if (t < 0) t = 0;
+ else if (t > 1) t = 1;
+
+ // Find the closest point on the segment
+ float closestX = x1 + t * dx;
+ float closestY = y1 + t * dy;
+
+ // Return the distance from p to the closest point
+ return sqrtf((px - closestX) * (px - closestX) + (py - closestY) * (py - closestY));
+}
+
+void compute_agent_metrics(Drive* env, int agent_idx) {
+ Agent* agent = &env->agents[agent_idx];
+
+ reset_agent_metrics(env, agent_idx);
+
+ if(agent->sim_x == INVALID_POSITION) return; // invalid agent position
+
+ // Compute displacement error
+ float displacement_error = compute_displacement_error(agent, env->timestep);
+
+ if (displacement_error > 0.0f) { // Only count valid displacements
+ agent->cumulative_displacement += displacement_error;
+ agent->displacement_sample_count++;
+
+ // Compute running average
+ agent->metrics_array[AVG_DISPLACEMENT_ERROR_IDX] =
+ agent->cumulative_displacement / agent->displacement_sample_count;
}
- for(int i=0;iexpert_static_car_count;i++){
- env->expert_static_car_indices[i] = expert_static_car_indices[i];
+
+ int collided = 0;
+ float half_length = agent->sim_length/2.0f;
+ float half_width = agent->sim_width/2.0f;
+ float cos_heading = cosf(agent->sim_heading);
+ float sin_heading = sinf(agent->sim_heading);
+ float min_distance = (float)INT16_MAX;
+
+ int closest_lane_entity_idx = -1;
+ int closest_lane_geometry_idx = -1;
+
+ float corners[4][2];
+ for (int i = 0; i < 4; i++) {
+ corners[i][0] = agent->sim_x + (offsets[i][0]*half_length*cos_heading - offsets[i][1]*half_width*sin_heading);
+ corners[i][1] = agent->sim_y + (offsets[i][0]*half_length*sin_heading + offsets[i][1]*half_width*cos_heading);
}
- return;
-}
-void remove_bad_trajectories(Drive* env){
- set_start_position(env);
- int collided_agents[env->active_agent_count];
- int collided_with_indices[env->active_agent_count];
- memset(collided_agents, 0, env->active_agent_count * sizeof(int));
+ GridMapEntity entity_list[MAX_ENTITIES_PER_CELL*25]; // Array big enough for all neighboring cells
+ int list_size = checkNeighbors(env, agent->sim_x, agent->sim_y, entity_list, MAX_ENTITIES_PER_CELL*25, collision_offsets, 25);
+ for (int i = 0; i < list_size; i++) {
+ if(entity_list[i].entity_idx == -1) continue;
+
+ // Get the road element (only road elements are in grid)
+ if(entity_list[i].entity_type != ENTITY_TYPE_ROAD_ELEMENT) continue;
+
+ RoadMapElement* element = &env->road_elements[entity_list[i].entity_idx];
+ int geometry_idx = entity_list[i].geometry_idx;
+
+ // Check for offroad collision with road edges
+ if(is_road_edge(element->type)) {
+ float start[2] = {element->x[geometry_idx], element->y[geometry_idx]};
+ float end[2] = {element->x[geometry_idx + 1], element->y[geometry_idx + 1]};
+ for (int k = 0; k < 4; k++) { // Check each edge of the bounding box
+ int next = (k + 1) % 4;
+ if (check_line_intersection(corners[k], corners[next], start, end)) {
+ collided = OFFROAD;
+ break;
+ }
+ }
+ }
+
+ if (collided == OFFROAD) break;
+
+ // Find closest point on the road centerline to the agent
+ if(is_drivable_road_lane(element->type)) {
+ int elem_idx = entity_list[i].entity_idx;
+
+ float start[2] = {element->x[geometry_idx], element->y[geometry_idx]};
+ float end[2] = {element->x[geometry_idx + 1], element->y[geometry_idx + 1]};
+
+ float dist = point_to_segment_distance_2d(agent->sim_x, agent->sim_y, start[0], start[1], end[0], end[1]);
+ float heading_diff = fabsf(atan2f(end[1]-start[1], end[0]-start[0]) - agent->sim_heading);
+
+ // Normalize heading difference to [0, pi]
+ if (heading_diff > M_PI) heading_diff = 2.0f * M_PI - heading_diff;
+
+ // Penalize if heading differs by more than 30 degrees
+ if (heading_diff > (M_PI / 6.0f)) dist += 3.0f;
+
+ if (dist < min_distance) {
+ min_distance = dist;
+ closest_lane_entity_idx = elem_idx;
+ closest_lane_geometry_idx = geometry_idx;
+ }
+ }
+ }
+
+ // check if aligned with closest lane and set current lane
+ // 4.0m threshold: agents more than 4 meters from any lane are considered off-road
+ if (min_distance > 4.0f || closest_lane_entity_idx == -1) {
+ agent->metrics_array[LANE_ALIGNED_IDX] = 0.0f;
+ agent->current_lane_idx = -1;
+ } else {
+ agent->current_lane_idx = closest_lane_entity_idx;
+
+ int lane_aligned = check_lane_aligned(agent, &env->road_elements[closest_lane_entity_idx], closest_lane_geometry_idx, env->timestep);
+ agent->metrics_array[LANE_ALIGNED_IDX] = lane_aligned;
+ }
+
+ // Check for vehicle collisions
+ int car_collided_with_index = collision_check(env, agent_idx);
+ if (car_collided_with_index != -1) collided = VEHICLE_COLLISION;
+
+ agent->collision_state = collided;
+
+ return;
+}
+
+bool should_control_agent(Drive* env, int agent_idx){
+ // Check if we have room for more agents or are already at capacity
+ if (env->active_agent_count >= env->num_max_agents) {
+ return false;
+ }
+
+ Agent* agent = &env->agents[agent_idx];
+
+ if (env->control_mode == CONTROL_SDC_ONLY) {
+ return (agent_idx == env->sdc_index);
+ }
+
+ // Special mode: control only agents in prediction track list
+ if (env->control_mode == CONTROL_TRACKS_TO_PREDICT) {
+ for (int j = 0; j < env->num_tracks_to_predict; j++) {
+ if (env->tracks_to_predict[j] == agent_idx) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Standard mode: check type, distance to goal, and expert status
+ bool type_is_controllable = false;
+ if (env->control_mode == CONTROL_VEHICLES) {
+ type_is_controllable = (agent->type == VEHICLE);
+ } else { // CONTROL_AGENTS mode
+ type_is_controllable = (agent->type == VEHICLE || agent->type == PEDESTRIAN || agent->type == CYCLIST);
+ }
+
+ if (!type_is_controllable || agent->mark_as_expert) {
+ return false;
+ }
+
+ // Check distance to goal in agent's local frame
+ float cos_heading = cosf(agent->log_heading[0]);
+ float sin_heading = sinf(agent->log_heading[0]);
+ float goal_dx = agent->goal_position_x - agent->log_trajectory_x[0];
+ float goal_dy = agent->goal_position_y - agent->log_trajectory_y[0];
+
+ // Transform to agent's local frame
+ float local_goal_x = goal_dx * cos_heading + goal_dy * sin_heading;
+ float local_goal_y = -goal_dx * sin_heading + goal_dy * cos_heading;
+ float distance_to_goal = relative_distance_2d(0, 0, local_goal_x, local_goal_y);
+
+ return distance_to_goal >= MIN_DISTANCE_TO_GOAL;
+}
+
+void set_active_agents(Drive* env){
+ // Initialize
+ env->active_agent_count = 0; // Policy-controlled agents
+ env->static_agent_count = 0; // Non-moving background agents
+ env->expert_static_agent_count = 0; // Expert replay agents (non-controlled)
+ env->num_actors = 0; // Total agents created
+
+ int active_agent_indices[MAX_AGENTS];
+ int static_agent_indices[MAX_AGENTS];
+ int expert_static_agent_indices[MAX_AGENTS];
+
+ if(env->num_max_agents == 0){
+ env->num_max_agents = MAX_AGENTS;
+ }
+
+ // Iterate through entities to find agents to create and/or control
+ for(int i = 0; i < env->num_total_agents && env->num_actors < MAX_AGENTS; i++){
+
+ Agent* agent = &env->agents[i];
+
+ // Skip if not valid at initialization
+ if (agent->log_valid[env->init_steps] != 1) {
+ continue;
+ }
+
+ // Determine if entity should be created
+ bool should_create = false;
+ if (env->init_mode == INIT_ALL_VALID) {
+ should_create = true; // All valid entities
+ } else if (env->control_mode == CONTROL_VEHICLES) {
+ should_create = (agent->type == VEHICLE);
+ } else { // Control all agents
+ should_create = (is_controllable_agent(agent->type));
+ }
+
+ if (!should_create) continue;
+
+ env->num_actors++;
+
+ // Determine if this agent should be policy-controlled
+ bool is_controlled = false;
+
+ is_controlled = should_control_agent(env, i);
+
+ if(is_controlled){
+ active_agent_indices[env->active_agent_count] = i;
+ env->active_agent_count++;
+ env->agents[i].active_agent = 1;
+ } else if (env->init_mode != INIT_ONLY_CONTROLLABLE_AGENTS) {
+ static_agent_indices[env->static_agent_count] = i;
+ env->static_agent_count++;
+ env->agents[i].active_agent = 0;
+ if(env->agents[i].mark_as_expert == 1 || env->active_agent_count == env->num_max_agents) {
+ expert_static_agent_indices[env->expert_static_agent_count] = i;
+ env->expert_static_agent_count++;
+ env->agents[i].mark_as_expert = 1;
+ }
+ }
+ }
+
+ // Set up initial active agents
+ env->active_agent_indices = (int*)malloc(env->active_agent_count * sizeof(int));
+ env->static_agent_indices = (int*)malloc(env->static_agent_count * sizeof(int));
+ env->expert_static_agent_indices = (int*)malloc(env->expert_static_agent_count * sizeof(int));
+ for(int i=0;iactive_agent_count;i++){
+ env->active_agent_indices[i] = active_agent_indices[i];
+ };
+ for(int i=0;istatic_agent_count;i++){
+ env->static_agent_indices[i] = static_agent_indices[i];
+ }
+ for(int i=0;iexpert_static_agent_count;i++){
+ env->expert_static_agent_indices[i] = expert_static_agent_indices[i];
+ }
+
+ return;
+}
+
+void remove_bad_trajectories(Drive* env){
+
+ if (env->control_mode != CONTROL_TRACKS_TO_PREDICT) {
+ return; // Leave all trajectories in WOSAC control mode
+ }
+
+ set_start_position(env);
+ int collided_agents[env->active_agent_count];
+ int collided_with_indices[env->active_agent_count];
+ memset(collided_agents, 0, env->active_agent_count * sizeof(int));
+ for (int i = 0; i < env->active_agent_count; ++i) {
+ collided_with_indices[i] = -1;
+ }
// move experts through trajectories to check for collisions and remove as illegal agents
- for(int t = 0; t < TRAJECTORY_LENGTH; t++){
+ for(int t = 0; t < env->scenario_length; t++){
for(int i = 0; i < env->active_agent_count; i++){
int agent_idx = env->active_agent_indices[i];
move_expert(env, env->actions, agent_idx);
}
- for(int i = 0; i < env->expert_static_car_count; i++){
- int expert_idx = env->expert_static_car_indices[i];
- if(env->entities[expert_idx].x == -10000) continue;
+ for(int i = 0; i < env->expert_static_agent_count; i++){
+ int expert_idx = env->expert_static_agent_indices[i];
+ if(env->agents[expert_idx].sim_x == INVALID_POSITION) continue;
move_expert(env, env->actions, expert_idx);
}
// check collisions
for(int i = 0; i < env->active_agent_count; i++){
int agent_idx = env->active_agent_indices[i];
- env->entities[agent_idx].collision_state = 0;
+ env->agents[agent_idx].collision_state = 0;
int collided_with_index = collision_check(env, agent_idx);
- if(env->entities[agent_idx].collision_state > 0 && collided_agents[i] == 0){
+ if((collided_with_index >= 0) && collided_agents[i] == 0){
collided_agents[i] = 1;
collided_with_indices[i] = collided_with_index;
}
@@ -930,70 +1510,84 @@ void remove_bad_trajectories(Drive* env){
for(int i = 0; i< env->active_agent_count; i++){
if(collided_with_indices[i] == -1) continue;
- for(int j = 0; j < env->static_car_count; j++){
- int static_car_idx = env->static_car_indices[j];
- if(static_car_idx != collided_with_indices[i]) continue;
- env->entities[static_car_idx].traj_x[0] = -10000;
- env->entities[static_car_idx].traj_y[0] = -10000;
+ for(int j = 0; j < env->static_agent_count; j++){
+ int static_agent_idx = env->static_agent_indices[j];
+ if(static_agent_idx != collided_with_indices[i]) continue;
+ env->agents[static_agent_idx].log_trajectory_x[0] = INVALID_POSITION;
+ env->agents[static_agent_idx].log_trajectory_y[0] = INVALID_POSITION;
}
}
env->timestep = 0;
}
+
+void init_goal_positions(Drive* env){
+ for(int x = 0;xactive_agent_count; x++){
+ int agent_idx = env->active_agent_indices[x];
+ env->agents[agent_idx].init_goal_x = env->agents[agent_idx].goal_position_x;
+ env->agents[agent_idx].init_goal_y = env->agents[agent_idx].goal_position_y;
+ }
+}
+
void init(Drive* env){
env->human_agent_idx = 0;
env->timestep = 0;
load_map_binary(env->map_name, env);
- if (env->entities == NULL || env->map_entities == NULL) {
- printf("ERROR: Failed to load map: %s\n", env->map_name);
- exit(1); // Or handle gracefully
- }
- env->dynamics_model = CLASSIC;
set_means(env);
init_grid_map(env);
- env->vision_range = 21;
+ if (env->goal_behavior==GOAL_GENERATE_NEW) init_topology_graph(env);
+ env->grid_map->vision_range = 21;
init_neighbor_offsets(env);
- env->neighbor_cache_indices = (int*)calloc((env->grid_cols*env->grid_rows) + 1, sizeof(int));
cache_neighbor_offsets(env);
+ env->logs_capacity = 0;
set_active_agents(env);
+ env->logs_capacity = env->active_agent_count;
remove_bad_trajectories(env);
set_start_position(env);
+ init_goal_positions(env);
env->logs = (Log*)calloc(env->active_agent_count, sizeof(Log));
}
void c_close(Drive* env){
- for(int i = 0; i < env->num_objects; i++){
- free_entity(&env->entities[i]);
- }
- free(env->entities);
- for(int i = 0; i < env->num_roads; i++){
- free_map_entity(&env->map_entities[i]);
- }
- free(env->map_entities);
+ for(int i = 0; i < env->num_total_agents; i++) free_agent(&env->agents[i]);
+ for(int i = 0; i < env->num_road_elements; i++) free_road_element(&env->road_elements[i]);
+ for(int i = 0; i < env->num_traffic_elements; i++) free_traffic_element(&env->traffic_elements[i]);
+ free(env->agents);
+ free(env->road_elements);
+ free(env->traffic_elements);
free(env->active_agent_indices);
free(env->logs);
- free(env->map_corners);
- free(env->grid_cells);
+ // GridMap cleanup
+ int grid_cell_count = env->grid_map->grid_cols*env->grid_map->grid_rows;
+ for(int grid_index = 0; grid_index < grid_cell_count; grid_index++){
+ free(env->grid_map->cells[grid_index]);
+ }
+ free(env->grid_map->cells);
+ free(env->grid_map->cell_entities_count);
free(env->neighbor_offsets);
- free(env->neighbor_cache_entities);
- free(env->neighbor_cache_indices);
- free(env->static_car_indices);
- free(env->expert_static_car_indices);
+
+ for(int i = 0; i < grid_cell_count; i++){
+ free(env->grid_map->neighbor_cache_entities[i]);
+ }
+ free(env->grid_map->neighbor_cache_entities);
+ free(env->grid_map->neighbor_cache_count);
+ free(env->grid_map);
+ free(env->static_agent_indices);
+ free(env->expert_static_agent_indices);
+ free(env->objects_of_interest);
+ free(env->tracks_to_predict);
+ freeTopologyGraph(env->topology_graph);
// free(env->map_name);
+ free(env->ini_file);
}
void allocate(Drive* env){
init(env);
- int max_obs = 7 + 7*(MAX_CARS - 1) + 7*MAX_ROAD_SEGMENT_OBSERVATIONS;
- // printf("max obs: %d\n", max_obs*env->active_agent_count);
- // printf("num cars: %d\n", env->num_cars);
- // printf("num static cars: %d\n", env->static_car_count);
- // printf("active agent count: %d\n", env->active_agent_count);
- // printf("num objects: %d\n", env->num_objects);
+ int ego_dim = (env->dynamics_model == JERK) ? 10 : 7;
+ int max_obs = ego_dim + 7*(MAX_AGENTS - 1) + 7*MAX_ROAD_SEGMENT_OBSERVATIONS;
env->observations = (float*)calloc(env->active_agent_count*max_obs, sizeof(float));
- env->actions = (int*)calloc(env->active_agent_count*2, sizeof(int));
+ env->actions = (float*)calloc(env->active_agent_count*2, sizeof(float));
env->rewards = (float*)calloc(env->active_agent_count, sizeof(float));
env->terminals= (unsigned char*)calloc(env->active_agent_count, sizeof(unsigned char));
- // printf("allocated\n");
}
void free_allocated(Drive* env){
@@ -1017,115 +1611,272 @@ float normalize_heading(float heading){
return heading;
}
+float normalize_value(float value, float min, float max){
+ return (value - min) / (max - min);
+}
+
void move_dynamics(Drive* env, int action_idx, int agent_idx){
- if(env->dynamics_model == CLASSIC){
- // clip acceleration & steering
- Entity* agent = &env->entities[agent_idx];
- // Extract action components directly from the multi-discrete action array
- int (*action_array)[2] = (int(*)[2])env->actions;
- int acceleration_index = action_array[action_idx][0];
- int steering_index = action_array[action_idx][1];
- float acceleration = ACCELERATION_VALUES[acceleration_index];
- float steering = STEERING_VALUES[steering_index];
+ Agent* agent = &env->agents[agent_idx];
+ if (agent->removed) return;
+
+ if (agent->stopped) {
+ agent->sim_vx = 0.0f;
+ agent->sim_vy = 0.0f;
+ return;
+ }
+
+ if (env->dynamics_model == CLASSIC) {
+ // Classic dynamics model
+ float acceleration = 0.0f;
+ float steering = 0.0f;
+
+ if (env->action_type == 1) { // continuous
+ float (*action_array_f)[2] = (float(*)[2])env->actions;
+ acceleration = action_array_f[action_idx][0];
+ steering = action_array_f[action_idx][1];
+
+ acceleration *= ACCELERATION_VALUES[6];
+ steering *= STEERING_VALUES[12];
+ } else { // discrete
+ // Interpret action as a single integer: a = accel_idx * num_steer + steer_idx
+ int* action_array = (int*)env->actions;
+ int num_accel = sizeof(ACCELERATION_VALUES) / sizeof(ACCELERATION_VALUES[0]);
+ int num_steer = sizeof(STEERING_VALUES) / sizeof(STEERING_VALUES[0]);
+ int action_val = action_array[action_idx];
+ int acceleration_index = action_val / num_steer;
+ int steering_index = action_val % num_steer;
+ acceleration = ACCELERATION_VALUES[acceleration_index];
+ steering = STEERING_VALUES[steering_index];
+ }
// Current state
- float x = agent->x;
- float y = agent->y;
- float heading = agent->heading;
- float vx = agent->vx;
- float vy = agent->vy;
-
+ float x = agent->sim_x;
+ float y = agent->sim_y;
+ float heading = agent->sim_heading;
+ float vx = agent->sim_vx;
+ float vy = agent->sim_vy;
+ float length = agent->sim_length;
+
// Calculate current speed
float speed = sqrtf(vx*vx + vy*vy);
-
- // Time step (adjust as needed)
- const float dt = 0.1f;
+
// Update speed with acceleration
- speed = speed + 0.5f*acceleration*dt;
- // if (speed < 0) speed = 0; // Prevent going backward
+ speed = speed + acceleration * env->dt;
speed = clipSpeed(speed);
- // compute yaw rate
+
+ // Compute yaw rate
float beta = tanh(.5*tanf(steering));
- // new heading
- float yaw_rate = (speed*cosf(beta)*tanf(steering)) / agent->length;
- // new velocity
+
+ // New heading
+ float yaw_rate = (speed*cosf(beta)*tanf(steering)) / length;
+
+ // New velocity
float new_vx = speed*cosf(heading + beta);
float new_vy = speed*sinf(heading + beta);
+
// Update position
- x = x + (new_vx*dt);
- y = y + (new_vy*dt);
- heading = heading + yaw_rate*dt;
- // heading = normalize_heading(heading);
+ x = x + (new_vx*env->dt);
+ y = y + (new_vy*env->dt);
+ heading = heading + yaw_rate*env->dt;
+
// Apply updates to the agent's state
- agent->x = x;
- agent->y = y;
- agent->heading = heading;
- agent->heading_x = cosf(heading);
- agent->heading_y = sinf(heading);
- agent->vx = new_vx;
- agent->vy = new_vy;
+ agent->sim_x = x;
+ agent->sim_y = y;
+ agent->sim_heading = heading;
+ agent->sim_vx = new_vx;
+ agent->sim_vy = new_vy;
+ } else {
+ // JERK dynamics model
+ // Extract action components
+ float a_long, a_lat;
+ if (env->action_type == 1) { // continuous
+ float (*action_array_f)[2] = (float(*)[2])env->actions;
+
+ // Asymmetric scaling for longitudinal jerk to match discrete action space
+ // Discrete: JERK_LONG = [-15, -4, 0, 4] (more braking than acceleration)
+ float a_long_action = action_array_f[action_idx][0]; // [-1, 1]
+ if (a_long_action < 0) {
+ a_long = a_long_action * (-JERK_LONG[0]); // Negative: [-1, 0] → [-15, 0] (braking)
+ } else {
+ a_long = a_long_action * JERK_LONG[3]; // Positive: [0, 1] → [0, 4] (acceleration)
+ }
+
+ // Symmetric scaling for lateral jerk
+ a_lat = action_array_f[action_idx][1] * JERK_LAT[2];
+ } else { // discrete
+ int (*action_array)[2] = (int(*)[2])env->actions;
+ int a_long_idx = action_array[action_idx][0];
+ int a_lat_idx = action_array[action_idx][1];
+ a_long = JERK_LONG[a_long_idx];
+ a_lat = JERK_LAT[a_lat_idx];
+ }
+
+ // Calculate new acceleration
+ float a_long_new = agent->a_long + a_long * env->dt;
+ float a_lat_new = agent->a_lat + a_lat * env->dt;
+
+ // Make it easy to stop with 0 accel
+ if (agent->a_long * a_long_new < 0) {
+ a_long_new = 0.0f;
+ } else {
+ a_long_new = clip(a_long_new, -5.0f, 2.5f);
+ }
+
+ if (agent->a_lat * a_lat_new < 0) {
+ a_lat_new = 0.0f;
+ } else {
+ a_lat_new = clip(a_lat_new, -4.0f, 4.0f);
+ }
+
+ float heading_x = cosf(agent->sim_heading);
+ float heading_y = sinf(agent->sim_heading);
+
+ // Calculate new velocity
+ float v_dot_heading = agent->sim_vx * heading_x + agent->sim_vy * heading_y;
+ float signed_v = copysignf(sqrtf(agent->sim_vx*agent->sim_vx + agent->sim_vy*agent->sim_vy), v_dot_heading);
+ float v_new = signed_v + 0.5f * (a_long_new + agent->a_long) * env->dt;
+
+ // Make it easy to stop with 0 vel
+ if (signed_v * v_new < 0) {
+ v_new = 0.0f;
+ } else {
+ v_new = clip(v_new, -2.0f, 20.0f);
+ }
+
+ // Calculate new steering angle
+ float signed_curvature = a_lat_new / fmaxf(v_new * v_new, 1e-5f);
+ signed_curvature = copysignf(fmaxf(fabsf(signed_curvature), 1e-5f), signed_curvature);
+ float steering_angle = atanf(signed_curvature * agent->wheelbase);
+ float delta_steer = clip(steering_angle - agent->steering_angle, -0.6f * env->dt, 0.6f * env->dt);
+ float new_steering_angle = clip(agent->steering_angle + delta_steer, -0.55f, 0.55f);
+
+ // Update curvature and accel to account for limited steering
+ signed_curvature = tanf(new_steering_angle) / agent->wheelbase;
+ a_lat_new = v_new * v_new * signed_curvature;
+
+ // Calculate resulting movement using bicycle dynamics
+ float d = 0.5f * (v_new + signed_v) * env->dt;
+ float theta = d * signed_curvature;
+ float dx_local, dy_local;
+
+ if (fabsf(signed_curvature) < 1e-5f || fabsf(theta) < 1e-5f) {
+ dx_local = d;
+ dy_local = 0.0f;
+ } else {
+ dx_local = sinf(theta) / signed_curvature;
+ dy_local = (1.0f - cosf(theta)) / signed_curvature;
+ }
+
+ float dx = dx_local * heading_x - dy_local * heading_y;
+ float dy = dx_local * heading_y + dy_local * heading_x;
+
+ // Update agent state
+ agent->sim_x += dx;
+ agent->sim_y += dy;
+ agent->jerk_long = (a_long_new - agent->a_long) / env->dt;
+ agent->jerk_lat = (a_lat_new - agent->a_lat) / env->dt;
+ agent->a_long = a_long_new;
+ agent->a_lat = a_lat_new;
+ agent->sim_heading = normalize_heading(agent->sim_heading + theta);
+ agent->sim_vx = v_new * cosf(agent->sim_heading);
+ agent->sim_vy = v_new * sinf(agent->sim_heading);
+ agent->steering_angle = new_steering_angle;
}
+
return;
}
-float normalize_value(float value, float min, float max){
- return (value - min) / (max - min);
+void c_get_global_agent_state(Drive* env, float* x_out, float* y_out, float* z_out, float* heading_out, int* id_out) {
+ for(int i = 0; i < env->active_agent_count; i++){
+ int agent_idx = env->active_agent_indices[i];
+ Agent* agent = &env->agents[agent_idx];
+
+ // For WOSAC, we need the original world coordinates, so we add the world means back
+ x_out[i] = agent->sim_x + env->world_mean_x;
+ y_out[i] = agent->sim_y + env->world_mean_y;
+ z_out[i] = agent->sim_z;
+ heading_out[i] = agent->sim_heading;
+ id_out[i] = env->tracks_to_predict[i];
+ }
}
-float reverse_normalize_value(float value, float min, float max){
- return value*50.0f;
+void c_get_global_ground_truth_trajectories(Drive* env, float* x_out, float* y_out, float* z_out, float* heading_out, int* valid_out, int* id_out, int* scenario_id_out) {
+ for(int i = 0; i < env->active_agent_count; i++){
+ int agent_idx = env->active_agent_indices[i];
+ Agent* agent = &env->agents[agent_idx];
+ id_out[i] = env->tracks_to_predict[i];
+ scenario_id_out[i] = env->map_index;
+
+ for(int t = env->init_steps; t < agent->trajectory_length; t++){
+ int out_idx = i * (agent->trajectory_length - env->init_steps) + (t - env->init_steps);
+ // Add world means back to get original world coordinates
+ x_out[out_idx] = agent->log_trajectory_x[t] + env->world_mean_x;
+ y_out[out_idx] = agent->log_trajectory_y[t] + env->world_mean_y;
+ z_out[out_idx] = agent->log_trajectory_z[t];
+ heading_out[out_idx] = agent->log_heading[t];
+ valid_out[out_idx] = agent->log_valid[t];
+ }
+ }
}
void compute_observations(Drive* env) {
- int max_obs = 7 + 7*(MAX_CARS - 1) + 7*MAX_ROAD_SEGMENT_OBSERVATIONS;
+ int ego_dim = (env->dynamics_model == JERK) ? 10 : 7;
+ int max_obs = ego_dim + 7*(MAX_AGENTS - 1) + 7*MAX_ROAD_SEGMENT_OBSERVATIONS;
memset(env->observations, 0, max_obs*env->active_agent_count*sizeof(float));
- float (*observations)[max_obs] = (float(*)[max_obs])env->observations;
+ float (*observations)[max_obs] = (float(*)[max_obs])env->observations;
for(int i = 0; i < env->active_agent_count; i++) {
float* obs = &observations[i][0];
- Entity* ego_entity = &env->entities[env->active_agent_indices[i]];
- if(ego_entity->type > 3) break;
- if(ego_entity->respawn_timestep != -1) {
- obs[6] = 1;
- //continue;
- }
- float cos_heading = ego_entity->heading_x;
- float sin_heading = ego_entity->heading_y;
- float ego_speed = sqrtf(ego_entity->vx*ego_entity->vx + ego_entity->vy*ego_entity->vy);
+ Agent* ego_entity = &env->agents[env->active_agent_indices[i]];
+
+ float ego_heading = ego_entity->sim_heading;
+ float cos_heading = cosf(ego_heading);
+ float sin_heading = sinf(ego_heading);
+ float ego_speed = sqrtf(ego_entity->sim_vx*ego_entity->sim_vx + ego_entity->sim_vy*ego_entity->sim_vy);
+
// Set goal distances
- float goal_x = ego_entity->goal_position_x - ego_entity->x;
- float goal_y = ego_entity->goal_position_y - ego_entity->y;
+ float goal_x = ego_entity->goal_position_x - ego_entity->sim_x;
+ float goal_y = ego_entity->goal_position_y - ego_entity->sim_y;
+
// Rotate to ego vehicle's frame
float rel_goal_x = goal_x*cos_heading + goal_y*sin_heading;
float rel_goal_y = -goal_x*sin_heading + goal_y*cos_heading;
- //obs[0] = normalize_value(rel_goal_x, MIN_REL_GOAL_COORD, MAX_REL_GOAL_COORD);
- //obs[1] = normalize_value(rel_goal_y, MIN_REL_GOAL_COORD, MAX_REL_GOAL_COORD);
+
obs[0] = rel_goal_x* 0.005f;
obs[1] = rel_goal_y* 0.005f;
- //obs[2] = ego_speed / MAX_SPEED;
- obs[2] = ego_speed * 0.01f;
- obs[3] = ego_entity->width / MAX_VEH_WIDTH;
- obs[4] = ego_entity->length / MAX_VEH_LEN;
- obs[5] = (ego_entity->collision_state > 0) ? 1 : 0;
-
+ obs[2] = ego_speed / MAX_SPEED;
+ obs[3] = ego_entity->sim_width / MAX_VEH_WIDTH;
+ obs[4] = ego_entity->sim_length / MAX_VEH_LEN;
+ obs[5] = (ego_entity->collision_state > 0) ? 1.0f : 0.0f;
+
+ if (env->dynamics_model == JERK) {
+ obs[6] = ego_entity->steering_angle / M_PI;
+ // Asymmetric normalization for a_long to match action space
+ obs[7] = (ego_entity->a_long < 0) ? ego_entity->a_long / (-JERK_LONG[0]) : ego_entity->a_long / JERK_LONG[3];
+ obs[8] = ego_entity->a_lat / JERK_LAT[2];
+ obs[9] = (ego_entity->respawn_timestep != -1) ? 1 : 0;
+ } else {
+ obs[6] = (ego_entity->respawn_timestep != -1) ? 1 : 0;
+ }
+
// Relative Pos of other cars
- int obs_idx = 7; // Start after goal distances
+ int obs_idx = ego_dim;
int cars_seen = 0;
- for(int j = 0; j < MAX_CARS; j++) {
+ for(int j = 0; j < MAX_AGENTS; j++) {
int index = -1;
if(j < env->active_agent_count){
index = env->active_agent_indices[j];
- } else if (j < env->num_cars){
- index = env->static_car_indices[j - env->active_agent_count];
- }
+ } else if (j < env->num_actors){
+ index = env->static_agent_indices[j - env->active_agent_count];
+ }
if(index == -1) continue;
- if(env->entities[index].type > 3) break;
+ if(env->agents[index].type > 3) break;
if(index == env->active_agent_indices[i]) continue; // Skip self, but don't increment obs_idx
- Entity* other_entity = &env->entities[index];
+ Agent* other_entity = &env->agents[index];
if(ego_entity->respawn_timestep != -1) continue;
if(other_entity->respawn_timestep != -1) continue;
// Store original relative positions
- float dx = other_entity->x - ego_entity->x;
- float dy = other_entity->y - ego_entity->y;
+ float dx = other_entity->sim_x - ego_entity->sim_x;
+ float dy = other_entity->sim_y - ego_entity->sim_y;
float dist = (dx*dx + dy*dy);
if(dist > 2500.0f) continue;
// Rotate to ego vehicle's frame
@@ -1134,43 +1885,66 @@ void compute_observations(Drive* env) {
// Store observations with correct indexing
obs[obs_idx] = rel_x * 0.02f;
obs[obs_idx + 1] = rel_y * 0.02f;
- obs[obs_idx + 2] = other_entity->width / MAX_VEH_WIDTH;
- obs[obs_idx + 3] = other_entity->length / MAX_VEH_LEN;
+ obs[obs_idx + 2] = other_entity->sim_width / MAX_VEH_WIDTH;
+ obs[obs_idx + 3] = other_entity->sim_length / MAX_VEH_LEN;
// relative heading
- float rel_heading_x = other_entity->heading_x * ego_entity->heading_x +
- other_entity->heading_y * ego_entity->heading_y; // cos(a-b) = cos(a)cos(b) + sin(a)sin(b)
- float rel_heading_y = other_entity->heading_y * ego_entity->heading_x -
- other_entity->heading_x * ego_entity->heading_y; // sin(a-b) = sin(a)cos(b) - cos(a)sin(b)
+ float other_heading = other_entity->sim_heading;
+ float other_cos = cosf(other_heading);
+ float other_sin = sinf(other_heading);
+ float rel_heading_x = other_cos * cos_heading +
+ other_sin * sin_heading; // cos(a-b) = cos(a)cos(b) + sin(a)sin(b)
+ float rel_heading_y = other_sin * cos_heading -
+ other_cos * sin_heading; // sin(a-b) = sin(a)cos(b) - cos(a)sin(b)
obs[obs_idx + 4] = rel_heading_x;
obs[obs_idx + 5] = rel_heading_y;
// obs[obs_idx + 4] = cosf(rel_heading) / MAX_ORIENTATION_RAD;
// obs[obs_idx + 5] = sinf(rel_heading) / MAX_ORIENTATION_RAD;
// // relative speed
- float other_speed = sqrtf(other_entity->vx*other_entity->vx + other_entity->vy*other_entity->vy);
+ float other_speed = sqrtf(other_entity->sim_vx*other_entity->sim_vx + other_entity->sim_vy*other_entity->sim_vy);
obs[obs_idx + 6] = other_speed / MAX_SPEED;
cars_seen++;
obs_idx += 7; // Move to next observation slot
}
- int remaining_partner_obs = (MAX_CARS - 1 - cars_seen) * 7;
+ int remaining_partner_obs = (MAX_AGENTS - 1 - cars_seen) * 7;
memset(&obs[obs_idx], 0, remaining_partner_obs * sizeof(float));
obs_idx += remaining_partner_obs;
// map observations
- int entity_list[MAX_ROAD_SEGMENT_OBSERVATIONS*2]; // Array big enough for all neighboring cells
- int grid_idx = getGridIndex(env, ego_entity->x, ego_entity->y);
+ GridMapEntity entity_list[MAX_ENTITIES_PER_CELL*25];
+ int grid_idx = getGridIndex(env, ego_entity->sim_x, ego_entity->sim_y);
+
int list_size = get_neighbor_cache_entities(env, grid_idx, entity_list, MAX_ROAD_SEGMENT_OBSERVATIONS);
- for(int k = 0; k < list_size; k++){
- int entity_idx = entity_list[k*2];
- int geometry_idx = entity_list[k*2+1];
- MapEntity* entity = &env->map_entities[entity_idx];
- float start_x = entity->traj_x[geometry_idx];
- float start_y = entity->traj_y[geometry_idx];
- float end_x = entity->traj_x[geometry_idx+1];
- float end_y = entity->traj_y[geometry_idx+1];
+
+ for(int k = 0; k < list_size; k++) {
+ int entity_type = entity_list[k].entity_type;
+ int entity_idx = entity_list[k].entity_idx;
+ int geometry_idx = entity_list[k].geometry_idx;
+
+ // Only process road elements in observations
+ if(entity_type != ENTITY_TYPE_ROAD_ELEMENT) continue;
+
+ // Validate entity_idx before accessing
+ if(entity_idx < 0 || entity_idx >= env->num_road_elements) {
+ printf("ERROR: Invalid road element idx %d (max: %d)\n", entity_idx, env->num_road_elements-1);
+ continue;
+ }
+
+ RoadMapElement* element = &env->road_elements[entity_idx];
+
+ // Validate geometry_idx before accessing
+ if(geometry_idx < 0 || geometry_idx > element->segment_length) {
+ printf("ERROR: Invalid geometry_idx %d for road element %d (max: %d)\n",
+ geometry_idx, entity_idx, element->segment_length-1);
+ continue;
+ }
+ float start_x = element->x[geometry_idx];
+ float start_y = element->y[geometry_idx];
+ float end_x = element->x[geometry_idx+1];
+ float end_y = element->y[geometry_idx+1];
float mid_x = (start_x + end_x) / 2.0f;
float mid_y = (start_y + end_y) / 2.0f;
- float rel_x = mid_x - ego_entity->x;
- float rel_y = mid_y - ego_entity->y;
+ float rel_x = mid_x - ego_entity->sim_x;
+ float rel_y = mid_y - ego_entity->sim_y;
float x_obs = rel_x*cos_heading + rel_y*sin_heading;
float y_obs = -rel_x*sin_heading + rel_y*cos_heading;
float length = relative_distance_2d(mid_x, mid_y, end_x, end_y);
@@ -1194,7 +1968,7 @@ void compute_observations(Drive* env) {
obs[obs_idx + 3] = width / MAX_ROAD_SCALE;
obs[obs_idx + 4] = cos_angle;
obs[obs_idx + 5] = sin_angle;
- obs[obs_idx + 6] = entity->type - 4.0f;
+ obs[obs_idx + 6] = normalize_road_type(element->type);
obs_idx += 7;
}
int remaining_obs = (MAX_ROAD_SEGMENT_OBSERVATIONS - list_size) * 7;
@@ -1203,47 +1977,215 @@ void compute_observations(Drive* env) {
}
}
+static int find_forward_projection_on_lane(RoadMapElement* lane, Agent* agent, int timestep, int* out_segment_idx, float* out_fraction) {
+ int best_idx = -1;
+ float best_dist_sq = 1e30f;
+
+ float agent_x = agent->sim_x;
+ float agent_y = agent->sim_y;
+ float agent_heading = agent->sim_heading;
+ float agent_heading_x = cosf(agent_heading);
+ float agent_heading_y = sinf(agent_heading);
+
+ for (int i = 1; i < lane->segment_length; i++) {
+ float x0 = lane->x[i - 1];
+ float y0 = lane->y[i - 1];
+ float x1 = lane->x[i];
+ float y1 = lane->y[i];
+ float dx = x1 - x0;
+ float dy = y1 - y0;
+ float seg_len_sq = dx * dx + dy * dy;
+ if (seg_len_sq < 1e-6f) continue;
+
+ float to_agent_x = agent_x - x0;
+ float to_agent_y = agent_y - y0;
+ float t = (to_agent_x * dx + to_agent_y * dy) / seg_len_sq;
+ if (t < 0.0f) t = 0.0f;
+ else if (t > 1.0f) t = 1.0f;
+
+ float proj_x = x0 + t * dx;
+ float proj_y = y0 + t * dy;
+
+ float rel_x = proj_x - agent_x;
+ float rel_y = proj_y - agent_y;
+ float forward = rel_x * agent_heading_x + rel_y * agent_heading_y;
+ if (forward < 0.0f) continue;
+
+ float dist_sq = rel_x * rel_x + rel_y * rel_y;
+ if (dist_sq < best_dist_sq) {
+ best_dist_sq = dist_sq;
+ best_idx = i;
+ *out_fraction = t;
+ }
+ }
+
+ if (best_idx != -1) {
+ *out_segment_idx = best_idx;
+ return 1;
+ }
+
+ return 0;
+}
+
+void compute_new_goal(Drive* env, int agent_idx) {
+ Agent* agent = &env->agents[agent_idx];
+ int t = env->timestep;
+ int current_lane = agent->current_lane_idx;
+
+ if (current_lane == -1) return; // No current lane
+
+ // Target distance: 40m ahead along the lane topology from agent's current position
+ float target_distance = 40.0f;
+ int current_entity = current_lane;
+ RoadMapElement* lane = &env->road_elements[current_entity];
+
+ float agent_x = agent->sim_x;
+ float agent_y = agent->sim_y;
+ float agent_heading = agent->sim_heading;
+ float agent_heading_x = cosf(agent_heading);
+ float agent_heading_y = sinf(agent_heading);
+
+ int initial_segment_idx = 1;
+ float initial_fraction = 0.0f;
+ if (!find_forward_projection_on_lane(lane, agent, t, &initial_segment_idx, &initial_fraction)) {
+ int forward_idx = -1;
+ for (int i = 0; i < lane->segment_length; i++) {
+ float to_point_x = lane->x[i] - agent_x;
+ float to_point_y = lane->y[i] - agent_y;
+ float dot = to_point_x * agent_heading_x + to_point_y * agent_heading_y;
+ if (dot > 0.0f) {
+ forward_idx = i;
+ break;
+ }
+ }
+
+ if (forward_idx == -1) {
+ agent->goal_position_x = lane->x[lane->segment_length - 1];
+ agent->goal_position_y = lane->y[lane->segment_length - 1];
+ agent->sampled_new_goal = 0;
+ return;
+ }
+
+ initial_segment_idx = forward_idx;
+ if (initial_segment_idx == 0) initial_segment_idx = 1;
+ initial_fraction = 0.0f;
+ }
+
+ float remaining_distance = target_distance;
+ int first_lane = 1;
+
+ // Traverse the topology graph starting from the vehicle's position forward
+ while (current_entity != -1) {
+ lane = &env->road_elements[current_entity];
+
+ int start_idx = first_lane ? initial_segment_idx : 1;
+ // Ensure start_idx is at least 1 to avoid accessing x[i-1] with i=0
+ if (start_idx < 1) start_idx = 1;
+ first_lane = 0;
+
+ for (int i = start_idx; i < lane->segment_length; i++) {
+ float prev_x = lane->x[i - 1];
+ float prev_y = lane->y[i - 1];
+ float next_x = lane->x[i];
+ float next_y = lane->y[i];
+ float seg_dx = next_x - prev_x;
+ float seg_dy = next_y - prev_y;
+ float segment_length = relative_distance_2d(prev_x, prev_y, next_x, next_y);
+
+ if (remaining_distance <= segment_length) {
+ agent->goal_position_x = next_x;
+ agent->goal_position_y = next_y;
+ agent->sampled_new_goal = 0;
+ return;
+ }
+
+ remaining_distance -= segment_length;
+ }
+
+ int connected_lanes[5];
+ int num_connected = getNextLanes(env->topology_graph, current_entity, connected_lanes, 5);
+
+ if (num_connected == 0) {
+ agent->goal_position_x = lane->x[lane->segment_length - 1];
+ agent->goal_position_y = lane->y[lane->segment_length - 1];
+ agent->sampled_new_goal = 0;
+ return; // No further lanes to traverse
+ }
+
+ int random_idx = agent_idx % num_connected;
+ current_entity = connected_lanes[random_idx];
+ }
+}
+
void c_reset(Drive* env){
- env->timestep = 0;
+ env->timestep = env->init_steps;
set_start_position(env);
for(int x = 0;xactive_agent_count; x++){
env->logs[x] = (Log){0};
int agent_idx = env->active_agent_indices[x];
- env->entities[agent_idx].respawn_timestep = -1;
- env->entities[agent_idx].reached_goal = 0;
- env->entities[agent_idx].collided_before_goal = 0;
- env->entities[agent_idx].reached_goal_this_episode = 0;
- collision_check(env, agent_idx);
+ env->agents[agent_idx].respawn_timestep = -1;
+ env->agents[agent_idx].respawn_count = 0;
+ env->agents[agent_idx].collided_before_goal = 0;
+ env->agents[agent_idx].reached_goal_this_episode = 0;
+ env->agents[agent_idx].metrics_array[COLLISION_IDX] = 0.0f;
+ env->agents[agent_idx].metrics_array[OFFROAD_IDX] = 0.0f;
+ env->agents[agent_idx].metrics_array[REACHED_GOAL_IDX] = 0.0f;
+ env->agents[agent_idx].metrics_array[LANE_ALIGNED_IDX] = 0.0f;
+ env->agents[agent_idx].metrics_array[AVG_DISPLACEMENT_ERROR_IDX] = 0.0f;
+ env->agents[agent_idx].cumulative_displacement = 0.0f;
+ env->agents[agent_idx].displacement_sample_count = 0;
+ env->agents[agent_idx].stopped = 0;
+ env->agents[agent_idx].removed = 0;
+
+ if (env->goal_behavior==GOAL_GENERATE_NEW) {
+ env->agents[agent_idx].goal_position_x = env->agents[agent_idx].init_goal_x;
+ env->agents[agent_idx].goal_position_y = env->agents[agent_idx].init_goal_y;
+ env->agents[agent_idx].sampled_new_goal = 0;
+ }
+
+ compute_agent_metrics(env, agent_idx);
}
compute_observations(env);
}
void respawn_agent(Drive* env, int agent_idx){
- env->entities[agent_idx].x = env->entities[agent_idx].traj_x[0];
- env->entities[agent_idx].y = env->entities[agent_idx].traj_y[0];
- env->entities[agent_idx].heading = env->entities[agent_idx].traj_heading[0];
- env->entities[agent_idx].heading_x = cosf(env->entities[agent_idx].heading);
- env->entities[agent_idx].heading_y = sinf(env->entities[agent_idx].heading);
- env->entities[agent_idx].vx = env->entities[agent_idx].traj_vx[0];
- env->entities[agent_idx].vy = env->entities[agent_idx].traj_vy[0];
- env->entities[agent_idx].reached_goal = 0;
- env->entities[agent_idx].respawn_timestep = env->timestep;
+ Agent* agent = &env->agents[agent_idx];
+ agent->sim_x = agent->log_trajectory_x[0];
+ agent->sim_y = agent->log_trajectory_y[0];
+ agent->sim_heading = agent->log_heading[0];
+ agent->sim_vx = agent->log_velocity_x[0];
+ agent->sim_vy = agent->log_velocity_y[0];
+ agent->metrics_array[COLLISION_IDX] = 0.0f;
+ agent->metrics_array[OFFROAD_IDX] = 0.0f;
+ agent->metrics_array[REACHED_GOAL_IDX] = 0.0f;
+ agent->metrics_array[LANE_ALIGNED_IDX] = 0.0f;
+ agent->metrics_array[AVG_DISPLACEMENT_ERROR_IDX] = 0.0f;
+ agent->cumulative_displacement = 0.0f;
+ agent->displacement_sample_count = 0;
+ agent->respawn_timestep = env->timestep;
+ agent->stopped = 0;
+ agent->removed = 0;
+ agent->a_long = 0.0f;
+ agent->a_lat = 0.0f;
+ agent->jerk_long = 0.0f;
+ agent->jerk_lat = 0.0f;
+ agent->steering_angle = 0.0f;
}
void c_step(Drive* env){
memset(env->rewards, 0, env->active_agent_count * sizeof(float));
memset(env->terminals, 0, env->active_agent_count * sizeof(unsigned char));
env->timestep++;
- if(env->timestep == TRAJECTORY_LENGTH){
+ if(env->timestep == env->scenario_length){
add_log(env);
c_reset(env);
- return;
+ return;
}
- // Move statix experts
- for (int i = 0; i < env->expert_static_car_count; i++) {
- int expert_idx = env->expert_static_car_indices[i];
- if(env->entities[expert_idx].x == -10000.0f) continue;
+ // Move static experts
+ for (int i = 0; i < env->expert_static_agent_count; i++) {
+ int expert_idx = env->expert_static_agent_indices[i];
+ if(env->agents[expert_idx].sim_x == INVALID_POSITION) continue;
move_expert(env, env->actions, expert_idx);
}
// Process actions for all active agents
@@ -1251,72 +2193,103 @@ void c_step(Drive* env){
env->logs[i].score = 0.0f;
env->logs[i].episode_length += 1;
int agent_idx = env->active_agent_indices[i];
- env->entities[agent_idx].collision_state = 0;
+ env->agents[agent_idx].collision_state = 0;
move_dynamics(env, i, agent_idx);
- // move_expert(env, env->actions, agent_idx);
}
for(int i = 0; i < env->active_agent_count; i++){
int agent_idx = env->active_agent_indices[i];
- env->entities[agent_idx].collision_state = 0;
- //if(env->entities[agent_idx].respawn_timestep != -1) continue;
- collision_check(env, agent_idx);
- int collision_state = env->entities[agent_idx].collision_state;
-
+ env->agents[agent_idx].collision_state = 0;
+
+ compute_agent_metrics(env, agent_idx);
+ int collision_state = env->agents[agent_idx].collision_state;
+
if(collision_state > 0){
- if(collision_state == VEHICLE_COLLISION && env->entities[agent_idx].respawn_timestep == -1){
- if(env->entities[agent_idx].respawn_timestep != -1) {
- env->rewards[i] = env->reward_vehicle_collision_post_respawn;
- env->logs[i].episode_return += env->reward_vehicle_collision_post_respawn;
- } else {
- env->rewards[i] = env->reward_vehicle_collision;
- env->logs[i].episode_return += env->reward_vehicle_collision;
- env->logs[i].clean_collision_rate = 1.0f;
- }
+ if(collision_state == VEHICLE_COLLISION){
+ env->rewards[i] = env->reward_vehicle_collision;
+ env->logs[i].episode_return += env->reward_vehicle_collision;
env->logs[i].collision_rate = 1.0f;
+ env->logs[i].avg_collisions_per_agent += 1.0f;
}
else if(collision_state == OFFROAD){
env->rewards[i] = env->reward_offroad_collision;
env->logs[i].offroad_rate = 1.0f;
env->logs[i].episode_return += env->reward_offroad_collision;
+ env->logs[i].avg_offroad_per_agent += 1.0f;
}
- if(!env->entities[agent_idx].reached_goal_this_episode){
- env->entities[agent_idx].collided_before_goal = 1;
+ if(!env->agents[agent_idx].reached_goal_this_episode){
+ env->agents[agent_idx].collided_before_goal = 1;
}
- //printf("agent %d collided\n", agent_idx);
}
float distance_to_goal = relative_distance_2d(
- env->entities[agent_idx].x,
- env->entities[agent_idx].y,
- env->entities[agent_idx].goal_position_x,
- env->entities[agent_idx].goal_position_y);
- if(distance_to_goal < 2.0f){
- if(env->entities[agent_idx].respawn_timestep != -1){
+ env->agents[agent_idx].sim_x,
+ env->agents[agent_idx].sim_y,
+ env->agents[agent_idx].goal_position_x,
+ env->agents[agent_idx].goal_position_y
+ );
+
+ // Reward agent if it is within X meters of goal
+ if (distance_to_goal < env->goal_radius){
+ if (env->goal_behavior == GOAL_RESPAWN && env->agents[agent_idx].respawn_timestep != -1){
env->rewards[i] += env->reward_goal_post_respawn;
env->logs[i].episode_return += env->reward_goal_post_respawn;
- } else {
- env->rewards[i] += 1.0f;
- env->logs[i].episode_return += 1.0f;
- //env->terminals[i] = 1;
+ } else if (env->goal_behavior == GOAL_GENERATE_NEW) {
+ env->rewards[i] += env->reward_goal;
+ env->logs[i].episode_return += env->reward_goal;
+ env->agents[agent_idx].sampled_new_goal = 1;
+ env->logs[i].num_goals_reached += 1;
+ } else { // Zero out the velocity so that the agent stops at the goal
+ env->rewards[i] = env->reward_goal;
+ env->logs[i].episode_return = env->reward_goal;
+ env->logs[i].num_goals_reached = 1;
+ env->agents[agent_idx].stopped = 1;
+ env->agents[agent_idx].sim_vx=env->agents[agent_idx].sim_vy = 0.0f;
}
- env->entities[agent_idx].reached_goal = 1;
- env->entities[agent_idx].reached_goal_this_episode = 1;
+ env->agents[agent_idx].reached_goal_this_episode = 1;
+ env->agents[agent_idx].metrics_array[REACHED_GOAL_IDX] = 1.0f;
}
+
+ if(env->agents[agent_idx].sampled_new_goal && env->goal_behavior == GOAL_GENERATE_NEW){
+ compute_new_goal(env, agent_idx);
+ }
+
+
+ int lane_aligned = env->agents[agent_idx].metrics_array[LANE_ALIGNED_IDX];
+ env->logs[i].lane_alignment_rate = lane_aligned;
+
+ // Apply ADE reward
+ float current_ade = env->agents[agent_idx].metrics_array[AVG_DISPLACEMENT_ERROR_IDX];
+ if(current_ade > 0.0f && env->reward_ade != 0.0f) {
+ float ade_reward = env->reward_ade * current_ade;
+ env->rewards[i] += ade_reward;
+ env->logs[i].episode_return += ade_reward;
+ }
+ env->logs[i].avg_displacement_error = current_ade;
}
- for(int i = 0; i < env->active_agent_count; i++){
- int agent_idx = env->active_agent_indices[i];
- int reached_goal = env->entities[agent_idx].reached_goal;
- int collision_state = env->entities[agent_idx].collision_state;
- if(reached_goal){
- respawn_agent(env, agent_idx);
- //env->entities[agent_idx].x = -10000;
- //env->entities[agent_idx].y = -10000;
- //env->entities[agent_idx].respawn_timestep = env->timestep;
+ if (env->goal_behavior==GOAL_RESPAWN) {
+ for(int i = 0; i < env->active_agent_count; i++){
+ int agent_idx = env->active_agent_indices[i];
+ int reached_goal = env->agents[agent_idx].metrics_array[REACHED_GOAL_IDX];
+ if(reached_goal){
+ respawn_agent(env, agent_idx);
+ env->agents[agent_idx].respawn_count++;
+ }
+ }
+ }
+ else if (env->goal_behavior==GOAL_STOP) {
+ for(int i = 0; i < env->active_agent_count; i++){
+ int agent_idx = env->active_agent_indices[i];
+ int reached_goal = env->agents[agent_idx].metrics_array[REACHED_GOAL_IDX];
+ if(reached_goal){
+ env->agents[agent_idx].stopped = 1;
+ env->agents[agent_idx].sim_vx = env->agents[agent_idx].sim_vy = 0.0f;
+ }
}
}
+
compute_observations(env);
-}
+}
const Color STONE_GRAY = (Color){80, 80, 80, 255};
const Color PUFF_RED = (Color){187, 0, 0, 255};
@@ -1324,6 +2297,7 @@ const Color PUFF_CYAN = (Color){0, 187, 187, 255};
const Color PUFF_WHITE = (Color){241, 241, 241, 241};
const Color PUFF_BACKGROUND = (Color){6, 24, 24, 255};
const Color PUFF_BACKGROUND2 = (Color){18, 72, 72, 255};
+const Color LIGHTGREEN = (Color){152, 255, 152, 255};
typedef struct Client Client;
struct Client {
@@ -1333,8 +2307,8 @@ struct Client {
Vector3 camera_target;
float camera_zoom;
Camera3D camera;
- Model cars[6];
- int car_assignments[MAX_CARS]; // To keep car model assignments consistent per vehicle
+ Model cars[6];
+ int car_assignments[MAX_AGENTS]; // To keep car model assignments consistent per vehicle
Vector3 default_camera_position;
Vector3 default_camera_target;
};
@@ -1353,20 +2327,18 @@ Client* make_client(Drive* env){
client->cars[3] = LoadModel("resources/drive/YellowCar.glb");
client->cars[4] = LoadModel("resources/drive/GreenCar.glb");
client->cars[5] = LoadModel("resources/drive/GreyCar.glb");
- for (int i = 0; i < MAX_CARS; i++) {
+ for (int i = 0; i < MAX_AGENTS; i++) {
client->car_assignments[i] = (rand() % 4) + 1;
}
// Get initial target position from first active agent
- float map_center_x = (env->map_corners[0] + env->map_corners[2]) / 2.0f;
- float map_center_y = (env->map_corners[1] + env->map_corners[3]) / 2.0f;
Vector3 target_pos = {
- 0,
+ 0,
0, // Y is up
1 // Z is depth
};
-
+
// Set up camera to look at target from above and behind
- client->default_camera_position = (Vector3){
+ client->default_camera_position = (Vector3){
0, // Same X as target
120.0f, // 20 units above target
175.0f // 20 units behind target
@@ -1386,17 +2358,17 @@ void handle_camera_controls(Client* client) {
static Vector2 prev_mouse_pos = {0};
static bool is_dragging = false;
float camera_move_speed = 0.5f;
-
+
// Handle mouse drag for camera movement
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
prev_mouse_pos = GetMousePosition();
is_dragging = true;
}
-
+
if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) {
is_dragging = false;
}
-
+
if (is_dragging) {
Vector2 current_mouse_pos = GetMousePosition();
Vector2 delta = {
@@ -1407,7 +2379,7 @@ void handle_camera_controls(Client* client) {
// Update camera position (only X and Y)
client->camera.position.x += delta.x;
client->camera.position.y += delta.y;
-
+
// Update camera target (only X and Y)
client->camera.target.x += delta.x;
client->camera.target.y += delta.y;
@@ -1425,12 +2397,12 @@ void handle_camera_controls(Client* client) {
client->camera.position.y - client->camera.target.y,
client->camera.position.z - client->camera.target.z
};
-
+
// Scale the direction vector by the zoom factor
direction.x *= zoom_factor;
direction.y *= zoom_factor;
direction.z *= zoom_factor;
-
+
// Update the camera position based on the scaled direction
client->camera.position.x = client->camera.target.x + direction.x;
client->camera.position.y = client->camera.target.y + direction.y;
@@ -1438,12 +2410,12 @@ void handle_camera_controls(Client* client) {
}
}
-void draw_agent_obs(Drive* env, int agent_index){
+void draw_agent_obs(Drive* env, int agent_index, int mode, int obs_only, int lasers){
// Diamond dimensions
float diamond_height = 3.0f; // Total height of diamond
float diamond_width = 1.5f; // Width of diamond
float diamond_z = 8.0f; // Base Z position
-
+
// Define diamond points
Vector3 top_point = (Vector3){0.0f, 0.0f, diamond_z + diamond_height/2}; // Top point
Vector3 bottom_point = (Vector3){0.0f, 0.0f, diamond_z - diamond_height/2}; // Bottom point
@@ -1451,32 +2423,54 @@ void draw_agent_obs(Drive* env, int agent_index){
Vector3 back_point = (Vector3){0.0f, -diamond_width/2, diamond_z}; // Back point
Vector3 left_point = (Vector3){-diamond_width/2, 0.0f, diamond_z}; // Left point
Vector3 right_point = (Vector3){diamond_width/2, 0.0f, diamond_z}; // Right point
-
+
// Draw the diamond faces
// Top pyramid
- DrawTriangle3D(top_point, front_point, right_point, PUFF_CYAN); // Front-right face
- DrawTriangle3D(top_point, right_point, back_point, PUFF_CYAN); // Back-right face
- DrawTriangle3D(top_point, back_point, left_point, PUFF_CYAN); // Back-left face
- DrawTriangle3D(top_point, left_point, front_point, PUFF_CYAN); // Front-left face
-
- // Bottom pyramid
- DrawTriangle3D(bottom_point, right_point, front_point, PUFF_CYAN); // Front-right face
- DrawTriangle3D(bottom_point, back_point, right_point, PUFF_CYAN); // Back-right face
- DrawTriangle3D(bottom_point, left_point, back_point, PUFF_CYAN); // Back-left face
- DrawTriangle3D(bottom_point, front_point, left_point, PUFF_CYAN); // Front-left face
- if(!IsKeyDown(KEY_LEFT_CONTROL)){
+
+ if(mode ==0){
+ DrawTriangle3D(top_point, front_point, right_point, PUFF_CYAN); // Front-right face
+ DrawTriangle3D(top_point, right_point, back_point, PUFF_CYAN); // Back-right face
+ DrawTriangle3D(top_point, back_point, left_point, PUFF_CYAN); // Back-left face
+ DrawTriangle3D(top_point, left_point, front_point, PUFF_CYAN); // Front-left face
+
+ // Bottom pyramid
+ DrawTriangle3D(bottom_point, right_point, front_point, PUFF_CYAN); // Front-right face
+ DrawTriangle3D(bottom_point, back_point, right_point, PUFF_CYAN); // Back-right face
+ DrawTriangle3D(bottom_point, left_point, back_point, PUFF_CYAN); // Back-left face
+ DrawTriangle3D(bottom_point, front_point, left_point, PUFF_CYAN); // Front-left face
+ }
+ if(!IsKeyDown(KEY_LEFT_CONTROL) && obs_only==0){
return;
}
- int max_obs = 7 + 7*(MAX_CARS - 1) + 7*MAX_ROAD_SEGMENT_OBSERVATIONS;
+
+ int ego_dim = (env->dynamics_model == JERK) ? 10 : 7;
+ int max_obs = ego_dim + 7*(MAX_AGENTS - 1) + 7*MAX_ROAD_SEGMENT_OBSERVATIONS;
float (*observations)[max_obs] = (float(*)[max_obs])env->observations;
float* agent_obs = &observations[agent_index][0];
+ // self
+ int active_idx = env->active_agent_indices[agent_index];
+ float heading_self = env->agents[active_idx].sim_heading;
+ float heading_self_x = cosf(heading_self);
+ float heading_self_y = sinf(heading_self);
+ float px = env->agents[active_idx].sim_x;
+ float py = env->agents[active_idx].sim_y;
// draw goal
float goal_x = agent_obs[0] * 200;
float goal_y = agent_obs[1] * 200;
- DrawSphere((Vector3){goal_x, goal_y, 1}, 0.5f, GREEN);
+ if(mode == 0 ){
+ DrawSphere((Vector3){goal_x, goal_y, 1}, 0.5f, LIGHTGREEN);
+ DrawCircle3D((Vector3){goal_x, goal_y, 0.1f}, env->goal_radius, (Vector3){0, 0, 1}, 90.0f, Fade(LIGHTGREEN, 0.3f));
+ }
+
+ if (mode == 1){
+ float goal_x_world = px + (goal_x * heading_self_x - goal_y*heading_self_y);
+ float goal_y_world = py + (goal_x * heading_self_y + goal_y*heading_self_x);
+ DrawSphere((Vector3){goal_x_world, goal_y_world, 1}, 0.5f, LIGHTGREEN);
+ DrawCircle3D((Vector3){goal_x_world, goal_y_world, 0.1f}, env->goal_radius, (Vector3){0, 0, 1}, 90.0f, Fade(LIGHTGREEN, 0.3f));
+ }
// First draw other agent observations
- int obs_idx = 7; // Start after goal distances
- for(int j = 0; j < MAX_CARS - 1; j++) {
+ int obs_idx = ego_dim; // Start after ego obs
+ for(int j = 0; j < MAX_AGENTS - 1; j++) {
if(agent_obs[obs_idx] == 0 || agent_obs[obs_idx + 1] == 0) {
obs_idx += 7; // Move to next agent observation
continue;
@@ -1484,19 +2478,89 @@ void draw_agent_obs(Drive* env, int agent_index){
// Draw position of other agents
float x = agent_obs[obs_idx] * 50;
float y = agent_obs[obs_idx + 1] * 50;
- DrawLine3D(
- (Vector3){0, 0, 0},
- (Vector3){x, y, 1},
- ORANGE
- );
+ if(lasers && mode == 0){
+ DrawLine3D(
+ (Vector3){0, 0, 0},
+ (Vector3){x, y, 1},
+ ORANGE
+ );
+ }
+
+ float partner_x = px + (x*heading_self_x - y*heading_self_y);
+ float partner_y = py + (x*heading_self_y + y*heading_self_x);
+ if(lasers && mode ==1){
+ DrawLine3D(
+ (Vector3){px, py, 1},
+ (Vector3){partner_x,partner_y,1},
+ ORANGE
+ );
+ }
+
+ float half_width = 0.5*agent_obs[obs_idx + 2]*MAX_VEH_WIDTH;
+ float half_len = 0.5*agent_obs[obs_idx + 3]*MAX_VEH_LEN;
float theta_x = agent_obs[obs_idx + 4];
float theta_y = agent_obs[obs_idx + 5];
float partner_angle = atan2f(theta_y, theta_x);
+ float cos_heading = cosf(partner_angle);
+ float sin_heading = sinf(partner_angle);
+ Vector3 corners[4] = {
+ (Vector3){
+ x + (half_len * cos_heading - half_width * sin_heading),
+ y + (half_len * sin_heading + half_width * cos_heading),
+ 1
+ },
+ (Vector3){
+ x + (half_len * cos_heading + half_width * sin_heading),
+ y + (half_len * sin_heading - half_width * cos_heading),
+ 1
+ },
+ (Vector3){
+ x + (-half_len * cos_heading + half_width * sin_heading),
+ y + (-half_len * sin_heading - half_width * cos_heading),
+ 1
+ },
+ (Vector3){
+ x + (-half_len * cos_heading - half_width * sin_heading),
+ y + (-half_len * sin_heading + half_width * cos_heading),
+ 1
+ },
+ };
+
+ if(mode ==0){
+ for (int j = 0; j < 4; j++) {
+ DrawLine3D(corners[j], corners[(j+1)%4], ORANGE);
+ }
+ }
+
+ if(mode ==1){
+ Vector3 world_corners[4];
+ for (int j = 0; j < 4; j++) {
+ float lx = corners[j].x;
+ float ly = corners[j].y;
+
+ world_corners[j].x = px + (lx * heading_self_x - ly * heading_self_y);
+ world_corners[j].y = py + (lx * heading_self_y + ly * heading_self_x);
+ world_corners[j].z = 1;
+ }
+ for (int j = 0; j < 4; j++) {
+ DrawLine3D(world_corners[j], world_corners[(j+1)%4], ORANGE);
+ }
+ }
+
// draw an arrow above the car pointing in the direction that the partner is going
float arrow_length = 7.5f;
float arrow_x = x + arrow_length*cosf(partner_angle);
float arrow_y = y + arrow_length*sinf(partner_angle);
- DrawLine3D((Vector3){x, y, 1}, (Vector3){arrow_x, arrow_y, 1}, PUFF_WHITE);
+ float arrow_x_world;
+ float arrow_y_world;
+ if(mode ==0){
+ DrawLine3D((Vector3){x, y, 1}, (Vector3){arrow_x, arrow_y, 1}, PUFF_WHITE);
+ }
+ if(mode == 1){
+ arrow_x_world = px + (arrow_x * heading_self_x - arrow_y*heading_self_y);
+ arrow_y_world = py + (arrow_x * heading_self_y + arrow_y*heading_self_x);
+ DrawLine3D((Vector3){partner_x, partner_y, 1}, (Vector3){arrow_x_world, arrow_y_world, 1}, PUFF_WHITE);
+ }
// Calculate perpendicular offsets for arrow head
float arrow_size = 2.0f; // Size of the arrow head
float dx = arrow_x - x;
@@ -1506,27 +2570,54 @@ void draw_agent_obs(Drive* env, int agent_index){
// Normalize direction vector
dx /= length;
dy /= length;
-
+
// Calculate perpendicular vector
- float px = -dy * arrow_size;
- float py = dx * arrow_size;
-
+
+ float perp_x = -dy * arrow_size;
+ float perp_y = dx * arrow_size;
+
+ float arrow_x_end1 = arrow_x - dx*arrow_size + perp_x;
+ float arrow_y_end1 = arrow_y - dy*arrow_size + perp_y;
+ float arrow_x_end2 = arrow_x - dx*arrow_size - perp_x;
+ float arrow_y_end2 = arrow_y - dy*arrow_size - perp_y;
+
// Draw the two lines forming the arrow head
- DrawLine3D(
- (Vector3){arrow_x, arrow_y, 1},
- (Vector3){arrow_x - dx*arrow_size + px, arrow_y - dy*arrow_size + py, 1},
- PUFF_WHITE
- );
- DrawLine3D(
- (Vector3){arrow_x, arrow_y, 1},
- (Vector3){arrow_x - dx*arrow_size - px, arrow_y - dy*arrow_size - py, 1},
- PUFF_WHITE
- );
+ if(mode ==0){
+ DrawLine3D(
+ (Vector3){arrow_x, arrow_y, 1},
+ (Vector3){arrow_x_end1, arrow_y_end1, 1},
+ PUFF_WHITE
+ );
+ DrawLine3D(
+ (Vector3){arrow_x, arrow_y, 1},
+ (Vector3){arrow_x_end2, arrow_y_end2, 1},
+ PUFF_WHITE
+ );
+ }
+
+ if(mode==1){
+ float arrow_x_end1_world = px + (arrow_x_end1 * heading_self_x - arrow_y_end1*heading_self_y);
+ float arrow_y_end1_world = py + (arrow_x_end1 * heading_self_y + arrow_y_end1*heading_self_x);
+ float arrow_x_end2_world = px + (arrow_x_end2 * heading_self_x - arrow_y_end2*heading_self_y);
+ float arrow_y_end2_world = py + (arrow_x_end2 * heading_self_y + arrow_y_end2*heading_self_x);
+ DrawLine3D(
+ (Vector3){arrow_x_world, arrow_y_world, 1},
+ (Vector3){arrow_x_end1_world, arrow_y_end1_world, 1},
+ PUFF_WHITE
+ );
+ DrawLine3D(
+ (Vector3){arrow_x_world, arrow_y_world, 1},
+ (Vector3){arrow_x_end2_world, arrow_y_end2_world, 1},
+ PUFF_WHITE
+ );
+
+ }
}
+
obs_idx += 7; // Move to next agent observation (7 values per agent)
}
// Then draw map observations
- int map_start_idx = 7 + 7*(MAX_CARS - 1); // Start after agent observations
+ int map_start_idx = 7 + 7*(MAX_AGENTS - 1); // Start after agent observations
for(int k = 0; k < MAX_ROAD_SEGMENT_OBSERVATIONS; k++) { // Loop through potential map entities
int entity_idx = map_start_idx + k*7;
if(agent_obs[entity_idx] == 0 && agent_obs[entity_idx + 1] == 0){
@@ -1535,9 +2626,9 @@ void draw_agent_obs(Drive* env, int agent_index){
Color lineColor = BLUE; // Default color
int entity_type = (int)agent_obs[entity_idx + 6];
// Choose color based on entity type
- if(entity_type+4 != ROAD_EDGE){
- continue;
- }
+ int unnormalized_type = unnormalize_road_type(entity_type);
+ if(!is_road_edge(unnormalized_type)) continue;
+
lineColor = PUFF_CYAN;
// For road segments, draw line between start and end points
float x_middle = agent_obs[entity_idx] * 50;
@@ -1552,9 +2643,27 @@ void draw_agent_obs(Drive* env, int agent_index){
float y_start = y_middle - segment_length*sinf(rel_angle);
float x_end = x_middle + segment_length*cosf(rel_angle);
float y_end = y_middle + segment_length*sinf(rel_angle);
- DrawLine3D((Vector3){0,0,0}, (Vector3){x_middle, y_middle, 1}, lineColor);
- DrawCube((Vector3){x_middle, y_middle, 1}, 0.5f, 0.5f, 0.5f, lineColor);
- DrawLine3D((Vector3){x_start, y_start, 1}, (Vector3){x_end, y_end, 1}, BLUE);
+
+
+ if(lasers && mode ==0){
+ DrawLine3D((Vector3){0,0,0}, (Vector3){x_middle, y_middle, 1}, lineColor);
+ }
+
+ if(mode ==1){
+ float x_middle_world = px + (x_middle*heading_self_x - y_middle*heading_self_y);
+ float y_middle_world = py + (x_middle*heading_self_y + y_middle*heading_self_x);
+ float x_start_world = px + (x_start*heading_self_x - y_start*heading_self_y);
+ float y_start_world = py + (x_start*heading_self_y + y_start*heading_self_x);
+ float x_end_world = px + (x_end*heading_self_x - y_end*heading_self_y);
+ float y_end_world = py + (x_end*heading_self_y + y_end*heading_self_x);
+ DrawCube((Vector3){x_middle_world, y_middle_world, 1}, 0.5f, 0.5f, 0.5f, lineColor);
+ DrawLine3D((Vector3){x_start_world, y_start_world, 1}, (Vector3){x_end_world, y_end_world, 1}, BLUE);
+ if(lasers) DrawLine3D((Vector3){px,py,1}, (Vector3){x_middle_world, y_middle_world, 1}, lineColor);
+ }
+ if(mode ==0){
+ DrawCube((Vector3){x_middle, y_middle, 1}, 0.5f, 0.5f, 0.5f, lineColor);
+ DrawLine3D((Vector3){x_start, y_start, 1}, (Vector3){x_end, y_end, 1}, BLUE);
+ }
}
}
@@ -1565,58 +2674,59 @@ void draw_road_edge(Drive* env, float start_x, float start_y, float end_x, float
// Calculate curb dimensions
float curb_height = 0.5f; // Height of the curb
float curb_width = 0.3f; // Width/thickness of the curb
-
+ float road_z = 0.2f; // Ensure z-level for roads is below agents
+
// Calculate direction vector between start and end
Vector3 direction = {
end_x - start_x,
end_y - start_y,
0.0f
};
-
+
// Calculate length of the segment
float length = sqrtf(direction.x * direction.x + direction.y * direction.y);
-
+
// Normalize direction vector
Vector3 normalized_dir = {
direction.x / length,
direction.y / length,
0.0f
};
-
+
// Calculate perpendicular vector for width
Vector3 perpendicular = {
-normalized_dir.y,
normalized_dir.x,
0.0f
};
-
+
// Calculate the four bottom corners of the curb
Vector3 b1 = {
start_x - perpendicular.x * curb_width/2,
start_y - perpendicular.y * curb_width/2,
- 1.0f
+ road_z
};
Vector3 b2 = {
start_x + perpendicular.x * curb_width/2,
start_y + perpendicular.y * curb_width/2,
- 1.0f
+ road_z
};
Vector3 b3 = {
end_x + perpendicular.x * curb_width/2,
end_y + perpendicular.y * curb_width/2,
- 1.0f
+ road_z
};
Vector3 b4 = {
end_x - perpendicular.x * curb_width/2,
end_y - perpendicular.y * curb_width/2,
- 1.0f
+ road_z
};
-
+
// Draw the curb faces
// Bottom face
DrawTriangle3D(b1, b2, b3, CURB_BOTTOM);
DrawTriangle3D(b1, b3, b4, CURB_BOTTOM);
-
+
// Top face (raised by curb_height)
Vector3 t1 = {b1.x, b1.y, b1.z + curb_height};
Vector3 t2 = {b2.x, b2.y, b2.z + curb_height};
@@ -1624,7 +2734,7 @@ void draw_road_edge(Drive* env, float start_x, float start_y, float end_x, float
Vector3 t4 = {b4.x, b4.y, b4.z + curb_height};
DrawTriangle3D(t1, t3, t2, CURB_TOP);
DrawTriangle3D(t1, t4, t3, CURB_TOP);
-
+
// Side faces
DrawTriangle3D(b1, t1, b2, CURB_SIDE);
DrawTriangle3D(t1, t2, b2, CURB_SIDE);
@@ -1636,69 +2746,130 @@ void draw_road_edge(Drive* env, float start_x, float start_y, float end_x, float
DrawTriangle3D(t4, t1, b1, CURB_SIDE);
}
-void c_render(Drive* env) {
- if (env->client == NULL) {
- env->client = make_client(env);
- }
- Client* client = env->client;
- BeginDrawing();
- Color road = (Color){35, 35, 37, 255};
- ClearBackground(road);
- BeginMode3D(client->camera);
- handle_camera_controls(env->client);
-
- // Draw a grid to help with orientation
+void draw_scene(Drive* env, Client* client, int mode, int obs_only, int lasers, int show_grid){
+ // Draw a grid to help with orientation
// DrawGrid(20, 1.0f);
- DrawLine3D((Vector3){env->map_corners[0], env->map_corners[1], 0}, (Vector3){env->map_corners[2], env->map_corners[1], 0}, PUFF_CYAN);
- DrawLine3D((Vector3){env->map_corners[0], env->map_corners[1], 0}, (Vector3){env->map_corners[0], env->map_corners[3], 0}, PUFF_CYAN);
- DrawLine3D((Vector3){env->map_corners[2], env->map_corners[1], 0}, (Vector3){env->map_corners[2], env->map_corners[3], 0}, PUFF_CYAN);
- DrawLine3D((Vector3){env->map_corners[0], env->map_corners[3], 0}, (Vector3){env->map_corners[2], env->map_corners[3], 0}, PUFF_CYAN);
- for(int i = 0; i < env->num_entities; i++) {
- // Draw cars
- if(env->entities[i].type == 1 || env->entities[i].type == 2) {
- // Check if this vehicle is an active agent
- bool is_active_agent = false;
- bool is_static_car = false;
- int agent_index = -1;
- for(int j = 0; j < env->active_agent_count; j++) {
- if(env->active_agent_indices[j] == i) {
- is_active_agent = true;
- agent_index = j;
- break;
- }
+ DrawLine3D((Vector3){env->grid_map->top_left_x, env->grid_map->top_left_y, 0}, (Vector3){env->grid_map->bottom_right_x, env->grid_map->top_left_y, 0}, PUFF_CYAN);
+ DrawLine3D((Vector3){env->grid_map->top_left_x, env->grid_map->bottom_right_y, 0}, (Vector3){env->grid_map->top_left_x, env->grid_map->top_left_y, 0}, PUFF_CYAN);
+ DrawLine3D((Vector3){env->grid_map->bottom_right_x, env->grid_map->bottom_right_y, 0}, (Vector3){env->grid_map->bottom_right_x, env->grid_map->top_left_y, 0}, PUFF_CYAN);
+ DrawLine3D((Vector3){env->grid_map->top_left_x, env->grid_map->bottom_right_y, 0}, (Vector3){env->grid_map->bottom_right_x, env->grid_map->bottom_right_y, 0}, PUFF_CYAN);
+
+ for(int i = 0; i < env->num_total_agents; i++) {
+ Agent* agent = &env->agents[i];
+ // Draw objects
+ // Check if this vehicle is an active agent
+ bool is_active_agent = false;
+ bool is_static_agent = false;
+ int agent_index = -1;
+ for(int j = 0; j < env->active_agent_count; j++) {
+ if(env->active_agent_indices[j] == i) {
+ is_active_agent = true;
+ agent_index = j;
+ break;
}
- for(int j = 0; j < env->static_car_count; j++) {
- if(env->static_car_indices[j] == i) {
- is_static_car = true;
- break;
- }
+ }
+ for(int j = 0; j < env->static_agent_count; j++) {
+ if(env->static_agent_indices[j] == i) {
+ is_static_agent = true;
+ break;
}
- // HIDE CARS ON RESPAWN - IMPORTANT TO KNOW VISUAL SETTING
- if(!is_active_agent && !is_static_car || env->entities[i].respawn_timestep != -1){
+ }
+ // HIDE CARS ON RESPAWN - IMPORTANT TO KNOW VISUAL SETTING
+ if((!is_active_agent && !is_static_agent) || agent->respawn_timestep != -1){
+ continue;
+ }
+ Vector3 position;
+ float heading;
+ position = (Vector3){
+ agent->sim_x,
+ agent->sim_y,
+ 1
+ };
+ heading = agent->sim_heading;
+ // Create size vector
+ Vector3 size = {
+ agent->sim_length,
+ agent->sim_width,
+ agent->sim_height
+ };
+
+ bool is_expert = (!is_active_agent) && (agent->mark_as_expert == 1);
+
+ // Save current transform
+ if(mode==1){
+ float cos_heading = cosf(heading);
+ float sin_heading = sinf(heading);
+
+ // Calculate half dimensions
+ float half_len = agent->sim_length * 0.5f;
+ float half_width = agent->sim_width * 0.5f;
+
+ // Calculate the four corners of the collision box
+ Vector3 corners[4] = {
+ (Vector3){
+ position.x + (half_len * cos_heading - half_width * sin_heading),
+ position.y + (half_len * sin_heading + half_width * cos_heading),
+ position.z
+ },
+
+
+ (Vector3){
+ position.x + (half_len * cos_heading + half_width * sin_heading),
+ position.y + (half_len * sin_heading - half_width * cos_heading),
+ position.z
+ },
+ (Vector3){
+ position.x + (-half_len * cos_heading + half_width * sin_heading),
+ position.y + (-half_len * sin_heading - half_width * cos_heading),
+ position.z
+ },
+ (Vector3){
+ position.x + (-half_len * cos_heading - half_width * sin_heading),
+ position.y + (-half_len * sin_heading + half_width * cos_heading),
+ position.z
+ },
+
+
+ };
+
+ if(agent_index == env->human_agent_idx && !agent->metrics_array[REACHED_GOAL_IDX]) {
+ draw_agent_obs(env, agent_index, mode, obs_only, lasers);
+ }
+ if((obs_only || IsKeyDown(KEY_LEFT_CONTROL)) && agent_index != env->human_agent_idx){
continue;
}
- Vector3 position;
- float heading;
- position = (Vector3){
- env->entities[i].x,
- env->entities[i].y,
- 1
- };
- heading = env->entities[i].heading;
- // Create size vector
- Vector3 size = {
- env->entities[i].length,
- env->entities[i].width,
- env->entities[i].height
+
+ // --- Draw the car ---
+
+ Vector3 carPos = { position.x, position.y, position.z };
+ Color car_color = GRAY; // default for static
+ if (is_expert) car_color = GOLD; // expert replay
+ if (is_active_agent) car_color = BLUE; // policy-controlled
+ if (is_active_agent && agent->collision_state > 0) car_color = RED;
+ rlSetLineWidth(3.0f);
+ for (int j = 0; j < 4; j++) {
+ DrawLine3D(corners[j], corners[(j+1)%4], car_color);
+ }
+ // --- Draw a heading arrow pointing forward ---
+ Vector3 arrowStart = position;
+ Vector3 arrowEnd = {
+ position.x + cos_heading * half_len * 1.5f, // extend arrow beyond car
+ position.y + sin_heading * half_len * 1.5f,
+ position.z
};
- // Save current transform
+
+ DrawLine3D(arrowStart, arrowEnd, car_color);
+ DrawSphere(arrowEnd, 0.2f, car_color); // arrow tip
+
+ }
+ else {
rlPushMatrix();
// Translate to position, rotate around Y axis, then draw
rlTranslatef(position.x, position.y, position.z);
rlRotatef(heading*RAD2DEG, 0.0f, 0.0f, 1.0f); // Convert radians to degrees
- // Determine color based on active status and other conditions
- Color object_color = PUFF_BACKGROUND2; // Default color for non-active vehicles
- Color outline_color = PUFF_CYAN;
+ // Determine color based on status
+ Color object_color = PUFF_BACKGROUND2; // fill color unused for model tint
+ Color outline_color = PUFF_CYAN; // not used for model tint
Model car_model = client->cars[5];
if(is_active_agent){
car_model = client->cars[client->car_assignments[i %64]];
@@ -1707,16 +2878,16 @@ void c_render(Drive* env) {
object_color = PUFF_CYAN;
outline_color = PUFF_WHITE;
}
- if(is_active_agent && env->entities[i].collision_state > 0) {
+ if(is_active_agent && agent->collision_state > 0) {
car_model = client->cars[0]; // Collided agent
}
// Draw obs for human selected agent
- if(agent_index == env->human_agent_idx && !env->entities[agent_index].reached_goal) {
- draw_agent_obs(env, agent_index);
+ if(agent_index == env->human_agent_idx && !agent->metrics_array[REACHED_GOAL_IDX]) {
+ draw_agent_obs(env, agent_index, mode, obs_only, lasers);
}
// Draw cube for cars static and active
// Calculate scale factors based on desired size and model dimensions
-
+
BoundingBox bounds = GetModelBoundingBox(car_model);
Vector3 model_size = {
bounds.max.x - bounds.min.x,
@@ -1728,140 +2899,260 @@ void c_render(Drive* env) {
size.y / model_size.y,
size.z / model_size.z
};
- DrawModelEx(car_model, (Vector3){0, 0, 0}, (Vector3){1, 0, 0}, 90.0f, scale, WHITE);
- rlPopMatrix();
-
- float cos_heading = env->entities[i].heading_x;
- float sin_heading = env->entities[i].heading_y;
-
- // Calculate half dimensions
- float half_len = env->entities[i].length * 0.5f;
- float half_width = env->entities[i].width * 0.5f;
-
- // Calculate the four corners of the collision box
- Vector3 corners[4] = {
- (Vector3){
- position.x + (half_len * cos_heading - half_width * sin_heading),
- position.y + (half_len * sin_heading + half_width * cos_heading),
- position.z
- },
- (Vector3){
- position.x + (half_len * cos_heading + half_width * sin_heading),
- position.y + (half_len * sin_heading - half_width * cos_heading),
- position.z
- },
- (Vector3){
- position.x + (-half_len * cos_heading - half_width * sin_heading),
- position.y + (-half_len * sin_heading + half_width * cos_heading),
- position.z
- },
- (Vector3){
- position.x + (-half_len * cos_heading + half_width * sin_heading),
- position.y + (-half_len * sin_heading - half_width * cos_heading),
- position.z
- }
- };
-
- // Draw the corners as spheres
- /*
- for(int j = 0; j < 4; j++) {
- DrawSphere(corners[j], 0.3f, RED); // Draw red spheres at each corner
- }
- */
- for(int j = 0; j < 4; j++) {
- DrawLine3D(corners[j], corners[(j+1)%4], PURPLE); // Draw red lines between corners
+ if((obs_only || IsKeyDown(KEY_LEFT_CONTROL)) && agent_index != env->human_agent_idx){
+ rlPopMatrix();
+ continue;
}
- // FPV Camera Control
- if(IsKeyDown(KEY_SPACE) && env->human_agent_idx== agent_index){
- if(env->entities[agent_index].reached_goal){
- env->human_agent_idx = rand() % env->active_agent_count;
- }
- Vector3 camera_position = (Vector3){
- position.x - (25.0f * cosf(heading)),
- position.y - (25.0f * sinf(heading)),
- position.z + 15
- };
- Vector3 camera_target = (Vector3){
- position.x + 40.0f * cosf(heading),
- position.y + 40.0f * sinf(heading),
- position.z - 5.0f
+ DrawModelEx(car_model, (Vector3){0, 0, 0}, (Vector3){1, 0, 0}, 90.0f, scale, WHITE);
+ {
+ float cos_heading = cosf(heading);
+ float sin_heading = sinf(heading);
+ float half_len = agent->sim_length * 0.5f;
+ float half_width = agent->sim_width * 0.5f;
+ Vector3 corners[4] = {
+ (Vector3){ 0 + ( half_len * cos_heading - half_width * sin_heading), 0 + ( half_len * sin_heading + half_width * cos_heading), 0 },
+ (Vector3){ 0 + ( half_len * cos_heading + half_width * sin_heading), 0 + ( half_len * sin_heading - half_width * cos_heading), 0 },
+ (Vector3){ 0 + (-half_len * cos_heading + half_width * sin_heading), 0 + (-half_len * sin_heading - half_width * cos_heading), 0 },
+ (Vector3){ 0 + (-half_len * cos_heading - half_width * sin_heading), 0 + (-half_len * sin_heading + half_width * cos_heading), 0 },
};
- client->camera.position = camera_position;
- client->camera.target = camera_target;
- client->camera.up = (Vector3){0, 0, 1};
- }
- if(IsKeyReleased(KEY_SPACE)){
- client->camera.position = client->default_camera_position;
- client->camera.target = client->default_camera_target;
- client->camera.up = (Vector3){0, 0, 1};
+ Color wire_color = GRAY; // static
+ if (!is_active_agent && agent->mark_as_expert == 1) wire_color = GOLD; // expert replay
+ if (is_active_agent) wire_color = BLUE; // policy
+ if (is_active_agent && agent->collision_state > 0) wire_color = RED;
+ rlSetLineWidth(2.0f);
+ for (int j = 0; j < 4; j++) {
+ DrawLine3D(corners[j], corners[(j+1)%4], wire_color);
+ }
}
- // Draw goal position for active agents
+ rlPopMatrix();
+ }
- if(!is_active_agent || env->entities[i].valid == 0) {
- continue;
- }
- if(!IsKeyDown(KEY_LEFT_CONTROL)){
- DrawSphere((Vector3){
- env->entities[i].goal_position_x,
- env->entities[i].goal_position_y,
- 1
- }, 0.5f, DARKGREEN);
+ // FPV Camera Control
+ if(IsKeyDown(KEY_SPACE) && env->human_agent_idx== agent_index){
+ if(agent->metrics_array[REACHED_GOAL_IDX]){
+ env->human_agent_idx = rand() % env->active_agent_count;
}
+ Vector3 camera_position = (Vector3){
+ position.x - (25.0f * cosf(heading)),
+ position.y - (25.0f * sinf(heading)),
+ position.z + 15
+ };
+
+ Vector3 camera_target = (Vector3){
+ position.x + 40.0f * cosf(heading),
+ position.y + 40.0f * sinf(heading),
+ position.z - 5.0f
+ };
+ client->camera.position = camera_position;
+ client->camera.target = camera_target;
+ client->camera.up = (Vector3){0, 0, 1};
+ }
+ if(IsKeyReleased(KEY_SPACE)){
+ client->camera.position = client->default_camera_position;
+ client->camera.target = client->default_camera_target;
+ client->camera.up = (Vector3){0, 0, 1};
}
- // Draw road elements
- if(env->entities[i].type <=3 && env->entities[i].type >= 7){
+ // Draw goal position for active agents
+
+ if(!is_active_agent || agent->sim_valid == 0) {
continue;
}
- for(int j = 0; j < env->entities[i].array_size - 1; j++) {
+ if(!IsKeyDown(KEY_LEFT_CONTROL) && obs_only==0){
+ DrawSphere((Vector3){
+ agent->goal_position_x,
+ agent->goal_position_y,
+ 1
+ }, 0.5f, DARKGREEN);
+
+ DrawCircle3D((Vector3){
+ agent->goal_position_x,
+ agent->goal_position_y,
+ 0.1f
+ }, env->goal_radius, (Vector3){0, 0, 1}, 90.0f, Fade(LIGHTGREEN, 0.3f));
+ }
+
+ }
+ for (int i = 0; i < env->num_road_elements; i++) {
+ RoadMapElement* element = &env->road_elements[i];
+
+ for(int j = 0; j < element->segment_length - 1; j++) {
Vector3 start = {
- env->entities[i].traj_x[j],
- env->entities[i].traj_y[j],
+ element->x[j],
+ element->y[j],
1
};
Vector3 end = {
- env->entities[i].traj_x[j + 1],
- env->entities[i].traj_y[j + 1],
+ element->x[j + 1],
+ element->y[j + 1],
1
};
Color lineColor = GRAY;
- if (env->entities[i].type == ROAD_LANE) lineColor = GRAY;
- else if (env->entities[i].type == ROAD_LINE) lineColor = BLUE;
- else if (env->entities[i].type == ROAD_EDGE) lineColor = WHITE;
- else if (env->entities[i].type == DRIVEWAY) lineColor = RED;
- if(env->entities[i].type != ROAD_EDGE){
- continue;
- }
- if(!IsKeyDown(KEY_LEFT_CONTROL)){
+
+ if (is_road_lane(element->type)) lineColor = GRAY;
+ else if (is_road_line(element->type)) lineColor = BLUE;
+ else if (is_road_edge(element->type)) lineColor = WHITE;
+ else if (element->type == DRIVEWAY) lineColor = RED;
+ if(!IsKeyDown(KEY_LEFT_CONTROL) && obs_only==0){
draw_road_edge(env, start.x, start.y, end.x, end.y);
- // DrawLine3D(start, end, lineColor);
- // DrawCube(start, 0.5f, 0.5f, 0.5f, lineColor);
- // DrawCube(end, 0.5f, 0.5f, 0.5f, lineColor);
}
}
}
- // Draw grid cells using the stored bounds
- float grid_start_x = env->map_corners[0];
- float grid_start_y = env->map_corners[1];
- for(int i = 0; i < env->grid_cols; i++) {
- for(int j = 0; j < env->grid_rows; j++) {
- float x = grid_start_x + i*GRID_CELL_SIZE;
- float y = grid_start_y + j*GRID_CELL_SIZE;
- // int index = i * env->grid_rows + j;
- DrawCubeWires(
- (Vector3){x + GRID_CELL_SIZE/2, y + GRID_CELL_SIZE/2, 1},
- GRID_CELL_SIZE, GRID_CELL_SIZE, 0.1f, PUFF_BACKGROUND2);
+ if(show_grid) {
+ // Draw grid cells using the stored bounds
+ float grid_start_x = env->grid_map->top_left_x;
+ float grid_start_y = env->grid_map->bottom_right_y;
+ for(int i = 0; i < env->grid_map->grid_cols; i++) {
+ for(int j = 0; j < env->grid_map->grid_rows; j++) {
+ float x = grid_start_x + i*GRID_CELL_SIZE;
+ float y = grid_start_y + j*GRID_CELL_SIZE;
+ DrawCubeWires(
+ (Vector3){x + GRID_CELL_SIZE/2, y + GRID_CELL_SIZE/2, 1},
+ GRID_CELL_SIZE, GRID_CELL_SIZE, 0.1f, PUFF_BACKGROUND2);
+ }
}
}
+
EndMode3D();
+
+ // Draw track indices for the tracks to predict
+ if (mode == 1 && env->control_mode == CONTROL_TRACKS_TO_PREDICT) {
+ float map_width = env->grid_map->bottom_right_x - env->grid_map->top_left_x;
+ float map_height = env->grid_map->top_left_y - env->grid_map->bottom_right_y;
+ float pixels_per_world_unit = client->height / map_height;
+
+ for (int i = 0; i < env->active_agent_count; i++) {
+ // Ignore respawned agents
+ if (env->agents[i].respawn_timestep != -1) {
+ continue;
+ }
+ int agent_idx = env->active_agent_indices[i];
+ int womd_track_idx = env->tracks_to_predict[i];
+
+ float raw_x = -env->agents[agent_idx].sim_x * pixels_per_world_unit;
+ float raw_y = env->agents[agent_idx].sim_y * pixels_per_world_unit;
+
+ int screen_x = (int)raw_x + client->width/2 + 20;
+ int screen_y = (int)raw_y + client->height/2 - 25;
+
+ if (screen_x >= 0 && screen_x <= client->width &&
+ screen_y >= 0 && screen_y <= client->height) {
+ char text[32];
+ snprintf(text, sizeof(text), "%d", womd_track_idx);
+ int text_width = MeasureText(text, 20);
+ DrawText(text, screen_x - text_width/2, screen_y, 20, PUFF_WHITE);
+ }
+ }
+ }
+}
+
+void saveTopDownImage(Drive* env, Client* client, const char *filename, RenderTexture2D target, int map_height, int obs, int lasers, int trajectories, int frame_count, float* path, int log_trajectories, int show_grid){
+ // Top-down orthographic camera
+ Camera3D camera = {0};
+ camera.position = (Vector3){ 0.0f, 0.0f, 500.0f }; // above the scene
+ camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // look at origin
+ camera.up = (Vector3){ 0.0f, -1.0f, 0.0f };
+ camera.fovy = map_height;
+ camera.projection = CAMERA_ORTHOGRAPHIC;
+ Color road = (Color){35, 35, 37, 255};
+
+ BeginTextureMode(target);
+ ClearBackground(road);
+ BeginMode3D(camera);
+ rlEnableDepthTest();
+
+ // Draw log trajectories FIRST (in background at lower Z-level)
+ if(log_trajectories){
+ for(int i = 0; i < env->num_total_agents; i++) {
+ Agent* agent = &env->agents[i];
+ int idx = env->active_agent_indices[i];
+ for(int j=0; jtrajectory_length; j++){
+ float x = agent->log_trajectory_x[j];
+ float y = agent->log_trajectory_y[j];
+ float valid = agent->log_valid[j];
+ if(!valid) continue;
+ DrawSphere((Vector3){x,y,0.5f}, 0.3f, Fade(LIGHTGREEN, 0.6f));
+ }
+ }
+ }
+
+ // Draw current path trajectories SECOND (slightly higher than log trajectories)
+ if(trajectories){
+ for(int i=0; iactive_agent_indices[env->human_agent_idx];
+ Agent* agent = &env->agents[agent_idx];
+
+ Camera3D camera = {0};
+ // Position camera behind and above the agent
+ camera.position = (Vector3){
+ agent->sim_x - (25.0f * cosf(agent->sim_heading)),
+ agent->sim_y - (25.0f * sinf(agent->sim_heading)),
+ 15.0f
+ };
+ camera.target = (Vector3){
+ agent->sim_x + 40.0f * cosf(agent->sim_heading),
+ agent->sim_y + 40.0f * sinf(agent->sim_heading),
+ 1.0f
+ };
+ camera.up = (Vector3){ 0.0f, 0.0f, 1.0f };
+ camera.fovy = 45.0f;
+ camera.projection = CAMERA_PERSPECTIVE;
+
+ Color road = (Color){35, 35, 37, 255};
+
+ BeginTextureMode(target);
+ ClearBackground(road);
+ BeginMode3D(camera);
+ rlEnableDepthTest();
+ draw_scene(env, client, 0, obs_only, lasers, show_grid); // mode=0 for agent view
+ EndMode3D();
+ EndTextureMode();
+
+ // Save to file
+ Image img = LoadImageFromTexture(target.texture);
+ ImageFlipVertical(&img);
+ ExportImage(img, filename);
+ UnloadImage(img);
+}
+
+void c_render(Drive* env) {
+ if (env->client == NULL) {
+ env->client = make_client(env);
+ }
+ Client* client = env->client;
+ BeginDrawing();
+ Color road = (Color){35, 35, 37, 255};
+ ClearBackground(road);
+ BeginMode3D(client->camera);
+ handle_camera_controls(env->client);
+ draw_scene(env, client, 0, 0, 0, 0);
// Draw debug info
- DrawText(TextFormat("Camera Position: (%.2f, %.2f, %.2f)",
- client->camera.position.x,
- client->camera.position.y,
+ DrawText(TextFormat("Camera Position: (%.2f, %.2f, %.2f)",
+ client->camera.position.x,
+ client->camera.position.y,
client->camera.position.z), 10, 10, 20, PUFF_WHITE);
- DrawText(TextFormat("Camera Target: (%.2f, %.2f, %.2f)",
- client->camera.target.x,
- client->camera.target.y,
+ DrawText(TextFormat("Camera Target: (%.2f, %.2f, %.2f)",
+ client->camera.target.x,
+ client->camera.target.y,
client->camera.target.z), 10, 30, 20, PUFF_WHITE);
DrawText(TextFormat("Timestep: %d", env->timestep), 10, 50, 20, PUFF_WHITE);
// acceleration & steering
@@ -1869,13 +3160,20 @@ void c_render(Drive* env) {
DrawText(TextFormat("Controlling Agent: %d", env->human_agent_idx), 10, 70, 20, PUFF_WHITE);
DrawText(TextFormat("Agent Index: %d", human_idx), 10, 90, 20, PUFF_WHITE);
// Controls help
- DrawText("Controls: W/S - Accelerate/Brake, A/D - Steer, 1-4 - Switch Agent",
+ DrawText("Controls: W/S - Accelerate/Brake, A/D - Steer, 1-4 - Switch Agent",
10, client->height - 30, 20, PUFF_WHITE);
// acceleration & steering
- DrawText(TextFormat("Acceleration: %d", env->actions[env->human_agent_idx * 2]), 10, 110, 20, PUFF_WHITE);
- DrawText(TextFormat("Steering: %d", env->actions[env->human_agent_idx * 2 + 1]), 10, 130, 20, PUFF_WHITE);
- DrawText(TextFormat("Grid Rows: %d", env->grid_rows), 10, 150, 20, PUFF_WHITE);
- DrawText(TextFormat("Grid Cols: %d", env->grid_cols), 10, 170, 20, PUFF_WHITE);
+ if (env->action_type == 1) { // continuous (float)
+ float (*action_array_f)[2] = (float(*)[2])env->actions;
+ DrawText(TextFormat("Acceleration: %.2f", action_array_f[env->human_agent_idx][0]), 10, 110, 20, PUFF_WHITE);
+ DrawText(TextFormat("Steering: %.2f", action_array_f[env->human_agent_idx][1]), 10, 130, 20, PUFF_WHITE);
+ } else { // discrete (int)
+ int (*action_array)[2] = (int(*)[2])env->actions;
+ DrawText(TextFormat("Acceleration: %d", action_array[env->human_agent_idx][0]), 10, 110, 20, PUFF_WHITE);
+ DrawText(TextFormat("Steering: %d", action_array[env->human_agent_idx][1]), 10, 130, 20, PUFF_WHITE);
+ }
+ DrawText(TextFormat("Grid Rows: %d", env->grid_map->grid_rows), 10, 150, 20, PUFF_WHITE);
+ DrawText(TextFormat("Grid Cols: %d", env->grid_map->grid_cols), 10, 170, 20, PUFF_WHITE);
EndDrawing();
}
diff --git a/pufferlib/ocean/drive/drive.py b/pufferlib/ocean/drive/drive.py
index 107396725..ad6dbd62e 100644
--- a/pufferlib/ocean/drive/drive.py
+++ b/pufferlib/ocean/drive/drive.py
@@ -3,48 +3,143 @@
import json
import struct
import os
-import random
import pufferlib
from pufferlib.ocean.drive import binding
-class Drive(pufferlib.PufferEnv):
- def __init__(self, render_mode=None, report_interval=1,
- width=1280, height=1024,
- human_agent_idx=0,
- reward_vehicle_collision=-0.1,
- reward_offroad_collision=-0.1,
- reward_goal_post_respawn=0.5,
- reward_vehicle_collision_post_respawn=-0.25,
- spawn_immunity_timer=30,
- resample_frequency = 91,
- num_maps=100,
- num_agents=512,
- buf = None,
- seed=1):
+class Drive(pufferlib.PufferEnv):
+ def __init__(
+ self,
+ render_mode=None,
+ report_interval=1,
+ width=1280,
+ height=1024,
+ human_agent_idx=0,
+ reward_vehicle_collision=-0.1,
+ reward_offroad_collision=-0.1,
+ reward_goal=1.0,
+ reward_goal_post_respawn=0.5,
+ reward_ade=0.0,
+ goal_behavior=0,
+ goal_radius=2.0,
+ collision_behavior=0,
+ offroad_behavior=0,
+ dt=0.1,
+ scenario_length=None,
+ resample_frequency=91,
+ num_maps=100,
+ num_agents=512,
+ action_type="discrete",
+ dynamics_model="classic",
+ max_controlled_agents=-1,
+ buf=None,
+ seed=1,
+ init_steps=0,
+ init_mode="create_all_valid",
+ control_mode="control_vehicles",
+ ):
# env
+ self.dt = dt
self.render_mode = render_mode
self.num_maps = num_maps
self.report_interval = report_interval
self.reward_vehicle_collision = reward_vehicle_collision
self.reward_offroad_collision = reward_offroad_collision
+ self.reward_goal = reward_goal
self.reward_goal_post_respawn = reward_goal_post_respawn
- self.reward_vehicle_collision_post_respawn = reward_vehicle_collision_post_respawn
- self.spawn_immunity_timer = spawn_immunity_timer
+ self.goal_radius = goal_radius
+ self.goal_behavior = goal_behavior
+ self.collision_behavior = collision_behavior
+ self.offroad_behavior = offroad_behavior
+ self.reward_ade = reward_ade
self.human_agent_idx = human_agent_idx
+ self.scenario_length = scenario_length
self.resample_frequency = resample_frequency
- self.num_obs = 7 + 63*7 + 200*7
- self.single_observation_space = gymnasium.spaces.Box(low=-1, high=1,
- shape=(self.num_obs,), dtype=np.float32)
- self.single_action_space = gymnasium.spaces.MultiDiscrete([7, 13])
- # self.single_action_space = gymnasium.spaces.Box(
- # low=-1, high=1, shape=(2,), dtype=np.float32
- # )
+ self.dynamics_model = dynamics_model
+
+ # Observation space calculation
+ if dynamics_model == "classic":
+ ego_features = 7
+ elif dynamics_model == "jerk":
+ ego_features = 10
+ else:
+ raise ValueError(f"dynamics_model must be 'classic' or 'jerk'. Got: {dynamics_model}")
+
+ self.ego_features = ego_features
+ partner_features = 7
+ road_features = 7
+ max_partner_objects = 63
+ max_road_objects = 200
+ self.num_obs = ego_features + max_partner_objects * partner_features + max_road_objects * road_features
+ self.single_observation_space = gymnasium.spaces.Box(low=-1, high=1, shape=(self.num_obs,), dtype=np.float32)
+ self.init_steps = init_steps
+ self.init_mode_str = init_mode
+ self.control_mode_str = control_mode
+
+ if self.control_mode_str == "control_vehicles":
+ self.control_mode = 0
+ elif self.control_mode_str == "control_agents":
+ self.control_mode = 1
+ elif self.control_mode_str == "control_tracks_to_predict":
+ self.control_mode = 2
+ elif self.control_mode_str == "control_sdc_only":
+ self.control_mode = 3
+ else:
+ raise ValueError(
+ f"control_mode must be one of 'control_vehicles', 'control_tracks_to_predict', or 'control_agents'. Got: {self.control_mode_str}"
+ )
+ if self.init_mode_str == "create_all_valid":
+ self.init_mode = 0
+ elif self.init_mode_str == "create_only_controlled":
+ self.init_mode = 1
+ else:
+ raise ValueError(
+ f"init_mode must be one of 'create_all_valid' or 'create_only_controlled'. Got: {self.init_mode_str}"
+ )
+
+ if action_type == "discrete":
+ if dynamics_model == "classic":
+ # Joint action space (assume dependence)
+ self.single_action_space = gymnasium.spaces.MultiDiscrete([7 * 13])
+ # Multi discrete (assume independence)
+ # self.single_action_space = gymnasium.spaces.MultiDiscrete([7, 13])
+ elif dynamics_model == "jerk":
+ self.single_action_space = gymnasium.spaces.MultiDiscrete([4, 3])
+ else:
+ raise ValueError(f"dynamics_model must be 'classic' or 'jerk'. Got: {dynamics_model}")
+ elif action_type == "continuous":
+ self.single_action_space = gymnasium.spaces.Box(low=-1, high=1, shape=(2,), dtype=np.float32)
+ else:
+ raise ValueError(f"action_space must be 'discrete' or 'continuous'. Got: {action_type}")
+
+ self._action_type_flag = 0 if action_type == "discrete" else 1
+
# Check if resources directory exists
binary_path = "resources/drive/binaries/map_000.bin"
if not os.path.exists(binary_path):
- raise FileNotFoundError(f"Required directory {binary_path} not found. Please ensure the Drive maps are downloaded and installed correctly per docs.")
- agent_offsets, map_ids, num_envs = binding.shared(num_agents=num_agents, num_maps=num_maps)
+ raise FileNotFoundError(
+ f"Required directory {binary_path} not found. Please ensure the Drive maps are downloaded and installed correctly per docs."
+ )
+
+ # Check maps availability
+ available_maps = len([name for name in os.listdir("resources/drive/binaries") if name.endswith(".bin")])
+ if num_maps > available_maps:
+ raise ValueError(
+ f"num_maps ({num_maps}) exceeds available maps in directory ({available_maps}). Please reduce num_maps or add more maps to resources/drive/binaries."
+ )
+ self.max_controlled_agents = int(max_controlled_agents)
+
+ # Iterate through all maps to count total agents that can be initialized for each map
+ agent_offsets, map_ids, num_envs = binding.shared(
+ num_agents=num_agents,
+ num_maps=num_maps,
+ init_mode=self.init_mode,
+ control_mode=self.control_mode,
+ init_steps=self.init_steps,
+ max_controlled_agents=self.max_controlled_agents,
+ goal_behavior=self.goal_behavior,
+ )
+
self.num_agents = num_agents
self.agent_offsets = agent_offsets
self.map_ids = map_ids
@@ -53,7 +148,7 @@ def __init__(self, render_mode=None, report_interval=1,
env_ids = []
for i in range(num_envs):
cur = agent_offsets[i]
- nxt = agent_offsets[i+1]
+ nxt = agent_offsets[i + 1]
env_id = binding.env_init(
self.observations[cur:nxt],
self.actions[cur:nxt],
@@ -61,14 +156,26 @@ def __init__(self, render_mode=None, report_interval=1,
self.terminals[cur:nxt],
self.truncations[cur:nxt],
seed,
+ action_type=self._action_type_flag,
human_agent_idx=human_agent_idx,
reward_vehicle_collision=reward_vehicle_collision,
reward_offroad_collision=reward_offroad_collision,
+ reward_goal=reward_goal,
reward_goal_post_respawn=reward_goal_post_respawn,
- reward_vehicle_collision_post_respawn=reward_vehicle_collision_post_respawn,
- spawn_immunity_timer=spawn_immunity_timer,
+ reward_ade=reward_ade,
+ goal_radius=goal_radius,
+ goal_behavior=self.goal_behavior,
+ collision_behavior=self.collision_behavior,
+ offroad_behavior=self.offroad_behavior,
+ dt=dt,
+ scenario_length=(int(scenario_length) if scenario_length is not None else None),
+ max_controlled_agents=self.max_controlled_agents,
map_id=map_ids[i],
- max_agents = nxt-cur
+ max_agents=nxt - cur,
+ ini_file="pufferlib/config/ocean/drive.ini",
+ init_steps=init_steps,
+ init_mode=self.init_mode,
+ control_mode=self.control_mode,
)
env_ids.append(env_id)
@@ -83,24 +190,32 @@ def step(self, actions):
self.terminals[:] = 0
self.actions[:] = actions
binding.vec_step(self.c_envs)
- self.tick+=1
+ self.tick += 1
info = []
if self.tick % self.report_interval == 0:
log = binding.vec_log(self.c_envs)
if log:
info.append(log)
- #print(log)
- if(self.tick > 0 and self.resample_frequency > 0 and self.tick % self.resample_frequency == 0):
+ # print(log)
+ if self.tick > 0 and self.resample_frequency > 0 and self.tick % self.resample_frequency == 0:
self.tick = 0
will_resample = 1
if will_resample:
binding.vec_close(self.c_envs)
- agent_offsets, map_ids, num_envs = binding.shared(num_agents=self.num_agents, num_maps=self.num_maps)
+ agent_offsets, map_ids, num_envs = binding.shared(
+ num_agents=self.num_agents,
+ num_maps=self.num_maps,
+ init_mode=self.init_mode,
+ control_mode=self.control_mode,
+ init_steps=self.init_steps,
+ max_controlled_agents=self.max_controlled_agents,
+ goal_behavior=self.goal_behavior,
+ )
env_ids = []
- seed = np.random.randint(0, 2**32-1)
+ seed = np.random.randint(0, 2**32 - 1)
for i in range(num_envs):
cur = agent_offsets[i]
- nxt = agent_offsets[i+1]
+ nxt = agent_offsets[i + 1]
env_id = binding.env_init(
self.observations[cur:nxt],
self.actions[cur:nxt],
@@ -108,32 +223,102 @@ def step(self, actions):
self.terminals[cur:nxt],
self.truncations[cur:nxt],
seed,
+ action_type=self._action_type_flag,
human_agent_idx=self.human_agent_idx,
reward_vehicle_collision=self.reward_vehicle_collision,
reward_offroad_collision=self.reward_offroad_collision,
+ reward_goal=self.reward_goal,
reward_goal_post_respawn=self.reward_goal_post_respawn,
- reward_vehicle_collision_post_respawn=self.reward_vehicle_collision_post_respawn,
- spawn_immunity_timer=self.spawn_immunity_timer,
+ reward_ade=self.reward_ade,
+ goal_radius=self.goal_radius,
+ goal_behavior=self.goal_behavior,
+ collision_behavior=self.collision_behavior,
+ offroad_behavior=self.offroad_behavior,
+ dt=self.dt,
+ scenario_length=(int(self.scenario_length) if self.scenario_length is not None else None),
+ max_controlled_agents=self.max_controlled_agents,
map_id=map_ids[i],
- max_agents = nxt-cur
+ max_agents=nxt - cur,
+ ini_file="pufferlib/config/ocean/drive.ini",
+ init_steps=self.init_steps,
+ init_mode=self.init_mode,
+ control_mode=self.control_mode,
)
env_ids.append(env_id)
self.c_envs = binding.vectorize(*env_ids)
binding.vec_reset(self.c_envs, seed)
self.terminals[:] = 1
- return (self.observations, self.rewards,
- self.terminals, self.truncations, info)
+ return (self.observations, self.rewards, self.terminals, self.truncations, info)
+
+ def get_global_agent_state(self):
+ """Get current global state of all active agents.
+
+ Returns:
+ dict with keys 'x', 'y', 'z', 'heading', 'id' containing numpy arrays
+ of shape (num_active_agents,)
+ """
+ num_agents = self.num_agents
+
+ states = {
+ "x": np.zeros(num_agents, dtype=np.float32),
+ "y": np.zeros(num_agents, dtype=np.float32),
+ "z": np.zeros(num_agents, dtype=np.float32),
+ "heading": np.zeros(num_agents, dtype=np.float32),
+ "id": np.zeros(num_agents, dtype=np.int32),
+ }
+
+ binding.vec_get_global_agent_state(
+ self.c_envs, states["x"], states["y"], states["z"], states["heading"], states["id"]
+ )
+
+ return states
+
+ def get_ground_truth_trajectories(self):
+ """Get ground truth trajectories for all active agents.
+
+ Returns:
+ dict with keys 'x', 'y', 'z', 'heading', 'valid', 'id', 'scenario_id' containing numpy arrays.
+ """
+ num_agents = self.num_agents
+
+ trajectories = {
+ "x": np.zeros((num_agents, self.scenario_length - self.init_steps), dtype=np.float32),
+ "y": np.zeros((num_agents, self.scenario_length - self.init_steps), dtype=np.float32),
+ "z": np.zeros((num_agents, self.scenario_length - self.init_steps), dtype=np.float32),
+ "heading": np.zeros((num_agents, self.scenario_length - self.init_steps), dtype=np.float32),
+ "valid": np.zeros((num_agents, self.scenario_length - self.init_steps), dtype=np.int32),
+ "id": np.zeros(num_agents, dtype=np.int32),
+ "scenario_id": np.zeros(num_agents, dtype=np.int32),
+ }
+
+ binding.vec_get_global_ground_truth_trajectories(
+ self.c_envs,
+ trajectories["x"],
+ trajectories["y"],
+ trajectories["z"],
+ trajectories["heading"],
+ trajectories["valid"],
+ trajectories["id"],
+ trajectories["scenario_id"],
+ )
+
+ for key in trajectories:
+ trajectories[key] = trajectories[key][:, None]
+
+ return trajectories
def render(self):
binding.vec_render(self.c_envs, 0)
-
+
def close(self):
binding.vec_close(self.c_envs)
+
def calculate_area(p1, p2, p3):
# Calculate the area of the triangle using the determinant method
- return 0.5 * abs((p1['x'] - p3['x']) * (p2['y'] - p1['y']) - (p1['x'] - p2['x']) * (p3['y'] - p1['y']))
+ return 0.5 * abs((p1["x"] - p3["x"]) * (p2["y"] - p1["y"]) - (p1["x"] - p2["x"]) * (p3["y"] - p1["y"]))
+
def simplify_polyline(geometry, polyline_reduction_threshold):
"""Simplify the given polyline using a method inspired by Visvalingham-Whyatt, optimized for Python."""
@@ -174,169 +359,214 @@ def simplify_polyline(geometry, polyline_reduction_threshold):
return [geometry[i] for i in range(num_points) if not skip[i]]
-def save_map_binary(map_data, output_file):
+
+def save_map_binary(map_data, output_file, unique_map_id):
trajectory_length = 91
"""Saves map data in a binary format readable by C"""
- with open(output_file, 'wb') as f:
+ with open(output_file, "wb") as f:
+ # Get metadata
+ metadata = map_data.get("metadata", {})
+ sdc_track_index = metadata.get("sdc_track_index", -1) # -1 as default if not found
+ tracks_to_predict = metadata.get("tracks_to_predict", [])
+
+ # Write sdc_track_index
+ f.write(struct.pack("i", sdc_track_index))
+
+ # Write tracks_to_predict info (indices only)
+ f.write(struct.pack("i", len(tracks_to_predict)))
+ for track in tracks_to_predict:
+ track_index = track.get("track_index", -1)
+ f.write(struct.pack("i", track_index))
+
# Count total entities
- print(len(map_data.get('objects', [])))
- print(len(map_data.get('roads', [])))
- num_objects = len(map_data.get('objects', []))
- num_roads = len(map_data.get('roads', []))
+ print(len(map_data.get("objects", [])))
+ print(len(map_data.get("roads", [])))
+ num_objects = len(map_data.get("objects", []))
+ num_roads = len(map_data.get("roads", []))
# num_entities = num_objects + num_roads
- f.write(struct.pack('i', num_objects))
- f.write(struct.pack('i', num_roads))
+ f.write(struct.pack("i", num_objects))
+ f.write(struct.pack("i", num_roads))
# f.write(struct.pack('i', num_entities))
# Write objects
- for obj in map_data.get('objects', []):
+ for obj in map_data.get("objects", []):
+ # Write unique map id
+ f.write(struct.pack("i", unique_map_id))
+
# Write base entity data
- obj_type = obj.get('type', 1)
- if(obj_type =='vehicle'):
+ obj_type = obj.get("type", 1)
+ if obj_type == "vehicle":
obj_type = 1
- elif(obj_type == 'pedestrian'):
+ elif obj_type == "pedestrian":
obj_type = 2
- elif(obj_type == 'cyclist'):
+ elif obj_type == "cyclist":
obj_type = 3
- if(obj_type == 0):
- print("Warning: Object with type 0 found")
- f.write(struct.pack('i', obj_type)) # type
- # f.write(struct.pack('i', obj.get('id', 0))) # id
- f.write(struct.pack('i', trajectory_length)) # array_size
+ f.write(struct.pack("i", obj_type)) # type
+ f.write(struct.pack("i", obj.get("id", 0))) # id
+ f.write(struct.pack("i", trajectory_length)) # array_size
# Write position arrays
- positions = obj.get('position', [])
+ positions = obj.get("position", [])
for i in range(trajectory_length):
- pos = positions[i] if i < len(positions) else {'x': 0.0, 'y': 0.0, 'z': 0.0}
- f.write(struct.pack('f', float(pos.get('x', 0.0))))
+ pos = positions[i] if i < len(positions) else {"x": 0.0, "y": 0.0, "z": 0.0}
+ f.write(struct.pack("f", float(pos.get("x", 0.0))))
for i in range(trajectory_length):
- pos = positions[i] if i < len(positions) else {'x': 0.0, 'y': 0.0, 'z': 0.0}
- f.write(struct.pack('f', float(pos.get('y', 0.0))))
+ pos = positions[i] if i < len(positions) else {"x": 0.0, "y": 0.0, "z": 0.0}
+ f.write(struct.pack("f", float(pos.get("y", 0.0))))
for i in range(trajectory_length):
- pos = positions[i] if i < len(positions) else {'x': 0.0, 'y': 0.0, 'z': 0.0}
- f.write(struct.pack('f', float(pos.get('z', 0.0))))
+ pos = positions[i] if i < len(positions) else {"x": 0.0, "y": 0.0, "z": 0.0}
+ f.write(struct.pack("f", float(pos.get("z", 0.0))))
# Write velocity arrays
- velocities = obj.get('velocity', [])
- for arr, key in [(velocities, 'x'), (velocities, 'y'), (velocities, 'z')]:
+ velocities = obj.get("velocity", [])
+ for arr, key in [(velocities, "x"), (velocities, "y"), (velocities, "z")]:
for i in range(trajectory_length):
- vel = arr[i] if i < len(arr) else {'x': 0.0, 'y': 0.0, 'z': 0.0}
- f.write(struct.pack('f', float(vel.get(key, 0.0))))
-
+ vel = arr[i] if i < len(arr) else {"x": 0.0, "y": 0.0, "z": 0.0}
+ f.write(struct.pack("f", float(vel.get(key, 0.0))))
+
# Write heading and valid arrays
- headings = obj.get('heading', [])
- f.write(struct.pack(f'{trajectory_length}f', *[float(headings[i]) if i < len(headings) else 0.0 for i in range(trajectory_length)]))
-
- valids = obj.get('valid', [])
- f.write(struct.pack(f'{trajectory_length}i', *[int(valids[i]) if i < len(valids) else 0 for i in range(trajectory_length)]))
-
+ headings = obj.get("heading", [])
+ f.write(
+ struct.pack(
+ f"{trajectory_length}f",
+ *[float(headings[i]) if i < len(headings) else 0.0 for i in range(trajectory_length)],
+ )
+ )
+
+ valids = obj.get("valid", [])
+ f.write(
+ struct.pack(
+ f"{trajectory_length}i",
+ *[int(valids[i]) if i < len(valids) else 0 for i in range(trajectory_length)],
+ )
+ )
+
# Write scalar fields
- f.write(struct.pack('f', float(obj.get('width', 0.0))))
- f.write(struct.pack('f', float(obj.get('length', 0.0))))
- f.write(struct.pack('f', float(obj.get('height', 0.0))))
- goal_pos = obj.get('goalPosition', {'x': 0, 'y': 0, 'z': 0}) # Get goalPosition object with default
- f.write(struct.pack('f', float(goal_pos.get('x', 0.0)))) # Get x value
- f.write(struct.pack('f', float(goal_pos.get('y', 0.0)))) # Get y value
- f.write(struct.pack('f', float(goal_pos.get('z', 0.0)))) # Get z value
- f.write(struct.pack('i', obj.get('mark_as_expert', 0)))
-
+ f.write(struct.pack("f", float(obj.get("width", 0.0))))
+ f.write(struct.pack("f", float(obj.get("length", 0.0))))
+ f.write(struct.pack("f", float(obj.get("height", 0.0))))
+ goal_pos = obj.get("goalPosition", {"x": 0, "y": 0, "z": 0}) # Get goalPosition object with default
+ f.write(struct.pack("f", float(goal_pos.get("x", 0.0)))) # Get x value
+ f.write(struct.pack("f", float(goal_pos.get("y", 0.0)))) # Get y value
+ f.write(struct.pack("f", float(goal_pos.get("z", 0.0)))) # Get z value
+ f.write(struct.pack("i", obj.get("mark_as_expert", 0)))
+
# Write roads
- for idx, road in enumerate(map_data.get('roads', [])):
- geometry = road.get('geometry', [])
- road_type = road.get('map_element_id', 0)
- road_type_word = road.get('type', 0)
- if(road_type_word == "lane"):
+ for idx, road in enumerate(map_data.get("roads", [])):
+ f.write(struct.pack("i", unique_map_id))
+
+ geometry = road.get("geometry", [])
+ road_type = road.get("map_element_id", 0)
+ road_type_word = road.get("type", 0)
+ if road_type_word == "lane":
road_type = 2
- elif(road_type_word == "road_edge"):
+ elif road_type_word == "road_edge":
road_type = 15
# breakpoint()
- if(len(geometry) > 10 and road_type <=16):
- geometry = simplify_polyline(geometry, .1)
+ if len(geometry) > 10 and road_type <= 16:
+ geometry = simplify_polyline(geometry, 0.1)
size = len(geometry)
# breakpoint()
- if(road_type >=0 and road_type <=3):
+ if road_type >= 0 and road_type <= 3:
road_type = 4
- elif(road_type >=5 and road_type <=13):
+ elif road_type >= 5 and road_type <= 13:
road_type = 5
- elif(road_type >=14 and road_type <=16):
+ elif road_type >= 14 and road_type <= 16:
road_type = 6
- elif(road_type == 17):
+ elif road_type == 17:
road_type = 7
- elif(road_type == 18):
+ elif road_type == 18:
road_type = 8
- elif(road_type == 19):
+ elif road_type == 19:
road_type = 9
- elif(road_type == 20):
+ elif road_type == 20:
road_type = 10
# Write base entity data
- f.write(struct.pack('i', road_type)) # type
- # f.write(struct.pack('i', road.get('id', 0))) # id
- f.write(struct.pack('i', size)) # array_size
-
+ f.write(struct.pack("i", road_type)) # type
+ f.write(struct.pack("i", road.get("id", 0))) # id
+ f.write(struct.pack("i", size)) # array_size
+
# Write position arrays
- for coord in ['x', 'y', 'z']:
+ for coord in ["x", "y", "z"]:
for point in geometry:
- f.write(struct.pack('f', float(point.get(coord, 0.0))))
+ f.write(struct.pack("f", float(point.get(coord, 0.0))))
+
+ # Write scalar fields
+ f.write(struct.pack("f", float(road.get("width", 0.0))))
+ f.write(struct.pack("f", float(road.get("length", 0.0))))
+ f.write(struct.pack("f", float(road.get("height", 0.0))))
+ goal_pos = road.get("goalPosition", {"x": 0, "y": 0, "z": 0}) # Get goalPosition object with default
+ f.write(struct.pack("f", float(goal_pos.get("x", 0.0)))) # Get x value
+ f.write(struct.pack("f", float(goal_pos.get("y", 0.0)))) # Get y value
+ f.write(struct.pack("f", float(goal_pos.get("z", 0.0)))) # Get z value
+ f.write(struct.pack("i", road.get("mark_as_expert", 0)))
-def load_map(map_name, binary_output=None):
+
+def load_map(map_name, unique_map_id, binary_output=None):
"""Loads a JSON map and optionally saves it as binary"""
- with open(map_name, 'r') as f:
+ with open(map_name, "r") as f:
map_data = json.load(f)
-
+
if binary_output:
- save_map_binary(map_data, binary_output)
+ save_map_binary(map_data, binary_output, unique_map_id)
+
def process_all_maps():
"""Process all maps and save them as binaries"""
- import os
from pathlib import Path
- # Handle potential symlink conflict
- resources_path = Path("resources")
- if resources_path.is_symlink():
- print("Removing conflicting symlink at 'resources'")
- resources_path.unlink()
-
# Create the binaries directory if it doesn't exist
binary_dir = Path("resources/drive/binaries")
binary_dir.mkdir(parents=True, exist_ok=True)
# Path to the training data
- data_dir = Path("data/carla")
-
- # Get all JSON files in data directory
+ data_dir = Path("data/processed/training")
+
+ # Get all JSON files in the training directory
json_files = sorted(data_dir.glob("*.json"))
-
+
print(f"Found {len(json_files)} JSON files")
-
+
# Process each JSON file
for i, map_path in enumerate(json_files[:10000]):
binary_file = f"map_{i:03d}.bin" # Use zero-padded numbers for consistent sorting
binary_path = binary_dir / binary_file
-
+
print(f"Processing {map_path.name} -> {binary_file}")
# try:
- load_map(str(map_path), str(binary_path))
+ load_map(str(map_path), i, str(binary_path))
# except Exception as e:
# print(f"Error processing {map_path.name}: {e}")
-def test_performance(timeout=10, atn_cache=1024, num_agents=1024, num_maps=8):
+
+def test_performance(timeout=10, atn_cache=1024, num_agents=1024):
import time
- print("Initializing Drive environment for performance test...")
- env = Drive(num_agents=num_agents, num_maps=num_maps)
+
+ env = Drive(
+ num_agents=num_agents,
+ num_maps=1,
+ control_mode="control_vehicles",
+ init_mode="create_all_valid",
+ init_steps=0,
+ scenario_length=91,
+ )
+
env.reset()
+
tick = 0
- actions = np.stack([
- np.random.randint(0, space.n + 1, (atn_cache, num_agents))
- for space in env.single_action_space
- ], axis=-1)
- print("Starting performance test...")
+ actions = np.stack(
+ [np.random.randint(0, space.n + 1, (atn_cache, num_agents)) for space in env.single_action_space], axis=-1
+ )
+
start = time.time()
while time.time() - start < timeout:
- atn = actions[tick % atn_cache]
+ atn = actions[tick % atn_cache]
env.step(atn)
tick += 1
- print(f'SPS: {num_agents * tick / (time.time() - start)}')
+ print(f"SPS: {num_agents * tick / (time.time() - start)}")
+
env.close()
-if __name__ == '__main__':
- # test_performance(num_agents=32)
+
+
+if __name__ == "__main__":
+ # test_performance()
process_all_maps()
diff --git a/pufferlib/ocean/drive/drivenet.h b/pufferlib/ocean/drive/drivenet.h
new file mode 100644
index 000000000..8b05e7020
--- /dev/null
+++ b/pufferlib/ocean/drive/drivenet.h
@@ -0,0 +1,247 @@
+#include
+#include "puffernet.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+typedef struct DriveNet DriveNet;
+struct DriveNet {
+ int num_agents;
+ int ego_dim;
+ float* obs_self;
+ float* obs_partner;
+ float* obs_road;
+ float* partner_linear_output;
+ float* road_linear_output;
+ float* partner_layernorm_output;
+ float* road_layernorm_output;
+ float* partner_linear_output_two;
+ float* road_linear_output_two;
+ Linear* ego_encoder;
+ Linear* road_encoder;
+ Linear* partner_encoder;
+ LayerNorm* ego_layernorm;
+ LayerNorm* road_layernorm;
+ LayerNorm* partner_layernorm;
+ Linear* ego_encoder_two;
+ Linear* road_encoder_two;
+ Linear* partner_encoder_two;
+ MaxDim1* partner_max;
+ MaxDim1* road_max;
+ CatDim1* cat1;
+ CatDim1* cat2;
+ GELU* gelu;
+ Linear* shared_embedding;
+ ReLU* relu;
+ LSTM* lstm;
+ Linear* actor;
+ Linear* value_fn;
+ Multidiscrete* multidiscrete;
+};
+
+DriveNet* init_drivenet(Weights* weights, int num_agents, int dynamics_model) {
+ DriveNet* net = calloc(1, sizeof(DriveNet));
+ int hidden_size = 256;
+ int input_size = 64;
+
+ int ego_dim = (dynamics_model == JERK) ? 10 : 7;
+
+ // Determine action space size based on dynamics model
+ int action_size, logit_sizes[2];
+ int action_dim;
+ if (dynamics_model == CLASSIC) {
+ action_size = 7 * 13; // Joint action space
+ logit_sizes[0] = 7 * 13;
+ action_dim = 1;
+ } else { // JERK
+ action_size = 7; // 4 + 3
+ logit_sizes[0] = 4;
+ logit_sizes[1] = 3;
+ action_dim = 2;
+ }
+
+ net->num_agents = num_agents;
+ net->ego_dim = ego_dim;
+ net->obs_self = calloc(num_agents*ego_dim, sizeof(float));
+ net->obs_partner = calloc(num_agents*63*7, sizeof(float));
+ net->obs_road = calloc(num_agents*200*13, sizeof(float));
+ net->partner_linear_output = calloc(num_agents*63*input_size, sizeof(float));
+ net->road_linear_output = calloc(num_agents*200*input_size, sizeof(float));
+ net->partner_linear_output_two = calloc(num_agents*63*input_size, sizeof(float));
+ net->road_linear_output_two = calloc(num_agents*200*input_size, sizeof(float));
+ net->partner_layernorm_output = calloc(num_agents*63*input_size, sizeof(float));
+ net->road_layernorm_output = calloc(num_agents*200*input_size, sizeof(float));
+ net->ego_encoder = make_linear(weights, num_agents, ego_dim, input_size);
+ net->ego_layernorm = make_layernorm(weights, num_agents, input_size);
+ net->ego_encoder_two = make_linear(weights, num_agents, input_size, input_size);
+ net->road_encoder = make_linear(weights, num_agents, 13, input_size);
+ net->road_layernorm = make_layernorm(weights, num_agents, input_size);
+ net->road_encoder_two = make_linear(weights, num_agents, input_size, input_size);
+ net->partner_encoder = make_linear(weights, num_agents, 7, input_size);
+ net->partner_layernorm = make_layernorm(weights, num_agents, input_size);
+ net->partner_encoder_two = make_linear(weights, num_agents, input_size, input_size);
+ net->partner_max = make_max_dim1(num_agents, 63, input_size);
+ net->road_max = make_max_dim1(num_agents, 200, input_size);
+ net->cat1 = make_cat_dim1(num_agents, input_size, input_size);
+ net->cat2 = make_cat_dim1(num_agents, input_size + input_size, input_size);
+ net->gelu = make_gelu(num_agents, 3*input_size);
+ net->shared_embedding = make_linear(weights, num_agents, input_size*3, hidden_size);
+ net->relu = make_relu(num_agents, hidden_size);
+ net->actor = make_linear(weights, num_agents, hidden_size, action_size);
+ net->value_fn = make_linear(weights, num_agents, hidden_size, 1);
+ net->lstm = make_lstm(weights, num_agents, hidden_size, 256);
+ memset(net->lstm->state_h, 0, num_agents*256*sizeof(float));
+ memset(net->lstm->state_c, 0, num_agents*256*sizeof(float));
+ net->multidiscrete = make_multidiscrete(num_agents, logit_sizes, action_dim);
+ return net;
+}
+
+void free_drivenet(DriveNet* net) {
+ free(net->obs_self);
+ free(net->obs_partner);
+ free(net->obs_road);
+ free(net->partner_linear_output);
+ free(net->road_linear_output);
+ free(net->partner_linear_output_two);
+ free(net->road_linear_output_two);
+ free(net->partner_layernorm_output);
+ free(net->road_layernorm_output);
+ free(net->ego_encoder);
+ free(net->road_encoder);
+ free(net->partner_encoder);
+ free(net->ego_layernorm);
+ free(net->road_layernorm);
+ free(net->partner_layernorm);
+ free(net->ego_encoder_two);
+ free(net->road_encoder_two);
+ free(net->partner_encoder_two);
+ free(net->partner_max);
+ free(net->road_max);
+ free(net->cat1);
+ free(net->cat2);
+ free(net->gelu);
+ free(net->shared_embedding);
+ free(net->relu);
+ free(net->multidiscrete);
+ free(net->actor);
+ free(net->value_fn);
+ free(net->lstm);
+ free(net);
+}
+
+void forward(DriveNet* net, float* observations, int* actions) {
+ int ego_dim = net->ego_dim;
+
+ // Clear previous observations
+ memset(net->obs_self, 0, net->num_agents * ego_dim * sizeof(float));
+ memset(net->obs_partner, 0, net->num_agents * 63 * 7 * sizeof(float));
+ memset(net->obs_road, 0, net->num_agents * 200 * 13 * sizeof(float));
+
+ for (int b = 0; b < net->num_agents; b++) {
+ int b_offset = b * (ego_dim + 63*7 + 200*7);
+ int partner_offset = b_offset + ego_dim;
+ int road_offset = b_offset + ego_dim + 63*7;
+
+ // Process self observation
+ for(int i = 0; i < ego_dim; i++) {
+ net->obs_self[b * ego_dim + i] = observations[b_offset + i];
+ }
+
+ // Process partner observation
+ for(int i = 0; i < 63; i++) {
+ for(int j = 0; j < 7; j++) {
+ net->obs_partner[b*63*7 + i*7 + j] = observations[partner_offset + i*7 + j];
+ }
+ }
+
+ // Process road observation
+ for(int i = 0; i < 200; i++) {
+ for(int j = 0; j < 7; j++) {
+ net->obs_road[b*200*13 + i*13 + j] = observations[road_offset + i*7 + j];
+ }
+ for(int j = 0; j < 7; j++) {
+ if(j == observations[road_offset+i*7 + 6]) {
+ net->obs_road[b*200*13 + i*13 + 6 + j] = 1.0f;
+ } else {
+ net->obs_road[b*200*13 + i*13 + 6 + j] = 0.0f;
+ }
+ }
+ }
+ }
+
+ // Forward pass through the network
+ linear(net->ego_encoder, net->obs_self);
+ layernorm(net->ego_layernorm, net->ego_encoder->output);
+ linear(net->ego_encoder_two, net->ego_layernorm->output);
+ for (int b = 0; b < net->num_agents; b++) {
+ for (int obj = 0; obj < 63; obj++) {
+ // Get the 7 features for this object
+ float* obj_features = &net->obs_partner[b*63*7 + obj*7];
+ // Apply linear layer to this object
+ _linear(obj_features, net->partner_encoder->weights, net->partner_encoder->bias,
+ &net->partner_linear_output[b*63*64 + obj*64], 1, 7, 64);
+ }
+ }
+
+ for (int b = 0; b < net->num_agents; b++) {
+ for (int obj = 0; obj < 63; obj++) {
+ float* after_first = &net->partner_linear_output[b*63*64 + obj*64];
+ _layernorm(after_first, net->partner_layernorm->weights, net->partner_layernorm->bias,
+ &net->partner_layernorm_output[b*63*64 + obj*64], 1, 64);
+ }
+ }
+ for (int b = 0; b < net->num_agents; b++) {
+ for (int obj = 0; obj < 63; obj++) {
+ // Get the 7 features for this object
+ float* obj_features = &net->partner_layernorm_output[b*63*64 + obj*64];
+ // Apply linear layer to this object
+ _linear(obj_features, net->partner_encoder_two->weights, net->partner_encoder_two->bias,
+ &net->partner_linear_output_two[b*63*64 + obj*64], 1, 64, 64);
+
+ }
+ }
+
+ // Process road objects: apply linear to each object individually
+ for (int b = 0; b < net->num_agents; b++) {
+ for (int obj = 0; obj < 200; obj++) {
+ // Get the 13 features for this object
+ float* obj_features = &net->obs_road[b*200*13 + obj*13];
+ // Apply linear layer to this object
+ _linear(obj_features, net->road_encoder->weights, net->road_encoder->bias,
+ &net->road_linear_output[b*200*64 + obj*64], 1, 13, 64);
+ }
+ }
+
+ // Apply layer norm and second linear to each road object
+ for (int b = 0; b < net->num_agents; b++) {
+ for (int obj = 0; obj < 200; obj++) {
+ float* after_first = &net->road_linear_output[b*200*64 + obj*64];
+ _layernorm(after_first, net->road_layernorm->weights, net->road_layernorm->bias,
+ &net->road_layernorm_output[b*200*64 + obj*64], 1, 64);
+ }
+ }
+ for (int b = 0; b < net->num_agents; b++) {
+ for (int obj = 0; obj < 200; obj++) {
+ float* after_first = &net->road_layernorm_output[b*200*64 + obj*64];
+ _linear(after_first, net->road_encoder_two->weights, net->road_encoder_two->bias,
+ &net->road_linear_output_two[b*200*64 + obj*64], 1, 64, 64);
+ }
+ }
+
+ max_dim1(net->partner_max, net->partner_linear_output_two);
+ max_dim1(net->road_max, net->road_linear_output_two);
+ cat_dim1(net->cat1, net->ego_encoder_two->output, net->road_max->output);
+ cat_dim1(net->cat2, net->cat1->output, net->partner_max->output);
+ gelu(net->gelu, net->cat2->output);
+ linear(net->shared_embedding, net->gelu->output);
+ relu(net->relu, net->shared_embedding->output);
+ lstm(net->lstm, net->relu->output);
+ linear(net->actor, net->lstm->state_h);
+ linear(net->value_fn, net->lstm->state_h);
+
+ // Get action by taking argmax of actor output
+ softmax_multidiscrete(net->multidiscrete, net->actor->output, actions);
+}
diff --git a/pufferlib/ocean/drive/error.h b/pufferlib/ocean/drive/error.h
new file mode 100644
index 000000000..b1eb78e7e
--- /dev/null
+++ b/pufferlib/ocean/drive/error.h
@@ -0,0 +1,81 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+#include
+#include
+#include
+#include
+
+// Error types enumeration
+typedef enum {
+ ERROR_NONE = 0,
+ ERROR_NULL_POINTER,
+ ERROR_INVALID_ARGUMENT,
+ ERROR_OUT_OF_BOUNDS,
+ ERROR_MEMORY_ALLOCATION,
+ ERROR_FILE_NOT_FOUND,
+ ERROR_INITIALIZATION_FAILED,
+ ERROR_UNKNOWN
+} ErrorType;
+
+const char* error_type_to_string(ErrorType type) {
+ switch (type) {
+ case ERROR_NONE: return "No Error";
+ case ERROR_NULL_POINTER: return "Null Pointer";
+ case ERROR_INVALID_ARGUMENT: return "Invalid Argument";
+ case ERROR_OUT_OF_BOUNDS: return "Out of Bounds";
+ case ERROR_MEMORY_ALLOCATION: return "Memory Allocation Failed";
+ case ERROR_FILE_NOT_FOUND: return "File Not Found";
+ case ERROR_INITIALIZATION_FAILED: return "Initialization Failed";
+ default: return "Unknown Error";
+ }
+}
+
+// Enhanced error function with custom message support
+void raise_error_with_message(ErrorType type, const char* format, ...) {
+ printf("Error occurred: %s", error_type_to_string(type));
+
+ if (format != NULL) {
+ printf(" - ");
+ va_list args;
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+ }
+ printf("\n");
+ exit(EXIT_FAILURE);
+}
+
+// Simple error function (backward compatibility)
+void raise_error(ErrorType type) {
+ raise_error_with_message(type, NULL);
+}
+
+// Convenience macros for common error patterns
+#define RAISE_FILE_ERROR(path) \
+ raise_error_with_message(ERROR_FILE_NOT_FOUND, "at path: %s", path)
+
+#define RAISE_BOUNDS_ERROR() \
+ raise_error(ERROR_OUT_OF_BOUNDS)
+
+#define RAISE_BOUNDS_ERROR_WITH_BOUNDS(index, min, max) \
+ raise_error_with_message(ERROR_OUT_OF_BOUNDS, "index %d exceeds minimum of %d and maximum %d", index, min, max)
+
+#define RAISE_NULL_ERROR() \
+ raise_error(ERROR_NULL_POINTER)
+
+#define RAISE_NULL_ERROR_WITH_NAME(var_name) \
+ raise_error_with_message(ERROR_NULL_POINTER, "variable '%s' is null", var_name)
+
+#define RAISE_MEMORY_ERROR() \
+ raise_error(ERROR_MEMORY_ALLOCATION)
+
+#define RAISE_MEMORY_ERROR_WITH_SIZE(size) \
+ raise_error_with_message(ERROR_MEMORY_ALLOCATION, "failed to allocate %zu bytes", size)
+
+#define RAISE_INVALID_ARG_ERROR() \
+ raise_error(ERROR_INVALID_ARGUMENT)
+
+#define RAISE_INVALID_ARG_ERROR_WITH_ARG(arg_name, value) \
+ raise_error_with_message(ERROR_INVALID_ARGUMENT, "invalid value for '%s': %d", arg_name, value)
+#endif
diff --git a/pufferlib/ocean/drive/visualize.c b/pufferlib/ocean/drive/visualize.c
new file mode 100644
index 000000000..9642e2cbd
--- /dev/null
+++ b/pufferlib/ocean/drive/visualize.c
@@ -0,0 +1,527 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include "rlgl.h"
+#include
+#include
+#include
+#include
+#include "error.h"
+#include "drive.h"
+#include "drivenet.h"
+#include "libgen.h"
+#include "../env_config.h"
+#define TRAJECTORY_LENGTH_DEFAULT 91
+
+typedef struct {
+ int pipefd[2];
+ pid_t pid;
+} VideoRecorder;
+
+bool OpenVideo(VideoRecorder *recorder, const char *output_filename, int width, int height) {
+ if (pipe(recorder->pipefd) == -1) {
+ fprintf(stderr, "Failed to create pipe\n");
+ return false;
+ }
+
+ recorder->pid = fork();
+ if (recorder->pid == -1) {
+ fprintf(stderr, "Failed to fork\n");
+ return false;
+ }
+
+ char size_str[64];
+ snprintf(size_str, sizeof(size_str), "%dx%d", width, height);
+
+ if (recorder->pid == 0) { // Child process: run ffmpeg
+ close(recorder->pipefd[1]);
+ dup2(recorder->pipefd[0], STDIN_FILENO);
+ close(recorder->pipefd[0]);
+ // Close all other file descriptors to prevent leaks
+ for (int fd = 3; fd < 256; fd++) {
+ close(fd);
+ }
+ execlp("ffmpeg", "ffmpeg",
+ "-y",
+ "-f", "rawvideo",
+ "-pix_fmt", "rgba",
+ "-s", size_str,
+ "-r", "30",
+ "-i", "-",
+ "-c:v", "libx264",
+ "-pix_fmt", "yuv420p",
+ "-preset", "ultrafast",
+ "-crf", "23",
+ "-loglevel", "error",
+ output_filename,
+ NULL);
+ TraceLog(LOG_ERROR, "Failed to launch ffmpeg");
+ return false;
+ }
+
+ close(recorder->pipefd[0]); // Close read end in parent
+ return true;
+}
+
+void WriteFrame(VideoRecorder *recorder, int width, int height) {
+ unsigned char *screen_data = rlReadScreenPixels(width, height);
+ write(recorder->pipefd[1], screen_data, width * height * 4 * sizeof(*screen_data));
+ RL_FREE(screen_data);
+}
+
+void CloseVideo(VideoRecorder *recorder) {
+ close(recorder->pipefd[1]);
+ waitpid(recorder->pid, NULL, 0);
+}
+
+void renderTopDownView(Drive* env, Client* client, int map_height, int obs, int lasers, int trajectories, int frame_count, float* path, int log_trajectories, int show_grid, int img_width, int img_height) {
+
+ BeginDrawing();
+
+ // Top-down orthographic camera
+ Camera3D camera = {0};
+ camera.position = (Vector3){ 0.0f, 0.0f, 500.0f }; // above the scene
+ camera.target = (Vector3){ 0.0f, 0.0f, 0.0f }; // look at origin
+ camera.up = (Vector3){ 0.0f, -1.0f, 0.0f };
+ camera.fovy = map_height;
+ camera.projection = CAMERA_ORTHOGRAPHIC;
+
+ client->width = img_width;
+ client->height = img_height;
+
+ Color road = (Color){35, 35, 37, 255};
+ ClearBackground(road);
+ BeginMode3D(camera);
+ rlEnableDepthTest();
+
+ // Draw human replay trajectories if enabled
+ if(log_trajectories){
+ for(int i=0; iactive_agent_count; i++){
+ int idx = env->active_agent_indices[i];
+ Vector3 prev_point = {0};
+ bool has_prev = false;
+
+ for(int j = 0; j < env->agents[idx].trajectory_length; j++){
+ float x = env->agents[idx].log_trajectory_x[j];
+ float y = env->agents[idx].log_trajectory_y[j];
+ float valid = env->agents[idx].log_valid[j];
+
+ if(!valid) {
+ has_prev = false;
+ continue;
+ }
+
+ Vector3 curr_point = {x, y, 0.5f};
+
+ if(has_prev) {
+ DrawLine3D(prev_point, curr_point, Fade(LIGHTGREEN, 0.6f));
+ }
+
+ prev_point = curr_point;
+ has_prev = true;
+ }
+ }
+}
+
+ // Draw agent trajs
+ if(trajectories){
+ for(int i=0; iactive_agent_indices[env->human_agent_idx];
+ Agent* agent = &env->agents[agent_idx];
+
+ BeginDrawing();
+
+ Camera3D camera = {0};
+ // Position camera behind and above the agent
+ camera.position = (Vector3){
+ agent->sim_x - (25.0f * cosf(agent->sim_heading)),
+ agent->sim_y - (25.0f * sinf(agent->sim_heading)),
+ 15.0f
+ };
+ camera.target = (Vector3){
+ agent->sim_x + 40.0f * cosf(agent->sim_heading),
+ agent->sim_y + 40.0f * sinf(agent->sim_heading),
+ 1.0f
+ };
+ camera.up = (Vector3){ 0.0f, 0.0f, 1.0f };
+ camera.fovy = 45.0f;
+ camera.projection = CAMERA_PERSPECTIVE;
+
+ Color road = (Color){35, 35, 37, 255};
+
+ ClearBackground(road);
+ BeginMode3D(camera);
+ rlEnableDepthTest();
+ draw_scene(env, client, 0, obs_only, lasers, show_grid); // mode=0 for agent view
+ EndMode3D();
+ EndDrawing();
+}
+
+static int run_cmd(const char *cmd) {
+ int rc = system(cmd);
+ if (rc != 0) {
+ fprintf(stderr, "[ffmpeg] command failed (%d): %s\n", rc, cmd);
+ }
+ return rc;
+}
+
+// Make a high-quality GIF from numbered PNG frames like frame_000.png
+static int make_gif_from_frames(const char *pattern, int fps,
+ const char *palette_path,
+ const char *out_gif) {
+ char cmd[1024];
+
+ // 1) Generate palette (no quotes needed for simple filter)
+ // NOTE: if your frames start at 000, you don't need -start_number.
+ snprintf(cmd, sizeof(cmd),
+ "ffmpeg -y -framerate %d -i %s -vf palettegen %s",
+ fps, pattern, palette_path);
+ if (run_cmd(cmd) != 0) return -1;
+
+ // 2) Use palette to encode the GIF
+ snprintf(cmd, sizeof(cmd),
+ "ffmpeg -y -framerate %d -i %s -i %s -lavfi paletteuse -loop 0 %s",
+ fps, pattern, palette_path, out_gif);
+ if (run_cmd(cmd) != 0) return -1;
+
+ return 0;
+}
+
+
+int eval_gif(const char* map_name, const char* policy_name, int show_grid, int obs_only, int lasers, int log_trajectories, int frame_skip, float goal_radius, int init_steps, int max_controlled_agents, const char* view_mode, const char* output_topdown, const char* output_agent, int num_maps, int scenario_length_override, int init_mode, int control_mode, int goal_behavior) {
+
+ // Parse configuration from INI file
+ env_init_config conf = {0}; // Initialize to zero
+ const char* ini_file = "pufferlib/config/ocean/drive.ini";
+ if(ini_parse(ini_file, handler, &conf) < 0) {
+ fprintf(stderr, "Error: Could not load %s. Cannot determine environment configuration.\n", ini_file);
+ return -1;
+ }
+
+ char map_buffer[100];
+ if (map_name == NULL) {
+ srand(time(NULL));
+ int random_map = rand() % num_maps;
+ sprintf(map_buffer, "resources/drive/binaries/map_%03d.bin", random_map); // random map file
+ map_name = map_buffer;
+ }
+
+ if (frame_skip <= 0) {
+ frame_skip = 1; // Default: render every frame
+ }
+
+ // Check if map file exists
+ FILE* map_file = fopen(map_name, "rb");
+ if (map_file == NULL) {
+ RAISE_FILE_ERROR(map_name);
+ }
+ fclose(map_file);
+
+ FILE* policy_file = fopen(policy_name, "rb");
+ if (policy_file == NULL) {
+ RAISE_FILE_ERROR(policy_name);
+ }
+ fclose(policy_file);
+
+ Drive env = {
+ .dynamics_model = conf.dynamics_model,
+ .reward_vehicle_collision = conf.reward_vehicle_collision,
+ .reward_offroad_collision = conf.reward_offroad_collision,
+ .reward_ade = conf.reward_ade,
+ .goal_radius = conf.goal_radius,
+ .dt = conf.dt,
+ .map_name = (char*)map_name,
+ .init_steps = init_steps,
+ .max_controlled_agents = max_controlled_agents,
+ .collision_behavior = conf.collision_behavior,
+ .offroad_behavior = conf.offroad_behavior,
+ .goal_behavior = goal_behavior,
+ .init_mode = init_mode,
+ .control_mode = control_mode,
+ };
+
+ env.scenario_length = (scenario_length_override > 0) ? scenario_length_override :
+ (conf.scenario_length > 0) ? conf.scenario_length : TRAJECTORY_LENGTH_DEFAULT;
+ allocate(&env);
+
+ // Set which vehicle to focus on for obs mode
+ env.human_agent_idx = 0;
+
+ c_reset(&env);
+ // Make client for rendering
+ Client* client = (Client*)calloc(1, sizeof(Client));
+ env.client = client;
+
+ SetConfigFlags(FLAG_WINDOW_HIDDEN);
+
+ SetTargetFPS(6000);
+
+ float map_width = env.grid_map->bottom_right_x - env.grid_map->top_left_x;
+ float map_height = env.grid_map->top_left_y - env.grid_map->bottom_right_y;
+
+ printf("Map size: %.1fx%.1f\n", map_width, map_height);
+ float scale = 6.0f; // Can be used to increase the video quality
+
+ // Calculate video width and height; round to nearest even number
+ int img_width = (int)roundf(map_width * scale / 2.0f) * 2;
+ int img_height = (int)roundf(map_height * scale / 2.0f) * 2;
+ InitWindow(img_width, img_height, "Puffer Drive");
+ SetConfigFlags(FLAG_MSAA_4X_HINT);
+
+ Weights* weights = load_weights(policy_name);
+ printf("Active agents in map: %d\n", env.active_agent_count);
+ DriveNet* net = init_drivenet(weights, env.active_agent_count, env.dynamics_model);
+
+ int frame_count = env.scenario_length > 0 ? env.scenario_length : TRAJECTORY_LENGTH_DEFAULT;
+ int log_trajectory = log_trajectories;
+ char filename_topdown[256];
+ char filename_agent[256];
+
+ if (output_topdown != NULL && output_agent != NULL) {
+ strcpy(filename_topdown, output_topdown);
+ strcpy(filename_agent, output_agent);
+ } else {
+ char policy_base[256];
+ strcpy(policy_base, policy_name);
+ *strrchr(policy_base, '.') = '\0';
+
+ char map[256];
+ strcpy(map, basename((char*)map_name));
+ *strrchr(map, '.') = '\0';
+
+ // Create video directory if it doesn't exist
+ char video_dir[256];
+ sprintf(video_dir, "%s/video", policy_base);
+ char mkdir_cmd[512];
+ snprintf(mkdir_cmd, sizeof(mkdir_cmd), "mkdir -p \"%s\"", video_dir);
+ system(mkdir_cmd);
+
+ sprintf(filename_topdown, "%s/video/%s_topdown.mp4", policy_base, map);
+ sprintf(filename_agent, "%s/video/%s_agent.mp4", policy_base, map);
+ }
+
+ bool render_topdown = (strcmp(view_mode, "both") == 0 || strcmp(view_mode, "topdown") == 0);
+ bool render_agent = (strcmp(view_mode, "both") == 0 || strcmp(view_mode, "agent") == 0);
+
+ printf("Rendering: %s\n", view_mode);
+
+ int rendered_frames = 0;
+ double startTime = GetTime();
+
+ VideoRecorder topdown_recorder, agent_recorder;
+
+ if (render_topdown) {
+ if (!OpenVideo(&topdown_recorder, filename_topdown, img_width, img_height)) {
+ CloseWindow();
+ return -1;
+ }
+ }
+
+ if (render_agent) {
+ if (!OpenVideo(&agent_recorder, filename_agent, img_width, img_height)) {
+ if (render_topdown) CloseVideo(&topdown_recorder);
+ CloseWindow();
+ return -1;
+ }
+ }
+
+ if (render_topdown) {
+ printf("Recording topdown view...\n");
+ for(int i = 0; i < frame_count; i++) {
+ if (i % frame_skip == 0) {
+ renderTopDownView(&env, client, map_height, 0, 0, 0, frame_count, NULL, log_trajectories, show_grid, img_width, img_height);
+ WriteFrame(&topdown_recorder, img_width, img_height);
+ rendered_frames++;
+ }
+ int (*actions)[2] = (int(*)[2])env.actions;
+ forward(net, env.observations, (int*)env.actions);
+ c_step(&env);
+ }
+
+ }
+
+ if (render_agent) {
+ c_reset(&env);
+ printf("Recording agent view...\n");
+ for(int i = 0; i < frame_count; i++) {
+ if (i % frame_skip == 0) {
+ renderAgentView(&env, client, map_height, obs_only, lasers, show_grid);
+ WriteFrame(&agent_recorder, img_width, img_height);
+ rendered_frames++;
+ }
+ int (*actions)[2] = (int(*)[2])env.actions;
+ forward(net, env.observations, (int*)env.actions);
+ c_step(&env);
+ }
+ }
+
+ double endTime = GetTime();
+ double elapsedTime = endTime - startTime;
+ double writeFPS = (elapsedTime > 0) ? rendered_frames / elapsedTime : 0;
+
+ printf("Wrote %d frames in %.2f seconds (%.2f FPS) to %s \n",
+ rendered_frames, elapsedTime, writeFPS, filename_topdown);
+
+ if (render_topdown) {
+ CloseVideo(&topdown_recorder);
+ }
+ if (render_agent) {
+ CloseVideo(&agent_recorder);
+ }
+ CloseWindow();
+
+ // Clean up resources
+ free(client);
+ free_allocated(&env);
+ free_drivenet(net);
+ free(weights);
+ return 0;
+}
+
+int main(int argc, char* argv[]) {
+ int show_grid = 0;
+ int obs_only = 0;
+ int lasers = 0;
+ int log_trajectories = 1;
+ int frame_skip = 1;
+ float goal_radius = 2.0f;
+ int init_steps = 0;
+ const char* map_name = NULL;
+ const char* policy_name = "resources/drive/puffer_drive_weights.bin";
+ int max_controlled_agents = -1;
+ int num_maps = 1;
+ int scenario_length_cli = -1;
+ int init_mode = 0;
+ int control_mode = 0;
+ int goal_behavior = 0;
+
+ const char* view_mode = "both"; // "both", "topdown", "agent"
+ const char* output_topdown = NULL;
+ const char* output_agent = NULL;
+
+ // Parse command line arguments
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--show-grid") == 0) {
+ show_grid = 1;
+ } else if (strcmp(argv[i], "--obs-only") == 0) {
+ obs_only = 1;
+ } else if (strcmp(argv[i], "--lasers") == 0) {
+ lasers = 1;
+ } else if (strcmp(argv[i], "--log-trajectories") == 0) {
+ log_trajectories = 1;
+ } else if (strcmp(argv[i], "--frame-skip") == 0) {
+ if (i + 1 < argc) {
+ frame_skip = atoi(argv[i + 1]);
+ i++; // Skip the next argument since we consumed it
+ if (frame_skip <= 0) {
+ frame_skip = 1; // Ensure valid value
+ }
+ }
+ } else if (strcmp(argv[i], "--goal-radius") == 0) {
+ if (i + 1 < argc) {
+ goal_radius = atof(argv[i + 1]);
+ i++;
+ if (goal_radius <= 0) {
+ goal_radius = 2.0f; // Ensure valid value
+ }
+ }
+ } else if (strcmp(argv[i], "--map-name") == 0) {
+ // Check if there's a next argument for the map path
+ if (i + 1 < argc) {
+ map_name = argv[i + 1];
+ i++; // Skip the next argument since we used it as map path
+ } else {
+ fprintf(stderr, "Error: --map-name option requires a map file path\n");
+ return 1;
+ }
+ } else if (strcmp(argv[i], "--policy-name") == 0) {
+ if (i + 1 < argc) {
+ policy_name = argv[i + 1];
+ i++;
+ } else {
+ fprintf(stderr, "Error: --policy-name option requires a policy file path\n");
+ return 1;
+ }
+ } else if (strcmp(argv[i], "--view") == 0) {
+ if (i + 1 < argc) {
+ view_mode = argv[i + 1];
+ i++;
+ if (strcmp(view_mode, "both") != 0 &&
+ strcmp(view_mode, "topdown") != 0 &&
+ strcmp(view_mode, "agent") != 0) {
+ fprintf(stderr, "Error: --view must be 'both', 'topdown', or 'agent'\n");
+ return 1;
+ }
+ } else {
+ fprintf(stderr, "Error: --view option requires a value (both/topdown/agent)\n");
+ return 1;
+ }
+ } else if (strcmp(argv[i], "--output-topdown") == 0) {
+ if (i + 1 < argc) {
+ output_topdown = argv[i + 1];
+ i++;
+ }
+ } else if (strcmp(argv[i], "--output-agent") == 0) {
+ if (i + 1 < argc) {
+ output_agent = argv[i + 1];
+ i++;
+ }
+ } else if (strcmp(argv[i], "--init-steps") == 0) {
+ if (i + 1 < argc) {
+ init_steps = atoi(argv[i + 1]);
+ i++;
+ if (init_steps < 0) {
+ init_steps = 0;
+ }
+ }
+ } else if (strcmp(argv[i], "--init-mode") == 0) {
+ if (i + 1 < argc) {
+ init_mode = atoi(argv[i + 1]);
+ i++;
+ }
+ } else if (strcmp(argv[i], "--control-mode") == 0) {
+ if (i + 1 < argc) {
+ control_mode = atoi(argv[i + 1]);
+ i++;
+ }
+ } else if (strcmp(argv[i], "--max-controlled-agents") == 0) {
+ if (i + 1 < argc) {
+ max_controlled_agents = atoi(argv[i + 1]);
+ i++;
+ }
+ } else if (strcmp(argv[i], "--num-maps") == 0) {
+ if (i + 1 < argc) {
+ num_maps = atoi(argv[i + 1]);
+ i++;
+ }
+ } else if (strcmp(argv[i], "--scenario-length") == 0) {
+ if (i + 1 < argc) {
+ scenario_length_cli = atoi(argv[i + 1]);
+ i++;
+ }
+ } else if (strcmp(argv[i], "--goal-behavior") == 0) {
+ if (i + 1 < argc) {
+ goal_behavior = atoi(argv[i + 1]);
+ i++;
+ }
+ }
+ }
+
+ eval_gif(map_name, policy_name, show_grid, obs_only, lasers, log_trajectories, frame_skip, goal_radius, init_steps, max_controlled_agents, view_mode, output_topdown, output_agent, num_maps, scenario_length_cli, init_mode, control_mode, goal_behavior);
+ return 0;
+}
diff --git a/pufferlib/ocean/drone_race/binding.c b/pufferlib/ocean/drone_race/binding.c
deleted file mode 100644
index 9b3591ffe..000000000
--- a/pufferlib/ocean/drone_race/binding.c
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "drone_race.h"
-
-#define Env DroneRace
-#include "../env_binding.h"
-
-static int my_init(Env *env, PyObject *args, PyObject *kwargs) {
- env->max_rings = unpack(kwargs, "max_rings");
- env->max_moves = unpack(kwargs, "max_moves");
- init(env);
- return 0;
-}
-
-static int my_log(PyObject *dict, Log *log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "episode_length", log->episode_length);
- assign_to_dict(dict, "n", log->n);
- return 0;
-}
diff --git a/pufferlib/ocean/drone_race/drone_race.c b/pufferlib/ocean/drone_race/drone_race.c
deleted file mode 100644
index 3646a44dc..000000000
--- a/pufferlib/ocean/drone_race/drone_race.c
+++ /dev/null
@@ -1,178 +0,0 @@
-// Standalone C demo for DroneRace environment
-// Compile using: ./scripts/build_ocean.sh drone [local|fast]
-// Run with: ./drone
-
-#include "drone_race.h"
-#include "puffernet.h"
-#include
-
-#ifdef __EMSCRIPTEN__
-#include
-#endif
-
-double randn(double mean, double std) {
- static int has_spare = 0;
- static double spare;
-
- if (has_spare) {
- has_spare = 0;
- return mean + std * spare;
- }
-
- has_spare = 1;
- double u, v, s;
- do {
- u = 2.0 * rand() / RAND_MAX - 1.0;
- v = 2.0 * rand() / RAND_MAX - 1.0;
- s = u * u + v * v;
- } while (s >= 1.0 || s == 0.0);
-
- s = sqrt(-2.0 * log(s) / s);
- spare = v * s;
- return mean + std * (u * s);
-}
-
-typedef struct LinearContLSTM LinearContLSTM;
-struct LinearContLSTM {
- int num_agents;
- float *obs;
- float *log_std;
- Linear *encoder;
- GELU *gelu1;
- LSTM *lstm;
- Linear *actor;
- Linear *value_fn;
- int num_actions;
-};
-
-LinearContLSTM *make_linearcontlstm(Weights *weights, int num_agents, int input_dim,
- int logit_sizes[], int num_actions) {
- LinearContLSTM *net = calloc(1, sizeof(LinearContLSTM));
- net->num_agents = num_agents;
- net->obs = calloc(num_agents * input_dim, sizeof(float));
- net->num_actions = logit_sizes[0];
- net->log_std = weights->data;
- weights->idx += net->num_actions;
- net->encoder = make_linear(weights, num_agents, input_dim, 128);
- net->gelu1 = make_gelu(num_agents, 128);
- int atn_sum = 0;
- for (int i = 0; i < num_actions; i++) {
- atn_sum += logit_sizes[i];
- }
- net->actor = make_linear(weights, num_agents, 128, atn_sum);
- net->value_fn = make_linear(weights, num_agents, 128, 1);
- net->lstm = make_lstm(weights, num_agents, 128, 128);
- return net;
-}
-
-void free_linearcontlstm(LinearContLSTM *net) {
- free(net->obs);
- free(net->encoder);
- free(net->gelu1);
- free(net->actor);
- free(net->value_fn);
- free(net->lstm);
- free(net);
-}
-
-void forward_linearcontlstm(LinearContLSTM *net, float *observations, float *actions) {
- linear(net->encoder, observations);
- gelu(net->gelu1, net->encoder->output);
- lstm(net->lstm, net->gelu1->output);
- linear(net->actor, net->lstm->state_h);
- linear(net->value_fn, net->lstm->state_h);
- for (int i = 0; i < net->num_actions; i++) {
- float std = expf(net->log_std[i]);
- float mean = net->actor->output[i];
- actions[i] = randn(mean, std);
- }
-}
-
-void generate_dummy_actions(DroneRace *env) {
- // Generate random floats in [-1, 1] range
- env->actions[0] = ((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f;
- env->actions[1] = ((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f;
- env->actions[2] = ((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f;
- env->actions[3] = ((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f;
-}
-
-#ifdef __EMSCRIPTEN__
-typedef struct {
- DroneRace *env;
- LinearContLSTM *net;
- Weights *weights;
-} WebRenderArgs;
-
-void emscriptenStep(void *e) {
- WebRenderArgs *args = (WebRenderArgs *)e;
- DroneRace *env = args->env;
- LinearContLSTM *net = args->net;
-
- forward_linearcontlstm(net, env->observations, env->actions);
- c_step(env);
- c_render(env);
- return;
-}
-
-WebRenderArgs *web_args = NULL;
-#endif
-
-int main() {
- srand(time(NULL)); // Seed random number generator
-
- DroneRace *env = calloc(1, sizeof(DroneRace));
- env->max_moves = 1000;
- env->max_rings = 10;
-
- size_t obs_size = 25;
- size_t act_size = 4;
- env->observations = (float *)calloc(obs_size, sizeof(float));
- env->actions = (float *)calloc(act_size, sizeof(float));
- env->rewards = (float *)calloc(1, sizeof(float));
- env->terminals = (unsigned char *)calloc(1, sizeof(float));
-
- Weights *weights = load_weights("resources/drone/drone_weights.bin", 136073);
- int logit_sizes[1] = {4};
- LinearContLSTM *net = make_linearcontlstm(weights, 1, 25, logit_sizes, 1);
-
- if (!env->observations || !env->actions || !env->rewards) {
- fprintf(stderr, "ERROR: Failed to allocate memory for demo buffers.\n");
- free(env->observations);
- free(env->actions);
- free(env->rewards);
- free(env->terminals);
- free(env);
- return 0;
- }
-
- init(env);
- c_reset(env);
-
-#ifdef __EMSCRIPTEN__
- WebRenderArgs *args = calloc(1, sizeof(WebRenderArgs));
- args->env = env;
- args->net = net;
- args->weights = weights;
- web_args = args;
-
- emscripten_set_main_loop_arg(emscriptenStep, args, 0, true);
-#else
- c_render(env);
-
- while (!WindowShouldClose()) {
- forward_linearcontlstm(net, env->observations, env->actions);
- c_step(env);
- c_render(env);
- }
-
- c_close(env);
- free_linearcontlstm(net);
- free(env->observations);
- free(env->actions);
- free(env->rewards);
- free(env->terminals);
- free(env);
-#endif
-
- return 0;
-}
diff --git a/pufferlib/ocean/drone_race/drone_race.h b/pufferlib/ocean/drone_race/drone_race.h
deleted file mode 100644
index 78acfc8e6..000000000
--- a/pufferlib/ocean/drone_race/drone_race.h
+++ /dev/null
@@ -1,466 +0,0 @@
-// Originally made by Sam Turner and Finlay Sanders, 2025.
-// Included in pufferlib under the original project's MIT license.
-// https://github.com/stmio/drone
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "raylib.h"
-#include "dronelib.h"
-
-typedef struct Client Client;
-struct Client {
- Camera3D camera;
- float width;
- float height;
-
- float camera_distance;
- float camera_azimuth;
- float camera_elevation;
- bool is_dragging;
- Vector2 last_mouse_pos;
-
- // Trailing path buffer (for rendering only)
- Vec3 trail[TRAIL_LENGTH];
- int trail_index;
- int trail_count;
-};
-
-typedef struct DroneRace DroneRace;
-struct DroneRace {
- float *observations;
- float *actions;
- float *rewards;
- unsigned char *terminals;
-
- Log log;
- int tick;
- int report_interval;
- int score;
- float episodic_return;
-
- int max_rings;
- int ring_idx;
- Ring *ring_buffer;
-
- int max_moves;
- int moves_left;
-
- Drone drone;
- Client *client;
-};
-
-void init(DroneRace *env) {
- env->log = (Log){0};
- env->tick = 0;
- // one extra ring for observation (requires current ring, next ring)
- // max_rings and moves_left are initialised in binding.c
- env->ring_buffer = (Ring *)malloc((env->max_rings + 1) * sizeof(Ring));
-}
-
-void add_log(DroneRace *env) {
- env->log.score += env->score;
- env->log.episode_return += env->episodic_return;
- env->log.episode_length += env->tick;
- env->log.perf += (float)env->ring_idx / (float)env->max_rings;
- env->log.n += 1.0f;
-}
-
-void compute_observations(DroneRace *env) {
- Drone *drone = &env->drone;
-
- Quat q_inv = quat_inverse(drone->quat);
- Ring curr_ring = env->ring_buffer[env->ring_idx];
- Ring next_ring = env->ring_buffer[env->ring_idx + 1];
-
- Vec3 to_curr_ring = quat_rotate(q_inv, sub3(curr_ring.pos, drone->pos));
- Vec3 to_next_ring = quat_rotate(q_inv, sub3(next_ring.pos, drone->pos));
-
- Vec3 curr_ring_norm = quat_rotate(q_inv, curr_ring.normal);
- Vec3 next_ring_norm = quat_rotate(q_inv, next_ring.normal);
-
- Vec3 linear_vel_body = quat_rotate(q_inv, drone->vel);
- Vec3 drone_up_world = quat_rotate(drone->quat, (Vec3){0.0f, 0.0f, 1.0f});
-
- env->observations[0] = to_curr_ring.x / GRID_SIZE;
- env->observations[1] = to_curr_ring.y / GRID_SIZE;
- env->observations[2] = to_curr_ring.z / GRID_SIZE;
-
- env->observations[3] = curr_ring_norm.x;
- env->observations[4] = curr_ring_norm.y;
- env->observations[5] = curr_ring_norm.z;
-
- env->observations[6] = to_next_ring.x / GRID_SIZE;
- env->observations[7] = to_next_ring.y / GRID_SIZE;
- env->observations[8] = to_next_ring.z / GRID_SIZE;
-
- env->observations[9] = next_ring_norm.x;
- env->observations[10] = next_ring_norm.y;
- env->observations[11] = next_ring_norm.z;
-
- env->observations[12] = linear_vel_body.x / drone->max_vel;
- env->observations[13] = linear_vel_body.y / drone->max_vel;
- env->observations[14] = linear_vel_body.z / drone->max_vel;
-
- env->observations[15] = drone->omega.x / drone->max_omega;
- env->observations[16] = drone->omega.y / drone->max_omega;
- env->observations[17] = drone->omega.z / drone->max_omega;
-
- env->observations[18] = drone_up_world.x;
- env->observations[19] = drone_up_world.y;
- env->observations[20] = drone_up_world.z;
-
- env->observations[21] = drone->quat.w;
- env->observations[22] = drone->quat.x;
- env->observations[23] = drone->quat.y;
- env->observations[24] = drone->quat.z;
-}
-
-void c_reset(DroneRace *env) {
- env->tick = 0;
- env->score = 0;
- env->episodic_return = 0.0f;
-
- env->moves_left = env->max_moves;
-
- env->ring_idx = 0;
-
- Drone *drone = &env->drone;
-
- float size = rndf(0.05f, 0.8);
- init_drone(drone, size, 0.1f);
-
- //init_drone(drone, 0.8f, 0.0f);
- //init_drone(drone, 0.05f, 0.0f);
-
- // creates rings at least MARGIN apart
- float ring_radius = 2.0f;
- if (env->max_rings + 1 > 0) {
- env->ring_buffer[0] = rndring(ring_radius);
- }
-
- for (int i = 1; i < env->max_rings + 1; i++) {
- do {
- env->ring_buffer[i] = rndring(ring_radius);
- } while (norm3(sub3(env->ring_buffer[i].pos, env->ring_buffer[i - 1].pos)) < 2.0f*ring_radius);
- }
-
- // start drone at least MARGIN away from the first ring
- do {
- drone->pos = (Vec3){rndf(-9, 9), rndf(-9, 9), rndf(-9, 9)};
- } while (norm3(sub3(drone->pos, env->ring_buffer[0].pos)) < 2.0f*ring_radius);
-
- drone->prev_pos = drone->pos;
- drone->vel = (Vec3){0.0f, 0.0f, 0.0f};
- drone->omega = (Vec3){0.0f, 0.0f, 0.0f};
- drone->quat = (Quat){1.0f, 0.0f, 0.0f, 0.0f};
- compute_observations(env);
-}
-
-void c_step(DroneRace *env) {
-
- env->tick++;
- env->rewards[0] = 0;
- env->terminals[0] = 0;
- env->log.score = 0;
-
- Drone *drone = &env->drone;
- move_drone(drone, env->actions);
-
- // check out of bounds
- bool out_of_bounds = drone->pos.x < -GRID_SIZE || drone->pos.x > GRID_SIZE ||
- drone->pos.y < -GRID_SIZE || drone->pos.y > GRID_SIZE ||
- drone->pos.z < -GRID_SIZE || drone->pos.z > GRID_SIZE;
-
- if (out_of_bounds) {
- env->rewards[0] -= 1;
- env->episodic_return -= 1;
- env->terminals[0] = 1;
- add_log(env);
- c_reset(env);
- compute_observations(env);
- return;
- }
-
- Ring *ring = &env->ring_buffer[env->ring_idx];
- float reward = check_ring(drone, ring);
- env->rewards[0] += reward;
- env->episodic_return += reward;
-
- if (reward > 0) {
- env->score++;
- env->ring_idx++;
- } else if (reward < 0) {
- env->terminals[0] = 1;
- add_log(env);
- c_reset(env);
- return;
- }
-
- // truncate
- env->moves_left -= 1;
- if (env->moves_left == 0 || env->ring_idx == env->max_rings) {
- env->terminals[0] = 1;
- add_log(env);
- c_reset(env);
- return;
- }
-
- drone->prev_pos = drone->pos;
-
- compute_observations(env);
-}
-
-void c_close_client(Client *client) {
- CloseWindow();
- free(client);
-}
-
-void c_close(DroneRace *env) {
- free(env->ring_buffer);
-
- if (env->client != NULL) {
- c_close_client(env->client);
- }
-}
-
-static void update_camera_position(Client *c) {
- float r = c->camera_distance;
- float az = c->camera_azimuth;
- float el = c->camera_elevation;
-
- float x = r * cosf(el) * cosf(az);
- float y = r * cosf(el) * sinf(az);
- float z = r * sinf(el);
-
- c->camera.position = (Vector3){x, y, z};
- c->camera.target = (Vector3){0, 0, 0};
-}
-
-void handle_camera_controls(Client *client) {
- Vector2 mouse_pos = GetMousePosition();
-
- if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
- client->is_dragging = true;
- client->last_mouse_pos = mouse_pos;
- }
-
- if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) {
- client->is_dragging = false;
- }
-
- if (client->is_dragging && IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
- Vector2 mouse_delta = {mouse_pos.x - client->last_mouse_pos.x,
- mouse_pos.y - client->last_mouse_pos.y};
-
- float sensitivity = 0.005f;
-
- client->camera_azimuth -= mouse_delta.x * sensitivity;
-
- client->camera_elevation += mouse_delta.y * sensitivity;
- client->camera_elevation =
- clampf(client->camera_elevation, -PI / 2.0f + 0.1f, PI / 2.0f - 0.1f);
-
- client->last_mouse_pos = mouse_pos;
-
- update_camera_position(client);
- }
-
- float wheel = GetMouseWheelMove();
- if (wheel != 0) {
- client->camera_distance -= wheel * 2.0f;
- client->camera_distance = clampf(client->camera_distance, 5.0f, 50.0f);
- update_camera_position(client);
- }
-}
-
-Client *make_client(DroneRace *env) {
- Client *client = (Client *)calloc(1, sizeof(Client));
-
- client->width = WIDTH;
- client->height = HEIGHT;
-
- SetConfigFlags(FLAG_MSAA_4X_HINT); // antialiasing
- InitWindow(WIDTH, HEIGHT, "PufferLib DroneRace");
-
-#ifndef __EMSCRIPTEN__
- SetTargetFPS(60);
-#endif
-
- if (!IsWindowReady()) {
- TraceLog(LOG_ERROR, "Window failed to initialize\n");
- free(client);
- return NULL;
- }
-
- client->camera_distance = 40.0f;
- client->camera_azimuth = 0.0f;
- client->camera_elevation = PI / 10.0f;
- client->is_dragging = false;
- client->last_mouse_pos = (Vector2){0.0f, 0.0f};
-
- client->camera.up = (Vector3){0.0f, 0.0f, 1.0f};
- client->camera.fovy = 45.0f;
- client->camera.projection = CAMERA_PERSPECTIVE;
-
- update_camera_position(client);
-
- // Initialize trail buffer
- client->trail_index = 0;
- client->trail_count = 0;
- Drone *drone = &env->drone;
- for (int i = 0; i < TRAIL_LENGTH; i++) {
- client->trail[i] = drone->pos;
- }
-
- return client;
-}
-
-void DrawRing3D(Ring ring, float thickness, Color entryColor, Color exitColor) {
- float half_thick = thickness / 2.0f;
-
- Vector3 center_pos = {ring.pos.x, ring.pos.y, ring.pos.z};
-
- Vector3 entry_start_pos = {center_pos.x - half_thick * ring.normal.x,
- center_pos.y - half_thick * ring.normal.y,
- center_pos.z - half_thick * ring.normal.z};
-
- DrawCylinderWiresEx(entry_start_pos, center_pos, ring.radius, ring.radius, 32, entryColor);
-
- Vector3 exit_end_pos = {center_pos.x + half_thick * ring.normal.x,
- center_pos.y + half_thick * ring.normal.y,
- center_pos.z + half_thick * ring.normal.z};
-
- DrawCylinderWiresEx(center_pos, exit_end_pos, ring.radius, ring.radius, 32, exitColor);
-}
-
-void c_render(DroneRace *env) {
- Drone *drone = &env->drone;
- if (env->client == NULL) {
- env->client = make_client(env);
- if (env->client == NULL) {
- TraceLog(LOG_ERROR, "Failed to initialize client for rendering\n");
- return;
- }
- }
-
- if (WindowShouldClose()) {
- c_close(env);
- exit(0);
- }
-
- if (IsKeyDown(KEY_ESCAPE)) {
- c_close(env);
- exit(0);
- }
-
- handle_camera_controls(env->client);
-
- Client *client = env->client;
- client->trail[client->trail_index] = drone->pos;
- client->trail_index = (client->trail_index + 1) % TRAIL_LENGTH;
- if (client->trail_count < TRAIL_LENGTH)
- client->trail_count++;
-
- BeginDrawing();
- ClearBackground((Color){6, 24, 24, 255});
-
- BeginMode3D(client->camera);
-
- // draws bounding cube
- DrawCubeWires((Vector3){0.0f, 0.0f, 0.0f}, GRID_SIZE * 2.0f, GRID_SIZE * 2.0f, GRID_SIZE * 2.0f,
- WHITE);
-
- // draws drone body
- float r = drone->arm_len;
- DrawSphere((Vector3){drone->pos.x, drone->pos.y, drone->pos.z}, r/2.0f, RED);
-
- // draws rotors according to thrust
- float T[4];
- for (int i = 0; i < 4; i++) {
- float rpm = (env->actions[i] + 1.0f) * 0.5f * drone->max_rpm;
- T[i] = drone->k_thrust * rpm * rpm;
- }
-
- const float rotor_radius = r / 4.0f;
- const float visual_arm_len = 1.0f * drone->arm_len;
-
- Vec3 rotor_offsets_body[4] = {{+r, 0.0f, 0.0f},
- {-r, 0.0f, 0.0f},
- {0.0f, +r, 0.0f},
- {0.0f, -r, 0.0f}};
-
- Color base_colors[4] = {ORANGE, PURPLE, LIME, SKYBLUE};
-
- for (int i = 0; i < 4; i++) {
- Vec3 world_off = quat_rotate(drone->quat, rotor_offsets_body[i]);
-
- Vector3 rotor_pos = {drone->pos.x + world_off.x, drone->pos.y + world_off.y,
- drone->pos.z + world_off.z};
-
- float rpm = (env->actions[i] + 1.0f) * 0.5f * drone->max_rpm;
- float intensity = 0.75f + 0.25f * (rpm / drone->max_rpm);
-
- Color rotor_color = (Color){(unsigned char)(base_colors[i].r * intensity),
- (unsigned char)(base_colors[i].g * intensity),
- (unsigned char)(base_colors[i].b * intensity), 255};
-
- DrawSphere(rotor_pos, rotor_radius, rotor_color);
-
- DrawCylinderEx((Vector3){drone->pos.x, drone->pos.y, drone->pos.z}, rotor_pos, 0.02f, 0.02f, 8,
- BLACK);
- }
-
- // draws line with direction and magnitude of velocity / 10
- if (norm3(drone->vel) > 0.1f) {
- DrawLine3D((Vector3){drone->pos.x, drone->pos.y, drone->pos.z},
- (Vector3){drone->pos.x + drone->vel.x * 0.1f, drone->pos.y + drone->vel.y * 0.1f,
- drone->pos.z + drone->vel.z * 0.1f},
- MAGENTA);
- }
-
- // Draw trailing path
- for (int i = 1; i < client->trail_count; i++) {
- int idx0 = (client->trail_index + i) % TRAIL_LENGTH;
- int idx1 = (client->trail_index + i - 1) % TRAIL_LENGTH;
- float alpha = (float)i / client->trail_count * 0.8f; // fade out
- Color trail_color = ColorAlpha(YELLOW, alpha);
- DrawLine3D((Vector3){client->trail[idx0].x, client->trail[idx0].y, client->trail[idx0].z},
- (Vector3){client->trail[idx1].x, client->trail[idx1].y, client->trail[idx1].z},
- trail_color);
- }
-
- // draws current and previous ring
- float ring_thickness = 0.2f;
- DrawRing3D(env->ring_buffer[env->ring_idx], ring_thickness, GREEN, BLUE);
- if (env->ring_idx > 0) {
- DrawRing3D(env->ring_buffer[env->ring_idx - 1], ring_thickness, GREEN, BLUE);
- }
-
- EndMode3D();
-
- // Draw 2D stats
- DrawText(TextFormat("Targets left: %d", env->max_rings - env->ring_idx), 10, 10, 20, WHITE);
- DrawText(TextFormat("Moves left: %d", env->moves_left), 10, 40, 20, WHITE);
- DrawText(TextFormat("Episode Return: %.2f", env->episodic_return), 10, 70, 20, WHITE);
-
- DrawText("Motor Thrusts:", 10, 110, 20, WHITE);
- DrawText(TextFormat("Front: %.3f", T[0]), 10, 135, 18, ORANGE);
- DrawText(TextFormat("Back: %.3f", T[1]), 10, 155, 18, PURPLE);
- DrawText(TextFormat("Right: %.3f", T[2]), 10, 175, 18, LIME);
- DrawText(TextFormat("Left: %.3f", T[3]), 10, 195, 18, SKYBLUE);
-
- DrawText(TextFormat("Pos: (%.1f, %.1f, %.1f)", drone->pos.x, drone->pos.y, drone->pos.z), 10, 225, 18,
- WHITE);
- DrawText(TextFormat("Vel: %.2f m/s", norm3(drone->vel)), 10, 245, 18, WHITE);
-
- DrawText("Left click + drag: Rotate camera", 10, 275, 16, LIGHTGRAY);
- DrawText("Mouse wheel: Zoom in/out", 10, 295, 16, LIGHTGRAY);
-
- EndDrawing();
-}
diff --git a/pufferlib/ocean/drone_race/drone_race.py b/pufferlib/ocean/drone_race/drone_race.py
deleted file mode 100644
index 9b8c9af86..000000000
--- a/pufferlib/ocean/drone_race/drone_race.py
+++ /dev/null
@@ -1,95 +0,0 @@
-import numpy as np
-import gymnasium
-
-import pufferlib
-from pufferlib.ocean.drone_race import binding
-
-class DroneRace(pufferlib.PufferEnv):
- def __init__(
- self,
- num_envs=16,
- render_mode=None,
- report_interval=1,
- buf=None,
- seed=0,
- max_rings=10,
- max_moves=1000,
- ):
- self.single_observation_space = gymnasium.spaces.Box(
- low=-1,
- high=1,
- shape=(25,),
- dtype=np.float32,
- )
-
- self.single_action_space = gymnasium.spaces.Box(
- low=-1, high=1, shape=(4,), dtype=np.float32
- )
-
- self.num_agents = num_envs
- self.render_mode = render_mode
- self.report_interval = report_interval
- self.tick = 0
-
- super().__init__(buf)
- self.actions = self.actions.astype(np.float32)
-
- c_envs = []
- for env_num in range(num_envs):
- c_envs.append(binding.env_init(
- self.observations[env_num:(env_num+1)],
- self.actions[env_num:(env_num+1)],
- self.rewards[env_num:(env_num+1)],
- self.terminals[env_num:(env_num+1)],
- self.truncations[env_num:(env_num+1)],
- env_num,
- report_interval=self.report_interval,
- max_rings=max_rings,
- max_moves=max_moves,
- ))
-
- self.c_envs = binding.vectorize(*c_envs)
-
- def reset(self, seed=None):
- self.tick = 0
- binding.vec_reset(self.c_envs, seed)
- return self.observations, []
-
- def step(self, actions):
- self.actions[:] = actions
-
- self.tick += 1
- binding.vec_step(self.c_envs)
-
- info = []
- if self.tick % self.report_interval == 0:
- log_data = binding.vec_log(self.c_envs)
- if log_data:
- info.append(log_data)
-
- return (self.observations, self.rewards, self.terminals, self.truncations, info)
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-def test_performance(timeout=10, atn_cache=1024):
- env = DroneRace(num_envs=1000)
- env.reset()
- tick = 0
-
- actions = [env.action_space.sample() for _ in range(atn_cache)]
-
- import time
- start = time.time()
- while time.time() - start < timeout:
- atn = actions[tick % atn_cache]
- env.step(atn)
- tick += 1
-
- print(f"SPS: {env.num_agents * tick / (time.time() - start)}")
-
-if __name__ == "__main__":
- test_performance()
diff --git a/pufferlib/ocean/drone_race/dronelib.h b/pufferlib/ocean/drone_race/dronelib.h
deleted file mode 100644
index 8445405fd..000000000
--- a/pufferlib/ocean/drone_race/dronelib.h
+++ /dev/null
@@ -1,374 +0,0 @@
-// Originally made by Sam Turner and Finlay Sanders, 2025.
-// Included in pufferlib under the original project's MIT license.
-// https://github.com/stmio/drone
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "raylib.h"
-
-// Visualisation properties
-#define WIDTH 1080
-#define HEIGHT 720
-#define TRAIL_LENGTH 50
-#define HORIZON 1024
-
-// Physical constants for the drone
-#define BASE_MASS 1.0f // kg
-#define BASE_IXX 0.01f // kgm^2
-#define BASE_IYY 0.01f // kgm^2
-#define BASE_IZZ 0.02f // kgm^2
-#define BASE_ARM_LEN 0.1f // m
-#define BASE_K_THRUST 3e-5f // thrust coefficient
-#define BASE_K_ANG_DAMP 0.2f // angular damping coefficient
-#define BASE_K_DRAG 1e-6f // drag (torque) coefficient
-#define BASE_B_DRAG 0.1f // linear drag coefficient
-#define BASE_GRAVITY 9.81f // m/s^2
-#define BASE_MAX_RPM 750.0f // rad/s
-#define BASE_MAX_VEL 50.0f // m/s
-#define BASE_MAX_OMEGA 50.0f // rad/s
-
-// Simulation properties
-#define GRID_SIZE 10.0f
-#define MARGIN (GRID_SIZE - 1)
-#define V_TARGET 0.05f
-#define DT 0.05f
-#define DT_RNG 0.1f
-
-// Corner to corner distance
-#define MAX_DIST sqrtf(3*(2*GRID_SIZE)*(2*GRID_SIZE))
-
-typedef struct Log Log;
-struct Log {
- float episode_return;
- float episode_length;
- float collision_rate;
- float oob;
- float score;
- float perf;
- float n;
-};
-
-typedef struct {
- float w, x, y, z;
-} Quat;
-
-typedef struct {
- float x, y, z;
-} Vec3;
-
-static inline float clampf(float v, float min, float max) {
- if (v < min)
- return min;
- if (v > max)
- return max;
- return v;
-}
-
-static inline float rndf(float a, float b) {
- return a + ((float)rand() / (float)RAND_MAX) * (b - a);
-}
-
-static inline Vec3 add3(Vec3 a, Vec3 b) { return (Vec3){a.x + b.x, a.y + b.y, a.z + b.z}; }
-
-static inline Vec3 sub3(Vec3 a, Vec3 b) { return (Vec3){a.x - b.x, a.y - b.y, a.z - b.z}; }
-
-static inline Vec3 scalmul3(Vec3 a, float b) { return (Vec3){a.x * b, a.y * b, a.z * b}; }
-
-static inline float dot3(Vec3 a, Vec3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
-
-static inline float norm3(Vec3 a) { return sqrtf(dot3(a, a)); }
-
-static inline void clamp3(Vec3 *vec, float min, float max) {
- vec->x = clampf(vec->x, min, max);
- vec->y = clampf(vec->y, min, max);
- vec->z = clampf(vec->z, min, max);
-}
-
-static inline void clamp4(float a[4], float min, float max) {
- a[0] = clampf(a[0], min, max);
- a[1] = clampf(a[1], min, max);
- a[2] = clampf(a[2], min, max);
- a[3] = clampf(a[3], min, max);
-}
-
-static inline Quat quat_mul(Quat q1, Quat q2) {
- Quat out;
- out.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z;
- out.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y;
- out.y = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x;
- out.z = q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w;
- return out;
-}
-
-static inline void quat_normalize(Quat *q) {
- float n = sqrtf(q->w * q->w + q->x * q->x + q->y * q->y + q->z * q->z);
- if (n > 0.0f) {
- q->w /= n;
- q->x /= n;
- q->y /= n;
- q->z /= n;
- }
-}
-
-static inline Vec3 quat_rotate(Quat q, Vec3 v) {
- Quat qv = {0.0f, v.x, v.y, v.z};
- Quat tmp = quat_mul(q, qv);
- Quat q_conj = {q.w, -q.x, -q.y, -q.z};
- Quat res = quat_mul(tmp, q_conj);
- return (Vec3){res.x, res.y, res.z};
-}
-
-static inline Quat quat_inverse(Quat q) { return (Quat){q.w, -q.x, -q.y, -q.z}; }
-
-Quat rndquat() {
- float u1 = rndf(0.0f, 1.0f);
- float u2 = rndf(0.0f, 1.0f);
- float u3 = rndf(0.0f, 1.0f);
-
- float sqrt_1_minus_u1 = sqrtf(1.0f - u1);
- float sqrt_u1 = sqrtf(u1);
-
- float pi_2_u2 = 2.0f * M_PI * u2;
- float pi_2_u3 = 2.0f * M_PI * u3;
-
- Quat q;
- q.w = sqrt_1_minus_u1 * sinf(pi_2_u2);
- q.x = sqrt_1_minus_u1 * cosf(pi_2_u2);
- q.y = sqrt_u1 * sinf(pi_2_u3);
- q.z = sqrt_u1 * cosf(pi_2_u3);
-
- return q;
-}
-
-typedef struct {
- Vec3 pos;
- Quat orientation;
- Vec3 normal;
- float radius;
-} Ring;
-
-Ring rndring(float radius) {
- Ring ring;
-
- ring.pos.x = rndf(-GRID_SIZE + 2*radius, GRID_SIZE - 2*radius);
- ring.pos.y = rndf(-GRID_SIZE + 2*radius, GRID_SIZE - 2*radius);
- ring.pos.z = rndf(-GRID_SIZE + 2*radius, GRID_SIZE - 2*radius);
-
- ring.orientation = rndquat();
-
- Vec3 base_normal = {0.0f, 0.0f, 1.0f};
- ring.normal = quat_rotate(ring.orientation, base_normal);
-
- ring.radius = radius;
-
- return ring;
-}
-
-typedef struct {
- Vec3 pos[TRAIL_LENGTH];
- int index;
- int count;
-} Trail;
-
-
-typedef struct {
- Vec3 spawn_pos;
- Vec3 pos; // global position (x, y, z)
- Vec3 prev_pos;
- Vec3 vel; // linear velocity (u, v, w)
- Quat quat; // roll/pitch/yaw (phi/theta/psi) as a quaternion
- Vec3 omega; // angular velocity (p, q, r)
-
- Vec3 target_pos;
- Vec3 target_vel;
-
- float last_abs_reward;
- float last_target_reward;
- float last_collision_reward;
- float episode_return;
- float collisions;
- int episode_length;
- float score;
- int ring_idx;
-
- // Physical properties. Modeled as part of the drone
- // to make domain randomization easier.
- float mass; // kg
- float ixx; // kgm^2
- float iyy; // kgm^2
- float izz; // kgm^2
- float arm_len; // m
- float k_thrust; // thrust coefficient
- float k_ang_damp; // angular damping coefficient
- float k_drag; // drag (torque) coefficient
- float b_drag; // linear drag coefficient
- float gravity; // m/s^2
- float max_rpm; // rad/s
- float max_vel; // m/s
- float max_omega; // rad/s
-} Drone;
-
-// Physical constants for the drone
-#define BASE_MASS 1.0f // kg
-#define BASE_IXX 0.01f // kgm^2
-#define BASE_IYY 0.01f // kgm^2
-#define BASE_IZZ 0.02f // kgm^2
-#define BASE_ARM_LEN 0.1f // m
-#define BASE_K_THRUST 3e-5f // thrust coefficient
-#define BASE_K_ANG_DAMP 0.2f // angular damping coefficient
-#define BASE_K_DRAG 1e-6f // drag (torque) coefficient
-#define BASE_B_DRAG 0.1f // linear drag coefficient
-#define BASE_GRAVITY 9.81f // m/s^2
-#define BASE_MAX_RPM 750.0f // rad/s
-#define BASE_MAX_VEL 50.0f // m/s
-#define BASE_MAX_OMEGA 50.0f // rad/s
-
-
-void init_drone(Drone* drone, float size, float dr) {
-
- drone->arm_len = size / 2.0f;
-
- // m ~ x^3
- float mass_scale = powf(drone->arm_len, 3.0f) / powf(BASE_ARM_LEN, 3.0f);
- drone->mass = BASE_MASS * mass_scale * rndf(1.0f - dr, 1.0f + dr);
-
- // I ~ mx^2
- float base_Iscale = BASE_MASS * BASE_ARM_LEN * BASE_ARM_LEN;
- float I_scale = drone->mass * powf(drone->arm_len, 2.0f) / base_Iscale;
- drone->ixx = BASE_IXX * I_scale * rndf(1.0f - dr, 1.0f + dr);
- drone->iyy = BASE_IYY * I_scale * rndf(1.0f - dr, 1.0f + dr);
- drone->izz = BASE_IZZ * I_scale * rndf(1.0f - dr, 1.0f + dr);
-
- // k_thrust ~ m/l
- float k_thrust_scale = (drone->mass * drone->arm_len) / (BASE_MASS * BASE_ARM_LEN);
- drone->k_thrust = BASE_K_THRUST * k_thrust_scale * rndf(1.0f - dr, 1.0f + dr);
-
- // k_ang_damp ~ I
- float base_avg_inertia = (BASE_IXX + BASE_IYY + BASE_IZZ) / 3.0f;
- float avg_inertia = (drone->ixx + drone->iyy + drone->izz) / 3.0f;
- float avg_inertia_scale = avg_inertia / base_avg_inertia;
- drone->k_ang_damp = BASE_K_ANG_DAMP * avg_inertia_scale * rndf(1.0f - dr, 1.0f + dr);
-
- // drag ~ x^2
- float drag_scale = powf(drone->arm_len, 2.0f) / powf(BASE_ARM_LEN, 2.0f);
- drone->k_drag = BASE_K_DRAG * drag_scale * rndf(1.0f - dr, 1.0f + dr);
- drone->b_drag = BASE_B_DRAG * drag_scale * rndf(1.0f - dr, 1.0f + dr);
-
- // Small gravity randomization
- drone->gravity = BASE_GRAVITY * rndf(0.99f, 1.01f);
-
- // RPM ~ 1/x
- float rpm_scale = (BASE_ARM_LEN) / (drone->arm_len);
- drone->max_rpm = BASE_MAX_RPM * rpm_scale * rndf(1.0f - dr, 1.0f + dr);
-
- drone->max_vel = BASE_MAX_VEL;
- drone->max_omega = BASE_MAX_OMEGA;
-}
-
-void move_drone(Drone* drone, float* actions) {
- clamp4(actions, -1.0f, 1.0f);
-
- // motor thrusts
- float T[4];
- for (int i = 0; i < 4; i++) {
- T[i] = drone->k_thrust*powf((actions[i] + 1.0f) * 0.5f * drone->max_rpm, 2.0f);
- }
-
-
- // body frame net force
- Vec3 F_body = {0.0f, 0.0f, T[0] + T[1] + T[2] + T[3]};
-
- // body frame torques
- Vec3 M = {drone->arm_len*(T[1] - T[3]), drone->arm_len*(T[2] - T[0]),
- drone->k_drag*(T[0] - T[1] + T[2] - T[3])};
-
- // applies angular damping to torques
- M.x -= drone->k_ang_damp * drone->omega.x;
- M.y -= drone->k_ang_damp * drone->omega.y;
- M.z -= drone->k_ang_damp * drone->omega.z;
-
- // body frame force -> world frame force
- Vec3 F_world = quat_rotate(drone->quat, F_body);
-
- // world frame linear drag
- F_world.x -= drone->b_drag * drone->vel.x;
- F_world.y -= drone->b_drag * drone->vel.y;
- F_world.z -= drone->b_drag * drone->vel.z;
-
- // world frame gravity
- Vec3 accel = {
- F_world.x / drone->mass,
- F_world.y / drone->mass,
- (F_world.z / drone->mass) - drone->gravity
- };
-
- // from the definition of q dot
- Quat omega_q = {0.0f, drone->omega.x, drone->omega.y, drone->omega.z};
- Quat q_dot = quat_mul(drone->quat, omega_q);
-
- q_dot.w *= 0.5f;
- q_dot.x *= 0.5f;
- q_dot.y *= 0.5f;
- q_dot.z *= 0.5f;
-
- // Domain randomized dt
- float dt = DT * rndf(1.0f - DT_RNG, 1.0 + DT_RNG);
-
- // integrations
- drone->pos.x += drone->vel.x * dt;
- drone->pos.y += drone->vel.y * dt;
- drone->pos.z += drone->vel.z * dt;
-
- drone->vel.x += accel.x * dt;
- drone->vel.y += accel.y * dt;
- drone->vel.z += accel.z * dt;
-
- drone->omega.x += (M.x / drone->ixx) * dt;
- drone->omega.y += (M.y / drone->iyy) * dt;
- drone->omega.z += (M.z / drone->izz) * dt;
-
- clamp3(&drone->vel, -drone->max_vel, drone->max_vel);
- clamp3(&drone->omega, -drone->max_omega, drone->max_omega);
-
- drone->quat.w += q_dot.w * dt;
- drone->quat.x += q_dot.x * dt;
- drone->quat.y += q_dot.y * dt;
- drone->quat.z += q_dot.z * dt;
-
- quat_normalize(&drone->quat);
-}
-
-float check_ring(Drone* drone, Ring* ring) {
- // previous dot product negative if on the 'entry' side of the ring's plane
- float prev_dot = dot3(sub3(drone->prev_pos, ring->pos), ring->normal);
-
- // new dot product positive if on the 'exit' side of the ring's plane
- float new_dot = dot3(sub3(drone->pos, ring->pos), ring->normal);
-
- bool valid_dir = (prev_dot < 0.0f && new_dot > 0.0f);
- bool invalid_dir = (prev_dot > 0.0f && new_dot < 0.0f);
-
- // if we have crossed the plane of the ring
- if (valid_dir || invalid_dir) {
- // find intesection with ring's plane
- Vec3 dir = sub3(drone->pos, drone->prev_pos);
- float t = -prev_dot / dot3(ring->normal, dir); // possible nan
-
- Vec3 intersection = add3(drone->prev_pos, scalmul3(dir, t));
- float dist = norm3(sub3(intersection, ring->pos));
-
- // reward or terminate based on distance to ring center
- if (dist < (ring->radius - 0.5) && valid_dir) {
- return 1.0f;
- } else if (dist < ring->radius + 0.5) {
- return -1.0f;
- }
- }
- return 0.0f;
-}
diff --git a/pufferlib/ocean/drone_swarm/binding.c b/pufferlib/ocean/drone_swarm/binding.c
deleted file mode 100644
index a7c930f62..000000000
--- a/pufferlib/ocean/drone_swarm/binding.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "drone_swarm.h"
-
-#define Env DroneSwarm
-#include "../env_binding.h"
-
-static int my_init(Env *env, PyObject *args, PyObject *kwargs) {
- env->num_agents = unpack(kwargs, "num_agents");
- env->max_rings = unpack(kwargs, "max_rings");
- init(env);
- return 0;
-}
-
-static int my_log(PyObject *dict, Log *log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "rings_passed", log->rings_passed);
- assign_to_dict(dict, "collision_rate", log->collision_rate);
- assign_to_dict(dict, "oob", log->oob);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "episode_length", log->episode_length);
- assign_to_dict(dict, "n", log->n);
- return 0;
-}
diff --git a/pufferlib/ocean/drone_swarm/drone_swarm.c b/pufferlib/ocean/drone_swarm/drone_swarm.c
deleted file mode 100644
index 9a765209b..000000000
--- a/pufferlib/ocean/drone_swarm/drone_swarm.c
+++ /dev/null
@@ -1,180 +0,0 @@
-// Standalone C demo for DroneSwarm environment
-// Compile using: ./scripts/build_ocean.sh drone [local|fast]
-// Run with: ./drone
-
-#include "drone_swarm.h"
-#include "puffernet.h"
-#include
-
-#ifdef __EMSCRIPTEN__
-#include
-#endif
-
-double randn(double mean, double std) {
- static int has_spare = 0;
- static double spare;
-
- if (has_spare) {
- has_spare = 0;
- return mean + std * spare;
- }
-
- has_spare = 1;
- double u, v, s;
- do {
- u = 2.0 * rand() / RAND_MAX - 1.0;
- v = 2.0 * rand() / RAND_MAX - 1.0;
- s = u * u + v * v;
- } while (s >= 1.0 || s == 0.0);
-
- s = sqrt(-2.0 * log(s) / s);
- spare = v * s;
- return mean + std * (u * s);
-}
-
-typedef struct LinearContLSTM LinearContLSTM;
-struct LinearContLSTM {
- int num_agents;
- float *obs;
- float *log_std;
- Linear *encoder;
- GELU *gelu1;
- LSTM *lstm;
- Linear *actor;
- Linear *value_fn;
- int num_actions;
-};
-
-LinearContLSTM *make_linearcontlstm(Weights *weights, int num_agents, int input_dim,
- int logit_sizes[], int num_actions) {
- LinearContLSTM *net = calloc(1, sizeof(LinearContLSTM));
- net->num_agents = num_agents;
- net->obs = calloc(num_agents * input_dim, sizeof(float));
- net->num_actions = logit_sizes[0];
- net->log_std = weights->data;
- weights->idx += net->num_actions;
- net->encoder = make_linear(weights, num_agents, input_dim, 128);
- net->gelu1 = make_gelu(num_agents, 128);
- int atn_sum = 0;
- for (int i = 0; i < num_actions; i++) {
- atn_sum += logit_sizes[i];
- }
- net->actor = make_linear(weights, num_agents, 128, atn_sum);
- net->value_fn = make_linear(weights, num_agents, 128, 1);
- net->lstm = make_lstm(weights, num_agents, 128, 128);
- return net;
-}
-
-void free_linearcontlstm(LinearContLSTM *net) {
- free(net->obs);
- free(net->encoder);
- free(net->gelu1);
- free(net->actor);
- free(net->value_fn);
- free(net->lstm);
- free(net);
-}
-
-void forward_linearcontlstm(LinearContLSTM *net, float *observations, float *actions) {
- linear(net->encoder, observations);
- gelu(net->gelu1, net->encoder->output);
- lstm(net->lstm, net->gelu1->output);
- linear(net->actor, net->lstm->state_h);
- linear(net->value_fn, net->lstm->state_h);
- for (int i = 0; i < net->num_actions; i++) {
- float std = expf(net->log_std[i]);
- float mean = net->actor->output[i];
- actions[i] = randn(mean, std);
- }
-}
-
-void generate_dummy_actions(DroneSwarm *env) {
- // Generate random floats in [-1, 1] range
- env->actions[0] = ((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f;
- env->actions[1] = ((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f;
- env->actions[2] = ((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f;
- env->actions[3] = ((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f;
-}
-
-#ifdef __EMSCRIPTEN__
-typedef struct {
- DroneSwarm *env;
- LinearContLSTM *net;
- Weights *weights;
-} WebRenderArgs;
-
-void emscriptenStep(void *e) {
- WebRenderArgs *args = (WebRenderArgs *)e;
- DroneSwarm *env = args->env;
- LinearContLSTM *net = args->net;
-
- forward_linearcontlstm(net, env->observations, env->actions);
- c_step(env);
- c_render(env);
- return;
-}
-
-WebRenderArgs *web_args = NULL;
-#endif
-
-int main() {
- srand(time(NULL)); // Seed random number generator
-
- DroneSwarm *env = calloc(1, sizeof(DroneSwarm));
- env->num_agents = 64;
- env->max_rings = 10;
- env->task = TASK_ORBIT;
- init(env);
-
- size_t obs_size = 41;
- size_t act_size = 4;
- env->observations = (float *)calloc(env->num_agents * obs_size, sizeof(float));
- env->actions = (float *)calloc(env->num_agents * act_size, sizeof(float));
- env->rewards = (float *)calloc(env->num_agents, sizeof(float));
- env->terminals = (unsigned char *)calloc(env->num_agents, sizeof(float));
-
- //Weights *weights = load_weights("resources/drone/drone_weights.bin", 136073);
- //int logit_sizes[1] = {4};
- //LinearContLSTM *net = make_linearcontlstm(weights, env->num_agents, obs_size, logit_sizes, 1);
-
- if (!env->observations || !env->actions || !env->rewards) {
- fprintf(stderr, "ERROR: Failed to allocate memory for demo buffers.\n");
- free(env->observations);
- free(env->actions);
- free(env->rewards);
- free(env->terminals);
- free(env);
- return 0;
- }
-
- init(env);
- c_reset(env);
-
-#ifdef __EMSCRIPTEN__
- WebRenderArgs *args = calloc(1, sizeof(WebRenderArgs));
- args->env = env;
- args->net = net;
- args->weights = weights;
- web_args = args;
-
- emscripten_set_main_loop_arg(emscriptenStep, args, 0, true);
-#else
- c_render(env);
-
- while (!WindowShouldClose()) {
- //forward_linearcontlstm(net, env->observations, env->actions);
- c_step(env);
- c_render(env);
- }
-
- c_close(env);
- //free_linearcontlstm(net);
- free(env->observations);
- free(env->actions);
- free(env->rewards);
- free(env->terminals);
- free(env);
-#endif
-
- return 0;
-}
diff --git a/pufferlib/ocean/drone_swarm/drone_swarm.h b/pufferlib/ocean/drone_swarm/drone_swarm.h
deleted file mode 100644
index 9e8bcf767..000000000
--- a/pufferlib/ocean/drone_swarm/drone_swarm.h
+++ /dev/null
@@ -1,778 +0,0 @@
-// Originally made by Sam Turner and Finlay Sanders, 2025.
-// Included in pufferlib under the original project's MIT license.
-// https://github.com/stmio/drone
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "raylib.h"
-#include "dronelib.h"
-
-#define TASK_IDLE 0
-#define TASK_HOVER 1
-#define TASK_ORBIT 2
-#define TASK_FOLLOW 3
-#define TASK_CUBE 4
-#define TASK_CONGO 5
-#define TASK_FLAG 6
-#define TASK_RACE 7
-#define TASK_N 8
-
-char* TASK_NAMES[TASK_N] = {
- "Idle", "Hover", "Orbit", "Follow",
- "Cube", "Congo", "FLAG", "Race"
-};
-
-#define R (Color){255, 0, 0, 255}
-#define W (Color){255, 255, 255, 255}
-#define B (Color){0, 0, 255, 255}
-Color FLAG_COLORS[64] = {
- B, B, B, B, R, R, R, R,
- B, B, B, B, W, W, W, W,
- B, B, B, B, R, R, R, R,
- B, B, B, B, W, W, W, W,
- R, R, R, R, R, R, R, R,
- W, W, W, W, W, W, W, W,
- R, R, R, R, R, R, R, R,
- W, W, W, W, W, W, W, W
-};
-#undef R
-#undef W
-#undef B
-
-typedef struct Client Client;
-struct Client {
- Camera3D camera;
- float width;
- float height;
-
- float camera_distance;
- float camera_azimuth;
- float camera_elevation;
- bool is_dragging;
- Vector2 last_mouse_pos;
-
- // Trailing path buffer (for rendering only)
- Trail* trails;
-};
-
-typedef struct {
- float *observations;
- float *actions;
- float *rewards;
- unsigned char *terminals;
-
- Log log;
- int tick;
- int report_interval;
-
- int task;
- int num_agents;
- Drone* agents;
-
- int max_rings;
- Ring* ring_buffer;
-
- Client *client;
-} DroneSwarm;
-
-void init(DroneSwarm *env) {
- env->agents = calloc(env->num_agents, sizeof(Drone));
- env->ring_buffer = calloc(env->max_rings, sizeof(Ring));
- env->log = (Log){0};
- env->tick = 0;
-}
-
-void add_log(DroneSwarm *env, int idx, bool oob) {
- Drone *agent = &env->agents[idx];
- env->log.score += agent->score;
- env->log.episode_return += agent->episode_return;
- env->log.episode_length += agent->episode_length;
- env->log.collision_rate += agent->collisions / (float)agent->episode_length;
- env->log.perf += agent->score / (float)agent->episode_length;
- if (oob) {
- env->log.oob += 1.0f;
- }
- env->log.n += 1.0f;
-
- agent->episode_length = 0;
- agent->episode_return = 0.0f;
-}
-
-Drone* nearest_drone(DroneSwarm* env, Drone *agent) {
- float min_dist = 999999.0f;
- Drone *nearest = NULL;
- for (int i = 0; i < env->num_agents; i++) {
- Drone *other = &env->agents[i];
- if (other == agent) {
- continue;
- }
- float dx = agent->pos.x - other->pos.x;
- float dy = agent->pos.y - other->pos.y;
- float dz = agent->pos.z - other->pos.z;
- float dist = sqrtf(dx*dx + dy*dy + dz*dz);
- if (dist < min_dist) {
- min_dist = dist;
- nearest = other;
- }
- }
- if (nearest == NULL) {
- int x = 0;
-
- }
- return nearest;
-}
-
-void compute_observations(DroneSwarm *env) {
- int idx = 0;
- for (int i = 0; i < env->num_agents; i++) {
- Drone *agent = &env->agents[i];
-
- Quat q_inv = quat_inverse(agent->quat);
- Vec3 linear_vel_body = quat_rotate(q_inv, agent->vel);
- Vec3 drone_up_world = quat_rotate(agent->quat, (Vec3){0.0f, 0.0f, 1.0f});
-
- // TODO: Need abs observations now right?
- env->observations[idx++] = linear_vel_body.x / agent->max_vel;
- env->observations[idx++] = linear_vel_body.y / agent->max_vel;
- env->observations[idx++] = linear_vel_body.z / agent->max_vel;
-
- env->observations[idx++] = agent->omega.x / agent->max_omega;
- env->observations[idx++] = agent->omega.y / agent->max_omega;
- env->observations[idx++] = agent->omega.z / agent->max_omega;
-
- env->observations[idx++] = drone_up_world.x;
- env->observations[idx++] = drone_up_world.y;
- env->observations[idx++] = drone_up_world.z;
-
- env->observations[idx++] = agent->quat.w;
- env->observations[idx++] = agent->quat.x;
- env->observations[idx++] = agent->quat.y;
- env->observations[idx++] = agent->quat.z;
-
- env->observations[idx++] = agent->rpms[0] / agent->max_rpm;
- env->observations[idx++] = agent->rpms[1] / agent->max_rpm;
- env->observations[idx++] = agent->rpms[2] / agent->max_rpm;
- env->observations[idx++] = agent->rpms[3] / agent->max_rpm;
-
- env->observations[idx++] = agent->pos.x / GRID_X;
- env->observations[idx++] = agent->pos.y / GRID_Y;
- env->observations[idx++] = agent->pos.z / GRID_Z;
-
- env->observations[idx++] = agent->spawn_pos.x / GRID_X;
- env->observations[idx++] = agent->spawn_pos.y / GRID_Y;
- env->observations[idx++] = agent->spawn_pos.z / GRID_Z;
-
- float dx = agent->target_pos.x - agent->pos.x;
- float dy = agent->target_pos.y - agent->pos.y;
- float dz = agent->target_pos.z - agent->pos.z;
- env->observations[idx++] = clampf(dx, -1.0f, 1.0f);
- env->observations[idx++] = clampf(dy, -1.0f, 1.0f);
- env->observations[idx++] = clampf(dz, -1.0f, 1.0f);
- env->observations[idx++] = dx / GRID_X;
- env->observations[idx++] = dy / GRID_Y;
- env->observations[idx++] = dz / GRID_Z;
-
- env->observations[idx++] = agent->last_collision_reward;
- env->observations[idx++] = agent->last_target_reward;
- env->observations[idx++] = agent->last_abs_reward;
-
- // Multiagent obs
- Drone* nearest = nearest_drone(env, agent);
- if (env->num_agents > 1) {
- env->observations[idx++] = clampf(nearest->pos.x - agent->pos.x, -1.0f, 1.0f);
- env->observations[idx++] = clampf(nearest->pos.y - agent->pos.y, -1.0f, 1.0f);
- env->observations[idx++] = clampf(nearest->pos.z - agent->pos.z, -1.0f, 1.0f);
- } else {
- env->observations[idx++] = 0.0f;
- env->observations[idx++] = 0.0f;
- env->observations[idx++] = 0.0f;
- }
-
- // Ring obs
- if (env->task == TASK_RACE) {
- Ring ring = env->ring_buffer[agent->ring_idx];
- Vec3 to_ring = quat_rotate(q_inv, sub3(ring.pos, agent->pos));
- Vec3 ring_norm = quat_rotate(q_inv, ring.normal);
- env->observations[idx++] = to_ring.x / GRID_X;
- env->observations[idx++] = to_ring.y / GRID_Y;
- env->observations[idx++] = to_ring.z / GRID_Z;
- env->observations[idx++] = ring_norm.x;
- env->observations[idx++] = ring_norm.y;
- env->observations[idx++] = ring_norm.z;
- } else {
- env->observations[idx++] = 0.0f;
- env->observations[idx++] = 0.0f;
- env->observations[idx++] = 0.0f;
- env->observations[idx++] = 0.0f;
- env->observations[idx++] = 0.0f;
- env->observations[idx++] = 0.0f;
- }
- }
-}
-
-void move_target(DroneSwarm* env, Drone *agent) {
- agent->target_pos.x += agent->target_vel.x;
- agent->target_pos.y += agent->target_vel.y;
- agent->target_pos.z += agent->target_vel.z;
- if (agent->target_pos.x < -GRID_X || agent->target_pos.x > GRID_X) {
- agent->target_vel.x = -agent->target_vel.x;
- }
- if (agent->target_pos.y < -GRID_Y || agent->target_pos.y > GRID_Y) {
- agent->target_vel.y = -agent->target_vel.y;
- }
- if (agent->target_pos.z < -GRID_Z || agent->target_pos.z > GRID_Z) {
- agent->target_vel.z = -agent->target_vel.z;
- }
-}
-
-void set_target_idle(DroneSwarm* env, int idx) {
- Drone *agent = &env->agents[idx];
- agent->target_pos = (Vec3){rndf(-MARGIN_X, MARGIN_X), rndf(-MARGIN_Y, MARGIN_Y), rndf(-MARGIN_Z, MARGIN_Z)};
- agent->target_vel = (Vec3){rndf(-V_TARGET, V_TARGET), rndf(-V_TARGET, V_TARGET), rndf(-V_TARGET, V_TARGET)};
-}
-
-void set_target_hover(DroneSwarm* env, int idx) {
- Drone *agent = &env->agents[idx];
- agent->target_pos = agent->pos;
- agent->target_vel = (Vec3){0.0f, 0.0f, 0.0f};
-}
-
-void set_target_orbit(DroneSwarm* env, int idx) {
- // Fibbonacci sphere algorithm
- float R = 8.0f;
- float phi = PI * (sqrt(5.0f) - 1.0f);
- float y = 1.0f - 2*((float)idx / (float)env->num_agents);
- float radius = sqrtf(1.0f - y*y);
-
- float theta = phi * idx;
-
- float x = cos(theta) * radius;
- float z = sin(theta) * radius;
-
- Drone *agent = &env->agents[idx];
- agent->target_pos = (Vec3){R*x, R*z, R*y}; // convert to z up
- agent->target_vel = (Vec3){0.0f, 0.0f, 0.0f};
-}
-
-void set_target_follow(DroneSwarm* env, int idx) {
- Drone* agent = &env->agents[idx];
- if (idx == 0) {
- set_target_idle(env, idx);
- } else {
- agent->target_pos = env->agents[0].target_pos;
- agent->target_vel = env->agents[0].target_vel;
- }
-}
-
-void set_target_cube(DroneSwarm* env, int idx) {
- Drone* agent = &env->agents[idx];
- float z = idx / 16;
- idx = idx % 16;
- float x = (float)(idx % 4);
- float y = (float)(idx / 4);
- agent->target_pos = (Vec3){4*x - 6, 4*y - 6, 4*z - 6};
- agent->target_vel = (Vec3){0.0f, 0.0f, 0.0f};
-}
-
-void set_target_congo(DroneSwarm* env, int idx) {
- if (idx == 0) {
- set_target_idle(env, idx);
- return;
- }
- Drone* follow = &env->agents[idx - 1];
- Drone* lead = &env->agents[idx];
- lead->target_pos = follow->target_pos;
- lead->target_vel = follow->target_vel;
-
- // TODO: Slow hack
- for (int i = 0; i < 40; i++) {
- move_target(env, lead);
- }
-}
-
-void set_target_flag(DroneSwarm* env, int idx) {
- Drone* agent = &env->agents[idx];
- float x = (float)(idx % 8);
- float y = (float)(idx / 8);
- x = 2.0f*x - 7;
- y = 5 - 1.5f*y;
- agent->target_pos = (Vec3){0.0f, x, y};
- agent->target_vel = (Vec3){0.0f, 0.0f, 0.0f};
-}
-
-void set_target_race(DroneSwarm* env, int idx) {
- Drone* agent = &env->agents[idx];
- agent->target_pos = env->ring_buffer[agent->ring_idx].pos;
- agent->target_vel = (Vec3){0.0f, 0.0f, 0.0f};
-}
-
-void set_target(DroneSwarm* env, int idx) {
- if (env->task == TASK_IDLE) {
- set_target_idle(env, idx);
- } else if (env->task == TASK_HOVER) {
- set_target_hover(env, idx);
- } else if (env->task == TASK_ORBIT) {
- set_target_orbit(env, idx);
- } else if (env->task == TASK_FOLLOW) {
- set_target_follow(env, idx);
- } else if (env->task == TASK_CUBE) {
- set_target_cube(env, idx);
- } else if (env->task == TASK_CONGO) {
- set_target_congo(env, idx);
- } else if (env->task == TASK_FLAG) {
- set_target_flag(env, idx);
- } else if (env->task == TASK_RACE) {
- set_target_race(env, idx);
- }
-}
-
-float compute_reward(DroneSwarm* env, Drone *agent, bool collision) {
- // Distance reward
- float dx = (agent->pos.x - agent->target_pos.x);
- float dy = (agent->pos.y - agent->target_pos.y);
- float dz = (agent->pos.z - agent->target_pos.z);
- float dist = sqrtf(dx*dx + dy*dy + dz*dz);
- float dist_reward = 1.0 - dist/MAX_DIST;
- //dist = clampf(dist, 0.0f, 1.0f);
- //float dist_reward = 1.0f - dist;
-
- // Density penalty
- float density_reward = 0.0f;
- if (collision && env->num_agents > 1) {
- Drone *nearest = nearest_drone(env, agent);
- dx = agent->pos.x - nearest->pos.x;
- dy = agent->pos.y - nearest->pos.y;
- dz = agent->pos.z - nearest->pos.z;
- float min_dist = sqrtf(dx*dx + dy*dy + dz*dz);
- if (min_dist < 1.0f) {
- density_reward = -1.0f;
- agent->collisions += 1.0f;
- }
- }
-
- float abs_reward = dist_reward + density_reward;
-
- // Prevent negative dist and density from making a positive reward
- if (dist_reward < 0.0f && density_reward < 0.0f) {
- abs_reward *= -1.0f;
- }
-
- float delta_reward = abs_reward - agent->last_abs_reward;
-
- agent->last_collision_reward = density_reward;
- agent->last_target_reward = dist_reward;
- agent->last_abs_reward = abs_reward;
-
- agent->episode_length++;
- agent->score += abs_reward;
-
- return delta_reward;
-}
-
-void reset_agent(DroneSwarm* env, Drone *agent, int idx) {
- agent->episode_return = 0.0f;
- agent->episode_length = 0;
- agent->collisions = 0.0f;
- agent->score = 0.0f;
- agent->pos = (Vec3){rndf(-9, 9), rndf(-9, 9), rndf(-9, 9)};
- agent->spawn_pos = agent->pos;
- agent->vel = (Vec3){0.0f, 0.0f, 0.0f};
- agent->omega = (Vec3){0.0f, 0.0f, 0.0f};
- agent->quat = (Quat){1.0f, 0.0f, 0.0f, 0.0f};
- agent->ring_idx = 0;
-
- //float size = 0.2f;
- //init_drone(agent, size, 0.0f);
- float size = rndf(0.1f, 0.4);
- init_drone(agent, size, 0.1f);
- compute_reward(env, agent, env->task != TASK_RACE);
-}
-
-void c_reset(DroneSwarm *env) {
- env->tick = 0;
- //env->task = rand() % (TASK_N - 1);
- //env->task = TASK_FLAG;
- env->task = TASK_CONGO;
- //env->task = rand() % (TASK_N - 1);
- /*
- if (rand() % 4) {
- env->task = TASK_RACE;
- } else {
- env->task = rand() % (TASK_N - 1);
- }
- */
- //env->task = TASK_RACE;
- //env->task = TASK_HOVER;
- //env->task = TASK_FLAG;
-
- for (int i = 0; i < env->num_agents; i++) {
- Drone *agent = &env->agents[i];
- reset_agent(env, agent, i);
- set_target(env, i);
- }
-
- for (int i = 0; i < env->max_rings; i++) {
- Ring *ring = &env->ring_buffer[i];
- *ring = (Ring){0};
- }
- if (env->task == TASK_RACE) {
- float ring_radius = 2.0f;
- if (env->max_rings + 1 > 0) {
- env->ring_buffer[0] = rndring(ring_radius);
- }
-
- for (int i = 1; i < env->max_rings; i++) {
- do {
- env->ring_buffer[i] = rndring(ring_radius);
- } while (norm3(sub3(env->ring_buffer[i].pos, env->ring_buffer[i - 1].pos)) < 2.0f*ring_radius);
- }
-
- // start drone at least MARGIN away from the first ring
- for (int i = 0; i < env->num_agents; i++) {
- Drone *drone = &env->agents[i];
- do {
- drone->pos = (Vec3){rndf(-9, 9), rndf(-9, 9), rndf(-9, 9)};
- } while (norm3(sub3(drone->pos, env->ring_buffer[0].pos)) < 2.0f*ring_radius);
- }
- }
-
- compute_observations(env);
-}
-
-void c_step(DroneSwarm *env) {
- env->tick = (env->tick + 1) % HORIZON;
- for (int i = 0; i < env->num_agents; i++) {
- Drone *agent = &env->agents[i];
- env->rewards[i] = 0;
- env->terminals[i] = 0;
-
- float* atn = &env->actions[4*i];
- move_drone(agent, atn);
-
- // check out of bounds
- bool out_of_bounds = agent->pos.x < -GRID_X || agent->pos.x > GRID_X ||
- agent->pos.y < -GRID_Y || agent->pos.y > GRID_Y ||
- agent->pos.z < -GRID_Z || agent->pos.z > GRID_Z;
-
- move_target(env, agent);
-
- float reward = 0.0f;
- if (env->task == TASK_RACE) {
- Ring *ring = &env->ring_buffer[agent->ring_idx];
- reward = compute_reward(env, agent, true);
- float passed_ring = check_ring(agent, ring);
- if (passed_ring > 0) {
- agent->ring_idx = (agent->ring_idx + 1) % env->max_rings;
- env->log.rings_passed += 1.0f;
- set_target(env, i);
- compute_reward(env, agent, true);
- }
- reward += passed_ring;
- } else {
- // Delta reward
- reward = compute_reward(env, agent, true);
- }
-
- env->rewards[i] += reward;
- agent->episode_return += reward;
-
- if (out_of_bounds) {
- env->rewards[i] -= 1;
- env->terminals[i] = 1;
- add_log(env, i, true);
- reset_agent(env, agent, i);
- } else if (env->tick >= HORIZON - 1) {
- env->terminals[i] = 1;
- add_log(env, i, false);
- }
- }
- if (env->tick >= HORIZON - 1) {
- c_reset(env);
- }
-
- compute_observations(env);
-}
-
-void c_close_client(Client *client) {
- CloseWindow();
- free(client);
-}
-
-void c_close(DroneSwarm *env) {
- if (env->client != NULL) {
- c_close_client(env->client);
- }
-}
-
-static void update_camera_position(Client *c) {
- float r = c->camera_distance;
- float az = c->camera_azimuth;
- float el = c->camera_elevation;
-
- float x = r * cosf(el) * cosf(az);
- float y = r * cosf(el) * sinf(az);
- float z = r * sinf(el);
-
- c->camera.position = (Vector3){x, y, z};
- c->camera.target = (Vector3){0, 0, 0};
-}
-
-void handle_camera_controls(Client *client) {
- Vector2 mouse_pos = GetMousePosition();
-
- if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
- client->is_dragging = true;
- client->last_mouse_pos = mouse_pos;
- }
-
- if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) {
- client->is_dragging = false;
- }
-
- if (client->is_dragging && IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
- Vector2 mouse_delta = {mouse_pos.x - client->last_mouse_pos.x,
- mouse_pos.y - client->last_mouse_pos.y};
-
- float sensitivity = 0.005f;
-
- client->camera_azimuth -= mouse_delta.x * sensitivity;
-
- client->camera_elevation += mouse_delta.y * sensitivity;
- client->camera_elevation =
- clampf(client->camera_elevation, -PI / 2.0f + 0.1f, PI / 2.0f - 0.1f);
-
- client->last_mouse_pos = mouse_pos;
-
- update_camera_position(client);
- }
-
- float wheel = GetMouseWheelMove();
- if (wheel != 0) {
- client->camera_distance -= wheel * 2.0f;
- client->camera_distance = clampf(client->camera_distance, 5.0f, 50.0f);
- update_camera_position(client);
- }
-}
-
-Client *make_client(DroneSwarm *env) {
- Client *client = (Client *)calloc(1, sizeof(Client));
-
- client->width = WIDTH;
- client->height = HEIGHT;
-
- SetConfigFlags(FLAG_MSAA_4X_HINT); // antialiasing
- InitWindow(WIDTH, HEIGHT, "PufferLib DroneSwarm");
-
-#ifndef __EMSCRIPTEN__
- SetTargetFPS(60);
-#endif
-
- if (!IsWindowReady()) {
- TraceLog(LOG_ERROR, "Window failed to initialize\n");
- free(client);
- return NULL;
- }
-
- client->camera_distance = 40.0f;
- client->camera_azimuth = 0.0f;
- client->camera_elevation = PI / 10.0f;
- client->is_dragging = false;
- client->last_mouse_pos = (Vector2){0.0f, 0.0f};
-
- client->camera.up = (Vector3){0.0f, 0.0f, 1.0f};
- client->camera.fovy = 45.0f;
- client->camera.projection = CAMERA_PERSPECTIVE;
-
- update_camera_position(client);
-
- // Initialize trail buffer
- client->trails = (Trail*)calloc(env->num_agents, sizeof(Trail));
- for (int i = 0; i < env->num_agents; i++) {
- Trail* trail = &client->trails[i];
- trail->index = 0;
- trail->count = 0;
- for (int j = 0; j < TRAIL_LENGTH; j++) {
- trail->pos[j] = env->agents[i].pos;
- }
- }
-
- return client;
-}
-
-const Color PUFF_RED = (Color){187, 0, 0, 255};
-const Color PUFF_CYAN = (Color){0, 187, 187, 255};
-const Color PUFF_WHITE = (Color){241, 241, 241, 241};
-const Color PUFF_BACKGROUND = (Color){6, 24, 24, 255};
-
-void DrawRing3D(Ring ring, float thickness, Color entryColor, Color exitColor) {
- float half_thick = thickness / 2.0f;
-
- Vector3 center_pos = {ring.pos.x, ring.pos.y, ring.pos.z};
-
- Vector3 entry_start_pos = {center_pos.x - half_thick * ring.normal.x,
- center_pos.y - half_thick * ring.normal.y,
- center_pos.z - half_thick * ring.normal.z};
-
- DrawCylinderWiresEx(entry_start_pos, center_pos, ring.radius, ring.radius, 32, entryColor);
-
- Vector3 exit_end_pos = {center_pos.x + half_thick * ring.normal.x,
- center_pos.y + half_thick * ring.normal.y,
- center_pos.z + half_thick * ring.normal.z};
-
- DrawCylinderWiresEx(center_pos, exit_end_pos, ring.radius, ring.radius, 32, exitColor);
-}
-
-
-void c_render(DroneSwarm *env) {
- if (env->client == NULL) {
- env->client = make_client(env);
- if (env->client == NULL) {
- TraceLog(LOG_ERROR, "Failed to initialize client for rendering\n");
- return;
- }
- }
-
- if (WindowShouldClose()) {
- c_close(env);
- exit(0);
- }
-
- if (IsKeyDown(KEY_ESCAPE)) {
- c_close(env);
- exit(0);
- }
-
- if (IsKeyPressed(KEY_SPACE)) {
- env->task = (env->task + 1) % TASK_N;
- for (int i = 0; i < env->num_agents; i++) {
- set_target(env, i);
- }
- }
-
- handle_camera_controls(env->client);
-
- Client *client = env->client;
-
- for (int i = 0; i < env->num_agents; i++) {
- Drone *agent = &env->agents[i];
- Trail *trail = &client->trails[i];
- trail->pos[trail->index] = agent->pos;
- trail->index = (trail->index + 1) % TRAIL_LENGTH;
- if (trail->count < TRAIL_LENGTH) {
- trail->count++;
- }
- if (env->terminals[i]) {
- trail->index = 0;
- trail->count = 0;
- }
- }
-
- BeginDrawing();
- ClearBackground(PUFF_BACKGROUND);
-
- BeginMode3D(client->camera);
-
- // draws bounding cube
- DrawCubeWires((Vector3){0.0f, 0.0f, 0.0f}, GRID_X * 2.0f,
- GRID_Y * 2.0f, GRID_Z * 2.0f, WHITE);
-
- for (int i = 0; i < env->num_agents; i++) {
- Drone *agent = &env->agents[i];
-
- // draws drone body
- Color body_color = FLAG_COLORS[i];
- DrawSphere((Vector3){agent->pos.x, agent->pos.y, agent->pos.z}, 0.3f, body_color);
-
- // draws rotors according to thrust
- float T[4];
- for (int j = 0; j < 4; j++) {
- float rpm = (env->actions[4*i + j] + 1.0f) * 0.5f * agent->max_rpm;
- T[j] = agent->k_thrust * rpm * rpm;
- }
-
- const float rotor_radius = 0.15f;
- const float visual_arm_len = agent->arm_len * 4.0f;
-
- Vec3 rotor_offsets_body[4] = {{+visual_arm_len, 0.0f, 0.0f},
- {-visual_arm_len, 0.0f, 0.0f},
- {0.0f, +visual_arm_len, 0.0f},
- {0.0f, -visual_arm_len, 0.0f}};
-
- //Color base_colors[4] = {ORANGE, PURPLE, LIME, SKYBLUE};
- Color base_colors[4] = {body_color, body_color, body_color, body_color};
-
- for (int j = 0; j < 4; j++) {
- Vec3 world_off = quat_rotate(agent->quat, rotor_offsets_body[j]);
-
- Vector3 rotor_pos = {agent->pos.x + world_off.x, agent->pos.y + world_off.y,
- agent->pos.z + world_off.z};
-
- float rpm = (env->actions[4*i + j] + 1.0f) * 0.5f * agent->max_rpm;
- float intensity = 0.75f + 0.25f * (rpm / agent->max_rpm);
-
- Color rotor_color = (Color){(unsigned char)(base_colors[j].r * intensity),
- (unsigned char)(base_colors[j].g * intensity),
- (unsigned char)(base_colors[j].b * intensity), 255};
-
- DrawSphere(rotor_pos, rotor_radius, rotor_color);
-
- DrawCylinderEx((Vector3){agent->pos.x, agent->pos.y, agent->pos.z}, rotor_pos, 0.02f, 0.02f, 8,
- BLACK);
- }
-
- // draws line with direction and magnitude of velocity / 10
- if (norm3(agent->vel) > 0.1f) {
- DrawLine3D((Vector3){agent->pos.x, agent->pos.y, agent->pos.z},
- (Vector3){agent->pos.x + agent->vel.x * 0.1f, agent->pos.y + agent->vel.y * 0.1f,
- agent->pos.z + agent->vel.z * 0.1f},
- MAGENTA);
- }
-
- // Draw trailing path
- Trail *trail = &client->trails[i];
- if (trail->count <= 2) {
- continue;
- }
- for (int j = 0; j < trail->count - 1; j++) {
- int idx0 = (trail->index - j - 1 + TRAIL_LENGTH) % TRAIL_LENGTH;
- int idx1 = (trail->index - j - 2 + TRAIL_LENGTH) % TRAIL_LENGTH;
- float alpha = (float)(TRAIL_LENGTH - j) / (float)trail->count * 0.8f; // fade out
- Color trail_color = ColorAlpha((Color){0, 187, 187, 255}, alpha);
- DrawLine3D((Vector3){trail->pos[idx0].x, trail->pos[idx0].y, trail->pos[idx0].z},
- (Vector3){trail->pos[idx1].x, trail->pos[idx1].y, trail->pos[idx1].z},
- trail_color);
- }
-
- }
-
- // Rings
- if (env->task == TASK_RACE) {
- float ring_thickness = 0.2f;
- for (int i = 0; i < env->max_rings; i++) {
- Ring ring = env->ring_buffer[i];
- DrawRing3D(ring, ring_thickness, GREEN, BLUE);
- }
- }
-
- if (IsKeyDown(KEY_TAB)) {
- for (int i = 0; i < env->num_agents; i++) {
- Drone *agent = &env->agents[i];
- Vec3 target_pos = agent->target_pos;
- DrawSphere((Vector3){target_pos.x, target_pos.y, target_pos.z}, 0.45f, (Color){0, 255, 255, 100});
- }
- }
-
- EndMode3D();
-
- DrawText("Left click + drag: Rotate camera", 10, 10, 16, PUFF_WHITE);
- DrawText("Mouse wheel: Zoom in/out", 10, 30, 16, PUFF_WHITE);
- DrawText(TextFormat("Task: %s", TASK_NAMES[env->task]), 10, 50, 16, PUFF_WHITE);
-
- EndDrawing();
-}
diff --git a/pufferlib/ocean/drone_swarm/drone_swarm.py b/pufferlib/ocean/drone_swarm/drone_swarm.py
deleted file mode 100644
index 3503a7aa4..000000000
--- a/pufferlib/ocean/drone_swarm/drone_swarm.py
+++ /dev/null
@@ -1,94 +0,0 @@
-import numpy as np
-import gymnasium
-
-import pufferlib
-from pufferlib.ocean.drone_swarm import binding
-
-class DroneSwarm(pufferlib.PufferEnv):
- def __init__(
- self,
- num_envs=16,
- num_drones=64,
- max_rings=5,
- render_mode=None,
- report_interval=1024,
- buf=None,
- seed=0,
- ):
- self.single_observation_space = gymnasium.spaces.Box(
- low=-1,
- high=1,
- shape=(41,),
- dtype=np.float32,
- )
-
- self.single_action_space = gymnasium.spaces.Box(
- low=-1, high=1, shape=(4,), dtype=np.float32
- )
-
- self.num_agents = num_envs*num_drones
- self.render_mode = render_mode
- self.report_interval = report_interval
- self.tick = 0
-
- super().__init__(buf)
- self.actions = self.actions.astype(np.float32)
-
- c_envs = []
- for i in range(num_envs):
- c_envs.append(binding.env_init(
- self.observations[i*num_drones:(i+1)*num_drones],
- self.actions[i*num_drones:(i+1)*num_drones],
- self.rewards[i*num_drones:(i+1)*num_drones],
- self.terminals[i*num_drones:(i+1)*num_drones],
- self.truncations[i*num_drones:(i+1)*num_drones],
- i,
- num_agents=num_drones,
- max_rings=max_rings,
- ))
-
- self.c_envs = binding.vectorize(*c_envs)
-
- def reset(self, seed=None):
- self.tick = 0
- binding.vec_reset(self.c_envs, seed)
- return self.observations, []
-
- def step(self, actions):
- self.actions[:] = actions
-
- self.tick += 1
- binding.vec_step(self.c_envs)
-
- info = []
- if self.tick % self.report_interval == 0:
- log_data = binding.vec_log(self.c_envs)
- if log_data:
- info.append(log_data)
-
- return (self.observations, self.rewards, self.terminals, self.truncations, info)
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-def test_performance(timeout=10, atn_cache=1024):
- env = DroneSwarm(num_envs=1000)
- env.reset()
- tick = 0
-
- actions = [env.action_space.sample() for _ in range(atn_cache)]
-
- import time
- start = time.time()
- while time.time() - start < timeout:
- atn = actions[tick % atn_cache]
- env.step(atn)
- tick += 1
-
- print(f"SPS: {env.num_agents * tick / (time.time() - start)}")
-
-if __name__ == "__main__":
- test_performance()
diff --git a/pufferlib/ocean/drone_swarm/dronelib.h b/pufferlib/ocean/drone_swarm/dronelib.h
deleted file mode 100644
index 32435e81b..000000000
--- a/pufferlib/ocean/drone_swarm/dronelib.h
+++ /dev/null
@@ -1,414 +0,0 @@
-// Originally made by Sam Turner and Finlay Sanders, 2025.
-// Included in pufferlib under the original project's MIT license.
-// https://github.com/stmio/drone
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "raylib.h"
-
-// Visualisation properties
-#define WIDTH 1080
-#define HEIGHT 720
-#define TRAIL_LENGTH 50
-#define HORIZON 1024
-
-// Physical constants for the drone
-#define BASE_MASS 1.0f // kg
-#define BASE_IXX 0.01f // kgm^2
-#define BASE_IYY 0.01f // kgm^2
-#define BASE_IZZ 0.02f // kgm^2
-#define BASE_ARM_LEN 0.1f // m
-#define BASE_K_THRUST 3e-5f // thrust coefficient
-#define BASE_K_ANG_DAMP 0.2f // angular damping coefficient
-#define BASE_K_DRAG 1e-6f // drag (torque) coefficient
-#define BASE_B_DRAG 0.1f // linear drag coefficient
-#define BASE_GRAVITY 9.81f // m/s^2
-#define BASE_MAX_RPM 750.0f // rad/s
-#define BASE_MAX_VEL 50.0f // m/s
-#define BASE_MAX_OMEGA 50.0f // rad/s
-#define BASE_K_MOT 0.1f // s (Motor lag constant)
-#define BASE_J_MOT 1e-5f // kgm^2 (Motor rotational inertia)
-
-// Simulation properties
-#define GRID_X 30.0f
-#define GRID_Y 30.0f
-#define GRID_Z 10.0f
-#define MARGIN_X (GRID_X - 1)
-#define MARGIN_Y (GRID_Y - 1)
-#define MARGIN_Z (GRID_Z - 1)
-#define V_TARGET 0.05f
-#define DT 0.05f
-#define DT_RNG 0.0f
-
-// Corner to corner distance
-#define MAX_DIST sqrtf((2*GRID_X)*(2*GRID_X) + (2*GRID_Y)*(2*GRID_Y) + (2*GRID_Z)*(2*GRID_Z))
-
-typedef struct Log Log;
-struct Log {
- float episode_return;
- float episode_length;
- float rings_passed;
- float collision_rate;
- float oob;
- float score;
- float perf;
- float n;
-};
-
-typedef struct {
- float w, x, y, z;
-} Quat;
-
-typedef struct {
- float x, y, z;
-} Vec3;
-
-static inline float clampf(float v, float min, float max) {
- if (v < min)
- return min;
- if (v > max)
- return max;
- return v;
-}
-
-static inline float rndf(float a, float b) {
- return a + ((float)rand() / (float)RAND_MAX) * (b - a);
-}
-
-static inline Vec3 add3(Vec3 a, Vec3 b) { return (Vec3){a.x + b.x, a.y + b.y, a.z + b.z}; }
-
-static inline Vec3 sub3(Vec3 a, Vec3 b) { return (Vec3){a.x - b.x, a.y - b.y, a.z - b.z}; }
-
-static inline Vec3 scalmul3(Vec3 a, float b) { return (Vec3){a.x * b, a.y * b, a.z * b}; }
-
-static inline float dot3(Vec3 a, Vec3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; }
-
-static inline float norm3(Vec3 a) { return sqrtf(dot3(a, a)); }
-
-static inline void clamp3(Vec3 *vec, float min, float max) {
- vec->x = clampf(vec->x, min, max);
- vec->y = clampf(vec->y, min, max);
- vec->z = clampf(vec->z, min, max);
-}
-
-static inline void clamp4(float a[4], float min, float max) {
- a[0] = clampf(a[0], min, max);
- a[1] = clampf(a[1], min, max);
- a[2] = clampf(a[2], min, max);
- a[3] = clampf(a[3], min, max);
-}
-
-static inline Quat quat_mul(Quat q1, Quat q2) {
- Quat out;
- out.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z;
- out.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y;
- out.y = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x;
- out.z = q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w;
- return out;
-}
-
-static inline void quat_normalize(Quat *q) {
- float n = sqrtf(q->w * q->w + q->x * q->x + q->y * q->y + q->z * q->z);
- if (n > 0.0f) {
- q->w /= n;
- q->x /= n;
- q->y /= n;
- q->z /= n;
- }
-}
-
-static inline Vec3 quat_rotate(Quat q, Vec3 v) {
- Quat qv = {0.0f, v.x, v.y, v.z};
- Quat tmp = quat_mul(q, qv);
- Quat q_conj = {q.w, -q.x, -q.y, -q.z};
- Quat res = quat_mul(tmp, q_conj);
- return (Vec3){res.x, res.y, res.z};
-}
-
-static inline Quat quat_inverse(Quat q) { return (Quat){q.w, -q.x, -q.y, -q.z}; }
-
-Quat rndquat() {
- float u1 = rndf(0.0f, 1.0f);
- float u2 = rndf(0.0f, 1.0f);
- float u3 = rndf(0.0f, 1.0f);
-
- float sqrt_1_minus_u1 = sqrtf(1.0f - u1);
- float sqrt_u1 = sqrtf(u1);
-
- float pi_2_u2 = 2.0f * M_PI * u2;
- float pi_2_u3 = 2.0f * M_PI * u3;
-
- Quat q;
- q.w = sqrt_1_minus_u1 * sinf(pi_2_u2);
- q.x = sqrt_1_minus_u1 * cosf(pi_2_u2);
- q.y = sqrt_u1 * sinf(pi_2_u3);
- q.z = sqrt_u1 * cosf(pi_2_u3);
-
- return q;
-}
-
-typedef struct {
- Vec3 pos;
- Quat orientation;
- Vec3 normal;
- float radius;
-} Ring;
-
-Ring rndring(float radius) {
- Ring ring;
-
- ring.pos.x = rndf(-GRID_X + 2*radius, GRID_X - 2*radius);
- ring.pos.y = rndf(-GRID_Y + 2*radius, GRID_Y - 2*radius);
- ring.pos.z = rndf(-GRID_Z + 2*radius, GRID_Z - 2*radius);
-
- ring.orientation = rndquat();
-
- Vec3 base_normal = {0.0f, 0.0f, 1.0f};
- ring.normal = quat_rotate(ring.orientation, base_normal);
-
- ring.radius = radius;
-
- return ring;
-}
-
-typedef struct {
- Vec3 pos[TRAIL_LENGTH];
- int index;
- int count;
-} Trail;
-
-
-typedef struct {
- Vec3 spawn_pos;
- Vec3 pos; // global position (x, y, z)
- Vec3 prev_pos;
- Vec3 vel; // linear velocity (u, v, w)
- Quat quat; // roll/pitch/yaw (phi/theta/psi) as a quaternion
- Vec3 omega; // angular velocity (p, q, r)
- float rpms[4]; // motor RPMs
-
- Vec3 target_pos;
- Vec3 target_vel;
-
- float last_abs_reward;
- float last_target_reward;
- float last_collision_reward;
- float episode_return;
- float collisions;
- int episode_length;
- float score;
- int ring_idx;
-
- // Physical properties. Modeled as part of the drone
- // to make domain randomization easier.
- float mass; // kg
- float ixx; // kgm^2
- float iyy; // kgm^2
- float izz; // kgm^2
- float arm_len; // m
- float k_thrust; // thrust coefficient
- float k_ang_damp; // angular damping coefficient
- float k_drag; // drag (torque) coefficient
- float b_drag; // linear drag coefficient
- float gravity; // m/s^2
- float max_rpm; // rad/s
- float max_vel; // m/s
- float max_omega; // rad/s
- float k_mot; // s
- float j_mot; // kgm^2
-} Drone;
-
-
-void init_drone(Drone* drone, float size, float dr) {
- drone->arm_len = size / 2.0f;
-
- // m ~ x^3
- float mass_scale = powf(drone->arm_len, 3.0f) / powf(BASE_ARM_LEN, 3.0f);
- drone->mass = BASE_MASS * mass_scale * rndf(1.0f - dr, 1.0f + dr);
-
- // I ~ mx^2
- float base_Iscale = BASE_MASS * BASE_ARM_LEN * BASE_ARM_LEN;
- float I_scale = drone->mass * powf(drone->arm_len, 2.0f) / base_Iscale;
- drone->ixx = BASE_IXX * I_scale * rndf(1.0f - dr, 1.0f + dr);
- drone->iyy = BASE_IYY * I_scale * rndf(1.0f - dr, 1.0f + dr);
- drone->izz = BASE_IZZ * I_scale * rndf(1.0f - dr, 1.0f + dr);
-
- // k_thrust ~ m/l
- float k_thrust_scale = (drone->mass * drone->arm_len) / (BASE_MASS * BASE_ARM_LEN);
- drone->k_thrust = BASE_K_THRUST * k_thrust_scale * rndf(1.0f - dr, 1.0f + dr);
-
- // k_ang_damp ~ I
- float base_avg_inertia = (BASE_IXX + BASE_IYY + BASE_IZZ) / 3.0f;
- float avg_inertia = (drone->ixx + drone->iyy + drone->izz) / 3.0f;
- float avg_inertia_scale = avg_inertia / base_avg_inertia;
- drone->k_ang_damp = BASE_K_ANG_DAMP * avg_inertia_scale * rndf(1.0f - dr, 1.0f + dr);
-
- // drag ~ x^2
- float drag_scale = powf(drone->arm_len, 2.0f) / powf(BASE_ARM_LEN, 2.0f);
- drone->k_drag = BASE_K_DRAG * drag_scale * rndf(1.0f - dr, 1.0f + dr);
- drone->b_drag = BASE_B_DRAG * drag_scale * rndf(1.0f - dr, 1.0f + dr);
-
- // Small gravity randomization
- drone->gravity = BASE_GRAVITY * rndf(0.99f, 1.01f);
-
- // RPM ~ 1/x
- float rpm_scale = (BASE_ARM_LEN) / (drone->arm_len);
- drone->max_rpm = BASE_MAX_RPM * rpm_scale * rndf(1.0f - dr, 1.0f + dr);
-
- drone->max_vel = BASE_MAX_VEL;
- drone->max_omega = BASE_MAX_OMEGA;
-
- for (int i = 0; i < 4; i++) {
- drone->rpms[i] = 0.0f;
- }
- drone->k_mot = BASE_K_MOT * rndf(1.0f - dr, 1.0f + dr);
- drone->j_mot = BASE_J_MOT * I_scale * rndf(1.0f - dr, 1.0f + dr);
-}
-
-void explicit_euler(Drone* drone, Vec3 v_dot, Quat q_dot, Vec3 w_dot, float rpm_dot[4], float dt) {
- drone->pos.x += drone->vel.x * dt;
- drone->pos.y += drone->vel.y * dt;
- drone->pos.z += drone->vel.z * dt;
-
- drone->vel.x += v_dot.x * dt;
- drone->vel.y += v_dot.y * dt;
- drone->vel.z += v_dot.z * dt;
-
- drone->omega.x += w_dot.x * dt;
- drone->omega.y += w_dot.y * dt;
- drone->omega.z += w_dot.z * dt;
-
- drone->quat.w += q_dot.w * dt;
- drone->quat.x += q_dot.x * dt;
- drone->quat.y += q_dot.y * dt;
- drone->quat.z += q_dot.z * dt;
-
- drone->rpms[0] += rpm_dot[0] * dt;
- drone->rpms[1] += rpm_dot[1] * dt;
- drone->rpms[2] += rpm_dot[2] * dt;
- drone->rpms[3] += rpm_dot[3] * dt;
-}
-
-void move_drone(Drone* drone, float* actions) {
- // Physics outlined in:
- // https://pmc.ncbi.nlm.nih.gov/articles/PMC10468397/pdf/41586_2023_Article_6419.pdf
- clamp4(actions, -1.0f, 1.0f);
-
- // first order rpm lag
- float target_rpms[4];
- for (int i = 0; i < 4; i++) {
- target_rpms[i] = (actions[i] + 1.0f) * 0.5f * drone->max_rpm;
- }
-
- // rpm rates
- float rpm_dot[4];
- for (int i = 0; i < 4; i++) {
- rpm_dot[i] = (1.0f / drone->k_mot) * (target_rpms[i] - drone->rpms[i]);
- }
-
- // motor thrusts
- float T[4];
- for (int i = 0; i < 4; i++) {
- T[i] = drone->k_thrust * powf(drone->rpms[i], 2.0f);
- }
-
- // body frame net force
- Vec3 F_prop_body = {0.0f, 0.0f, T[0] + T[1] + T[2] + T[3]};
-
- // body frame force -> world frame force
- Vec3 F_prop = quat_rotate(drone->quat, F_prop_body);
-
- // world frame linear drag
- Vec3 F_aero;
- F_aero.x = -drone->b_drag * drone->vel.x;
- F_aero.y = -drone->b_drag * drone->vel.y;
- F_aero.z = -drone->b_drag * drone->vel.z;
-
- // velocity rates, a = F/m
- Vec3 v_dot;
- v_dot.x = (F_prop.x + F_aero.x) / drone->mass;
- v_dot.y = (F_prop.y + F_aero.y) / drone->mass;
- v_dot.z = ((F_prop.z + F_aero.z) / drone->mass) - drone->gravity;
-
- // quaternion rates
- Quat omega_q = {0.0f, drone->omega.x, drone->omega.y, drone->omega.z};
- Quat q_dot = quat_mul(drone->quat, omega_q);
- q_dot.w *= 0.5f;
- q_dot.x *= 0.5f;
- q_dot.y *= 0.5f;
- q_dot.z *= 0.5f;
-
- // body frame torques
- Vec3 Tau_prop;
- Tau_prop.x = drone->arm_len*(T[1] - T[3]);
- Tau_prop.y = drone->arm_len*(T[2] - T[0]);
- Tau_prop.z = drone->k_drag*(T[0] - T[1] + T[2] - T[3]);
-
- // torque from chaging motor speeds
- float Tau_mot_z = drone->j_mot * (rpm_dot[0] - rpm_dot[1] + rpm_dot[2] - rpm_dot[3]);
-
- // torque from angular damping
- Vec3 Tau_aero;
- Tau_aero.x = -drone->k_ang_damp * drone->omega.x;
- Tau_aero.y = -drone->k_ang_damp * drone->omega.y;
- Tau_aero.z = -drone->k_ang_damp * drone->omega.z;
-
- // gyroscopic torque
- Vec3 Tau_iner;
- Tau_iner.x = (drone->iyy - drone->izz) * drone->omega.y * drone->omega.z;
- Tau_iner.y = (drone->izz - drone->ixx) * drone->omega.z * drone->omega.x;
- Tau_iner.z = (drone->ixx - drone->iyy) * drone->omega.x * drone->omega.y;
-
- // angular velocity rates
- Vec3 w_dot;
- w_dot.x = (Tau_prop.x + Tau_aero.x + Tau_iner.x) / drone->ixx;
- w_dot.y = (Tau_prop.y + Tau_aero.y + Tau_iner.y) / drone->iyy;
- w_dot.z = (Tau_prop.z + Tau_aero.z + Tau_iner.z + Tau_mot_z) / drone->izz;
-
- // Domain randomized dt
- float dt = DT * rndf(1.0f - DT_RNG, 1.0 + DT_RNG);
-
- // update drone state
- drone->prev_pos = drone->pos;
- explicit_euler(drone, v_dot, q_dot, w_dot, rpm_dot, dt);
-
- // clamp and normalise for observations
- clamp3(&drone->vel, -drone->max_vel, drone->max_vel);
- clamp3(&drone->omega, -drone->max_omega, drone->max_omega);
- quat_normalize(&drone->quat);
-}
-
-float check_ring(Drone* drone, Ring* ring) {
- // previous dot product negative if on the 'entry' side of the ring's plane
- float prev_dot = dot3(sub3(drone->prev_pos, ring->pos), ring->normal);
-
- // new dot product positive if on the 'exit' side of the ring's plane
- float new_dot = dot3(sub3(drone->pos, ring->pos), ring->normal);
-
- bool valid_dir = (prev_dot < 0.0f && new_dot > 0.0f);
- bool invalid_dir = (prev_dot > 0.0f && new_dot < 0.0f);
-
- // if we have crossed the plane of the ring
- if (valid_dir || invalid_dir) {
- // find intesection with ring's plane
- Vec3 dir = sub3(drone->pos, drone->prev_pos);
- float t = -prev_dot / dot3(ring->normal, dir); // possible nan
-
- Vec3 intersection = add3(drone->prev_pos, scalmul3(dir, t));
- float dist = norm3(sub3(intersection, ring->pos));
-
- // reward or terminate based on distance to ring center
- if (dist < (ring->radius - 0.5) && valid_dir) {
- return 1.0f;
- } else if (dist < ring->radius + 0.5) {
- return -0.0f;
- }
- }
- return 0.0f;
-}
diff --git a/pufferlib/ocean/enduro/binding.c b/pufferlib/ocean/enduro/binding.c
deleted file mode 100644
index 04919d12d..000000000
--- a/pufferlib/ocean/enduro/binding.c
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "enduro.h"
-#include
-#define Env Enduro
-#include "../env_binding.h"
-
-static int my_init(Env* env, PyObject* args, PyObject* kwargs) {
- env->width = unpack(kwargs, "width");
- env->height = unpack(kwargs, "height");
- env->car_width = unpack(kwargs, "car_width");
- env->car_height = unpack(kwargs, "car_height");
- env->max_enemies = unpack(kwargs, "max_enemies");
- env->continuous = unpack(kwargs, "continuous");
-
- PyObject* seed_val = PyDict_GetItemString(kwargs, "seed");
- if (seed_val) {
- env->seed = unpack(kwargs, "seed");
- // Initialize the RNG state with the seed
- env->rng_state = env->seed;
- }
-
- return 0;
-}
-
-static int my_log(PyObject* dict, Log* log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "episode_length", log->episode_length);
- assign_to_dict(dict, "reward", log->reward);
- assign_to_dict(dict, "step_rew_car_passed_no_crash", log->step_rew_car_passed_no_crash);
- assign_to_dict(dict, "crashed_penalty", log->crashed_penalty);
- assign_to_dict(dict, "passed_cars", log->passed_cars);
- assign_to_dict(dict, "passed_by_enemy", log->passed_by_enemy);
- assign_to_dict(dict, "cars_to_pass", log->cars_to_pass);
- assign_to_dict(dict, "days_completed", log->days_completed);
- assign_to_dict(dict, "days_failed", log->days_failed);
- assign_to_dict(dict, "collisions_player_vs_car", log->collisions_player_vs_car);
- assign_to_dict(dict, "collisions_player_vs_road", log->collisions_player_vs_road);
- return 0;
-}
diff --git a/pufferlib/ocean/enduro/enduro.c b/pufferlib/ocean/enduro/enduro.c
deleted file mode 100644
index 01cbe15fa..000000000
--- a/pufferlib/ocean/enduro/enduro.c
+++ /dev/null
@@ -1,97 +0,0 @@
-// puffer_enduro.c
-
-#define MAX_ENEMIES 10
-
-#include
-#include
-#include
-#include
-#include "enduro.h"
-#include "raylib.h"
-#include "puffernet.h"
-
-void get_input(Enduro* env) {
- if ((IsKeyDown(KEY_DOWN) && IsKeyDown(KEY_RIGHT)) || (IsKeyDown(KEY_S) && IsKeyDown(KEY_D))) {
- env->actions[0] = ACTION_DOWNRIGHT; // Decelerate and move right
- } else if ((IsKeyDown(KEY_DOWN) && IsKeyDown(KEY_LEFT)) || (IsKeyDown(KEY_S) && IsKeyDown(KEY_A))) {
- env->actions[0] = ACTION_DOWNLEFT; // Decelerate and move left
- } else if (IsKeyDown(KEY_SPACE) && (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D))) {
- env->actions[0] = ACTION_RIGHTFIRE; // Accelerate and move right
- } else if (IsKeyDown(KEY_SPACE) && (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A))) {
- env->actions[0] = ACTION_LEFTFIRE; // Accelerate and move left
- } else if (IsKeyDown(KEY_SPACE)) {
- env->actions[0] = ACTION_FIRE; // Accelerate
- } else if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)) {
- env->actions[0] = ACTION_DOWN; // Decelerate
- } else if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) {
- env->actions[0] = ACTION_LEFT; // Move left
- } else if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) {
- env->actions[0] = ACTION_RIGHT; // Move right
- } else {
- env->actions[0] = ACTION_NOOP; // No action
- }
-}
-
-int demo() {
- Weights* weights = load_weights("resources/enduro/enduro_weights.bin", 142218);
- int logit_sizes[1] = {9};
- LinearLSTM* net = make_linearlstm(weights, 1, 68, logit_sizes, 1);
-
- Enduro env = {
- .num_envs = 1,
- .max_enemies = MAX_ENEMIES,
- .obs_size = OBSERVATIONS_MAX_SIZE
- };
-
- allocate(&env);
-
- init(&env);
- c_reset(&env);
- c_render(&env);
-
- while (!WindowShouldClose()) {
- if (IsKeyDown(KEY_LEFT_SHIFT)) {
- get_input(&env);
- } else {
- forward_linearlstm(net, env.observations, env.actions);
- }
-
- c_step(&env);
- c_render(&env);
- }
-
- free_linearlstm(net);
- free(weights);
- free_allocated(&env);
- return 0;
-}
-
-void perftest(float test_time) {
- Enduro env = {
- .num_envs = 1,
- .max_enemies = MAX_ENEMIES,
- .obs_size = OBSERVATIONS_MAX_SIZE
- };
-
- allocate(&env);
- init(&env);
- c_reset(&env);
-
- int start = time(NULL);
- int i = 0;
- while (time(NULL) - start < test_time) {
- env.actions[0] = rand()%9;
- c_step(&env);
- i++;
- }
-
- int end = time(NULL);
- printf("SPS: %f\n", i / (float)(end - start));
- free_allocated(&env);
-}
-
-int main() {
- demo();
- //perftest(10.0f);
- return 0;
-}
diff --git a/pufferlib/ocean/enduro/enduro.h b/pufferlib/ocean/enduro/enduro.h
deleted file mode 100644
index 0961caf3c..000000000
--- a/pufferlib/ocean/enduro/enduro.h
+++ /dev/null
@@ -1,2268 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "raylib.h"
-
-// Constant defs
-#define MAX_ENEMIES 10
-#define OBSERVATIONS_MAX_SIZE (8 + (5 * MAX_ENEMIES) + 9 + 1)
-#define TARGET_FPS 60 // Used to calculate wiggle spawn frequency
-#define LOG_BUFFER_SIZE 4096
-#define SCREEN_WIDTH 152
-#define SCREEN_HEIGHT 210
-#define PLAYABLE_AREA_TOP 0
-#define PLAYABLE_AREA_BOTTOM 154
-#define PLAYABLE_AREA_LEFT 0
-#define PLAYABLE_AREA_RIGHT 152
-#define ACTION_HEIGHT (PLAYABLE_AREA_BOTTOM - PLAYABLE_AREA_TOP)
-#define CAR_WIDTH 16
-#define CAR_HEIGHT 11
-#define CRASH_NOOP_DURATION_CAR_VS_CAR 90 // How long controls are disabled after car v car collision
-#define CRASH_NOOP_DURATION_CAR_VS_ROAD 20 // How long controls are disabled after car v road edge collision
-#define INITIAL_CARS_TO_PASS 200
-#define VANISHING_POINT_Y 52
-#define VANISHING_POINT_TRANSITION_SPEED 1.0f
-#define CURVE_TRANSITION_SPEED 0.05f
-#define LOGICAL_VANISHING_Y (VANISHING_POINT_Y + 12) // Separate logical vanishing point for cars disappearing
-#define PLAYER_MAX_Y (ACTION_HEIGHT - CAR_HEIGHT) // Max y is car length from bottom
-#define PLAYER_MIN_Y (ACTION_HEIGHT - CAR_HEIGHT - 9) // Min y is 2 car lengths from bottom
-#define ACCELERATION_RATE 0.2f
-#define DECELERATION_RATE 0.01f
-#define MIN_SPEED -2.5f
-#define MAX_SPEED 7.5f
-#define ENEMY_CAR_SPEED 0.1f
-
-const float MAX_SPAWN_INTERVALS[] = {0.5f, 0.25f, 0.4f};
-
-// Times of day logic
-#define NUM_BACKGROUND_TRANSITIONS 16
-// Seconds spent in each time of day
-static const float BACKGROUND_TRANSITION_TIMES[] = {
- 20.0f, 40.0f, 60.0f, 100.0f, 108.0f, 114.0f, 116.0f, 120.0f,
- 124.0f, 130.0f, 134.0f, 138.0f, 170.0f, 198.0f, 214.0f, 232.0f
-};
-
-// Curve constants
-#define CURVE_STRAIGHT 0
-#define CURVE_LEFT -1
-#define CURVE_RIGHT 1
-#define NUM_LANES 3
-#define CURVE_VANISHING_POINT_SHIFT 55.0f
-#define CURVE_PLAYER_SHIFT_FACTOR 0.025f // Moves player car towards outside edge of curves
-
-// Curve wiggle effect timing and amplitude
-#define WIGGLE_AMPLITUDE 10.0f // Maximum 'bump-in' offset in pixels
-#define WIGGLE_SPEED 10.1f // Speed at which the wiggle moves down the screen
-#define WIGGLE_LENGTH 26.0f // Vertical length of the wiggle effect
-
-
-// Rendering constants
-#define SCORE_DIGITS 5
-#define CARS_DIGITS 4
-#define DIGIT_WIDTH 8
-#define DIGIT_HEIGHT 9
-
-// Magic numbers - don't change
-// The below block is specific to resolution 152x210px
-#define INITIAL_PLAYER_X 69.0f // Adjusted from 77.0f
-#define PLAYER_MIN_X 57.5f // Adjusted from 65.5f
-#define PLAYER_MAX_X 83.5f // Adjusted from 91.5f
-#define VANISHING_POINT_X 78.0f // Adjusted from 86
-#define VANISHING_POINT_X_LEFT 102.0f // Adjusted from 110.0f
-#define VANISHING_POINT_X_RIGHT 54.0f // Adjusted from 62.0f
-#define ROAD_LEFT_OFFSET 46.0f // Adjusted from 50.0f
-#define ROAD_RIGHT_OFFSET 47.0f // Adjusted from 51.0f
-
-#define CONTINUOUS_SCALE (1) // Scale enemy cars continuously with y?
-
-typedef struct Log Log;
-struct Log {
- float perf;
- float score;
- float episode_return;
- float episode_length;
- float reward;
- float step_rew_car_passed_no_crash;
- float crashed_penalty;
- float passed_cars;
- float passed_by_enemy;
- float cars_to_pass;
- float days_completed;
- float days_failed;
- float collisions_player_vs_car;
- float collisions_player_vs_road;
- float n;
-};
-
-// Car struct for enemy cars
-typedef struct Car {
- int lane; // Lane index: 0=left lane, 1=mid, 2=right lane
- float x; // Current x position
- float y; // Current y position
- float last_x; // x post last step
- float last_y; // y post last step
- int passed; // Flag to indicate if car has been passed by player
- int colorIndex; // Car color idx (0-5)
-} Car;
-
-// Rendering struct
-typedef struct GameState {
- Texture2D spritesheet;
- RenderTexture2D renderTarget; // for scaling up render
- // Indices into asset_map[] for various assets
- int backgroundIndices[16];
- int mountainIndices[16];
- int digitIndices[11]; // 0-9 and "CAR"
- int greenDigitIndices[10]; // Green digits 0-9
- int yellowDigitIndices[10]; // Yellow digits 0-9
- // Enemy car indices: [color][tread]
- int enemyCarIndices[6][2];
- int enemyCarNightTailLightsIndex;
- int enemyCarNightFogTailLightsIndex;
- // Player car indices
- int playerCarLeftTreadIndex;
- int playerCarRightTreadIndex;
- // Flag indices
- int levelCompleteFlagLeftIndex;
- int levelCompleteFlagRightIndex;
- // For car animation
- float carAnimationTimer;
- float carAnimationInterval;
- unsigned char showLeftTread;
- float mountainPosition; // Position of the mountain texture
- // Variables for alternating flags
- unsigned char victoryAchieved;
- int flagTimer;
- unsigned char showLeftFlag; // true shows left flag, false shows right flag
- int victoryDisplayTimer; // Timer for how long victory effects have been displayed
- // Variables for scrolling yellow digits
- float yellowDigitOffset; // Offset for scrolling effect
- int yellowDigitCurrent; // Current yellow digit being displayed
- int yellowDigitNext; // Next yellow digit to scroll in
- // Variables for scrolling digits
- float scoreDigitOffsets[SCORE_DIGITS]; // Offset for scrolling effect for each digit
- int scoreDigitCurrents[SCORE_DIGITS]; // Current digit being displayed for each position
- int scoreDigitNexts[SCORE_DIGITS]; // Next digit to scroll in for each position
- unsigned char scoreDigitScrolling[SCORE_DIGITS]; // Scrolling state for each digit
- int scoreTimer; // Timer to control score increment
- int day;
- int carsLeftGameState;
- int score; // Score for scoreboard rendering
- // Background state vars
- int currentBackgroundIndex;
- int previousBackgroundIndex;
- float elapsedTime;
- // Variable needed from Enduro to maintain separation
- float speed;
- float min_speed;
- float max_speed;
- int current_curve_direction;
- float current_curve_factor;
- float player_x;
- float player_y;
- float initial_player_x;
- float vanishing_point_x;
- float t_p;
- unsigned char dayCompleted;
-} GameState;
-
-typedef struct Client Client;
-typedef struct Enduro Enduro;
-// Game environment struct
-typedef struct Enduro {
- Client* client;
- Log log;
- float* observations;
- int* actions;
- float* rewards;
- unsigned char* terminals;
- size_t obs_size;
- int num_envs;
- float width;
- float height;
- float car_width;
- float car_height;
- int max_enemies;
- float elapsedTimeEnv;
- int initial_cars_to_pass;
- float min_speed;
- float max_speed;
- float player_x;
- float player_y;
- float speed;
- int score;
- int day;
- int lane;
- int tick;
- int numEnemies;
- int carsToPass;
- float collision_cooldown_car_vs_car; // Timer for car vs car collisions
- float collision_cooldown_car_vs_road; // Timer for car vs road edge collisions
- int drift_direction; // Which way player car drifts whilst noops after crash w/ other car
- float action_height;
- Car enemyCars[MAX_ENEMIES];
- float initial_player_x;
- float road_scroll_offset;
- // Road curve variables
- int current_curve_stage;
- int steps_in_current_stage;
- int current_curve_direction; // 1: Right, -1: Left, 0: Straight
- float current_curve_factor;
- float target_curve_factor;
- float current_step_threshold;
- float target_vanishing_point_x; // Next curve direction vanishing point
- float current_vanishing_point_x; // Current interpolated vanishing point
- float base_target_vanishing_point_x; // Target for the base vanishing point
- float vanishing_point_x;
- float base_vanishing_point_x;
- float t_p;
- // Roadside wiggle effect
- float wiggle_y; // Current y position of the wiggle
- float wiggle_speed; // Speed at which the wiggle moves down the screen
- float wiggle_length; // Vertical length of the wiggle effect
- float wiggle_amplitude; // How far into road wiggle extends
- unsigned char wiggle_active; // Whether the wiggle is active
- // Player car acceleration
- int currentGear;
- float gearSpeedThresholds[4]; // Speeds at which gear changes occur
- float gearAccelerationRates[4]; // Acceleration rates per gear
- float gearTimings[4]; // Time durations per gear
- float gearElapsedTime; // Time spent in current gear
- // Enemy spawning
- float enemySpawnTimer;
- float enemySpawnInterval; // Spawn interval based on current stage
- // Enemy movement speed
- float enemySpeed;
- // Day completed (victory) variables
- unsigned char dayCompleted;
- // Logging
- float last_road_left;
- float last_road_right;
- int closest_edge_lane;
- int last_spawned_lane;
- // Vars that increment log struct
- float tracking_episode_return;
- float tracking_episode_length;
- float tracking_score;
- float tracking_reward;
- float tracking_step_rew_car_passed_no_crash;
- float tracking_crashed_penalty;
- float tracking_passed_cars;
- float tracking_passed_by_enemy;
- float tracking_cars_to_pass;
- float tracking_days_completed;
- float tracking_days_failed;
- float tracking_collisions_player_vs_car;
- float tracking_collisions_player_vs_road;
-
- // Rendering
- float parallaxFactor;
- // Variables for time of day
- float dayTransitionTimes[NUM_BACKGROUND_TRANSITIONS];
- int dayTimeIndex;
- int currentDayTimeIndex;
- int previousDayTimeIndex;
- // RNG
- unsigned int rng_state;
- int reset_count;
- // Rewards
- // Reward flag for stepwise rewards if car passed && !crashed
- // Effectively spreads out reward for passing cars
- unsigned char car_passed_no_crash_active;
- float step_rew_car_passed_no_crash;
- float crashed_penalty;
- int continuous;
-
- int seed;
-} Enduro;
-
-// Action enumeration
-typedef enum {
- ACTION_NOOP = 0,
- ACTION_FIRE = 1,
- ACTION_RIGHT = 2,
- ACTION_LEFT = 3,
- ACTION_DOWN = 4,
- ACTION_DOWNRIGHT = 5,
- ACTION_DOWNLEFT = 6,
- ACTION_RIGHTFIRE = 7,
- ACTION_LEFTFIRE = 8,
-} Action;
-
-Rectangle asset_map[] = {
- (Rectangle){ 328, 15, 152, 210 }, // 0_bg
- (Rectangle){ 480, 15, 152, 210 }, // 1_bg
- (Rectangle){ 632, 15, 152, 210 }, // 2_bg
- (Rectangle){ 784, 15, 152, 210 }, // 3_bg
- (Rectangle){ 0, 225, 152, 210 }, // 4_bg
- (Rectangle){ 152, 225, 152, 210 }, // 5_bg
- (Rectangle){ 304, 225, 152, 210 }, // 6_bg
- (Rectangle){ 456, 225, 152, 210 }, // 7_bg
- (Rectangle){ 608, 225, 152, 210 }, // 8_bg
- (Rectangle){ 760, 225, 152, 210 }, // 9_bg
- (Rectangle){ 0, 435, 152, 210 }, // 10_bg
- (Rectangle){ 152, 435, 152, 210 }, // 11_bg
- (Rectangle){ 304, 435, 152, 210 }, // 12_bg
- (Rectangle){ 456, 435, 152, 210 }, // 13_bg
- (Rectangle){ 608, 435, 152, 210 }, // 14_bg
- (Rectangle){ 760, 435, 152, 210 }, // 15_bg
- (Rectangle){ 0, 0, 100, 6 }, // 0_mtns
- (Rectangle){ 100, 0, 100, 6 }, // 1_mtns
- (Rectangle){ 200, 0, 100, 6 }, // 2_mtns
- (Rectangle){ 300, 0, 100, 6 }, // 3_mtns
- (Rectangle){ 400, 0, 100, 6 }, // 4_mtns
- (Rectangle){ 500, 0, 100, 6 }, // 5_mtns
- (Rectangle){ 600, 0, 100, 6 }, // 6_mtns
- (Rectangle){ 700, 0, 100, 6 }, // 7_mtns
- (Rectangle){ 800, 0, 100, 6 }, // 8_mtns
- (Rectangle){ 0, 6, 100, 6 }, // 9_mtns
- (Rectangle){ 100, 6, 100, 6 }, // 10_mtns
- (Rectangle){ 200, 6, 100, 6 }, // 11_mtns
- (Rectangle){ 300, 6, 100, 6 }, // 12_mtns
- (Rectangle){ 400, 6, 100, 6 }, // 13_mtns
- (Rectangle){ 500, 6, 100, 6 }, // 14_mtns
- (Rectangle){ 600, 6, 100, 6 }, // 15_mtns
- (Rectangle){ 700, 6, 8, 9 }, // digits_0
- (Rectangle){ 708, 6, 8, 9 }, // digits_1
- (Rectangle){ 716, 6, 8, 9 }, // digits_2
- (Rectangle){ 724, 6, 8, 9 }, // digits_3
- (Rectangle){ 732, 6, 8, 9 }, // digits_4
- (Rectangle){ 740, 6, 8, 9 }, // digits_5
- (Rectangle){ 748, 6, 8, 9 }, // digits_6
- (Rectangle){ 756, 6, 8, 9 }, // digits_7
- (Rectangle){ 764, 6, 8, 9 }, // digits_8
- (Rectangle){ 772, 6, 8, 9 }, // digits_9
- (Rectangle){ 780, 6, 8, 9 }, // digits_car
- (Rectangle){ 788, 6, 8, 9 }, // green_digits_0
- (Rectangle){ 796, 6, 8, 9 }, // green_digits_1
- (Rectangle){ 804, 6, 8, 9 }, // green_digits_2
- (Rectangle){ 812, 6, 8, 9 }, // green_digits_3
- (Rectangle){ 820, 6, 8, 9 }, // green_digits_4
- (Rectangle){ 828, 6, 8, 9 }, // green_digits_5
- (Rectangle){ 836, 6, 8, 9 }, // green_digits_6
- (Rectangle){ 844, 6, 8, 9 }, // green_digits_7
- (Rectangle){ 852, 6, 8, 9 }, // green_digits_8
- (Rectangle){ 860, 6, 8, 9 }, // green_digits_9
- (Rectangle){ 932, 6, 8, 9 }, // yellow_digits_0
- (Rectangle){ 0, 15, 8, 9 }, // yellow_digits_1
- (Rectangle){ 8, 15, 8, 9 }, // yellow_digits_2
- (Rectangle){ 16, 15, 8, 9 }, // yellow_digits_3
- (Rectangle){ 24, 15, 8, 9 }, // yellow_digits_4
- (Rectangle){ 32, 15, 8, 9 }, // yellow_digits_5
- (Rectangle){ 40, 15, 8, 9 }, // yellow_digits_6
- (Rectangle){ 48, 15, 8, 9 }, // yellow_digits_7
- (Rectangle){ 56, 15, 8, 9 }, // yellow_digits_8
- (Rectangle){ 64, 15, 8, 9 }, // yellow_digits_9
- (Rectangle){ 72, 15, 16, 11 }, // enemy_car_blue_left_tread
- (Rectangle){ 88, 15, 16, 11 }, // enemy_car_blue_right_tread
- (Rectangle){ 104, 15, 16, 11 }, // enemy_car_gold_left_tread
- (Rectangle){ 120, 15, 16, 11 }, // enemy_car_gold_right_tread
- (Rectangle){ 168, 15, 16, 11 }, // enemy_car_pink_left_tread
- (Rectangle){ 184, 15, 16, 11 }, // enemy_car_pink_right_tread
- (Rectangle){ 200, 15, 16, 11 }, // enemy_car_salmon_left_tread
- (Rectangle){ 216, 15, 16, 11 }, // enemy_car_salmon_right_tread
- (Rectangle){ 232, 15, 16, 11 }, // enemy_car_teal_left_tread
- (Rectangle){ 248, 15, 16, 11 }, // enemy_car_teal_right_tread
- (Rectangle){ 264, 15, 16, 11 }, // enemy_car_yellow_left_tread
- (Rectangle){ 280, 15, 16, 11 }, // enemy_car_yellow_right_tread
- (Rectangle){ 136, 15, 16, 11 }, // enemy_car_night_fog_tail_lights
- (Rectangle){ 152, 15, 16, 11 }, // enemy_car_night_tail_lights
- (Rectangle){ 296, 15, 16, 11 }, // player_car_left_tread
- (Rectangle){ 312, 15, 16, 11 }, // player_car_right_tread
- (Rectangle){ 900, 6, 32, 9 }, // level_complete_flag_right
- (Rectangle){ 868, 6, 32, 9 }, // level_complete_flag_left
-};
-
-enum AssetIndices {
- ASSET_BG_0 = 0,
- ASSET_BG_1 = 1,
- ASSET_BG_2 = 2,
- ASSET_BG_3 = 3,
- ASSET_BG_4 = 4,
- ASSET_BG_5 = 5,
- ASSET_BG_6 = 6,
- ASSET_BG_7 = 7,
- ASSET_BG_8 = 8,
- ASSET_BG_9 = 9,
- ASSET_BG_10 = 10,
- ASSET_BG_11 = 11,
- ASSET_BG_12 = 12,
- ASSET_BG_13 = 13,
- ASSET_BG_14 = 14,
- ASSET_BG_15 = 15,
-
- ASSET_MOUNTAIN_0 = 16,
- ASSET_MOUNTAIN_1,
- ASSET_MOUNTAIN_2,
- ASSET_MOUNTAIN_3,
- ASSET_MOUNTAIN_4,
- ASSET_MOUNTAIN_5,
- ASSET_MOUNTAIN_6,
- ASSET_MOUNTAIN_7,
- ASSET_MOUNTAIN_8,
- ASSET_MOUNTAIN_9,
- ASSET_MOUNTAIN_10,
- ASSET_MOUNTAIN_11,
- ASSET_MOUNTAIN_12,
- ASSET_MOUNTAIN_13,
- ASSET_MOUNTAIN_14,
- ASSET_MOUNTAIN_15,
- ASSET_DIGITS_0 = 32,
- ASSET_DIGITS_1 = 33,
- ASSET_DIGITS_2 = 34,
- ASSET_DIGITS_3 = 35,
- ASSET_DIGITS_4 = 36,
- ASSET_DIGITS_5 = 37,
- ASSET_DIGITS_6 = 38,
- ASSET_DIGITS_7 = 39,
- ASSET_DIGITS_8 = 40,
- ASSET_DIGITS_9 = 41,
- ASSET_DIGITS_CAR = 42,
- ASSET_GREEN_DIGITS_0 = 43,
- ASSET_GREEN_DIGITS_1 = 44,
- ASSET_GREEN_DIGITS_2 = 45,
- ASSET_GREEN_DIGITS_3 = 46,
- ASSET_GREEN_DIGITS_4 = 47,
- ASSET_GREEN_DIGITS_5 = 48,
- ASSET_GREEN_DIGITS_6 = 49,
- ASSET_GREEN_DIGITS_7 = 50,
- ASSET_GREEN_DIGITS_8 = 51,
- ASSET_GREEN_DIGITS_9 = 52,
- ASSET_YELLOW_DIGITS_0 = 53,
- ASSET_YELLOW_DIGITS_1 = 54,
- ASSET_YELLOW_DIGITS_2 = 55,
- ASSET_YELLOW_DIGITS_3 = 56,
- ASSET_YELLOW_DIGITS_4 = 57,
- ASSET_YELLOW_DIGITS_5 = 58,
- ASSET_YELLOW_DIGITS_6 = 59,
- ASSET_YELLOW_DIGITS_7 = 60,
- ASSET_YELLOW_DIGITS_8 = 61,
- ASSET_YELLOW_DIGITS_9 = 62,
- ASSET_ENEMY_CAR_BLUE_LEFT_TREAD = 63,
- ASSET_ENEMY_CAR_BLUE_RIGHT_TREAD = 64,
- ASSET_ENEMY_CAR_GOLD_LEFT_TREAD = 65,
- ASSET_ENEMY_CAR_GOLD_RIGHT_TREAD = 66,
- ASSET_ENEMY_CAR_PINK_LEFT_TREAD = 67,
- ASSET_ENEMY_CAR_PINK_RIGHT_TREAD = 68,
- ASSET_ENEMY_CAR_SALMON_LEFT_TREAD = 69,
- ASSET_ENEMY_CAR_SALMON_RIGHT_TREAD = 70,
- ASSET_ENEMY_CAR_TEAL_LEFT_TREAD = 71,
- ASSET_ENEMY_CAR_TEAL_RIGHT_TREAD = 72,
- ASSET_ENEMY_CAR_YELLOW_LEFT_TREAD = 73,
- ASSET_ENEMY_CAR_YELLOW_RIGHT_TREAD = 74,
- ASSET_ENEMY_CAR_NIGHT_FOG_TAIL_LIGHTS = 75,
- ASSET_ENEMY_CAR_NIGHT_TAIL_LIGHTS = 76,
- ASSET_PLAYER_CAR_LEFT_TREAD = 77,
- ASSET_PLAYER_CAR_RIGHT_TREAD = 78,
- ASSET_LEVEL_COMPLETE_FLAG_RIGHT = 79,
- ASSET_LEVEL_COMPLETE_FLAG_LEFT = 80,
-};
-
-// Client struct
-struct Client {
- float width;
- float height;
- GameState gameState;
-};
-
-// Prototypes //
-// RNG
-unsigned int xorshift32(unsigned int *state);
-
-// Logging
-void add_log(Enduro* env);
-
-// Environment functions
-void allocate(Enduro* env);
-void init(Enduro* env);
-void free_allocated(Enduro* env);
-void reset_round(Enduro* env);
-void c_reset(Enduro* env);
-unsigned char check_collision(Enduro* env, Car* car);
-int get_player_lane(Enduro* env);
-float get_car_scale(float y);
-void add_enemy_car(Enduro* env);
-void update_time_of_day(Enduro* env);
-void accelerate(Enduro* env);
-void c_step(Enduro* env);
-void update_road_curve(Enduro* env);
-float quadratic_bezier(float bottom_x, float control_x, float top_x, float t);
-float road_edge_x(Enduro* env, float y, float offset, unsigned char left);
-float car_x_in_lane(Enduro* env, int lane, float y);
-void compute_observations(Enduro* env);
-
-// Client functions
-Client* make_client(Enduro* env);
-void close_client(Client* client);
-void render_car(GameState* gameState);
-
-// GameState rendering functions
-void initRaylib(GameState* gameState);
-void loadTextures(GameState* gameState);
-void updateCarAnimation(GameState* gameState);
-void updateScoreboard(GameState* gameState);
-void renderBackground(GameState* gameState);
-void renderScoreboard(GameState* gameState);
-void updateMountains(GameState* gameState);
-void renderMountains(GameState* gameState);
-void updateVictoryEffects(GameState* gameState);
-void c_render(Enduro* env);
-void cleanup(GameState* gameState);
-
-// Function definitions //
-// RNG
-unsigned int xorshift32(unsigned int *state) {
- unsigned int x = *state;
- x ^= x << 13;
- x ^= x >> 17;
- x ^= x << 5;
- *state = x;
- return x;
-}
-
-void add_log(Enduro* env) {
- env->log.episode_return += env->tracking_episode_return;
- env->log.episode_length += env->tracking_episode_length;
- env->log.score += env->tracking_score;
- env->log.perf += fminf(env->tracking_days_completed/10.0f, 1.0f);
- env->log.reward += env->tracking_reward;
- env->log.step_rew_car_passed_no_crash += env->tracking_step_rew_car_passed_no_crash;
- env->log.crashed_penalty += env->tracking_crashed_penalty;
- env->log.passed_cars += env->tracking_passed_cars;
- env->log.passed_by_enemy += env->tracking_passed_by_enemy;
- env->log.cars_to_pass += env->tracking_cars_to_pass;
- env->log.days_completed += env->tracking_days_completed;
- env->log.days_failed += env->tracking_days_failed;
- env->log.collisions_player_vs_car += env->tracking_collisions_player_vs_car;
- env->log.collisions_player_vs_road += env->tracking_collisions_player_vs_road;
-
- // Episode counter
- env->log.n += 1.0f;
-}
-
-void init(Enduro* env) {
- env->rng_state = env->seed;
- env->reset_count = 0;
- env->last_road_left = -1.0f;
- env->last_road_right = -1.0f;
-
- if (env->rng_state == 0) { // Activate with seed==0
- // Start the environment at the beginning of the day
- env->rng_state = 0;
- env->elapsedTimeEnv = 0.0f;
- env->currentDayTimeIndex = 0;
- env->previousDayTimeIndex = NUM_BACKGROUND_TRANSITIONS;
- } else {
- // Randomize elapsed time within the day's total duration
- float total_day_duration = BACKGROUND_TRANSITION_TIMES[NUM_BACKGROUND_TRANSITIONS - 1];
- env->elapsedTimeEnv = ((float)xorshift32(&env->rng_state) / (float)UINT32_MAX) * total_day_duration;
-
- // Determine the current time index
- env->currentDayTimeIndex = 0;
- for (int i = 0; i < NUM_BACKGROUND_TRANSITIONS - 1; i++) {
- if (env->elapsedTimeEnv >= env->dayTransitionTimes[i] &&
- env->elapsedTimeEnv < env->dayTransitionTimes[i + 1]) {
- env->currentDayTimeIndex = i;
- break;
- }
- }
-
- // Handle the last interval
- if (env->elapsedTimeEnv >= BACKGROUND_TRANSITION_TIMES[NUM_BACKGROUND_TRANSITIONS - 1]) {
- env->currentDayTimeIndex = NUM_BACKGROUND_TRANSITIONS - 1;
- }
- }
-
- env->numEnemies = 0;
- for (int i = 0; i < MAX_ENEMIES; i++) {
- env->enemyCars[i].lane = -1; // Default invalid lane
- env->enemyCars[i].y = 0.0f;
- env->enemyCars[i].passed = 0;
- }
-
- env->obs_size = OBSERVATIONS_MAX_SIZE;
- env->max_enemies = MAX_ENEMIES;
- env->score = 0;
- env->numEnemies = 0;
- env->player_x = INITIAL_PLAYER_X;
- env->player_y = PLAYER_MAX_Y;
- env->speed = MIN_SPEED;
- env->carsToPass = INITIAL_CARS_TO_PASS;
- env->width = SCREEN_WIDTH;
- env->height = SCREEN_HEIGHT;
- env->car_width = CAR_WIDTH;
- env->car_height = CAR_HEIGHT;
-
- memcpy(env->dayTransitionTimes, BACKGROUND_TRANSITION_TIMES, sizeof(BACKGROUND_TRANSITION_TIMES));
-
- env->tick = 0;
- env->collision_cooldown_car_vs_car = 0.0f;
- env->collision_cooldown_car_vs_road = 0.0f;
- env->action_height = ACTION_HEIGHT;
- env->elapsedTimeEnv = 0.0f;
- env->enemySpawnTimer = 0.0f;
- env->enemySpawnInterval = 0.8777f;
- env->last_spawned_lane = -1;
- env->closest_edge_lane = -1;
- env->base_vanishing_point_x = 86.0f;
- env->current_vanishing_point_x = 86.0f;
- env->target_vanishing_point_x = 86.0f;
- env->vanishing_point_x = 86.0f;
- env->initial_player_x = INITIAL_PLAYER_X;
- env->player_y = PLAYER_MAX_Y;
- env->min_speed = MIN_SPEED;
- env->enemySpeed = ENEMY_CAR_SPEED;
- env->max_speed = MAX_SPEED;
- env->initial_cars_to_pass = INITIAL_CARS_TO_PASS;
- env->day = 1;
- env->drift_direction = 0; // Means in noop, but only if crashed state
- env->crashed_penalty = 0.0f;
- env->car_passed_no_crash_active = 1;
- env->step_rew_car_passed_no_crash = 0.0f;
- env->current_curve_stage = 0; // 0: straight
- env->steps_in_current_stage = 0;
- env->current_curve_direction = CURVE_STRAIGHT;
- env->current_curve_factor = 0.0f;
- env->target_curve_factor = 0.0f;
- env->current_step_threshold = 0.0f;
- env->wiggle_y = VANISHING_POINT_Y;
- env->wiggle_speed = WIGGLE_SPEED;
- env->wiggle_length = WIGGLE_LENGTH;
- env->wiggle_amplitude = WIGGLE_AMPLITUDE;
- env->wiggle_active = true;
- env->currentGear = 0;
- env->gearElapsedTime = 0.0f;
- env->gearTimings[0] = 4.0f;
- env->gearTimings[1] = 2.5f;
- env->gearTimings[2] = 3.25f;
- env->gearTimings[3] = 1.5f;
- float totalSpeedRange = env->max_speed - env->min_speed;
- float totalTime = 0.0f;
- for (int i = 0; i < 4; i++) {
- totalTime += env->gearTimings[i];
- }
- float cumulativeSpeed = env->min_speed;
- for (int i = 0; i < 4; i++) {
- float gearTime = env->gearTimings[i];
- float gearSpeedIncrement = totalSpeedRange * (gearTime / totalTime);
- env->gearSpeedThresholds[i] = cumulativeSpeed + gearSpeedIncrement;
- env->gearAccelerationRates[i] = gearSpeedIncrement / (gearTime * TARGET_FPS);
- cumulativeSpeed = env->gearSpeedThresholds[i];
- }
-
- // Randomize the initial time of day for each environment
- if (env->rng_state == 0) {
- env->elapsedTimeEnv = 0;
- env->currentDayTimeIndex = 0;
- env->dayTimeIndex = 0;
- env->previousDayTimeIndex = 0;
- } else {
- float total_day_duration = BACKGROUND_TRANSITION_TIMES[15];
- env->elapsedTimeEnv = ((float)rand_r(&env->rng_state) / (float)RAND_MAX) * total_day_duration;
- env->currentDayTimeIndex = 0;
- env->dayTimeIndex = 0;
- env->previousDayTimeIndex = 0;
-
- // Advance currentDayTimeIndex to match randomized elapsedTimeEnv
- for (int i = 0; i < NUM_BACKGROUND_TRANSITIONS; i++) {
- if (env->elapsedTimeEnv >= env->dayTransitionTimes[i]) {
- env->currentDayTimeIndex = i;
- } else {
- break;
- }
- }
-
- env->previousDayTimeIndex = (env->currentDayTimeIndex > 0) ? env->currentDayTimeIndex - 1 : NUM_BACKGROUND_TRANSITIONS - 1;
- }
-
- env->road_scroll_offset = 1.0f;
- env->base_target_vanishing_point_x = 86.0f;
- env->t_p = 86.0f;
- env->parallaxFactor = 1.0f;
- env->dayCompleted = 0;
- env->lane = 1;
- env->terminals[0] = 0;
-
- // Reset rewards and logs
- env->rewards[0] = 0.0f;
- // Initialize tracking variables
- env->tracking_episode_return = 0.0f;
- env->tracking_episode_length = 0.0f;
- env->tracking_score = 0.0f;
- env->tracking_reward = 0.0f;
- env->tracking_step_rew_car_passed_no_crash = 0.0f;
- env->tracking_crashed_penalty = 0.0f;
- env->tracking_passed_cars = 0.0f;
- env->tracking_passed_by_enemy = 0.0f;
- env->tracking_cars_to_pass = INITIAL_CARS_TO_PASS;
- env->tracking_days_completed = 0.0f;
- env->tracking_days_failed = 0.0f;
- env->tracking_collisions_player_vs_car = 0.0f;
- env->tracking_collisions_player_vs_road = 0.0f;
-
- env->log.episode_return = 0.0f;
- env->log.episode_length = 0.0f;
- env->log.score = 0.0f;
- env->log.reward = 0.0f;
- env->log.step_rew_car_passed_no_crash = 0.0f;
- env->log.crashed_penalty = 0.0f;
- env->log.passed_cars = 0.0f;
- env->log.passed_by_enemy = 0.0f;
- env->log.cars_to_pass = INITIAL_CARS_TO_PASS;
- env->log.days_completed = 0;
- env->log.days_failed = 0;
- env->log.collisions_player_vs_car = 0.0f;
- env->log.collisions_player_vs_road = 0.0f;
- env->log.n = 0.0f;
-}
-
-void allocate(Enduro* env) {
- env->observations = (float*)calloc(env->obs_size, sizeof(float));
- env->actions = (int*)calloc(1, sizeof(int));
- env->rewards = (float*)calloc(1, sizeof(float));
- env->terminals = (unsigned char*)calloc(1, sizeof(unsigned char));
-}
-
-void free_allocated(Enduro* env) {
- free(env->observations);
- free(env->actions);
- free(env->rewards);
- free(env->terminals);
-}
-
-void c_close(Enduro* env) {
-}
-
-// Called when a day is failed by player
-// Restarts the game at Day 1
-void reset_round(Enduro* env) {
- // Preserve RNG state
- unsigned int preserved_rng_state = env->rng_state;
-
- // Reset most environment variables
- env->score = 0;
- env->carsToPass = INITIAL_CARS_TO_PASS;
- env->day = 1;
- env->tick = 0;
- env->numEnemies = 0;
- env->speed = env->min_speed;
- env->player_x = env->initial_player_x;
- env->player_y = PLAYER_MAX_Y;
- env->car_passed_no_crash_active = 0;
- env->step_rew_car_passed_no_crash = 0.0f;
- env->crashed_penalty = 0.0f;
- env->collision_cooldown_car_vs_car = 0.0f;
- env->collision_cooldown_car_vs_road = 0.0f;
- env->enemySpawnTimer = 0.0f;
- env->enemySpawnInterval = 0.8777f;
- env->last_spawned_lane = -1;
- env->closest_edge_lane = -1;
- env->base_vanishing_point_x = 86.0f;
- env->current_vanishing_point_x = 86.0f;
- env->target_vanishing_point_x = 86.0f;
- env->vanishing_point_x = 86.0f;
- env->initial_player_x = INITIAL_PLAYER_X;
- env->player_y = PLAYER_MAX_Y;
- env->min_speed = MIN_SPEED;
- env->enemySpeed = ENEMY_CAR_SPEED;
- env->max_speed = MAX_SPEED;
- env->initial_cars_to_pass = INITIAL_CARS_TO_PASS;
- env->day = 1;
- env->drift_direction = 0; // Means in noop, but only if crashed state
- env->crashed_penalty = 0.0f;
- env->car_passed_no_crash_active = 1;
- env->step_rew_car_passed_no_crash = 0.0f;
- env->current_curve_stage = 0; // 0: straight
- env->steps_in_current_stage = 0;
- env->current_curve_direction = CURVE_STRAIGHT;
- env->current_curve_factor = 0.0f;
- env->target_curve_factor = 0.0f;
- env->current_step_threshold = 0.0f;
- env->wiggle_y = VANISHING_POINT_Y;
- env->wiggle_speed = WIGGLE_SPEED;
- env->wiggle_length = WIGGLE_LENGTH;
- env->wiggle_amplitude = WIGGLE_AMPLITUDE;
- env->wiggle_active = true;
- env->currentGear = 0;
- env->gearElapsedTime = 0.0f;
- env->gearTimings[0] = 4.0f;
- env->gearTimings[1] = 2.5f;
- env->gearTimings[2] = 3.25f;
- env->gearTimings[3] = 1.5f;
- float totalSpeedRange = env->max_speed - env->min_speed;
- float totalTime = 0.0f;
- for (int i = 0; i < 4; i++) {
- totalTime += env->gearTimings[i];
- }
- float cumulativeSpeed = env->min_speed;
- for (int i = 0; i < 4; i++) {
- float gearTime = env->gearTimings[i];
- float gearSpeedIncrement = totalSpeedRange * (gearTime / totalTime);
- env->gearSpeedThresholds[i] = cumulativeSpeed + gearSpeedIncrement;
- env->gearAccelerationRates[i] = gearSpeedIncrement / (gearTime * TARGET_FPS);
- cumulativeSpeed = env->gearSpeedThresholds[i];
- }
-
- // Reset enemy cars
- for (int i = 0; i < MAX_ENEMIES; i++) {
- env->enemyCars[i].lane = -1;
- env->enemyCars[i].y = 0.0f;
- env->enemyCars[i].passed = 0;
- }
-
- // Reset rewards and logs
- env->rewards[0] = 0.0f;
- env->tracking_episode_return = 0.0f;
- env->tracking_episode_length = 0.0f;
- env->tracking_score = 0.0f;
- env->tracking_reward = 0.0f;
- env->tracking_step_rew_car_passed_no_crash = 0.0f;
- env->tracking_crashed_penalty = 0.0f;
- env->tracking_passed_cars = 0.0f;
- env->tracking_passed_by_enemy = 0.0f;
- env->tracking_cars_to_pass = INITIAL_CARS_TO_PASS;
- env->tracking_collisions_player_vs_car = 0.0f;
- env->tracking_collisions_player_vs_road = 0.0f;
-
- // Restore preserved RNG state to maintain reproducibility
- env->rng_state = preserved_rng_state;
-
- // Restart the environment at the beginning of the day
- env->elapsedTimeEnv = 0.0f;
- env->currentDayTimeIndex = 0;
- env->previousDayTimeIndex = NUM_BACKGROUND_TRANSITIONS - 1;
-
- // Reset flags and transient states
- env->dayCompleted = 0;
- env->terminals[0] = 0;
- env->rewards[0] = 0.0f;
-}
-
-// Reset all init vars; only called once after init
-void c_reset(Enduro* env) {
- // No random after first reset
- int reset_seed = (env->reset_count == 0) ? xorshift32(&env->rng_state) : 0;
- env->rng_state = reset_seed;
- init(env);
- env->reset_count += 1;
-}
-
-unsigned char check_collision(Enduro* env, Car* car) {
- // Compute the scale factor based on vanishing point reference
- float depth = (car->y - VANISHING_POINT_Y) / (PLAYABLE_AREA_BOTTOM - VANISHING_POINT_Y);
- float scale = fmax(0.1f, 0.9f * depth);
- float car_width = CAR_WIDTH * scale;
- float car_height = CAR_HEIGHT * scale;
- float car_center_x = car_x_in_lane(env, car->lane, car->y);
- float car_x = car_center_x - car_width / 2.0f;
- return !(env->player_x > car_x + car_width
- || env->player_x + CAR_WIDTH < car_x
- || env->player_y > car->y + car_height
- || env->player_y + CAR_HEIGHT < car->y);
-}
-
-// Determines which of the 3 lanes the player's car is in
-int get_player_lane(Enduro* env) {
- float player_center_x = env->player_x + CAR_WIDTH / 2.0f;
- float offset = (env->player_x - env->initial_player_x) * 0.5f;
- float left_edge = road_edge_x(env, env->player_y, offset, true);
- float right_edge = road_edge_x(env, env->player_y, offset, false);
- float lane_width = (right_edge - left_edge) / 3.0f;
- env->lane = (int)((player_center_x - left_edge) / lane_width);
- if (env->lane < 0) env->lane = 0;
- if (env->lane > 2) env->lane = 2;
- return env->lane;
-}
-
-float get_car_scale(float y) {
- float depth = (y - VANISHING_POINT_Y) / (PLAYABLE_AREA_BOTTOM - VANISHING_POINT_Y);
- return fmaxf(0.1f, 0.9f * depth);
-}
-
-void add_enemy_car(Enduro* env) {
- if (env->numEnemies >= MAX_ENEMIES) {
- return;
- }
-
- int player_lane = get_player_lane(env);
- int possible_lanes[NUM_LANES];
- int num_possible_lanes = 0;
-
- // Determine the furthest lane from the player
- int furthest_lane;
- if (player_lane == 0) {
- furthest_lane = 2;
- } else if (player_lane == 2) {
- furthest_lane = 0;
- } else {
- // Player is in the middle lane
- // Decide based on player's position relative to the road center
- float player_center_x = env->player_x + CAR_WIDTH / 2.0f;
- float road_center_x = (road_edge_x(env, env->player_y, 0, true) +
- road_edge_x(env, env->player_y, 0, false)) / 2.0f;
- if (player_center_x < road_center_x) {
- furthest_lane = 2; // Player is on the left side, choose rightmost lane
- } else {
- furthest_lane = 0; // Player is on the right side, choose leftmost lane
- }
- }
-
- if (env->speed <= 0.0f) {
- // Only spawn in the lane furthest from the player
- possible_lanes[num_possible_lanes++] = furthest_lane;
- } else {
- for (int i = 0; i < NUM_LANES; i++) {
- possible_lanes[num_possible_lanes++] = i;
- }
- }
-
- if (num_possible_lanes == 0) {
- return; // Rare
- }
-
- // Randomly select a lane
- int lane = possible_lanes[rand() % num_possible_lanes];
- // Preferentially spawn in the last_spawned_lane 30% of the time
- if (rand() % 100 < 60 && env->last_spawned_lane != -1) {
- lane = env->last_spawned_lane;
- }
- env->last_spawned_lane = lane;
- // Init car
- Car car = {
- .lane = lane,
- .x = car_x_in_lane(env, lane, VANISHING_POINT_Y),
- .y = (env->speed > 0.0f) ? VANISHING_POINT_Y + 10.0f : PLAYABLE_AREA_BOTTOM + CAR_HEIGHT,
- .last_x = car_x_in_lane(env, lane, VANISHING_POINT_Y),
- .last_y = VANISHING_POINT_Y,
- .passed = false,
- .colorIndex = rand() % 6
- };
- // Ensure minimum spacing between cars in the same lane
- float depth = (car.y - VANISHING_POINT_Y) / (PLAYABLE_AREA_BOTTOM - VANISHING_POINT_Y);
- float scale = fmax(0.1f, 0.9f * depth + 0.1f);
- float scaled_car_length = CAR_HEIGHT * scale;
- // Randomize min spacing between 1.0f and 6.0f car lengths
- float dynamic_spacing_factor = (rand() / (float)RAND_MAX) * 6.0f + 0.5f;
- float min_spacing = dynamic_spacing_factor * scaled_car_length;
- for (int i = 0; i < env->numEnemies; i++) {
- Car* existing_car = &env->enemyCars[i];
- if (existing_car->lane != car.lane) {
- continue;
- }
- float y_distance = fabs(existing_car->y - car.y);
- if (y_distance < min_spacing) {
- return; // Too close, do not spawn this car
- }
- }
- // Ensure not occupying all lanes within vertical range of 6 car lengths
- float min_vertical_range = 6.0f * CAR_HEIGHT;
- int lanes_occupied = 0;
- unsigned char lane_occupied[NUM_LANES] = { false };
- for (int i = 0; i < env->numEnemies; i++) {
- Car* existing_car = &env->enemyCars[i];
- float y_distance = fabs(existing_car->y - car.y);
- if (y_distance < min_vertical_range) {
- lane_occupied[existing_car->lane] = true;
- }
- }
- for (int i = 0; i < NUM_LANES; i++) {
- if (lane_occupied[i]) lanes_occupied++;
- }
- if (lanes_occupied >= NUM_LANES - 1 && !lane_occupied[lane]) {
- return;
- }
- env->enemyCars[env->numEnemies++] = car;
-}
-
-void update_time_of_day(Enduro* env) {
- float elapsedTime = env->elapsedTimeEnv;
- float totalDuration = env->dayTransitionTimes[15];
-
- if (elapsedTime >= totalDuration) {
- elapsedTime -= totalDuration;
- env->elapsedTimeEnv = elapsedTime; // Reset elapsed time
- env->dayTimeIndex = 0;
- }
-
- env->previousDayTimeIndex = env->currentDayTimeIndex;
-
- while (env->dayTimeIndex < 15 &&
- elapsedTime >= env->dayTransitionTimes[env->dayTimeIndex]) {
- env->dayTimeIndex++;
- }
- env->currentDayTimeIndex = env->dayTimeIndex % 16;
-}
-
-void clamp_speed(Enduro* env) {
- if (env->speed < env->min_speed || env->speed > env->max_speed) {
- env->speed = fmaxf(env->min_speed, fminf(env->speed, env->max_speed));
- }
-}
-
-void clamp_gear(Enduro* env) {
- if (env->currentGear < 0 || env->currentGear > 3) {
- env->currentGear = 0;
- }
-}
-
-void accelerate(Enduro* env) {
- clamp_speed(env);
- clamp_gear(env);
-
- if (env->speed < env->max_speed) {
- // Gear transition
- if (env->speed >= env->gearSpeedThresholds[env->currentGear] && env->currentGear < 3) {
- env->currentGear++;
- env->gearElapsedTime = 0.0f;
- }
-
- // Calculate new speed
- float accel = env->gearAccelerationRates[env->currentGear];
- float multiplier = (env->currentGear == 0) ? 4.0f : 2.0f;
- env->speed += accel * multiplier;
-
- clamp_speed(env);
-
- // Cap speed to gear threshold
- if (env->speed > env->gearSpeedThresholds[env->currentGear]) {
- env->speed = env->gearSpeedThresholds[env->currentGear];
- }
- }
- clamp_speed(env);
-}
-
-void c_step(Enduro* env) {
- env->rewards[0] = 0.0f;
- env->elapsedTimeEnv += (1.0f / TARGET_FPS);
- update_time_of_day(env);
- update_road_curve(env);
- env->tracking_episode_length += 1;
- env->terminals[0] = 0;
- env->road_scroll_offset += env->speed;
-
- // Update enemy car positions
- for (int i = 0; i < env->numEnemies; i++) {
- Car* car = &env->enemyCars[i];
- // Compute movement speed adjusted for scaling
- float scale = get_car_scale(car->y);
- float movement_speed = env->speed * scale * 0.75f;
- // Update car position
- car->y += movement_speed;
- }
-
- // Calculate road edges
- float road_left = road_edge_x(env, env->player_y, 0, true);
- float road_right = road_edge_x(env, env->player_y, 0, false) - CAR_WIDTH;
-
- env->last_road_left = road_left;
- env->last_road_right = road_right;
-
- // Reduced handling on snow
- unsigned char isSnowStage = (env->currentDayTimeIndex == 3);
- float movement_amount = 0.5f; // Default
- if (isSnowStage) {
- movement_amount = 0.3f; // Snow
- }
-
- // Player movement logic == action space (Discrete[9])
- if (env->collision_cooldown_car_vs_car <= 0 && env->collision_cooldown_car_vs_road <= 0) {
- int act = env->actions[0];
- movement_amount = (((env->speed - env->min_speed) / (env->max_speed - env->min_speed)) + 0.3f); // Magic number
- switch (act) {
- case ACTION_NOOP:
- break;
- case ACTION_FIRE:
- accelerate(env);
- break;
- case ACTION_RIGHT:
- env->player_x += movement_amount;
- if (env->player_x > road_right) env->player_x = road_right;
- break;
- case ACTION_LEFT:
- env->player_x -= movement_amount;
- if (env->player_x < road_left) env->player_x = road_left;
- break;
- case ACTION_DOWN:
- if (env->speed > env->min_speed) env->speed -= DECELERATION_RATE;
- break;
- case ACTION_DOWNRIGHT:
- if (env->speed > env->min_speed) env->speed -= DECELERATION_RATE;
- env->player_x += movement_amount;
- if (env->player_x > road_right) env->player_x = road_right;
- break;
- case ACTION_DOWNLEFT:
- if (env->speed > env->min_speed) env->speed -= DECELERATION_RATE;
- env->player_x -= movement_amount;
- if (env->player_x < road_left) env->player_x = road_left;
- break;
- case ACTION_RIGHTFIRE:
- accelerate(env);
- env->player_x += movement_amount;
- if (env->player_x > road_right) env->player_x = road_right;
- break;
- case ACTION_LEFTFIRE:
- accelerate(env);
- env->player_x -= movement_amount;
- if (env->player_x < road_left) env->player_x = road_left;
- break;
-
- // Reset crashed_penalty
- env->crashed_penalty = 0.0f;
- }
-
- } else {
-
- if (env->collision_cooldown_car_vs_car > 0) {
- env->collision_cooldown_car_vs_car -= 1;
- env->crashed_penalty = -0.01f;
- }
- if (env->collision_cooldown_car_vs_road > 0) {
- env->collision_cooldown_car_vs_road -= 1;
- env->crashed_penalty = -0.01f;
- }
-
- // Drift towards furthest road edge
- if (env->drift_direction == 0) { // drift_direction is 0 when noop starts
- env->drift_direction = (env->player_x > (road_left + road_right) / 2) ? -1 : 1;
- // Remove enemy cars in middle lane and lane player is drifting towards
- // only if they are behind the player (y > player_y) to avoid crashes
- for (int i = 0; i < env->numEnemies; i++) {
- Car* car = &env->enemyCars[i];
-
- if ((car->lane == 1 || car->lane == env->lane + env->drift_direction) && (car->y > env->player_y)) {
- for (int j = i; j < env->numEnemies - 1; j++) {
- env->enemyCars[j] = env->enemyCars[j + 1];
- }
- env->numEnemies--;
- i--;
- }
- }
- }
- // Drift distance per step
- if (env->collision_cooldown_car_vs_road > 0) {
- env->player_x += env->drift_direction * 0.12f;
- } else {
- env->player_x += env->drift_direction * 0.25f;
- }
- }
-
- // Update player's lane
- env->lane = get_player_lane(env);
-
- // Compute is_lane_empty and nearest_car_distance
- float nearest_car_distance[NUM_LANES];
- bool is_lane_empty[NUM_LANES];
-
- float MAX_DISTANCE = PLAYABLE_AREA_BOTTOM - VANISHING_POINT_Y; // Maximum possible distance
-
- for (int l = 0; l < NUM_LANES; l++) {
- nearest_car_distance[l] = MAX_DISTANCE;
- is_lane_empty[l] = true;
- }
-
- for (int i = 0; i < env->numEnemies; i++) {
- Car* car = &env->enemyCars[i];
- if (car->lane >= 0 && car->lane < NUM_LANES && car->y < env->player_y) {
- float distance = env->player_y - car->y;
- if (distance < nearest_car_distance[car->lane]) {
- nearest_car_distance[car->lane] = distance;
- is_lane_empty[car->lane] = false;
- }
- }
- }
-
- // Give a reward if the player's lane is empty in front
- float reward_amount = 0.05f; // Empty lane reward
- if (is_lane_empty[env->lane]) {
- env->rewards[0] += reward_amount;
- }
-
- // Road curve/vanishing point movement logic
- // Adjust player's x position based on the current curve
- float curve_shift = -env->current_curve_factor * CURVE_PLAYER_SHIFT_FACTOR * fabs(env->speed);
- env->player_x += curve_shift;
- // Clamp player x position to within road edges
- if (env->player_x < road_left) env->player_x = road_left;
- if (env->player_x > road_right) env->player_x = road_right;
- // Update player's horizontal position ratio, t_p
- float t_p = (env->player_x - PLAYER_MIN_X) / (PLAYER_MAX_X - PLAYER_MIN_X);
- t_p = fmaxf(0.0f, fminf(1.0f, t_p));
- env->t_p = t_p;
- // Base vanishing point based on player's horizontal movement (without curve)
- env->base_vanishing_point_x = VANISHING_POINT_X_LEFT - t_p * (VANISHING_POINT_X_LEFT - VANISHING_POINT_X_RIGHT);
- // Adjust vanishing point based on current curve
- float curve_vanishing_point_shift = env->current_curve_direction * CURVE_VANISHING_POINT_SHIFT;
- env->vanishing_point_x = env->base_vanishing_point_x + curve_vanishing_point_shift;
-
- // After curve shift
- // Wiggle logic
- if (env->wiggle_active) {
- float min_wiggle_period = 5.8f; // Slow wiggle period at min speed
- float max_wiggle_period = 0.3f; // Fast wiggle period at max speed
- // Apply non-linear scaling for wiggle period using square root
- float speed_normalized = (env->speed - env->min_speed) / (env->max_speed - env->min_speed);
- speed_normalized = fmaxf(0.0f, fminf(1.0f, speed_normalized)); // Clamp between 0 and 1
- // Adjust wiggle period with non-linear scale
- float current_wiggle_period = min_wiggle_period - powf(speed_normalized, 0.25) * (min_wiggle_period - max_wiggle_period);
- // Calculate wiggle speed based on adjusted wiggle period
- env->wiggle_speed = (PLAYABLE_AREA_BOTTOM - VANISHING_POINT_Y) / (current_wiggle_period * TARGET_FPS);
- // Update wiggle position
- env->wiggle_y += env->wiggle_speed;
- // Reset wiggle when it reaches the bottom
- if (env->wiggle_y > PLAYABLE_AREA_BOTTOM) {
- env->wiggle_y = VANISHING_POINT_Y;
- }
- }
-
- // Player car moves forward slightly according to speed
- // Update player y position based on speed
- env->player_y = PLAYER_MAX_Y - (env->speed - env->min_speed) / (env->max_speed - env->min_speed) * (PLAYER_MAX_Y - PLAYER_MIN_Y);
- // Clamp player_y to measured range
- if (env->player_y < PLAYER_MIN_Y) env->player_y = PLAYER_MIN_Y;
- if (env->player_y > PLAYER_MAX_Y) env->player_y = PLAYER_MAX_Y;
-
- // Check for and handle collisions between player and road edges
- if (env->player_x <= road_left || env->player_x >= road_right) {
- env->tracking_collisions_player_vs_road++;
- env->rewards[0] -= 0.5f;
- env->speed = fmaxf((env->speed - 1.25f), MIN_SPEED);
- env->collision_cooldown_car_vs_road = CRASH_NOOP_DURATION_CAR_VS_ROAD;
- env->drift_direction = 0; // Reset drift direction, has priority over car collisions
- env->player_x = fmaxf(road_left + 1, fminf(road_right - 1, env->player_x));
- }
-
- // Enemy car logic
- for (int i = 0; i < env->numEnemies; i++) {
- Car* car = &env->enemyCars[i];
-
- // Remove off-screen cars that move below the screen
- if (car->y > PLAYABLE_AREA_BOTTOM + CAR_HEIGHT * 5) {
- // Remove car from array if it moves below the screen
- for (int j = i; j < env->numEnemies - 1; j++) {
- env->enemyCars[j] = env->enemyCars[j + 1];
- }
- env->numEnemies--;
- i--;
- continue;
- }
-
- // Remove cars that reach or surpass the logical vanishing point if moving up (player speed negative)
- if (env->speed < 0 && car->y <= LOGICAL_VANISHING_Y) {
- // Remove car from array if it reaches the logical vanishing point if moving down (player speed positive)
- for (int j = i; j < env->numEnemies - 1; j++) {
- env->enemyCars[j] = env->enemyCars[j + 1];
- }
- env->numEnemies--;
- i--;
- continue;
- }
-
- // If the car is behind the player and speed <= 0, move it to the furthest lane
- if (env->speed <= 0 && car->y >= env->player_y + CAR_HEIGHT) {
- // Determine the furthest lane
- int furthest_lane;
- int player_lane = get_player_lane(env);
- if (player_lane == 0) {
- furthest_lane = 2;
- } else if (player_lane == 2) {
- furthest_lane = 0;
- } else {
- // Player is in the middle lane
- // Decide based on player's position relative to the road center
- float player_center_x = env->player_x + CAR_WIDTH / 2.0f;
- float road_center_x = (road_edge_x(env, env->player_y, 0, true) +
- road_edge_x(env, env->player_y, 0, false)) / 2.0f;
- if (player_center_x < road_center_x) {
- furthest_lane = 2; // Player is on the left side
- } else {
- furthest_lane = 0; // Player is on the right side
- }
- }
- car->lane = furthest_lane;
- continue;
- }
-
- // Check for passing logic **only if not on collision cooldown**
- if (env->speed > 0 && car->last_y < env->player_y + CAR_HEIGHT
- && car->y >= env->player_y + CAR_HEIGHT
- && env->collision_cooldown_car_vs_car <= 0
- && env->collision_cooldown_car_vs_road <= 0) {
- if (env->carsToPass > 0) {
- env->carsToPass -= 1;
- }
- if (!car->passed) {
- env->tracking_passed_cars += 1;
- env->rewards[0] += 1.0f; // Car passed reward
- env->car_passed_no_crash_active = 1; // Stepwise rewards activated
- env->step_rew_car_passed_no_crash += 0.001f; // Stepwise reward
- }
- car->passed = true;
- } else if (env->speed < 0 && car->last_y > env->player_y && car->y <= env->player_y) {
- int maxCarsToPass = (env->day == 1) ? 200 : 300; // Day 1: 200 cars, Day 2+: 300 cars
- if (env->carsToPass == maxCarsToPass) {
- // Do nothing; log the event
- env->tracking_passed_by_enemy += 1.0f;
- } else {
- env->carsToPass += 1;
- env->tracking_passed_by_enemy += 1.0f;
- env->rewards[0] -= 0.1f;
- }
- }
-
- // Preserve last x and y for passing, obs
- car->last_y = car->y;
- car->last_x = car->x;
-
- // Check for and handle collisions between player and enemy cars
- if (env->collision_cooldown_car_vs_car <= 0 && check_collision(env, car)) {
- env->tracking_collisions_player_vs_car++;
- env->rewards[0] -= 0.5f;
- env->speed = 1 + MIN_SPEED;
- env->collision_cooldown_car_vs_car = CRASH_NOOP_DURATION_CAR_VS_CAR;
- env->drift_direction = 0; // Reset drift direction
- env->car_passed_no_crash_active = 0; // Stepwise rewards deactivated until next car passed
- env->step_rew_car_passed_no_crash = 0.0f; // Reset stepwise reward
- }
- }
-
- // Calculate enemy spawn interval based on player speed and day
- // Values measured from original gameplay
- float min_spawn_interval = 0.5f; // 0.8777f; // Minimum spawn interval
- float max_spawn_interval;
- int dayIndex = env->day - 1;
- int numMaxSpawnIntervals = sizeof(MAX_SPAWN_INTERVALS) / sizeof(MAX_SPAWN_INTERVALS[0]);
-
- if (dayIndex < numMaxSpawnIntervals) {
- max_spawn_interval = MAX_SPAWN_INTERVALS[dayIndex];
- } else {
- // For days beyond first, decrease max_spawn_interval further
- max_spawn_interval = MAX_SPAWN_INTERVALS[numMaxSpawnIntervals - 1] - (dayIndex - numMaxSpawnIntervals + 1) * 0.1f;
- if (max_spawn_interval < 0.1f) {
- max_spawn_interval = 0.1f;
- }
- }
-
- // Ensure min_spawn_interval is greater than or equal to max_spawn_interval
- if (min_spawn_interval < max_spawn_interval) {
- min_spawn_interval = max_spawn_interval;
- }
-
- // Calculate speed factor for enemy spawning
- float speed_factor = (env->speed - env->min_speed) / (env->max_speed - env->min_speed);
- if (speed_factor < 0.0f) speed_factor = 0.0f;
- if (speed_factor > 1.0f) speed_factor = 1.0f;
-
- // Interpolate between min and max spawn intervals to scale to player speed
- env->enemySpawnInterval = min_spawn_interval - speed_factor * (min_spawn_interval - max_spawn_interval) * 1.5f;
-
- // Update enemy spawn timer
- env->enemySpawnTimer += (1.0f / TARGET_FPS);
- if (env->enemySpawnTimer >= env->enemySpawnInterval) {
- env->enemySpawnTimer -= env->enemySpawnInterval;
-
- if (env->numEnemies < MAX_ENEMIES) {
- // Add a clumping factor based on speed
- float clump_probability = fminf((env->speed - env->min_speed) / (env->max_speed - env->min_speed), 1.0f); // Scales with speed
- int num_to_spawn = 1;
-
- // Randomly decide to spawn more cars in a clump
- if ((rand() / (float)RAND_MAX) < clump_probability) {
- num_to_spawn = 1 + rand() % 2; // Spawn 1 to 3 cars
- }
-
- // Track occupied lanes to prevent over-blocking
- int occupied_lanes[NUM_LANES] = {0};
-
- for (int i = 0; i < num_to_spawn && env->numEnemies < MAX_ENEMIES; i++) {
- // Find an unoccupied lane
- int lane;
- do {
- lane = rand() % NUM_LANES;
- } while (occupied_lanes[lane]);
-
- // Mark the lane as occupied
- occupied_lanes[lane] = 1;
-
- // Add the enemy car
- int previous_num_enemies = env->numEnemies;
- add_enemy_car(env);
- if (env->numEnemies > previous_num_enemies) {
- Car* new_car = &env->enemyCars[env->numEnemies - 1];
- new_car->lane = lane;
- new_car->y -= i * (CAR_HEIGHT * 3); // Vertical spacing for clump
- }
- }
- }
- }
-
- // Day completed logic
- if (env->carsToPass <= 0 && !env->dayCompleted) {
- env->dayCompleted = true;
- }
-
- // Handle day transition when background cycles back to 0
- if (env->currentDayTimeIndex == 0 && env->previousDayTimeIndex == 15) {
- // Background cycled back to 0
- if (env->dayCompleted) {
- env->tracking_days_completed += 1;
- env->day += 1;
- env->rewards[0] += 1.0f;
- env->carsToPass = 300; // Always 300 after the first day
- env->dayCompleted = false;
- add_log(env);
-
- } else {
- // Player failed to pass required cars, soft-reset environment
- env->tracking_days_failed += 1.0f;
- env->terminals[0] = true;
- add_log(env);
- compute_observations(env); // Call compute_observations before reset to log
- reset_round(env); // Reset round == soft reset
- return;
- }
- }
-
- // Reward each step after a car is passed until a collision occurs.
- // Then, no rewards per step until next car is passed.
- if (env->car_passed_no_crash_active) {
- env->rewards[0] += env->step_rew_car_passed_no_crash;
- }
-
- env->rewards[0] += env->crashed_penalty;
- env->tracking_crashed_penalty = env->crashed_penalty;
- env->tracking_step_rew_car_passed_no_crash = env->step_rew_car_passed_no_crash;
- env->tracking_reward = env->rewards[0];
- env->tracking_episode_return = env->rewards[0];
- env->tick++;
-
- float normalizedSpeed = fminf(fmaxf(env->speed, 1.0f), 2.0f);
- env->score += (int)normalizedSpeed;
-
- env->tracking_score = env->score;
- int local_cars_to_pass = env->carsToPass;
- env->tracking_cars_to_pass = (int)local_cars_to_pass;
-
- compute_observations(env);
-}
-
-void compute_observations(Enduro* env) {
- float* obs = env->observations;
- int obs_index = 0;
-
- // Most obs normalized to [0, 1]
- // Bounding box around player
- float player_x_norm = (env->player_x - env->last_road_left) / (env->last_road_right - env->last_road_left);
- float player_y_norm = (PLAYER_MAX_Y - env->player_y) / (PLAYER_MAX_Y - PLAYER_MIN_Y);
- // float player_width_norm = CAR_WIDTH / (env->last_road_right - env->last_road_left);
- // float player_height_norm = CAR_HEIGHT / (PLAYABLE_AREA_BOTTOM - VANISHING_POINT_Y);
-
- // Player position and speed
- // idx 1-3
- obs[obs_index++] = player_x_norm;
- obs[obs_index++] = player_y_norm;
- obs[obs_index++] = (env->speed - MIN_SPEED) / (MAX_SPEED - MIN_SPEED);
-
- // Road edges (separate lines for clarity)
- float road_left = road_edge_x(env, env->player_y, 0, true);
- float road_right = road_edge_x(env, env->player_y, 0, false) - CAR_WIDTH;
-
- // Road edges and last road edges
- // idx 4-7
- obs[obs_index++] = (road_left - PLAYABLE_AREA_LEFT) /
- (PLAYABLE_AREA_RIGHT - PLAYABLE_AREA_LEFT);
- obs[obs_index++] = (road_right - PLAYABLE_AREA_LEFT) /
- (PLAYABLE_AREA_RIGHT - PLAYABLE_AREA_LEFT);
- obs[obs_index++] = (env->last_road_left - PLAYABLE_AREA_LEFT) /
- (PLAYABLE_AREA_RIGHT - PLAYABLE_AREA_LEFT);
- obs[obs_index++] = (env->last_road_right - PLAYABLE_AREA_LEFT) /
- (PLAYABLE_AREA_RIGHT - PLAYABLE_AREA_LEFT);
-
- // Player lane number (0, 1, 2)
- // idx 8
- obs[obs_index++] = (float)get_player_lane(env) / (NUM_LANES - 1);
-
- // Enemy cars (numEnemies * 5 values (x, y, delta y, same lane as player car)) = 10 * 4 = 50 values
- // idx 9-58
- for (int i = 0; i < env->max_enemies; i++) {
- Car* car = &env->enemyCars[i];
-
- if (car->y > VANISHING_POINT_Y && car->y < PLAYABLE_AREA_BOTTOM) {
- // Enemy car buffer zone
- float buffer_x = CAR_WIDTH * 0.5f;
- float buffer_y = CAR_HEIGHT * 0.5f;
-
- // Normalize car x position relative to road edges
- float car_x_norm = ((car->x - buffer_x) - env->last_road_left) / (env->last_road_right - env->last_road_left);
- car_x_norm = fmaxf(0.0f, fminf(1.0f, car_x_norm)); // Clamp between 0 and 1
- // Normalize car y position relative to the full road height
- float car_y_norm = (PLAYABLE_AREA_BOTTOM - (car->y - buffer_y)) / (PLAYABLE_AREA_BOTTOM - VANISHING_POINT_Y);
- car_y_norm = fmaxf(0.0f, fminf(1.0f, car_y_norm)); // Clamp between 0 and 1
- // Calculate delta_x for lateral movement
- float delta_x_norm = (car->last_x - car->x) / (env->last_road_right - env->last_road_left);
- // Calculate delta_y for relative speed
- float delta_y_norm = (car->last_y - car->y) / (PLAYABLE_AREA_BOTTOM - VANISHING_POINT_Y);
- // Determine if the car is in the same lane as the player
- int is_same_lane = (car->lane == env->lane);
- // Add normalized car x position
- obs[obs_index++] = car_x_norm;
- // Add normalized car y position
- obs[obs_index++] = car_y_norm;
- // Add normalized delta x (lateral movement)
- obs[obs_index++] = delta_x_norm;
- // Add normalized delta y (relative speed)
- obs[obs_index++] = delta_y_norm;
- // Add lane information (binary flag for lane match)
- obs[obs_index++] = (float)is_same_lane;
- } else {
- // Default values for cars that don't exist
- obs[obs_index++] = 0.5f; // Neutral x position
- obs[obs_index++] = 0.5f; // Neutral y position
- obs[obs_index++] = 0.0f; // No movement (delta_x = 0)
- obs[obs_index++] = 0.0f; // No movement (delta_y = 0)
- obs[obs_index++] = 0.0f; // Not in the same lane
- }
- }
-
- // Curve direction
- // idx 59
- obs[obs_index++] = (float)(env->current_curve_direction + 1) / 2.0f;
-
- // Observation for player's drift due to road curvature
- // idx 60-62
- // Drift direction and magnitude
- float drift_magnitude = env->current_curve_factor * CURVE_PLAYER_SHIFT_FACTOR * fabs(env->speed);
- float drift_direction = (env->current_curve_factor > 0) ? 1.0f : -1.0f; // 1 for right drift, -1 for left drift
-
- // Normalize drift magnitude (assume max absolute curve factor is 1.0 for normalization)
- float max_drift_magnitude = CURVE_PLAYER_SHIFT_FACTOR * env->max_speed;
- float normalized_drift_magnitude = fabs(drift_magnitude) / max_drift_magnitude;
-
- // Add drift direction (-1.0 to 1.0), normalized magnitude (0.0 to 1.0), and curve factor (-1.0 to 1.0)
- obs[obs_index++] = drift_direction;
- obs[obs_index++] = normalized_drift_magnitude;
- obs[obs_index++] = env->current_curve_factor;
-
- // Time of day
- // idx 63
- float total_day_length = env->dayTransitionTimes[15];
- obs[obs_index++] = fmodf(env->elapsedTimeEnv, total_day_length) / total_day_length;
-
- // Cars to pass
- // idx 64
- obs[obs_index++] = (float)env->carsToPass / env->initial_cars_to_pass;
-
- // Compute per-lane observations: nearest enemy car distances in each lane
- // idx 65-67
- float nearest_car_distance[NUM_LANES];
- bool is_lane_empty[NUM_LANES];
-
- float MAX_DISTANCE = PLAYABLE_AREA_BOTTOM - VANISHING_POINT_Y; // Maximum possible distance
-
- for (int l = 0; l < NUM_LANES; l++) {
- nearest_car_distance[l] = MAX_DISTANCE;
- is_lane_empty[l] = true;
- }
-
- for (int i = 0; i < env->numEnemies; i++) {
- Car* car = &env->enemyCars[i];
- if (car->lane >= 0 && car->lane < NUM_LANES && car->y < env->player_y) {
- float distance = env->player_y - car->y;
- if (distance < nearest_car_distance[car->lane]) {
- nearest_car_distance[car->lane] = distance;
- is_lane_empty[car->lane] = false;
- }
- }
- }
-
- // Add per-lane normalized distances to observations
- for (int l = 0; l < NUM_LANES; l++) {
- float normalized_distance;
- if (is_lane_empty[l]) {
- normalized_distance = 1.0f; // No enemy car in front in this lane
- } else {
- normalized_distance = nearest_car_distance[l] / MAX_DISTANCE;
- }
- obs[obs_index++] = normalized_distance;
- }
-}
-
-// When to curve road and how to curve it, including dense smooth transitions
-// An ugly, dense function, but it is necessary
-void update_road_curve(Enduro* env) {
- int* current_curve_stage = &env->current_curve_stage;
- int* steps_in_current_stage = &env->steps_in_current_stage;
-
- // Map speed to the scale between 0.5 and 3.5
- float speed_scale = 0.5f + ((fabs(env->speed) / env->max_speed) * (MAX_SPEED - MIN_SPEED));
- float vanishing_point_transition_speed = VANISHING_POINT_TRANSITION_SPEED + speed_scale;
-
- // Randomize step thresholds and curve directions
- int step_thresholds[3];
- int curve_directions[3];
- int last_direction = 0; // Tracks the last curve direction, initialized to straight (0)
-
- for (int i = 0; i < 3; i++) {
- // Generate random step thresholds
- step_thresholds[i] = 1500 + rand() % 3801; // Random value between 1500 and 3800
-
- // Generate a random curve direction (-1, 0, 1) with rules
- int direction_choices[] = {-1, 0, 1};
- int next_direction;
-
- do {
- next_direction = direction_choices[rand() % 3];
- } while ((last_direction == -1 && next_direction == 1) || (last_direction == 1 && next_direction == -1));
-
- curve_directions[i] = next_direction;
- last_direction = next_direction;
- }
-
- // Use step thresholds and curve directions dynamically
- env->current_step_threshold = step_thresholds[*current_curve_stage % 3];
- (*steps_in_current_stage)++;
-
- if (*steps_in_current_stage >= step_thresholds[*current_curve_stage % 3]) {
- env->target_curve_factor = (float)curve_directions[*current_curve_stage % 3];
- *steps_in_current_stage = 0;
- *current_curve_stage = (*current_curve_stage + 1) % 3;
- }
-
- // Determine sizes of step_thresholds and curve_directions
- size_t step_thresholds_size = sizeof(step_thresholds) / sizeof(step_thresholds[0]);
- size_t curve_directions_size = sizeof(curve_directions) / sizeof(curve_directions[0]);
-
- // Find the maximum size
- size_t max_size = (step_thresholds_size > curve_directions_size) ? step_thresholds_size : curve_directions_size;
-
- // Adjust arrays dynamically
- int adjusted_step_thresholds[max_size];
- int adjusted_curve_directions[max_size];
-
- for (size_t i = 0; i < max_size; i++) {
- adjusted_step_thresholds[i] = step_thresholds[i % step_thresholds_size];
- adjusted_curve_directions[i] = curve_directions[i % curve_directions_size];
- }
-
- // Use adjusted arrays for current calculations
- env->current_step_threshold = adjusted_step_thresholds[*current_curve_stage % max_size];
- (*steps_in_current_stage)++;
-
- if (*steps_in_current_stage >= adjusted_step_thresholds[*current_curve_stage]) {
- env->target_curve_factor = (float)adjusted_curve_directions[*current_curve_stage % max_size];
- *steps_in_current_stage = 0;
- *current_curve_stage = (*current_curve_stage + 1) % max_size;
- }
-
- if (env->current_curve_factor < env->target_curve_factor) {
- env->current_curve_factor = fminf(env->current_curve_factor + CURVE_TRANSITION_SPEED, env->target_curve_factor);
- } else if (env->current_curve_factor > env->target_curve_factor) {
- env->current_curve_factor = fmaxf(env->current_curve_factor - CURVE_TRANSITION_SPEED, env->target_curve_factor);
- }
- env->current_curve_direction = fabsf(env->current_curve_factor) < 0.1f ? CURVE_STRAIGHT
- : (env->current_curve_factor > 0) ? CURVE_RIGHT : CURVE_LEFT;
-
- // Move the vanishing point gradually
- env->base_target_vanishing_point_x = VANISHING_POINT_X_LEFT - env->t_p * (VANISHING_POINT_X_LEFT - VANISHING_POINT_X_RIGHT);
- float target_shift = env->current_curve_direction * CURVE_VANISHING_POINT_SHIFT;
- env->target_vanishing_point_x = env->base_target_vanishing_point_x + target_shift;
-
- if (env->current_vanishing_point_x < env->target_vanishing_point_x) {
- env->current_vanishing_point_x = fminf(env->current_vanishing_point_x + vanishing_point_transition_speed, env->target_vanishing_point_x);
- } else if (env->current_vanishing_point_x > env->target_vanishing_point_x) {
- env->current_vanishing_point_x = fmaxf(env->current_vanishing_point_x - vanishing_point_transition_speed, env->target_vanishing_point_x);
- }
- env->vanishing_point_x = env->current_vanishing_point_x;
-}
-
-// B(t) = (1−t)^2 * P0+2(1−t) * t * P1+t^2 * P2, t∈[0,1]
-// Quadratic bezier curve helper function
-float quadratic_bezier(float bottom_x, float control_x, float top_x, float t) {
- float one_minus_t = 1.0f - t;
- return one_minus_t * one_minus_t * bottom_x +
- 2.0f * one_minus_t * t * control_x +
- t * t * top_x;
-}
-
-// Computes the edges of the road. Use for both L and R.
-// Lots of magic numbers to replicate as exactly as possible
-// original Atari 2600 Enduro road rendering.
-float road_edge_x(Enduro* env, float y, float offset, unsigned char left) {
- float t = (PLAYABLE_AREA_BOTTOM - y) / (PLAYABLE_AREA_BOTTOM - VANISHING_POINT_Y);
- float base_offset = left ? -ROAD_LEFT_OFFSET : ROAD_RIGHT_OFFSET;
- float bottom_x = env->base_vanishing_point_x + base_offset + offset;
- float top_x = env->current_vanishing_point_x + offset;
- float edge_x;
- if (fabsf(env->current_curve_factor) < 0.01f) {
- // Straight road
- edge_x = bottom_x + t * (top_x - bottom_x);
- } else {
- // Adjust curve offset based on curve direction
- float curve_offset = (env->current_curve_factor > 0 ? -30.0f : 30.0f) * fabsf(env->current_curve_factor);
- float control_x = bottom_x + (top_x - bottom_x) * 0.5f + curve_offset;
- // Calculate edge using Bézier curve for proper curvature
- edge_x = quadratic_bezier(bottom_x, control_x, top_x, t);
- }
-
- // Wiggle effect
- float wiggle_offset = 0.0f;
- if (env->wiggle_active && y >= env->wiggle_y && y <= env->wiggle_y + env->wiggle_length) {
- float t_wiggle = (y - env->wiggle_y) / env->wiggle_length; // Ranges from 0 to 1
- // Trapezoidal wave calculation
- if (t_wiggle < 0.15f) {
- // Connection to road edge
- wiggle_offset = env->wiggle_amplitude * (t_wiggle / 0.15f);
- } else if (t_wiggle < 0.87f) {
- // Flat top of wiggle
- wiggle_offset = env->wiggle_amplitude;
- } else {
- // Reconnection to road edge
- wiggle_offset = env->wiggle_amplitude * ((1.0f - t_wiggle) / 0.13f);
- }
- // Wiggle towards road center
- wiggle_offset *= (left ? 1.0f : -1.0f);
- // Scale wiggle offset based on y position, starting at 0.03f at the vanishing point
- float depth = (y - VANISHING_POINT_Y) / (PLAYABLE_AREA_BOTTOM - VANISHING_POINT_Y);
- float scale = 0.03f + (depth * depth);
- if (scale > 0.3f) {
- scale = 0.3f;
- }
- wiggle_offset *= scale;
- }
- // Apply the wiggle offset
- edge_x += wiggle_offset;
- return edge_x;
-}
-
-// Computes x position of car in a given lane
-float car_x_in_lane(Enduro* env, int lane, float y) {
- // Set offset to 0 to ensure enemy cars align with the road rendering
- float offset = 0.0f;
- float left_edge = road_edge_x(env, y, offset, true);
- float right_edge = road_edge_x(env, y, offset, false);
- float lane_width = (right_edge - left_edge) / NUM_LANES;
- return left_edge + lane_width * (lane + 0.5f);
-}
-
-// Handles rendering logic
-Client* make_client(Enduro* env) {
- Client* client = (Client*)calloc(1, sizeof(Client));
-
- // State data from env (Enduro*)
- client->width = env->width;
- client->height = env->height;
-
- initRaylib(&client->gameState); // Pass gameState here
- loadTextures(&client->gameState);
-
- return client;
-}
-
-void close_client(Client* client) {
- cleanup(&client->gameState);
- CloseWindow();
- free(client);
-}
-
-void render_car(GameState* gameState) {
- int carAssetIndex = gameState->showLeftTread ? gameState->playerCarLeftTreadIndex : gameState->playerCarRightTreadIndex;
- Rectangle srcRect = asset_map[carAssetIndex];
- Vector2 position = { gameState->player_x, gameState->player_y };
- DrawTextureRec(gameState->spritesheet, srcRect, position, WHITE);
-}
-
-void initRaylib(GameState* gameState) {
- if (!IsWindowReady()) {
- InitWindow(SCREEN_WIDTH * 2, SCREEN_HEIGHT * 2, "puffer_enduro");
- SetTargetFPS(60);
- gameState->renderTarget = LoadRenderTexture(SCREEN_WIDTH, SCREEN_HEIGHT);
- }
-}
-
-void loadTextures(GameState* gameState) {
- // Load background and mountain textures for different times of day per original env
- gameState->spritesheet = LoadTexture("resources/enduro/enduro_spritesheet.png");
-
- // Initialize animation variables
- gameState->carAnimationTimer = 0.0f;
- gameState->carAnimationInterval = 0.05f; // Init; updated based on speed
- gameState->showLeftTread = true;
- gameState->mountainPosition = 0.0f;
-
- // Initialize victory effect variables
- gameState->showLeftFlag = true;
- gameState->flagTimer = 0;
- gameState->victoryDisplayTimer = 0;
- gameState->victoryAchieved = false;
-
- // Initialize scoreboard variables
- gameState->score = 0;
- gameState->scoreTimer = 0;
- gameState->carsLeftGameState = 0;
- gameState->day = 1;
-
- // Initialize score digits arrays
- for (int i = 0; i < SCORE_DIGITS; i++) {
- gameState->scoreDigitCurrents[i] = 0;
- gameState->scoreDigitNexts[i] = 0;
- gameState->scoreDigitOffsets[i] = 0.0f;
- gameState->scoreDigitScrolling[i] = false;
- }
-
- // Initialize time-of-day variables
- gameState->elapsedTime = 0.0f;
- gameState->currentBackgroundIndex = 0;
- gameState->previousBackgroundIndex = 0;
-
- // Initialize background and mountain indices
- for (int i = 0; i < 16; ++i) {
- gameState->backgroundIndices[i] = ASSET_BG_0 + i;
- gameState->mountainIndices[i] = ASSET_MOUNTAIN_0 + i;
- }
-
- // Initialize digit indices
- for (int i = 0; i < 10; ++i) {
- gameState->digitIndices[i] = ASSET_DIGITS_0 + i;
- gameState->greenDigitIndices[i] = ASSET_GREEN_DIGITS_0 + i;
- gameState->yellowDigitIndices[i] = ASSET_YELLOW_DIGITS_0 + i;
- }
- gameState->digitIndices[10] = ASSET_DIGITS_CAR; // Index for "CAR"
-
- // Initialize enemy car indices
- int baseEnemyCarIndex = ASSET_ENEMY_CAR_BLUE_LEFT_TREAD;
- for (int color = 0; color < 6; ++color) {
- for (int tread = 0; tread < 2; ++tread) {
- gameState->enemyCarIndices[color][tread] = baseEnemyCarIndex + color * 2 + tread;
- }
- }
-
- // Load other asset indices
- gameState->enemyCarNightTailLightsIndex = ASSET_ENEMY_CAR_NIGHT_TAIL_LIGHTS;
- gameState->enemyCarNightFogTailLightsIndex = ASSET_ENEMY_CAR_NIGHT_FOG_TAIL_LIGHTS;
- gameState->playerCarLeftTreadIndex = ASSET_PLAYER_CAR_LEFT_TREAD;
- gameState->playerCarRightTreadIndex = ASSET_PLAYER_CAR_RIGHT_TREAD;
- gameState->levelCompleteFlagLeftIndex = ASSET_LEVEL_COMPLETE_FLAG_LEFT;
- gameState->levelCompleteFlagRightIndex = ASSET_LEVEL_COMPLETE_FLAG_RIGHT;
-
- // Initialize animation variables
- gameState->carAnimationTimer = 0.0f;
- gameState->carAnimationInterval = 0.05f; // Initial interval, will be updated based on speed
- gameState->showLeftTread = true;
- gameState->mountainPosition = 0.0f;
-}
-
-void cleanup(GameState* gameState) {
- UnloadRenderTexture(gameState->renderTarget);
- UnloadTexture(gameState->spritesheet);
-}
-
-void updateCarAnimation(GameState* gameState) {
- // Update the animation interval based on the player's speed
- // Faster speed means faster alternation
- float minInterval = 0.005f; // Minimum interval at max speed
- float maxInterval = 0.075f; // Maximum interval at min speed
-
- float speedRatio = (gameState->speed - gameState->min_speed) / (gameState->max_speed - gameState->min_speed);
- gameState->carAnimationInterval = maxInterval - (maxInterval - minInterval) * speedRatio;
-
- // Update the animation timer
- gameState->carAnimationTimer += GetFrameTime(); // Time since last frame
-
- if (gameState->carAnimationTimer >= gameState->carAnimationInterval) {
- gameState->carAnimationTimer = 0.0f;
- gameState->showLeftTread = !gameState->showLeftTread; // Switch texture
- }
-}
-
-void updateScoreboard(GameState* gameState) {
- float normalizedSpeed = fminf(fmaxf(gameState->speed, 1.0f), 2.0f);
- // Determine the frame interval for score increment based on speed
- int frameInterval = (int)(30 / normalizedSpeed);
- gameState->scoreTimer++;
-
- if (gameState->scoreTimer >= frameInterval) {
- gameState->scoreTimer = 0;
- // Increment the score based on normalized speed
- gameState->score += (int)normalizedSpeed;
- if (gameState->score > 99999) {
- gameState->score = 0;
- }
- // Determine which digits have changed and start scrolling them
- int tempScore = gameState->score;
- for (int i = SCORE_DIGITS - 1; i >= 0; i--) {
- int newDigit = tempScore % 10;
- tempScore /= 10;
- if (newDigit != gameState->scoreDigitCurrents[i]) {
- gameState->scoreDigitNexts[i] = newDigit;
- gameState->scoreDigitOffsets[i] = 0.0f;
- gameState->scoreDigitScrolling[i] = true;
- }
- }
- }
- // Update scrolling digits
- float scrollSpeed = 0.55f * normalizedSpeed;
- for (int i = 0; i < SCORE_DIGITS; i++) {
- if (gameState->scoreDigitScrolling[i]) {
- gameState->scoreDigitOffsets[i] += scrollSpeed; // Scroll speed
- if (gameState->scoreDigitOffsets[i] >= DIGIT_HEIGHT) {
- gameState->scoreDigitOffsets[i] = 0.0f;
- gameState->scoreDigitCurrents[i] = gameState->scoreDigitNexts[i];
- gameState->scoreDigitScrolling[i] = false; // Stop scrolling
- }
- }
- }
-}
-
-void renderBackground(GameState* gameState) {
- int bgIndex = gameState->backgroundIndices[gameState->currentBackgroundIndex];
- Rectangle srcRect = asset_map[bgIndex];
- DrawTextureRec(gameState->spritesheet, srcRect, (Vector2){0, 0}, WHITE);
-}
-
-void renderScoreboard(GameState* gameState) {
- int digitWidth = DIGIT_WIDTH;
- int digitHeight = DIGIT_HEIGHT;
- // Convert bottom-left coordinates to top-left origin
- // -8 for x resolution change from 160 to 152
- int scoreStartX = 56 + digitWidth - 8;
- int scoreStartY = 173 - digitHeight;
- int dayX = 56 - 8;
- int dayY = 188 - digitHeight;
- int carsX = 72 - 8;
- int carsY = 188 - digitHeight;
-
- // Render score with scrolling effect
- for (int i = 0; i < SCORE_DIGITS; ++i) {
- int digitX = scoreStartX + i * digitWidth;
- int currentDigitIndex = gameState->scoreDigitCurrents[i];
- int nextDigitIndex = gameState->scoreDigitNexts[i];
-
- int currentAssetIndex, nextAssetIndex;
- if (i == SCORE_DIGITS - 1) {
- // Use yellow digits for the last digit
- currentAssetIndex = gameState->yellowDigitIndices[currentDigitIndex];
- nextAssetIndex = gameState->yellowDigitIndices[nextDigitIndex];
- } else {
- // Use regular digits
- currentAssetIndex = gameState->digitIndices[currentDigitIndex];
- nextAssetIndex = gameState->digitIndices[nextDigitIndex];
- }
- Rectangle srcRectCurrentFull = asset_map[currentAssetIndex];
- Rectangle srcRectNextFull = asset_map[nextAssetIndex];
-
- if (gameState->scoreDigitScrolling[i]) {
- // Scrolling effect for this digit
- float offset = gameState->scoreDigitOffsets[i];
- // Render current digit moving up
- Rectangle srcRectCurrent = srcRectCurrentFull;
- srcRectCurrent.height = digitHeight - (int)offset;
- Rectangle destRectCurrent = { digitX, scoreStartY + (int)offset, digitWidth, digitHeight - (int)offset };
- DrawTexturePro(
- gameState->spritesheet,
- srcRectCurrent,
- destRectCurrent,
- (Vector2){ 0, 0 },
- 0.0f,
- WHITE
- );
- // Render next digit coming up from below
- Rectangle srcRectNext = srcRectNextFull;
- srcRectNext.y += digitHeight - (int)offset;
- srcRectNext.height = (int)offset;
- Rectangle destRectNext = { digitX, scoreStartY, digitWidth, (int)offset };
- DrawTexturePro(
- gameState->spritesheet,
- srcRectNext,
- destRectNext,
- (Vector2){ 0, 0 },
- 0.0f,
- WHITE
- );
- } else {
- // No scrolling, render the current digit normally
- Rectangle srcRect = asset_map[currentAssetIndex];
- Vector2 position = { digitX, scoreStartY };
- DrawTextureRec(gameState->spritesheet, srcRect, position, WHITE);
- }
- }
-
- // Render day number
- int day = gameState->day % 10;
- int dayTextureIndex = day;
- // Pass dayCompleted condition from Enduro to GameState
- if (gameState->dayCompleted) {
- gameState->victoryAchieved = true;
- }
- Rectangle daySrcRect;
- if (gameState->victoryAchieved) {
- // Green day digits during victory
- int assetIndex = gameState->greenDigitIndices[dayTextureIndex];
- daySrcRect = asset_map[assetIndex];
- } else {
- // Use normal digits
- int assetIndex = gameState->digitIndices[dayTextureIndex];
- daySrcRect = asset_map[assetIndex];
- }
- Vector2 dayPosition = { dayX, dayY };
- DrawTextureRec(gameState->spritesheet, daySrcRect, dayPosition, WHITE);
-
- // Render "CAR" digit or flags for cars to pass
- if (gameState->victoryAchieved) {
- // Alternate between level_complete_flag_left and level_complete_flag_right
- int flagAssetIndex = gameState->showLeftFlag ? gameState->levelCompleteFlagLeftIndex : gameState->levelCompleteFlagRightIndex;
- Rectangle flagSrcRect = asset_map[flagAssetIndex];
- Rectangle destRect = { carsX, carsY, flagSrcRect.width, flagSrcRect.height };
- DrawTexturePro(
- gameState->spritesheet,
- flagSrcRect,
- destRect,
- (Vector2){ 0, 0 },
- 0.0f,
- WHITE
- );
- } else {
- // Render "CAR" label
- int carAssetIndex = gameState->digitIndices[10]; // Index for "CAR"
- Rectangle carSrcRect = asset_map[carAssetIndex];
- Vector2 carPosition = { carsX, carsY };
- DrawTextureRec(gameState->spritesheet, carSrcRect, carPosition, WHITE);
-
- // Render the remaining digits for cars to pass
- int cars = gameState->carsLeftGameState;
- if (cars < 0) cars = 0; // Ensure cars is not negative
- for (int i = 1; i < CARS_DIGITS; ++i) {
- int divisor = (int)pow(10, CARS_DIGITS - i - 1);
- int digit = (cars / divisor) % 10;
- if (digit < 0 || digit > 9) digit = 0; // Clamp digit to valid range
- int digitX = carsX + i * (digitWidth + 1); // Add spacing between digits
- int assetIndex = gameState->digitIndices[digit];
- Rectangle srcRect = asset_map[assetIndex];
- Vector2 position = { digitX, carsY };
- DrawTextureRec(gameState->spritesheet, srcRect, position, WHITE);
- }
- }
-}
-
-// Triggers the day completed 'victory' display
-// Solely for flapping flag visual effect
-void updateVictoryEffects(GameState* gameState) {
- if (!gameState->victoryAchieved) {
- return;
- }
- gameState->flagTimer++;
- // Modulo triggers flag direction change
- // Flag renders in that direction until next change
- if (gameState->flagTimer % 50 == 0) {
- gameState->showLeftFlag = !gameState->showLeftFlag;
- }
- gameState->victoryDisplayTimer++;
- if (gameState->victoryDisplayTimer >= 10) {
- gameState->victoryDisplayTimer = 0;
- }
-}
-
-void updateMountains(GameState* gameState) {
- // Mountain scrolling effect when road is curving
- float baseSpeed = 0.0f;
- float curveStrength = fabsf(gameState->current_curve_factor);
- float speedMultiplier = 1.0f; // Scroll speed
- float scrollSpeed = baseSpeed + curveStrength * speedMultiplier;
- int mountainIndex = gameState->mountainIndices[0]; // Use any mountain index since width is consistent
- int mountainWidth = asset_map[mountainIndex].width;
- if (gameState->current_curve_direction == 1) { // Turning left
- gameState->mountainPosition += scrollSpeed;
- if (gameState->mountainPosition >= mountainWidth) {
- gameState->mountainPosition -= mountainWidth;
- }
- } else if (gameState->current_curve_direction == -1) { // Turning right
- gameState->mountainPosition -= scrollSpeed;
- if (gameState->mountainPosition <= -mountainWidth) {
- gameState->mountainPosition += mountainWidth;
- }
- }
-}
-
-void renderMountains(GameState* gameState) {
- int mountainIndex = gameState->mountainIndices[gameState->currentBackgroundIndex];
- Rectangle srcRect = asset_map[mountainIndex];
- int mountainWidth = srcRect.width;
- int mountainY = 45; // Y position per original environment
-
- float playerCenterX = (PLAYER_MIN_X + PLAYER_MAX_X) / 2.0f;
- float playerOffset = gameState->player_x - playerCenterX;
- float parallaxFactor = 0.5f;
- float adjustedOffset = -playerOffset * parallaxFactor;
- float mountainX = -gameState->mountainPosition + adjustedOffset;
-
- BeginScissorMode(PLAYABLE_AREA_LEFT, 0, SCREEN_WIDTH - PLAYABLE_AREA_LEFT, SCREEN_HEIGHT);
- for (int x = (int)mountainX; x < SCREEN_WIDTH; x += mountainWidth) {
- DrawTextureRec(gameState->spritesheet, srcRect, (Vector2){x, mountainY}, WHITE);
- }
- for (int x = (int)mountainX - mountainWidth; x > -mountainWidth; x -= mountainWidth) {
- DrawTextureRec(gameState->spritesheet, srcRect, (Vector2){x, mountainY}, WHITE);
- }
- EndScissorMode();
-}
-
-void c_render(Enduro* env) {
- if (env->client == NULL) {
- env->client = make_client(env);
- }
- // Client* client = env->client;
- GameState* gameState = &env->client->gameState;
-
- // Copy env state to gameState
- gameState->speed = env->speed;
- gameState->min_speed = env->min_speed;
- gameState->max_speed = env->max_speed;
- gameState->current_curve_direction = env->current_curve_direction;
- gameState->current_curve_factor = env->current_curve_factor;
- gameState->player_x = env->player_x;
- gameState->player_y = env->player_y;
- gameState->initial_player_x = env->initial_player_x;
- gameState->vanishing_point_x = env->vanishing_point_x;
- gameState->t_p = env->t_p;
- gameState->dayCompleted = env->dayCompleted;
- gameState->currentBackgroundIndex = env->currentDayTimeIndex;
- gameState->carsLeftGameState = env->carsToPass;
- gameState->day = env->day;
- gameState->elapsedTime = env->elapsedTimeEnv;
- // -1 represents reset of env
- if (env->score == 0) {
- gameState->score = 0;
- }
-
- // Render to a texture for scaling up
- BeginTextureMode(gameState->renderTarget);
-
- // Do not call BeginDrawing() here
- ClearBackground(BLACK);
- BeginBlendMode(BLEND_ALPHA);
-
- renderBackground(gameState);
- updateCarAnimation(gameState);
- updateMountains(gameState);
- renderMountains(gameState);
-
- int bgIndex = gameState->currentBackgroundIndex;
- unsigned char isNightFogStage = (bgIndex == 13);
- unsigned char isNightStage = (bgIndex == 12 || bgIndex == 13 || bgIndex == 14);
-
- // During night fog stage, clip rendering to y >= 92
- float clipStartY = isNightFogStage ? 92.0f : VANISHING_POINT_Y;
- float clipHeight = PLAYABLE_AREA_BOTTOM - clipStartY;
- Rectangle clipRect = { PLAYABLE_AREA_LEFT, clipStartY, PLAYABLE_AREA_RIGHT - PLAYABLE_AREA_LEFT, clipHeight };
- BeginScissorMode(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
-
- // Render road edges
- float roadStartY = isNightFogStage ? 92.0f : VANISHING_POINT_Y;
- Vector2 previousLeftPoint = {0}, previousRightPoint = {0};
- unsigned char firstPoint = true;
-
- for (float y = roadStartY; y <= PLAYABLE_AREA_BOTTOM; y += 0.75f) {
- float adjusted_y = (env->speed < 0) ? y : y + fmod(env->road_scroll_offset, 0.75f);
- if (adjusted_y > PLAYABLE_AREA_BOTTOM) continue;
-
- float left_edge = road_edge_x(env, adjusted_y, 0, true);
- float right_edge = road_edge_x(env, adjusted_y, 0, false);
-
- // Road color based on y position
- Color roadColor;
- if (adjusted_y >= 52 && adjusted_y < 91) {
- roadColor = (Color){74, 74, 74, 255};
- } else if (adjusted_y >= 91 && adjusted_y < 106) {
- roadColor = (Color){111, 111, 111, 255};
- } else if (adjusted_y >= 106 && adjusted_y <= 154) {
- roadColor = (Color){170, 170, 170, 255};
- } else {
- roadColor = WHITE;
- }
-
- Vector2 currentLeftPoint = {left_edge, adjusted_y};
- Vector2 currentRightPoint = {right_edge, adjusted_y};
-
- if (!firstPoint) {
- DrawLineV(previousLeftPoint, currentLeftPoint, roadColor);
- DrawLineV(previousRightPoint, currentRightPoint, roadColor);
- }
-
- previousLeftPoint = currentLeftPoint;
- previousRightPoint = currentRightPoint;
- firstPoint = false;
- }
-
- // Render enemy cars scaled stages for distance/closeness effect
- unsigned char skipFogCars = isNightFogStage;
- for (int i = 0; i < env->numEnemies; i++) {
- Car* car = &env->enemyCars[i];
-
- // Don't render cars in fog
- if (skipFogCars && car->y < 92.0f) {
- continue;
- }
-
- // Determine the car scale based on distance
- float car_scale = get_car_scale(car->y);
- // Select the correct texture based on the car's color and current tread
- int carAssetIndex;
- if (isNightStage) {
- carAssetIndex = (bgIndex == 13) ? gameState->enemyCarNightFogTailLightsIndex : gameState->enemyCarNightTailLightsIndex;
- } else {
- int colorIndex = car->colorIndex;
- int treadIndex = gameState->showLeftTread ? 0 : 1;
- carAssetIndex = gameState->enemyCarIndices[colorIndex][treadIndex];
- }
- Rectangle srcRect = asset_map[carAssetIndex];
-
- // Compute car coordinates
- float car_center_x = car_x_in_lane(env, car->lane, car->y);
- float car_x = car_center_x - (srcRect.width * car_scale) / 2.0f;
- float car_y = car->y - (srcRect.height * car_scale) / 2.0f;
-
- DrawTexturePro(
- gameState->spritesheet,
- srcRect,
- (Rectangle){ car_x, car_y, srcRect.width * car_scale, srcRect.height * car_scale },
- (Vector2){ 0, 0 },
- 0.0f,
- WHITE
- );
- }
-
- render_car(gameState); // Unscaled player car
-
- EndScissorMode();
- EndBlendMode();
- updateVictoryEffects(gameState);
- updateScoreboard(gameState);
- renderScoreboard(gameState);
-
- // Update GameState data from environment data;
- env->client->gameState.victoryAchieved = env->dayCompleted;
-
- // Finish rendering to the texture
- EndTextureMode();
-
- // Now render the scaled-up texture to the screen
- BeginDrawing();
- ClearBackground(BLACK);
-
- // Draw the render texture scaled up
- DrawTexturePro(
- gameState->renderTarget.texture,
- (Rectangle){ 0, 0, (float)gameState->renderTarget.texture.width, -(float)gameState->renderTarget.texture.height },
- (Rectangle){ 0, 0, (float)SCREEN_WIDTH * 2, (float)SCREEN_HEIGHT * 2 },
- (Vector2){ 0, 0 },
- 0.0f,
- WHITE
- );
-
- EndDrawing();
-}
diff --git a/pufferlib/ocean/enduro/enduro.py b/pufferlib/ocean/enduro/enduro.py
deleted file mode 100644
index 286e8219e..000000000
--- a/pufferlib/ocean/enduro/enduro.py
+++ /dev/null
@@ -1,81 +0,0 @@
-import random
-import numpy as np
-import gymnasium
-
-import pufferlib
-from pufferlib.ocean.enduro import binding
-
-class Enduro(pufferlib.PufferEnv):
- def __init__(self, num_envs=1, render_mode=None,
- width=152, height=210, car_width=16, car_height=11,
- max_enemies=10, frameskip=1, continuous=False,
- log_interval=128, buf=None, seed=None):
-
- self.single_observation_space = gymnasium.spaces.Box(
- low=0, high=1, shape=(8 + (5 * max_enemies) + 9 + 1,), dtype=np.float32
- )
- # Example: 9 discrete actions
- self.single_action_space = gymnasium.spaces.Discrete(9)
-
- self.render_mode = render_mode
- self.num_agents = num_envs
- self.continuous = continuous
- self.log_interval = log_interval
- self.human_action = None
- self.tick = 0
- if seed is None:
- self.seed = random.randint(1, 1000000)
- else:
- self.seed = 0
- super().__init__(buf)
-
- self.c_envs = binding.vec_init(
- self.observations, self.actions, self.rewards,
- self.terminals, self.truncations, num_envs, self.seed,
- width=width, height=height, car_width=car_width,
- car_height=car_height, max_enemies=max_enemies,
- frameskip=frameskip, continuous=continuous
- )
-
- def reset(self, seed=None):
- binding.vec_reset(self.c_envs, seed)
- self.tick = 0
- return self.observations, []
-
- def step(self, actions):
- self.actions[:] = actions
-
- self.tick += 1
- binding.vec_step(self.c_envs)
-
- info = []
- if self.tick % self.log_interval == 0:
- info.append(binding.vec_log(self.c_envs))
-
- return (self.observations, self.rewards,
- self.terminals, self.truncations, info)
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-def test_performance(timeout=10, atn_cache=1024):
- env = Enduro(num_envs=2)
- env.reset(env.seed)
- tick = 0
-
- actions = np.random.randint(0, env.single_action_space.n, (atn_cache, env.num_agents))
-
- import time
- start = time.time()
- while time.time() - start < timeout:
- atn = actions[tick % atn_cache]
- env.step(atn)
- tick += 1
-
- print(f'SPS: {env.num_agents * tick / (time.time() - start)}')
-
-if __name__ == '__main__':
- test_performance()
\ No newline at end of file
diff --git a/pufferlib/ocean/env_binding.h b/pufferlib/ocean/env_binding.h
index f64b6148b..f11ea0f39 100644
--- a/pufferlib/ocean/env_binding.h
+++ b/pufferlib/ocean/env_binding.h
@@ -1,3 +1,4 @@
+#include "env_config.h"
#include
#include
@@ -134,15 +135,15 @@ static PyObject* env_init(PyObject* self, PyObject* args, PyObject* kwargs) {
return NULL;
}
// env->truncations = PyArray_DATA(truncations);
-
-
+
+
PyObject* seed_arg = PyTuple_GetItem(args, 5);
if (!PyObject_TypeCheck(seed_arg, &PyLong_Type)) {
PyErr_SetString(PyExc_TypeError, "seed must be an integer");
return NULL;
}
int seed = PyLong_AsLong(seed_arg);
-
+
// Assumes each process has the same number of environments
srand(seed);
@@ -410,10 +411,10 @@ static PyObject* vec_init(PyObject* self, PyObject* args, PyObject* kwargs) {
return NULL;
}
vec->envs[i] = env;
-
+
// // Make sure the log is initialized to 0
memset(&env->log, 0, sizeof(Log));
-
+
env->observations = (void*)((char*)PyArray_DATA(observations) + i*PyArray_STRIDE(observations, 0));
env->actions = (void*)((char*)PyArray_DATA(actions) + i*PyArray_STRIDE(actions, 0));
env->rewards = (void*)((char*)PyArray_DATA(rewards) + i*PyArray_STRIDE(rewards, 0));
@@ -423,7 +424,7 @@ static PyObject* vec_init(PyObject* self, PyObject* args, PyObject* kwargs) {
// Assumes each process has the same number of environments
int env_seed = i + seed*vec->num_envs;
srand(env_seed);
-
+
// Add the seed to kwargs for this environment
PyObject* py_seed = PyLong_FromLong(env_seed);
if (PyDict_SetItemString(kwargs, "seed", py_seed) < 0) {
@@ -496,7 +497,7 @@ static PyObject* vec_reset(PyObject* self, PyObject* args) {
return NULL;
}
int seed = PyLong_AsLong(seed_arg);
-
+
for (int i = 0; i < vec->num_envs; i++) {
// Assumes each process has the same number of environments
srand(i + seed*vec->num_envs);
@@ -542,7 +543,7 @@ static PyObject* vec_render(PyObject* self, PyObject* args) {
return NULL;
}
int env_id = PyLong_AsLong(env_id_arg);
-
+
c_render(vec->envs[env_id]);
Py_RETURN_NONE;
}
@@ -612,6 +613,214 @@ static PyObject* vec_close(PyObject* self, PyObject* args) {
Py_RETURN_NONE;
}
+static PyObject* get_global_agent_state(PyObject* self, PyObject* args) {
+ if (PyTuple_Size(args) != 5) {
+ PyErr_SetString(PyExc_TypeError, "get_global_agent_state requires 5 arguments");
+ return NULL;
+ }
+
+ Env* env = unpack_env(args);
+ if (!env) {
+ return NULL;
+ }
+
+ Drive* drive = (Drive*)env; // Cast to Drive*
+
+ // Get the numpy arrays from arguments
+ PyObject* x_arr = PyTuple_GetItem(args, 1);
+ PyObject* y_arr = PyTuple_GetItem(args, 2);
+ PyObject* z_arr = PyTuple_GetItem(args, 3);
+ PyObject* heading_arr = PyTuple_GetItem(args, 4);
+ PyObject* id_arr = PyTuple_GetItem(args, 5);
+
+ if (!PyArray_Check(x_arr) || !PyArray_Check(y_arr) ||
+ !PyArray_Check(z_arr) || !PyArray_Check(heading_arr) ||
+ !PyArray_Check(id_arr)) {
+ PyErr_SetString(PyExc_TypeError, "All output arrays must be NumPy arrays");
+ return NULL;
+ }
+
+ float* x_data = (float*)PyArray_DATA((PyArrayObject*)x_arr);
+ float* y_data = (float*)PyArray_DATA((PyArrayObject*)y_arr);
+ float* z_data = (float*)PyArray_DATA((PyArrayObject*)z_arr);
+ float* heading_data = (float*)PyArray_DATA((PyArrayObject*)heading_arr);
+ int* id_data = (int*)PyArray_DATA((PyArrayObject*)id_arr);
+
+ c_get_global_agent_state(drive, x_data, y_data, z_data, heading_data, id_data);
+
+ Py_RETURN_NONE;
+}
+static PyObject* vec_get_global_agent_state(PyObject* self, PyObject* args) {
+ if (PyTuple_Size(args) != 6) {
+ PyErr_SetString(PyExc_TypeError, "vec_get_global_agent_state requires 6 arguments");
+ return NULL;
+ }
+
+ VecEnv* vec = unpack_vecenv(args);
+ if (!vec) {
+ return NULL;
+ }
+
+ // Get the numpy arrays from arguments
+ PyObject* x_arr = PyTuple_GetItem(args, 1);
+ PyObject* y_arr = PyTuple_GetItem(args, 2);
+ PyObject* z_arr = PyTuple_GetItem(args, 3);
+ PyObject* heading_arr = PyTuple_GetItem(args, 4);
+ PyObject* id_arr = PyTuple_GetItem(args, 5);
+
+ if (!PyArray_Check(x_arr) || !PyArray_Check(y_arr) ||
+ !PyArray_Check(z_arr) || !PyArray_Check(heading_arr) ||
+ !PyArray_Check(id_arr)) {
+ PyErr_SetString(PyExc_TypeError, "All output arrays must be NumPy arrays");
+ return NULL;
+ }
+
+ PyArrayObject* x_array = (PyArrayObject*)x_arr;
+ PyArrayObject* y_array = (PyArrayObject*)y_arr;
+ PyArrayObject* z_array = (PyArrayObject*)z_arr;
+ PyArrayObject* heading_array = (PyArrayObject*)heading_arr;
+ PyArrayObject* id_array = (PyArrayObject*)id_arr;
+
+ // Get base pointers to the arrays
+ float* x_base = (float*)PyArray_DATA(x_array);
+ float* y_base = (float*)PyArray_DATA(y_array);
+ float* z_base = (float*)PyArray_DATA(z_array);
+ float* heading_base = (float*)PyArray_DATA(heading_array);
+ int* id_base = (int*)PyArray_DATA(id_array);
+
+ // Iterate through environments and write to correct offsets
+ int offset = 0;
+ for (int i = 0; i < vec->num_envs; i++) {
+ Drive* drive = (Drive*)vec->envs[i];
+
+ // Write to the arrays at the current offset
+ c_get_global_agent_state(drive,
+ &x_base[offset],
+ &y_base[offset],
+ &z_base[offset],
+ &heading_base[offset],
+ &id_base[offset]);
+
+ // Move offset forward by the number of agents in this environment
+ offset += drive->active_agent_count;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject* get_ground_truth_trajectories(PyObject* self, PyObject* args) {
+ if (PyTuple_Size(args) != 7) {
+ PyErr_SetString(PyExc_TypeError, "get_ground_truth_trajectories requires 7 arguments");
+ return NULL;
+ }
+
+ Env* env = unpack_env(args);
+ if (!env) {
+ return NULL;
+ }
+
+ Drive* drive = (Drive*)env;
+
+ // Get the numpy arrays from arguments
+ PyObject* x_arr = PyTuple_GetItem(args, 1);
+ PyObject* y_arr = PyTuple_GetItem(args, 2);
+ PyObject* z_arr = PyTuple_GetItem(args, 3);
+ PyObject* heading_arr = PyTuple_GetItem(args, 4);
+ PyObject* valid_arr = PyTuple_GetItem(args, 5);
+ PyObject* id_arr = PyTuple_GetItem(args, 6);
+ PyObject* scenario_id_arr = PyTuple_GetItem(args, 7);
+
+ if (!PyArray_Check(x_arr) || !PyArray_Check(y_arr) ||
+ !PyArray_Check(z_arr) || !PyArray_Check(heading_arr) ||
+ !PyArray_Check(valid_arr) || !PyArray_Check(id_arr) || !PyArray_Check(scenario_id_arr)) {
+ PyErr_SetString(PyExc_TypeError, "All output arrays must be NumPy arrays");
+ return NULL;
+ }
+
+ float* x_data = (float*)PyArray_DATA((PyArrayObject*)x_arr);
+ float* y_data = (float*)PyArray_DATA((PyArrayObject*)y_arr);
+ float* z_data = (float*)PyArray_DATA((PyArrayObject*)z_arr);
+ float* heading_data = (float*)PyArray_DATA((PyArrayObject*)heading_arr);
+ int* valid_data = (int*)PyArray_DATA((PyArrayObject*)valid_arr);
+ int* id_data = (int*)PyArray_DATA((PyArrayObject*)id_arr);
+ int* scenario_id_data = (int*)PyArray_DATA((PyArrayObject*)scenario_id_arr);
+
+ c_get_global_ground_truth_trajectories(drive, x_data, y_data, z_data, heading_data, valid_data, id_data, scenario_id_data);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject* vec_get_global_ground_truth_trajectories(PyObject* self, PyObject* args) {
+ if (PyTuple_Size(args) != 8) {
+ PyErr_SetString(PyExc_TypeError, "vec_get_global_ground_truth_trajectories requires 8 arguments");
+ return NULL;
+ }
+
+ VecEnv* vec = unpack_vecenv(args);
+ if (!vec) {
+ return NULL;
+ }
+
+ // Get the numpy arrays from arguments
+ PyObject* x_arr = PyTuple_GetItem(args, 1);
+ PyObject* y_arr = PyTuple_GetItem(args, 2);
+ PyObject* z_arr = PyTuple_GetItem(args, 3);
+ PyObject* heading_arr = PyTuple_GetItem(args, 4);
+ PyObject* valid_arr = PyTuple_GetItem(args, 5);
+ PyObject* id_arr = PyTuple_GetItem(args, 6);
+ PyObject* scenario_id_arr = PyTuple_GetItem(args, 7);
+
+ if (!PyArray_Check(x_arr) || !PyArray_Check(y_arr) ||
+ !PyArray_Check(z_arr) || !PyArray_Check(heading_arr) ||
+ !PyArray_Check(valid_arr) || !PyArray_Check(id_arr) || !PyArray_Check(scenario_id_arr)) {
+ PyErr_SetString(PyExc_TypeError, "All output arrays must be NumPy arrays");
+ return NULL;
+ }
+
+ PyArrayObject* x_array = (PyArrayObject*)x_arr;
+ PyArrayObject* y_array = (PyArrayObject*)y_arr;
+ PyArrayObject* z_array = (PyArrayObject*)z_arr;
+ PyArrayObject* heading_array = (PyArrayObject*)heading_arr;
+ PyArrayObject* valid_array = (PyArrayObject*)valid_arr;
+ PyArrayObject* id_array = (PyArrayObject*)id_arr;
+ PyArrayObject* scenario_id_array = (PyArrayObject*)scenario_id_arr;
+
+ // Get base pointers to the arrays
+ float* x_base = (float*)PyArray_DATA(x_array);
+ float* y_base = (float*)PyArray_DATA(y_array);
+ float* z_base = (float*)PyArray_DATA(z_array);
+ float* heading_base = (float*)PyArray_DATA(heading_array);
+ int* valid_base = (int*)PyArray_DATA(valid_array);
+ int* id_base = (int*)PyArray_DATA(id_array);
+ int* scenario_id_base = (int*)PyArray_DATA(scenario_id_array);
+
+ // Get number of timesteps from array shape
+ npy_intp* x_shape = PyArray_DIMS(x_array);
+ int num_timesteps = x_shape[1]; // Second dimension for 2D arrays
+
+ // Iterate through environments and write to correct offsets
+ int agent_offset = 0; // Offset for 1D arrays (id, scenario_id)
+ int traj_offset = 0; // Offset for 2D arrays (x, y, z, heading, valid)
+
+ for (int i = 0; i < vec->num_envs; i++) {
+ Drive* drive = (Drive*)vec->envs[i];
+
+ c_get_global_ground_truth_trajectories(drive,
+ &x_base[traj_offset],
+ &y_base[traj_offset],
+ &z_base[traj_offset],
+ &heading_base[traj_offset],
+ &valid_base[traj_offset],
+ &id_base[agent_offset],
+ &scenario_id_base[agent_offset]);
+
+ // Move offsets forward
+ agent_offset += drive->active_agent_count;
+ traj_offset += drive->active_agent_count * num_timesteps;
+ }
+
+ Py_RETURN_NONE;
+}
static double unpack(PyObject* kwargs, char* key) {
PyObject* val = PyDict_GetItemString(kwargs, key);
if (val == NULL) {
@@ -640,6 +849,32 @@ static double unpack(PyObject* kwargs, char* key) {
return 1;
}
+static char* unpack_str(PyObject* kwargs, char* key) {
+ PyObject* val = PyDict_GetItemString(kwargs, key);
+ if (val == NULL) {
+ char error_msg[100];
+ snprintf(error_msg, sizeof(error_msg), "Missing required keyword argument '%s'", key);
+ PyErr_SetString(PyExc_TypeError, error_msg);
+ return NULL;
+ }
+ if (!PyUnicode_Check(val)) {
+ char error_msg[100];
+ snprintf(error_msg, sizeof(error_msg), "Keyword argument '%s' must be a string", key);
+ PyErr_SetString(PyExc_TypeError, error_msg);
+ return NULL;
+ }
+ const char* str_val = PyUnicode_AsUTF8(val);
+ if (str_val == NULL) {
+ // PyUnicode_AsUTF8 sets an error on failure
+ return NULL;
+ }
+ char* ret = strdup(str_val);
+ if (ret == NULL) {
+ PyErr_SetString(PyExc_MemoryError, "strdup failed in unpack_str");
+ }
+ return ret;
+}
+
// Method table
static PyMethodDef methods[] = {
{"env_init", (PyCFunction)env_init, METH_VARARGS | METH_KEYWORDS, "Init environment with observation, action, reward, terminal, truncation arrays"},
@@ -657,6 +892,10 @@ static PyMethodDef methods[] = {
{"vec_render", vec_render, METH_VARARGS, "Render the vector of environments"},
{"vec_close", vec_close, METH_VARARGS, "Close the vector of environments"},
{"shared", (PyCFunction)my_shared, METH_VARARGS | METH_KEYWORDS, "Shared state"},
+ {"get_global_agent_state", get_global_agent_state, METH_VARARGS, "Get global agent state"},
+ {"vec_get_global_agent_state", vec_get_global_agent_state, METH_VARARGS, "Get agent state from vectorized env"},
+ {"get_ground_truth_trajectories", get_ground_truth_trajectories, METH_VARARGS, "Get ground truth trajectories"},
+ {"vec_get_global_ground_truth_trajectories", vec_get_global_ground_truth_trajectories, METH_VARARGS, "Get ground truth trajectories from vectorized env"},
MY_METHODS,
{NULL, NULL, 0, NULL}
};
diff --git a/pufferlib/ocean/env_config.h b/pufferlib/ocean/env_config.h
new file mode 100644
index 000000000..e8400c51c
--- /dev/null
+++ b/pufferlib/ocean/env_config.h
@@ -0,0 +1,98 @@
+#ifndef ENV_CONFIG_H
+#define ENV_CONFIG_H
+
+#include <../../inih-r62/ini.h>
+#include
+#include
+#include
+
+// Config struct for parsing INI files - contains all environment configuration
+typedef struct
+{
+ int action_type;
+ int dynamics_model;
+ float reward_vehicle_collision;
+ float reward_offroad_collision;
+ float reward_goal;
+ float reward_goal_post_respawn;
+ float reward_vehicle_collision_post_respawn;
+ float reward_ade;
+ float goal_radius;
+ int collision_behavior;
+ int offroad_behavior;
+ int spawn_immunity_timer;
+ float dt;
+ int goal_behavior;
+ int scenario_length;
+ int init_steps;
+ int init_mode;
+ int control_mode;
+} env_init_config;
+
+// INI file parser handler - parses all environment configuration from drive.ini
+static int handler(
+ void* config,
+ const char* section,
+ const char* name,
+ const char* value
+) {
+ env_init_config* env_config = (env_init_config*)config;
+ #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
+
+ if (MATCH("env", "action_type")) {
+ if (strcmp(value, "\"discrete\"") == 0 ||strcmp(value, "discrete") == 0) {
+ env_config->action_type = 0; // DISCRETE
+ } else if (strcmp(value, "\"continuous\"") == 0 || strcmp(value, "continuous") == 0) {
+ env_config->action_type = 1; // CONTINUOUS
+ } else {
+ printf("Warning: Unknown action_type value '%s', defaulting to DISCRETE\n", value);
+ env_config->action_type = 0; // Default to DISCRETE
+ }
+ } else if (MATCH("env", "dynamics_model")) {
+ if (strcmp(value, "\"classic\"") == 0 || strcmp(value, "classic") == 0) {
+ env_config->dynamics_model = 0; // CLASSIC
+ } else if (strcmp(value, "\"jerk\"") == 0 || strcmp(value, "jerk") == 0) {
+ env_config->dynamics_model = 1; // JERK
+ } else {
+ printf("Warning: Unknown dynamics_model value '%s', defaulting to JERK\n", value);
+ env_config->dynamics_model = 1; // Default to JERK
+ }
+ } else if (MATCH("env", "goal_behavior")) {
+ env_config->goal_behavior = atoi(value);
+ } else if (MATCH("env", "reward_vehicle_collision")) {
+ env_config->reward_vehicle_collision = atof(value);
+ } else if (MATCH("env", "reward_offroad_collision")) {
+ env_config->reward_offroad_collision = atof(value);
+ } else if (MATCH("env", "reward_goal")) {
+ env_config->reward_goal = atof(value);
+ } else if (MATCH("env", "reward_goal_post_respawn")) {
+ env_config->reward_goal_post_respawn = atof(value);
+ } else if (MATCH("env", "reward_vehicle_collision_post_respawn")) {
+ env_config->reward_vehicle_collision_post_respawn = atof(value);
+ } else if (MATCH("env", "reward_ade")) {
+ env_config->reward_ade = atof(value);
+ } else if (MATCH("env", "goal_radius")) {
+ env_config->goal_radius = atof(value);
+ } else if(MATCH("env", "collision_behavior")){
+ env_config->collision_behavior = atoi(value);
+ } else if(MATCH("env", "offroad_behavior")){
+ env_config->offroad_behavior = atoi(value);
+ } else if (MATCH("env", "spawn_immunity_timer")) {
+ env_config->spawn_immunity_timer = atoi(value);
+ } else if (MATCH("env", "dt")) {
+ env_config->dt = atof(value);
+ } else if (MATCH("env", "scenario_length")) {
+ env_config->scenario_length = atoi(value);
+ } else if (MATCH("env", "init_steps")) {
+ env_config->init_steps = atoi(value);
+ } else if (MATCH("env", "init_mode")) {
+ env_config->init_mode = atoi(value);
+ } else if (MATCH("env", "control_mode")) {
+ env_config->control_mode = atoi(value);
+ }
+
+ #undef MATCH
+ return 1;
+}
+
+#endif // ENV_CONFIG_H
diff --git a/pufferlib/ocean/environment.py b/pufferlib/ocean/environment.py
index 24c0e7193..feba8bead 100644
--- a/pufferlib/ocean/environment.py
+++ b/pufferlib/ocean/environment.py
@@ -1,6 +1,7 @@
import importlib
import pufferlib.emulation
+
def lazy_import(module_path, attr):
"""
Returns a callable that, when called with any arguments, will
@@ -9,165 +10,190 @@ def lazy_import(module_path, attr):
"""
return lambda *args, **kwargs: getattr(__import__(module_path, fromlist=[attr]), attr)(*args, **kwargs)
-def make_foraging(width=1080, height=720, num_agents=4096, horizon=512,
- discretize=True, food_reward=0.1, render_mode='rgb_array'):
+
+def make_foraging(
+ width=1080, height=720, num_agents=4096, horizon=512, discretize=True, food_reward=0.1, render_mode="rgb_array"
+):
from .grid import grid
+
init_fn = grid.init_foraging
reward_fn = grid.reward_foraging
- return grid.PufferGrid(width, height, num_agents,
- horizon, discretize=discretize, food_reward=food_reward, init_fn=init_fn, reward_fn=reward_fn, render_mode=render_mode)
-
-def make_predator_prey(width=1080, height=720, num_agents=4096, horizon=512,
- discretize=True, food_reward=0.1, render_mode='rgb_array'):
+ return grid.PufferGrid(
+ width,
+ height,
+ num_agents,
+ horizon,
+ discretize=discretize,
+ food_reward=food_reward,
+ init_fn=init_fn,
+ reward_fn=reward_fn,
+ render_mode=render_mode,
+ )
+
+
+def make_predator_prey(
+ width=1080, height=720, num_agents=4096, horizon=512, discretize=True, food_reward=0.1, render_mode="rgb_array"
+):
from .grid import grid
+
init_fn = grid.init_predator_prey
reward_fn = grid.reward_predator_prey
- return grid.PufferGrid(width, height, num_agents,
- horizon, discretize=discretize, food_reward=food_reward,
- init_fn=init_fn, reward_fn=reward_fn,
- render_mode=render_mode)
-
-def make_group(width=1080, height=720, num_agents=4096, horizon=512,
- discretize=True, food_reward=0.1, render_mode='rgb_array'):
+ return grid.PufferGrid(
+ width,
+ height,
+ num_agents,
+ horizon,
+ discretize=discretize,
+ food_reward=food_reward,
+ init_fn=init_fn,
+ reward_fn=reward_fn,
+ render_mode=render_mode,
+ )
+
+
+def make_group(
+ width=1080, height=720, num_agents=4096, horizon=512, discretize=True, food_reward=0.1, render_mode="rgb_array"
+):
from .grid import grid
+
init_fn = grid.init_group
reward_fn = grid.reward_group
- return grid.PufferGrid(width, height, num_agents,
- horizon, discretize=discretize, food_reward=food_reward,
- init_fn=init_fn, reward_fn=reward_fn,
- render_mode=render_mode)
-
-def make_puffer(width=1080, height=720, num_agents=4096, horizon=512,
- discretize=True, food_reward=0.1, render_mode='rgb_array'):
+ return grid.PufferGrid(
+ width,
+ height,
+ num_agents,
+ horizon,
+ discretize=discretize,
+ food_reward=food_reward,
+ init_fn=init_fn,
+ reward_fn=reward_fn,
+ render_mode=render_mode,
+ )
+
+
+def make_puffer(
+ width=1080, height=720, num_agents=4096, horizon=512, discretize=True, food_reward=0.1, render_mode="rgb_array"
+):
from .grid import grid
+
init_fn = grid.init_puffer
reward_fn = grid.reward_puffer
- return grid.PufferGrid(width, height, num_agents,
- horizon, discretize=discretize, food_reward=food_reward,
- init_fn=init_fn, reward_fn=reward_fn,
- render_mode=render_mode)
+ return grid.PufferGrid(
+ width,
+ height,
+ num_agents,
+ horizon,
+ discretize=discretize,
+ food_reward=food_reward,
+ init_fn=init_fn,
+ reward_fn=reward_fn,
+ render_mode=render_mode,
+ )
+
+
+def make_puffergrid(
+ render_mode="raylib", vision_range=5, num_envs=4096, num_maps=1000, max_map_size=9, report_interval=128, buf=None
+):
+ return PufferGrid(render_mode, vision_range, num_envs, num_maps, max_map_size, report_interval, buf)
-def make_puffergrid(render_mode='raylib', vision_range=5,
- num_envs=4096, num_maps=1000, max_map_size=9,
- report_interval=128, buf=None):
- return PufferGrid(render_mode, vision_range, num_envs,
- num_maps, max_map_size, report_interval, buf)
def make_continuous(discretize=False, buf=None, **kwargs):
from . import sanity
+
env = sanity.Continuous(discretize=discretize)
if not discretize:
env = pufferlib.ClipAction(env)
env = pufferlib.EpisodeStats(env)
return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
+
def make_squared(distance_to_target=3, num_targets=1, buf=None, **kwargs):
from . import sanity
+
env = sanity.Squared(distance_to_target=distance_to_target, num_targets=num_targets, **kwargs)
env = pufferlib.EpisodeStats(env)
return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf, **kwargs)
+
def make_bandit(num_actions=10, reward_scale=1, reward_noise=1, buf=None):
from . import sanity
- env = sanity.Bandit(num_actions=num_actions, reward_scale=reward_scale,
- reward_noise=reward_noise)
+
+ env = sanity.Bandit(num_actions=num_actions, reward_scale=reward_scale, reward_noise=reward_noise)
env = pufferlib.EpisodeStats(env)
return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
+
def make_memory(mem_length=2, mem_delay=2, buf=None, **kwargs):
from . import sanity
+
env = sanity.Memory(mem_length=mem_length, mem_delay=mem_delay)
env = pufferlib.EpisodeStats(env)
return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
+
def make_password(password_length=5, buf=None, **kwargs):
from . import sanity
+
env = sanity.Password(password_length=password_length)
env = pufferlib.EpisodeStats(env)
return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
+
def make_performance(delay_mean=0, delay_std=0, bandwidth=1, buf=None, **kwargs):
from . import sanity
+
env = sanity.Performance(delay_mean=delay_mean, delay_std=delay_std, bandwidth=bandwidth)
env = pufferlib.EpisodeStats(env)
return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
+
def make_performance_empiric(count_n=0, count_std=0, bandwidth=1, buf=None, **kwargs):
from . import sanity
+
env = sanity.PerformanceEmpiric(count_n=count_n, count_std=count_std, bandwidth=bandwidth)
env = pufferlib.EpisodeStats(env)
return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
+
def make_stochastic(p=0.7, horizon=100, buf=None, **kwargs):
from . import sanity
+
env = sanity.Stochastic(p=p, horizon=100)
env = pufferlib.EpisodeStats(env)
return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf)
+
def make_spaces(buf=None, **kwargs):
from . import sanity
+
env = sanity.Spaces()
env = pufferlib.EpisodeStats(env)
return pufferlib.emulation.GymnasiumPufferEnv(env=env, buf=buf, **kwargs)
+
def make_multiagent(buf=None, **kwargs):
from . import sanity
+
env = sanity.Multiagent()
env = pufferlib.MultiagentEpisodeStats(env)
return pufferlib.emulation.PettingZooPufferEnv(env=env, buf=buf)
+
MAKE_FUNCTIONS = {
- 'battle': 'Battle',
- 'breakout': 'Breakout',
- 'blastar': 'Blastar',
- 'convert': 'Convert',
- 'convert_circle': 'ConvertCircle',
- 'pong': 'Pong',
- 'freeway': 'Freeway',
- 'enduro': 'Enduro',
- 'tetris': 'Tetris',
- 'cartpole': 'Cartpole',
- 'moba': 'Moba',
- 'matsci': 'Matsci',
- 'memory': 'Memory',
- 'boids': 'Boids',
- 'drone_race': 'DroneRace',
- 'drone_swarm': 'DroneSwarm',
- 'nmmo3': 'NMMO3',
- 'snake': 'Snake',
- 'squared': 'Squared',
- 'pysquared': 'PySquared',
- 'connect4': 'Connect4',
- 'g2048': 'G2048',
- 'terraform': 'Terraform',
- 'template': 'Template',
- 'tripletriad': 'TripleTriad',
- 'tactical': 'Tactical',
- 'target': 'Target',
- 'go': 'Go',
- 'rware': 'Rware',
- 'trash_pickup': 'TrashPickupEnv',
- 'tower_climb': 'TowerClimb',
- 'grid': 'Grid',
- 'cpr': 'PyCPR',
- 'impulse_wars': 'ImpulseWars',
- 'drive': 'Drive',
- 'pacman': 'Pacman',
- 'checkers': 'Checkers',
- 'asteroids': 'Asteroids',
- 'whisker_racer': 'WhiskerRacer',
- 'spaces': make_spaces,
- 'multiagent': make_multiagent,
+ "drive": "Drive",
+ "spaces": make_spaces,
+ "multiagent": make_multiagent,
}
-def env_creator(name='squared', *args, **kwargs):
- if 'puffer_' not in name:
- raise pufferlib.APIUsageError(f'Invalid environment name: {name}')
+
+def env_creator(name="squared", *args, **kwargs):
+ if "puffer_" not in name:
+ raise pufferlib.APIUsageError(f"Invalid environment name: {name}")
# TODO: Robust sanity / ocean imports
- name = name.replace('puffer_', '')
+ name = name.replace("puffer_", "")
try:
- module = importlib.import_module(f'pufferlib.ocean.{name}.{name}')
+ module = importlib.import_module(f"pufferlib.ocean.{name}.{name}")
return getattr(module, MAKE_FUNCTIONS[name])
except ModuleNotFoundError:
return MAKE_FUNCTIONS[name]
diff --git a/pufferlib/ocean/freeway/binding.c b/pufferlib/ocean/freeway/binding.c
deleted file mode 100644
index 42eea05bb..000000000
--- a/pufferlib/ocean/freeway/binding.c
+++ /dev/null
@@ -1,31 +0,0 @@
-#include "freeway.h"
-
-#define Env Freeway
-#include "../env_binding.h"
-
-static int my_init(Env* env, PyObject* args, PyObject* kwargs) {
- env->frameskip = unpack(kwargs, "frameskip");
- env->width = unpack(kwargs, "width");
- env->height = unpack(kwargs, "height");
- env->player_width = unpack(kwargs, "player_width");
- env->player_height = unpack(kwargs, "player_height");
- env->car_width = unpack(kwargs, "car_width");
- env->car_height = unpack(kwargs, "car_height");
- env->lane_size = unpack(kwargs, "lane_size");
- env->level = unpack(kwargs, "level");
- env->difficulty = unpack(kwargs, "difficulty");
- env->use_dense_rewards = unpack(kwargs, "use_dense_rewards");
- env->env_randomization = unpack(kwargs, "env_randomization");
- env->enable_human_player = unpack(kwargs, "enable_human_player");
- init(env);
- return 0;
-}
-
-static int my_log(PyObject* dict, Log* log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "up_action_frac", log->up_action_frac);
- assign_to_dict(dict, "hits", log->hits);
- return 0;
-}
diff --git a/pufferlib/ocean/freeway/freeway.c b/pufferlib/ocean/freeway/freeway.c
deleted file mode 100644
index f36f2f9c8..000000000
--- a/pufferlib/ocean/freeway/freeway.c
+++ /dev/null
@@ -1,42 +0,0 @@
-#include
-#include "freeway.h"
-#include "puffernet.h"
-#include
-
-int main() {
- Weights* weights = load_weights("resources/freeway/freeway_weights.bin", 137092);
- int logit_sizes[1] = {3};
- LinearLSTM* net = make_linearlstm(weights, 1, 34, logit_sizes, 1);
-
- Freeway env = {
- .frameskip=4,
- .width=1216,
- .height=720,
- .player_width=64,
- .player_height=64,
- .car_width=64,
- .car_height=40,
- .lane_size=64,
- .difficulty=0,
- .level=4,
- .use_dense_rewards=1,
- .env_randomization=1,
- .enable_human_player=1,
- };
- allocate(&env);
-
- env.client = make_client(&env);
-
- c_reset(&env);
- while (!WindowShouldClose()) {
- forward_linearlstm(net, env.observations, env.actions);
- env.human_actions[0] = 0;
- if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)) env.human_actions[0] = 1;
- if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)) env.human_actions[0] = 2;
- c_step(&env);
- c_render(&env);
-
- }
- free_allocated(&env);
- close_client(env.client);
-}
diff --git a/pufferlib/ocean/freeway/freeway.h b/pufferlib/ocean/freeway/freeway.h
deleted file mode 100644
index c132fcab6..000000000
--- a/pufferlib/ocean/freeway/freeway.h
+++ /dev/null
@@ -1,622 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include "raylib.h"
-#include "freeway_levels.h"
-
-#define min(a, b) (((a) < (b)) ? (a) : (b))
-#define max(a, b) (((a) > (b)) ? (a) : (b))
-
-#define NOOP 0
-#define UP 1
-#define DOWN 2
-
-// Gameplay related
-#define TICK_RATE 1.0f/60.0f
-#define GAME_LENGTH 136.0f // Game length in seconds
-#define RANDOMIZE_SPEED_FREQ 360 // How many ticks before randomize the speed of the enemies
-#define TICKS_STUNT 40
-#define PENALTY_HIT -0.01f // Penalty for hitting an enemy
-// Rendering related
-#define HALF_LINEWIDTH 2
-#define DASH_SPACING 32
-#define DASH_SIZE 32
-
-// Based on https://ale.farama.org/environments/freeway/
-typedef struct Log Log;
-struct Log {
- float perf;
- float score;
- float episode_return;
- float episode_length;
- float up_action_frac;
- float hits;
- float n;
-};
-
-typedef struct FreewayPlayer FreewayPlayer;
-struct FreewayPlayer {
- float player_x;
- float player_y;
- int best_lane_idx;// furthest lane achieved so far
- int ticks_stunts_left;
- int score;
- int hits;
- int is_human;
-};
-
-typedef struct FreewayEnemy FreewayEnemy;
-struct FreewayEnemy {
- float enemy_x;
- float enemy_y;
- float enemy_initial_x;
- float enemy_vx; // velocity in pixels per second
- int speed_randomization; // 0 for no randomization, 1 for randomization
- int initial_speed_idx; // index of the initial speed in the speed array
- int current_speed_idx; // index of the current speed in the speed array
- int is_enabled;
- int lane_idx; // lane index
- int type;
- int enemy_width;
- int enemy_height;
-};
-
-typedef struct Client Client;
-typedef struct Freeway Freeway;
-struct Freeway {
- Client* client;
- Log log;
- float* observations;
- int* actions;
- int* human_actions;
- float* rewards;
- unsigned char* terminals;
-
- FreewayPlayer ai_player; // Player-Related
- FreewayPlayer human_player;
- int player_width;
- int player_height;
- float ep_return;
- int up_count;
-
- FreewayEnemy* enemies; // Enemy-Related
- int car_width;
- int car_height;
- int truck_width;
- int truck_height;
-
- int difficulty; // Global
- int level;
- int lane_size;
- float road_start;
- float road_end;
- int width;
- int height;
- int tick;
- float time_left;
- int frameskip;
- int use_dense_rewards;
- int env_randomization;
- int enable_human_player;
-};
-
-void load_level(Freeway* env, int level) {
- FreewayEnemy* enemy;
- for (int lane = 0; lane < NUM_LANES; lane++) {
- for (int i = 0; i < MAX_ENEMIES_PER_LANE; i++){
- enemy = &env->enemies[lane * MAX_ENEMIES_PER_LANE + i];
- enemy->is_enabled = (i < ENEMIES_PER_LANE[level][lane]);
- enemy->enemy_x = 0.0f;
- enemy->enemy_initial_x = ENEMIES_INITIAL_X[level][lane][i] * env->width;
- enemy->speed_randomization = SPEED_RANDOMIZATION[level];
- enemy->initial_speed_idx = ENEMIES_INITIAL_SPEED_IDX[level][lane];
- enemy->current_speed_idx = enemy->initial_speed_idx;
- enemy->lane_idx = lane;
- enemy->enemy_y = (env->road_start + (env->road_end - env->road_start) * lane / (float) NUM_LANES) - env->lane_size / 2;
- enemy->type = ENEMIES_TYPES[level][lane];
- enemy->enemy_width = enemy->type == 0 ? env->car_width : env->truck_width;
- enemy->enemy_height = enemy->type == 0 ? env->car_height : env->truck_height;
-
- enemy->enemy_vx = enemy->lane_idx < NUM_LANES/2 ? SPEED_VALUES[enemy->current_speed_idx] * TICK_RATE * env->width: -SPEED_VALUES[enemy->current_speed_idx] * TICK_RATE * env->width;
-
- }
- }
-}
-
-void init(Freeway* env) {
- env->ai_player.player_x = env->width / 4;
- env->ai_player.player_y = env->height / 2;
- env->ai_player.best_lane_idx = 0;
- env->ai_player.ticks_stunts_left = 0;
- env->ai_player.score = 0;
- env->ai_player.is_human = 0;
- env->ai_player.hits = 0;
-
- env->human_player.player_x = 3 * env->width / 4;
- env->human_player.player_y = env->height / 2;
- env->human_player.best_lane_idx = 0;
- env->human_player.ticks_stunts_left = 0;
- env->human_player.score = 0;
- env->human_player.is_human = 1;
- env->human_player.hits = 0;
-
-
- env->truck_height = env->car_height;
- env->truck_width = 2*env->car_width;
- env->road_start = env->height / 2 + (NUM_LANES * env->lane_size) / 2;
- env->road_end = env->road_start - (NUM_LANES * env->lane_size);
- //enemies
- env->enemies = (FreewayEnemy*)calloc(NUM_LANES*MAX_ENEMIES_PER_LANE, sizeof(FreewayEnemy));
- env->human_actions = (int*)calloc(1, sizeof(int));
- if ((env->level < 0) || (env->level >= NUM_LEVELS)) {
- env->level = rand() % NUM_LEVELS;
- }
- load_level(env, env->level);
-}
-
-void allocate(Freeway* env) {
- init(env);
- env->observations = (float*)calloc(4 + NUM_LANES*MAX_ENEMIES_PER_LANE, sizeof(float));
- env->actions = (int*)calloc(1, sizeof(int));
- env->rewards = (float*)calloc(1, sizeof(float));
- env->terminals = (unsigned char*)calloc(1, sizeof(unsigned char));
-}
-
-void c_close(Freeway* env) {
- free(env->human_actions);
- free(env->enemies);
-}
-
-void free_allocated(Freeway* env) {
- free(env->actions);
- free(env->observations);
- free(env->terminals);
- free(env->rewards);
- c_close(env);
-}
-
-void add_log(Freeway* env) {
- env->log.episode_length += env->tick;
- env->log.episode_return += env->ep_return;
- env->log.score += env->ai_player.score;
- env->log.perf += env->ai_player.score / ((float) HUMAN_HIGH_SCORE[env->level] * (GAME_LENGTH / 136.0f ));
- env->log.up_action_frac += env->up_count / (float) env->tick;
- env->log.hits += env->ai_player.hits;
- env->log.n += 1;
-}
-
-void compute_observations(Freeway* env) {
- env->observations[0] = env->ai_player.player_y / env->height;
- env->observations[1] = env->ai_player.best_lane_idx /(float) NUM_LANES;
- env->observations[2] = env->ai_player.score / (float) HUMAN_HIGH_SCORE[env->level];
- env->observations[3] = (env->ai_player.ticks_stunts_left > 0);
-
- FreewayEnemy* enemy;
- for (int lane = 0; lane < NUM_LANES; lane++) {
- for (int i = 0; i < MAX_ENEMIES_PER_LANE; i++){
- enemy = &env->enemies[lane*MAX_ENEMIES_PER_LANE + i];
- if (enemy->is_enabled){
- env->observations[4 + lane * MAX_ENEMIES_PER_LANE + i] = enemy->enemy_x / env->width;
- env->observations[4 + lane * MAX_ENEMIES_PER_LANE + i] += (lane < NUM_LANES/2 ? enemy->enemy_height/(2 * env->width): -enemy->enemy_height/(2 * env->width));
- }
- else {
- env->observations[4 + lane * MAX_ENEMIES_PER_LANE + i] = 0.0f;
- }
- }
- }
-}
-
-void spawn_enemies(Freeway* env) {
- float lane_offset_x;
- FreewayEnemy* enemy;
- for (int lane = 0; lane < NUM_LANES; lane++) {
- lane_offset_x = env->width * (rand() / (float) RAND_MAX);
- for (int i = 0; i < MAX_ENEMIES_PER_LANE; i++){
- enemy = &env->enemies[lane * MAX_ENEMIES_PER_LANE + i];
- if (enemy->is_enabled){
- enemy->enemy_x = enemy->enemy_initial_x;
- if (lane>=NUM_LANES/2){
- enemy->enemy_x = env->width - enemy->enemy_x;
- }
- if (env->env_randomization){
- enemy->enemy_x += lane_offset_x;
- }
- }
- }
- }
-}
-
-void reset_player(Freeway* env, FreewayPlayer* player) {
- player->player_y = env->height - env->player_height / 2;
- player->ticks_stunts_left = 0;
-}
-
-bool check_collision(float player_min_x, float player_max_x,
- float player_miny, float player_maxy,
- float enemy_minx, float enemy_maxx,
- float enemy_miny, float enemy_maxy) {
- return (player_min_x < enemy_maxx && player_max_x > enemy_minx &&
- player_miny < enemy_maxy && player_maxy > enemy_miny);
-}
-
-bool check_enemy_collisions(Freeway* env, FreewayPlayer* player){
- FreewayEnemy* enemy;
- for (int lane = 0; lane < NUM_LANES; lane++) {
- for (int i = 0; i < MAX_ENEMIES_PER_LANE; i++) {
- enemy = &env->enemies[lane*MAX_ENEMIES_PER_LANE + i];
- if (enemy->is_enabled) {
- float player_min_x = player->player_x - env->player_width / 2;
- float player_max_x = player->player_x + env->player_width / 2;
- float player_miny = player->player_y - env->player_height / 2;
- float player_maxy = player->player_y + env->player_height / 2;
-
- float enemy_minx = enemy->enemy_x - enemy->enemy_width / 2;
- float enemy_maxx = enemy->enemy_x + enemy->enemy_width / 2;
- float enemy_miny = enemy->enemy_y - enemy->enemy_height / 2;
- float enemy_maxy = enemy->enemy_y + enemy->enemy_height / 2;
-
- if (check_collision(player_min_x, player_max_x, player_miny, player_maxy,
- enemy_minx, enemy_maxx, enemy_miny, enemy_maxy)) {
- return true;
- }
- }
- }
- }
- return false;
-}
-
-void reached_end(Freeway* env, FreewayPlayer* player){
- reset_player(env, player);
- player->best_lane_idx = 0;
- player->score += 1;
-}
-
-void clip_player_position(Freeway* env, FreewayPlayer* player){
- if (player->player_y <= env->player_height/2){
- player->player_y = fmaxf(env->player_height/2, player->player_y);
- } else {
- player->player_y = fminf(env->height - env->player_height/2, player->player_y);
- }
-}
-
-void clip_enemy_position(Freeway* env, FreewayEnemy* enemy){
- if (enemy->enemy_x > env->width + enemy->enemy_width / 2) {
- enemy->enemy_x -= env->width;
- }
- else if (enemy->enemy_x < -enemy->enemy_width / 2){
- enemy->enemy_x += env->width;
- }
-}
-
-void randomize_enemy_speed(Freeway* env) {
- FreewayEnemy* enemy;
- for (int lane = 0; lane < NUM_LANES; lane++) {
- int delta_speed = (rand() % 3) - 1; // Randomly increase or decrease speed
- for (int i = 0; i < MAX_ENEMIES_PER_LANE; i++) {
- if (enemy->speed_randomization) {
- enemy = &env->enemies[lane*MAX_ENEMIES_PER_LANE + i];
- enemy->current_speed_idx = min(max(enemy->initial_speed_idx-2, enemy->current_speed_idx), enemy->initial_speed_idx+2);
- enemy->current_speed_idx = min(max(0, enemy->current_speed_idx + delta_speed), 5);
- enemy->enemy_vx = enemy->lane_idx < NUM_LANES/2 ? SPEED_VALUES[enemy->current_speed_idx] * TICK_RATE * env->width: -SPEED_VALUES[enemy->current_speed_idx] * TICK_RATE * env->width;
- }
- }
- }
-}
-
-void move_enemies(Freeway* env) {
- FreewayEnemy* enemy;
- for (int lane = 0; lane < NUM_LANES; lane++) {
- for (int i = 0; i < MAX_ENEMIES_PER_LANE; i++) {
- enemy = &env->enemies[lane*MAX_ENEMIES_PER_LANE + i];
- if (enemy->is_enabled) {
- enemy->enemy_x += enemy->enemy_vx;
- }
- clip_enemy_position(env, enemy);
- }
- }
-}
-
-void step_player(Freeway* env, FreewayPlayer* player, int action) {
- float player_dy = 0.0;
-
- if (action == DOWN) {
- player_dy = -1.0;
- }
- else if (action == UP) {
- player_dy = 1.0;
- env->up_count += 1;
- }
-
- if (player->ticks_stunts_left == 0){
- player->player_y -= player_dy * BASE_PLAYER_SPEED * env->height * TICK_RATE;
- }
- else {
- player->ticks_stunts_left -= 1;
- if (env->difficulty == 0){
- player->player_y += 1.5f * env->lane_size / (float) TICKS_STUNT;
- }
- }
- clip_player_position(env, player);
-
- if (player->ticks_stunts_left == 0) {
- if (check_enemy_collisions(env, player) && player->ticks_stunts_left < TICKS_STUNT/4){
- player->hits+=1;
- player->ticks_stunts_left = TICKS_STUNT;
- if (env->use_dense_rewards){
- env->rewards[0] += PENALTY_HIT;
- env->ep_return += PENALTY_HIT;
- }
- if (env->difficulty == 1){
- reset_player(env, player);
- }
- }
- }
-
- if (player->player_y <= env->road_start - (player->best_lane_idx+1) * env->lane_size){
- player->best_lane_idx += 1;
- if (env->use_dense_rewards){
- env->rewards[0] += 1.0 / (float) NUM_LANES;
- env->ep_return += 1.0 / (float) NUM_LANES;
- }
- else{
- if (player->best_lane_idx == NUM_LANES){
- env->rewards[0] = 1.0;
- env->ep_return += 1.0;
- }
- }
- }
-
- if (player->best_lane_idx == NUM_LANES) {
- reached_end(env, player);
- env->rewards[0] += 1.0;
- env->ep_return += 1.0;
- }
-}
-void c_reset(Freeway* env) {
- env->ai_player.player_y = env->height / 2;
- env->ai_player.best_lane_idx = 0;
- env->ai_player.ticks_stunts_left = 0;
- env->ai_player.score = 0;
- env->ai_player.hits = 0;
-
- env->human_player.player_y = env->height / 2;
- env->human_player.best_lane_idx = 0;
- env->human_player.ticks_stunts_left = 0;
- env->human_player.score = 0;
- env->human_player.hits = 0;
-
- env->ep_return = 0.0;
- env->tick = 0;
- env->up_count = 0;
- env->time_left = GAME_LENGTH;
- reset_player(env, &env->ai_player);
- reset_player(env, &env->human_player);
- spawn_enemies(env);
- compute_observations(env);
-}
-
-void c_step(Freeway* env) {
- env->terminals[0] = 0;
- env->rewards[0] = 0.0;
- int ai_action = env->actions[0];
- int human_action = env->human_actions[0];
- env->time_left = GAME_LENGTH - env->tick*TICK_RATE;
-
- for (int i = 0; i < env->frameskip; i++) {
- env->tick += 1;
- step_player(env, &env->ai_player, ai_action);
- if (env->enable_human_player){
- step_player(env, &env->human_player, human_action);
- }
- move_enemies(env);
- }
- if (env->tick * TICK_RATE >= GAME_LENGTH) {
- env->terminals[0] = 1.0;
- add_log(env);
- c_reset(env);
- }
- if (env->tick % RANDOMIZE_SPEED_FREQ == 0) {
- randomize_enemy_speed(env);
- }
- compute_observations(env);
-}
-
-
-
-typedef struct Client Client;
-struct Client {
- Texture2D chicken;
- Texture2D puffer;
- Texture2D car_body;
- Texture2D car_wheels;
- Texture2D truck_body;
- Texture2D truck_wheels;
-};
-
-static inline bool file_exists(const char* path) {
- return access(path, F_OK) != -1;
-}
-
-Client* make_client(Freeway* env) {
- Client* client = (Client*)calloc(1, sizeof(Client));
-
- InitWindow(env->width, env->height, "PufferLib Freeway");
- SetTargetFPS(60/env->frameskip);
- client->car_body = LoadTexture("resources/freeway/tex_car_body.png");
- client->car_wheels = LoadTexture("resources/freeway/tex_car_wheels.png");
- client->chicken = LoadTexture("resources/freeway/tex_chicken0.png");
- client->puffer = LoadTexture("resources/shared/puffers.png");
- client->truck_body = LoadTexture("resources/freeway/tex_truck_body.png");
- client->truck_wheels = LoadTexture("resources/freeway/tex_truck_wheels.png");
- return client;
-}
-
-void close_client(Client* client) {
- CloseWindow();
- free(client);
-}
-
-Color CAR_COLORS[10] = {
- (Color){ 139, 0, 0, 255 }, // Dark Red
- (Color){ 255, 140, 0, 255 }, // Dark Orange
- (Color){ 204, 204, 0, 255 }, // Dark Yellow
- (Color){ 0, 100, 0, 255 }, // Dark Green
- (Color){ 0, 0, 139, 255 }, // Dark Blue
- (Color){ 139, 0, 0, 255 }, // Dark Red
- (Color){ 255, 140, 0, 255 }, // Dark Orange
- (Color){ 204, 204, 0, 255 }, // Dark Yellow
- (Color){ 0, 100, 0, 255 }, // Dark Green
- (Color){ 0, 0, 139, 255 } // Dark Blue
-};
-void c_render(Freeway* env) {
- if (env->client == NULL) {
- env->client = make_client(env);
- }
-
- Client* client = env->client;
-
- if (IsKeyDown(KEY_ESCAPE)) {
- exit(0);
- }
- if (IsKeyPressed(KEY_TAB)) {
- ToggleFullscreen();
- }
-
- BeginDrawing();
- ClearBackground((Color){170, 170, 170, 255});
-
- // Draw the road
- DrawRectangle(
- 0,
- env->road_end,
- env->width, env->road_start - env->road_end, (Color){150, 150, 150, 255}
- );
- DrawRectangle(
- 0,
- env->road_end- HALF_LINEWIDTH,
- env->width, 2*HALF_LINEWIDTH, (Color){0, 255}
- );
- DrawRectangle(
- 0,
- env->road_start - HALF_LINEWIDTH,
- env->width, 2*HALF_LINEWIDTH, (Color){0, 255}
- );
-
- for (int lane = 1; lane < NUM_LANES; lane++) {
- if (lane != NUM_LANES/2){
- for (int dash = 0; dash < env->width / (DASH_SPACING + DASH_SIZE) ; dash++){
- int dash_start = DASH_SPACING / 2 + (DASH_SPACING + DASH_SIZE) * dash;
- DrawRectangle(
- dash_start,
- env->road_start + (env->road_end - env->road_start) * lane/NUM_LANES - HALF_LINEWIDTH,
- DASH_SIZE, 2*HALF_LINEWIDTH, (Color){235, 235, 235, 255}
- );
- }
- }
- }
-
- for (int dash = 0; dash < env->width / (DASH_SPACING + DASH_SIZE) ; dash++){
- int dash_start = DASH_SPACING / 2 + (DASH_SPACING + DASH_SIZE) * dash;
- DrawRectangle(
- dash_start,
- env->road_start + (env->road_end - env->road_start) / 2 - 3*HALF_LINEWIDTH,
- DASH_SIZE, 2*HALF_LINEWIDTH, (Color){235, 235, 100, 255}
- );
- DrawRectangle(
- dash_start,
- env->road_start + (env->road_end - env->road_start) / 2 + HALF_LINEWIDTH,
- DASH_SIZE, 2*HALF_LINEWIDTH, (Color){235, 235, 100, 255}
- );
- }
-
- // Draw ai player
- DrawTexturePro(
- client->puffer,
- (Rectangle){
- 0, 0, 128, 128,
- },
- (Rectangle){
- env->ai_player.player_x - env->player_width / 2,
- env->ai_player.player_y - env->player_height / 2,
- env->player_width,
- env->player_height,
- },
- (Vector2){0, 0},
- 0,
- WHITE
- );
-
- DrawTexturePro(
- client->puffer,
- (Rectangle){
- 128, 128, 128, 128,
- },
- (Rectangle){
- env->human_player.player_x - env->player_width / 2,
- env->human_player.player_y - env->player_height / 2,
- env->player_width,
- env->player_height,
- },
- (Vector2){0, 0},
- 0,
- WHITE
- );
-
- // Draw enemies
- Rectangle src_rec;
- FreewayEnemy* enemy;
- for (int lane = 0; lane < NUM_LANES; lane++) {
- for (int i = 0; i < MAX_ENEMIES_PER_LANE; i++) {
- enemy = &env->enemies[lane*MAX_ENEMIES_PER_LANE + i];
- if (enemy->is_enabled) {
- Texture2D body = enemy->type == 0 ? client->car_body : client->truck_body;
- Texture2D wheels = enemy->type == 0 ? client->car_wheels : client->truck_wheels;
- if (lane < NUM_LANES/2) {
- src_rec= enemy->type == 0 ? (Rectangle){16,0,16,10} : (Rectangle){32,10,32,10};
- }
- else {
- src_rec = enemy->type == 0 ? (Rectangle){16 + 16, 0, -16, 10} : (Rectangle){32 + 32, 10, -32, 10};
- }
- DrawTexturePro(
- body,
- src_rec,
- (Rectangle){
- enemy->enemy_x - enemy->enemy_width / 2,
- enemy->enemy_y - enemy->enemy_height/ 2,
- enemy->enemy_width,
- enemy->enemy_height,
- },
- (Vector2){0, 0},
- 0,
- CAR_COLORS[lane]
- );
- DrawTexturePro(
- wheels,
- src_rec,
- (Rectangle){
- enemy->enemy_x - enemy->enemy_width / 2,
- enemy->enemy_y - enemy->enemy_height/ 2,
- enemy->enemy_width,
- enemy->enemy_height,
- },
- (Vector2){0, 0},
- 0,
- CAR_COLORS[lane]
- );
- }
- }
- }
-
- // Draw UI
- int rounded_time_left = round(env->time_left);
- DrawText(TextFormat("P1 Score: %i", env->ai_player.score), 10, 3, 40, (Color) {255, 160, 160, 255});
- DrawText(TextFormat("P2 Score: %i", env->human_player.score), round(0.77*env->width), 3, 40, (Color) {255, 160, 160, 255});
- DrawText(TextFormat("Time: %i", rounded_time_left), round(0.45*env->width) - 40, 3, 40, (Color) {255, 160, 160, 255});
-
- EndDrawing();
-
- //PlaySound(client->sound);
-}
diff --git a/pufferlib/ocean/freeway/freeway.py b/pufferlib/ocean/freeway/freeway.py
deleted file mode 100644
index 6e33cea87..000000000
--- a/pufferlib/ocean/freeway/freeway.py
+++ /dev/null
@@ -1,129 +0,0 @@
-import numpy as np
-import gymnasium
-
-import pufferlib
-from pufferlib.ocean.freeway import binding
-
-
-class Freeway(pufferlib.PufferEnv):
- def __init__(
- self,
- num_envs=1,
- render_mode=None,
- frameskip=4,
- width=1216,
- height=720,
- player_width=64,
- player_height=64,
- car_width=64,
- car_height=40,
- lane_size=64,
- difficulty=0,
- level=0,
- use_dense_rewards=True,
- env_randomization=True,
- enable_human_player=False,
- log_interval=128,
- buf=None,
- seed=0,
- ):
- assert level < 8, "Level should be in {0, 1, 2, 3, 4, 5, 6, 7} or -1. Level -1 is a random mix of all 8 supported levels."
- self.single_observation_space = gymnasium.spaces.Box(
- low=0, high=1, shape=(34,), dtype=np.float32
- )
- self.render_mode = render_mode
- self.num_agents = num_envs
- self.log_interval = log_interval
- self.tick = 0
-
- self.single_action_space = gymnasium.spaces.Discrete(3)
-
- super().__init__(buf)
-
- self.c_envs = binding.vec_init(
- self.observations,
- self.actions,
- self.rewards,
- self.terminals,
- self.truncations,
- num_envs,
- seed,
- frameskip=frameskip,
- width=width,
- height=height,
- player_width=player_width,
- player_height=player_height,
- car_width=car_width,
- car_height=car_height,
- lane_size=lane_size,
- difficulty=difficulty,
- level = level,
- enable_human_player=enable_human_player,
- env_randomization=env_randomization,
- use_dense_rewards=use_dense_rewards,
- )
-
- def reset(self, seed=0):
- binding.vec_reset(self.c_envs, seed)
- self.tick = 0
- return self.observations, []
-
- def step(self, actions):
- self.actions[:] = actions
-
- self.tick += 1
- binding.vec_step(self.c_envs)
-
- info = []
- if self.tick % self.log_interval == 0:
- info.append(binding.vec_log(self.c_envs))
-
- return (self.observations, self.rewards,
- self.terminals, self.truncations, info)
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-def test_performance(timeout=60, level = 0,atn_cache=1024):
- env = Freeway(num_envs=1024, level=level)
- env.reset()
- tick = 0
-
- actions = np.random.randint(0, 3, (atn_cache, env.num_agents))
-
- import time
- start = time.time()
- while time.time() - start < timeout:
- atn = actions[tick % atn_cache]
- env.step(atn)
- tick += 1
- env.close()
- print(f'SPS: %f', env.num_agents * tick / (time.time() - start))
-
-def test_render(timeout=60, level = 0,atn_cache=1024):
- env = Freeway(num_envs=1, level=level)
- env.reset(seed=0)
- tick = 0
-
- actions = np.random.randint(0, 3, (atn_cache, env.num_agents))
-
- import time
- start = time.time()
- while time.time() - start < timeout:
- atn = actions[tick % atn_cache]
- obs, rew, term, trunc, i = env.step(atn)
- env.render()
- tick += 1
- if tick == 100:
- env.reset()
- env.close()
-
-
-if __name__ == '__main__':
- # test_performance()
- for level in range(0,8):
- test_performance(level = level, timeout=5, atn_cache=1024)
-
diff --git a/pufferlib/ocean/freeway/freeway_levels.h b/pufferlib/ocean/freeway/freeway_levels.h
deleted file mode 100644
index 22e5d7340..000000000
--- a/pufferlib/ocean/freeway/freeway_levels.h
+++ /dev/null
@@ -1,184 +0,0 @@
-#define BASE_ROAD_SPEED 1.0f/13.0f // inverse number of seconds to go from the left to the right (slowest enemy)
-#define MULT_ROAD_SPEED 1.35 // Factor of increase for the road speed (approximates the ratio between min speed and max speed of lvl1 (13/2.5)^(1/5))
-#define BASE_PLAYER_SPEED 1.0f/3.5f // inverse number of seconds to go from the bottom to the top of the screen for the player
-#define MAX_ENEMIES_PER_LANE 3
-#define NUM_LEVELS 8
-#define NUM_LANES 10
-
-const float SPEED0 = BASE_ROAD_SPEED;
-const float SPEED1 = MULT_ROAD_SPEED*BASE_ROAD_SPEED;
-const float SPEED2 = MULT_ROAD_SPEED*MULT_ROAD_SPEED*BASE_ROAD_SPEED;
-const float SPEED3 = MULT_ROAD_SPEED*MULT_ROAD_SPEED*MULT_ROAD_SPEED*BASE_ROAD_SPEED;
-const float SPEED4 = MULT_ROAD_SPEED*MULT_ROAD_SPEED*MULT_ROAD_SPEED*MULT_ROAD_SPEED*BASE_ROAD_SPEED;
-const float SPEED5 = MULT_ROAD_SPEED*MULT_ROAD_SPEED*MULT_ROAD_SPEED*MULT_ROAD_SPEED*MULT_ROAD_SPEED*BASE_ROAD_SPEED;
-
-const float SPEED_VALUES[6] = {SPEED0, SPEED1, SPEED2, SPEED3, SPEED4, SPEED5};
-
-const int HUMAN_HIGH_SCORE[] = {25, 20, 18, 20, 25, 18, 15, 18};
-
-const int ENEMIES_PER_LANE[NUM_LEVELS][NUM_LANES] = {
- // Level 0
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
- // Level 1
- {1, 2, 2, 3, 2, 1, 2, 3, 2, 2},
- // Level 2
- {3, 3, 1, 3, 1, 1, 3, 1, 3, 1},
- // Level 3
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
- // Level 4
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
- // Level 5
- {1, 2, 2, 3, 2, 1, 2, 3, 2, 2},
- // Level 6
- {3, 3, 1, 3, 1, 1, 3, 1, 3, 1},
- // Level 7
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
-};
-
-const float ENEMIES_TYPES[NUM_LEVELS][NUM_LANES] = {
- // Level 0
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- // Level 1
- {0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
- // Level 2
- {0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
- // Level 3
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
- // Level 4
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
- // Level 5
- {0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
- // Level 6
- {0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
- // Level 7
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
-};
-
-const int SPEED_RANDOMIZATION[NUM_LEVELS]= {0,0,0,0,1,1,1,1};
-
-
-const float ENEMIES_INITIAL_X[NUM_LEVELS][NUM_LANES][MAX_ENEMIES_PER_LANE] = {
- // Level 0
- {
- {0.0, 0.0, 0.0}, // lane 0 to 9
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- },
- {
- // Level 1
- {0.0, 0.0, 0.0}, // lane 0 to 9
- {0.0, 0.1, 0.0},
- {0.0, 0.2, 0.0},
- {0.0, 0.1, 0.2},
- {0.0, 0.4, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.4, 0.0},
- {0.0, 0.1, 0.2},
- {0.0, 0.2, 0.0},
- {0.0, 0.1, 0.0},
- },
- {
- // Level 2
- {0.0, 0.2, 0.4}, // lane 0 to 9
- {0.0, 0.2, 0.4},
- {0.0, 0.0, 0.0},
- {0.0, 0.2, 0.4},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.2, 0.4},
- {0.0, 0.0, 0.0},
- {0.0, 0.2, 0.4},
- {0.0, 0.2, 0.4},
- },
- {
- // Level 3
- {0.0, 0.0, 0.0}, // lane 0 to 9
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- },
- // Level 4
- {
- {0.0, 0.0, 0.0}, // lane 0 to 9
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- },
- {
- // Level 5
- {0.0, 0.0, 0.0}, // lane 0 to 9
- {0.0, 0.1, 0.0},
- {0.0, 0.2, 0.0},
- {0.0, 0.1, 0.2},
- {0.0, 0.4, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.4, 0.0},
- {0.0, 0.1, 0.2},
- {0.0, 0.2, 0.0},
- {0.0, 0.1, 0.0},
- },
- {
- // Level 6
- {0.0, 0.2, 0.4}, // lane 0 to 9
- {0.0, 0.2, 0.4},
- {0.0, 0.0, 0.0},
- {0.0, 0.2, 0.4},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.2, 0.4},
- {0.0, 0.0, 0.0},
- {0.0, 0.2, 0.4},
- {0.0, 0.2, 0.4},
- },
- {
- // Level 7
- {0.0, 0.0, 0.0}, // lane 0 to 9
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- {0.0, 0.0, 0.0},
- }
-};
-
-const float ENEMIES_INITIAL_SPEED_IDX[NUM_LEVELS][NUM_LANES] = {
- // Level 0
- {0,1,2,3,4,4,3,2,1,0},
- // Level 1
- {0,1,3,4,5,5,4,3,1,0},
- // Level 2
- {0,1,3,4,5,5,4,3,1,0},
- // Level 3
- {5,4,2,4,5,5,4,2,4,5},
- // Level 4
- {0,1,2,3,4,4,3,2,1,0},
- // Level 5
- {0,1,3,4,5,5,4,3,1,0},
- // Level 6
- {0,1,3,4,5,5,4,3,1,0},
- // Level 7
- {5,4,2,4,5,5,4,2,4,5},
-};
\ No newline at end of file
diff --git a/pufferlib/ocean/g2048/2048.h b/pufferlib/ocean/g2048/2048.h
deleted file mode 100755
index 64d69353a..000000000
--- a/pufferlib/ocean/g2048/2048.h
+++ /dev/null
@@ -1,382 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include "raylib.h"
-
-#define SIZE 4
-#define EMPTY 0
-#define UP 1
-#define DOWN 2
-#define LEFT 3
-#define RIGHT 4
-
-// Precomputed constants
-#define REWARD_MULTIPLIER 0.09090909f
-#define INVALID_MOVE_PENALTY -0.05f
-#define GAME_OVER_PENALTY -1.0f
-
-typedef struct {
- float perf;
- float score;
- float episode_return;
- float episode_length;
- float n;
-} Log;
-
-typedef struct {
- Log log; // Required
- unsigned char* observations; // Cheaper in memory if encoded in uint_8
- int* actions; // Required
- float* rewards; // Required
- unsigned char* terminals; // Required
- int score;
- int tick;
- unsigned char grid[SIZE][SIZE];
- float episode_reward; // Accumulate episode reward
-
- // Cached values to avoid recomputation
- int empty_count;
- bool game_over_cached;
- bool grid_changed;
-} Game;
-
-// Precomputed color table for rendering optimization
-const Color PUFF_BACKGROUND = (Color){6, 24, 24, 255};
-const Color PUFF_WHITE = (Color){241, 241, 241, 241};
-const Color PUFF_RED = (Color){187, 0, 0, 255};
-const Color PUFF_CYAN = (Color){0, 187, 187, 255};
-
-static Color tile_colors[12] = {
- {6, 24, 24, 255}, // Empty/background
- {187, 187, 187, 255}, // 2
- {170, 187, 187, 255}, // 4
- {150, 187, 187, 255}, // 8
- {130, 187, 187, 255}, // 16
- {110, 187, 187, 255}, // 32
- {90, 187, 187, 255}, // 64
- {70, 187, 187, 255}, // 128
- {50, 187, 187, 255}, // 256
- {30, 187, 187, 255}, // 512
- {10, 187, 187, 255}, // 1024
- {0, 187, 187, 255} // 2048+
-};
-
-// --- Logging ---
-void add_log(Game* game);
-
-// --- Required functions for env_binding.h ---
-void c_reset(Game* env);
-void c_step(Game* env);
-void c_render(Game* env);
-void c_close(Game* env);
-
-// Inline function for updating observations (avoid function call overhead)
-static inline void update_observations(Game* game) {
- for (int i = 0; i < SIZE; i++) {
- for (int j = 0; j < SIZE; j++) {
- game->observations[i * SIZE + j] = game->grid[i][j];
- }
- }
-}
-
-// Cache empty cell count during grid operations
-static inline void update_empty_count(Game* game) {
- int count = 0;
- for (int i = 0; i < SIZE; i++) {
- for (int j = 0; j < SIZE; j++) {
- if (game->grid[i][j] == EMPTY) count++;
- }
- }
- game->empty_count = count;
-}
-
-void add_log(Game* game) {
- game->log.score = (float)(1 << game->score);
- game->log.perf += ((float)game->score) * REWARD_MULTIPLIER;
- game->log.episode_length += game->tick;
- game->log.episode_return += game->episode_reward;
- game->log.n += 1;
-}
-
-void c_reset(Game* game) {
- for (int i = 0; i < SIZE; i++) {
- for (int j = 0; j < SIZE; j++) {
- game->grid[i][j] = EMPTY;
- }
- }
-
- game->score = 0;
- game->tick = 0;
- game->episode_reward = 0;
- game->empty_count = SIZE * SIZE;
- game->game_over_cached = false;
- game->grid_changed = true;
-
- if (game->terminals) game->terminals[0] = 0;
-
- // Add two random tiles at the start - optimized version
- for (int added = 0; added < 2; ) {
- int pos = rand() % (SIZE * SIZE);
- int i = pos / SIZE;
- int j = pos % SIZE;
- if (game->grid[i][j] == EMPTY) {
- game->grid[i][j] = (rand() % 10 == 0) ? 2 : 1;
- added++;
- game->empty_count--;
- }
- }
-
- update_observations(game);
-}
-
-void add_random_tile(Game* game) {
- if (game->empty_count == 0) return;
-
- // Use reservoir sampling for better performance
- int chosen_pos = -1;
- int count = 0;
-
- for (int pos = 0; pos < SIZE * SIZE; pos++) {
- int i = pos / SIZE;
- int j = pos % SIZE;
- if (game->grid[i][j] == EMPTY) {
- count++;
- if (rand() % count == 0) {
- chosen_pos = pos;
- }
- }
- }
-
- if (chosen_pos >= 0) {
- int i = chosen_pos / SIZE;
- int j = chosen_pos % SIZE;
- game->grid[i][j] = (rand() % 10 == 0) ? 2 : 1;
- game->empty_count--;
- game->grid_changed = true;
- }
-
- update_observations(game);
-}
-
-// Optimized slide and merge with fewer memory operations
-static inline bool slide_and_merge(unsigned char* row, float* reward) {
- bool moved = false;
- int write_pos = 0;
-
- // Single pass: slide and identify merge candidates
- for (int read_pos = 0; read_pos < SIZE; read_pos++) {
- if (row[read_pos] != EMPTY) {
- if (write_pos != read_pos) {
- row[write_pos] = row[read_pos];
- row[read_pos] = EMPTY;
- moved = true;
- }
- write_pos++;
- }
- }
-
- // Merge pass
- for (int i = 0; i < SIZE - 1; i++) {
- if (row[i] != EMPTY && row[i] == row[i + 1]) {
- row[i]++;
- *reward += ((float)row[i]) * REWARD_MULTIPLIER;
- // Shift remaining elements left
- for (int j = i + 1; j < SIZE - 1; j++) {
- row[j] = row[j + 1];
- }
- row[SIZE - 1] = EMPTY;
- moved = true;
- }
- }
-
- return moved;
-}
-
-bool move(Game* game, int direction, float* reward) {
- bool moved = false;
- unsigned char temp[SIZE];
-
- if (direction == UP || direction == DOWN) {
- for (int col = 0; col < SIZE; col++) {
- // Extract column
- for (int i = 0; i < SIZE; i++) {
- int idx = (direction == UP) ? i : SIZE - 1 - i;
- temp[i] = game->grid[idx][col];
- }
-
- if (slide_and_merge(temp, reward)) {
- moved = true;
- // Write back column
- for (int i = 0; i < SIZE; i++) {
- int idx = (direction == UP) ? i : SIZE - 1 - i;
- game->grid[idx][col] = temp[i];
- }
- }
- }
- } else {
- for (int row = 0; row < SIZE; row++) {
- // Extract row
- for (int i = 0; i < SIZE; i++) {
- int idx = (direction == LEFT) ? i : SIZE - 1 - i;
- temp[i] = game->grid[row][idx];
- }
-
- if (slide_and_merge(temp, reward)) {
- moved = true;
- // Write back row
- for (int i = 0; i < SIZE; i++) {
- int idx = (direction == LEFT) ? i : SIZE - 1 - i;
- game->grid[row][idx] = temp[i];
- }
- }
- }
- }
-
- if (!moved) {
- *reward = INVALID_MOVE_PENALTY;
- } else {
- game->grid_changed = true;
- game->game_over_cached = false; // Invalidate cache
- }
-
- return moved;
-}
-
-bool is_game_over(Game* game) {
- // Use cached result if grid hasn't changed
- if (!game->grid_changed && game->game_over_cached) {
- return game->game_over_cached;
- }
-
- // Quick check: if there are empty cells, game is not over
- if (game->empty_count > 0) {
- game->game_over_cached = false;
- game->grid_changed = false;
- return false;
- }
-
- // Check for possible merges
- for (int i = 0; i < SIZE; i++) {
- for (int j = 0; j < SIZE; j++) {
- unsigned char current = game->grid[i][j];
- if (i < SIZE - 1 && current == game->grid[i + 1][j]) {
- game->game_over_cached = false;
- game->grid_changed = false;
- return false;
- }
- if (j < SIZE - 1 && current == game->grid[i][j + 1]) {
- game->game_over_cached = false;
- game->grid_changed = false;
- return false;
- }
- }
- }
-
- game->game_over_cached = true;
- game->grid_changed = false;
- return true;
-}
-
-// Optimized score calculation
-static inline unsigned char calc_score(Game* game) {
- unsigned char max_tile = 0;
- // Unroll loop for better performance
- for (int i = 0; i < SIZE; i++) {
- for (int j = 0; j < SIZE; j++) {
- if (game->grid[i][j] > max_tile) {
- max_tile = game->grid[i][j];
- }
- }
- }
- return max_tile;
-}
-
-void c_step(Game* game) {
- float reward = 0.0f;
- bool did_move = move(game, game->actions[0] + 1, &reward);
- game->tick++;
-
- if (did_move) {
- add_random_tile(game);
- game->score = calc_score(game);
- update_empty_count(game); // Update after adding tile
- }
-
- bool game_over = is_game_over(game);
- game->terminals[0] = game_over ? 1 : 0;
-
- if (game_over) {
- reward = GAME_OVER_PENALTY;
- }
-
- game->rewards[0] = reward;
- game->episode_reward += reward;
-
- update_observations(game);
-
- if (game->terminals[0]) {
- add_log(game);
- c_reset(game);
- }
-}
-
-// Rendering optimizations
-void c_render(Game* game) {
- static bool window_initialized = false;
- static char score_text[32];
- static const int px = 100;
-
- if (!window_initialized) {
- InitWindow(px * SIZE, px * SIZE + 50, "2048");
- SetTargetFPS(30); // Increased for smoother rendering
- window_initialized = true;
- }
-
- if (IsKeyDown(KEY_ESCAPE)) {
- CloseWindow();
- exit(0);
- }
-
- BeginDrawing();
- ClearBackground(PUFF_BACKGROUND);
-
- // Draw grid
- for (int i = 0; i < SIZE; i++) {
- for (int j = 0; j < SIZE; j++) {
- int val = game->grid[i][j];
-
- // Use precomputed colors
- Color color = (val == 0) ? tile_colors[0] :
- (val <= 11) ? tile_colors[val] :
- (Color){60, 60, 60, 255};
-
- DrawRectangle(j * px, i * px, px - 5, px - 5, color);
-
- if (val > 0) {
- int display_val = 1 << val; // Power of 2
- // Pre-format text to avoid repeated formatting
- snprintf(score_text, sizeof(score_text), "%d", display_val);
- if (display_val < 1000) {
- DrawText(score_text, j * px + 30, i * px + 40, 32, PUFF_WHITE);
- } else {
- DrawText(score_text, j * px + 20, i * px + 40, 32, PUFF_WHITE);
- }
- }
- }
- }
-
- // Draw score (format once per frame)
- snprintf(score_text, sizeof(score_text), "Score: %d", 1 << game->score);
- DrawText(score_text, 10, px * SIZE + 10, 24, PUFF_WHITE);
-
- EndDrawing();
-}
-
-void c_close(Game* game) {
- if (IsWindowReady()) {
- CloseWindow();
- }
-}
diff --git a/pufferlib/ocean/g2048/binding.c b/pufferlib/ocean/g2048/binding.c
deleted file mode 100644
index f3c22e152..000000000
--- a/pufferlib/ocean/g2048/binding.c
+++ /dev/null
@@ -1,18 +0,0 @@
-#include "2048.h"
-
-#define Env Game
-#include "../env_binding.h"
-
-// 2048.h does not have a 'size' field, so my_init can just return 0
-static int my_init(Env* env, PyObject* args, PyObject* kwargs) {
- // No custom initialization needed for 2048
- return 0;
-}
-
-static int my_log(PyObject* dict, Log* log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "episode_length", log->episode_length);
- return 0;
-}
\ No newline at end of file
diff --git a/pufferlib/ocean/g2048/g2048.c b/pufferlib/ocean/g2048/g2048.c
deleted file mode 100644
index 195f4fc38..000000000
--- a/pufferlib/ocean/g2048/g2048.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include "2048.h"
-#include "puffernet.h"
-
-int main() {
- srand(time(NULL));
- Game env;
- unsigned char observations[SIZE * SIZE] = {0};
- unsigned char terminals[1] = {0};
- int actions[1] = {0};
- float rewards[1] = {0};
-
- env.observations = observations;
- env.terminals = terminals;
- env.actions = actions;
- env.rewards = rewards;
-
- Weights* weights = load_weights("resources/g2048/g2048_weights.bin", 134917);
- int logit_sizes[1] = {4};
- LinearLSTM* net = make_linearlstm(weights, 1, 16, logit_sizes, 1);
- c_reset(&env);
- c_render(&env);
-
- // Main game loop
- int frame = 0;
- while (!WindowShouldClose()) {
- c_render(&env);
- frame++;
-
- int action = 0;
- if (IsKeyDown(KEY_LEFT_SHIFT)) {
- if (IsKeyPressed(KEY_W) || IsKeyPressed(KEY_UP)) action = UP;
- else if (IsKeyPressed(KEY_S) || IsKeyPressed(KEY_DOWN)) action = DOWN;
- else if (IsKeyPressed(KEY_A) || IsKeyPressed(KEY_LEFT)) action = LEFT;
- else if (IsKeyPressed(KEY_D) || IsKeyPressed(KEY_RIGHT)) action = RIGHT;
- env.actions[0] = action - 1;
- } else if (frame % 10 != 0) {
- continue;
- } else {
- action = 1;
- for (int i = 0; i < 16; i++) {
- net->obs[i] = env.observations[i];
- }
- forward_linearlstm(net, net->obs, env.actions);
- }
-
- if (action != 0) {
- c_step(&env);
- }
- }
-
- free_linearlstm(net);
- c_close(&env);
- printf("Game Over! Final Max Tile: %d\n", env.score);
- return 0;
-}
diff --git a/pufferlib/ocean/g2048/g2048.py b/pufferlib/ocean/g2048/g2048.py
deleted file mode 100644
index a18bb0dc7..000000000
--- a/pufferlib/ocean/g2048/g2048.py
+++ /dev/null
@@ -1,69 +0,0 @@
-'''2048 Gymnasium-compatible environment using the C backend.'''
-
-import gymnasium
-import numpy as np
-
-import pufferlib
-from pufferlib.ocean.g2048 import binding
-
-class G2048(pufferlib.PufferEnv):
- def __init__(self, num_envs=1, render_mode=None, log_interval=128, buf=None, seed=0):
- self.single_observation_space = gymnasium.spaces.Box(
- low=0, high=100, shape=(4,4), dtype=np.uint8
- )
- self.single_action_space = gymnasium.spaces.Discrete(4)
- self.render_mode = render_mode
- self.num_agents = num_envs
- self.log_interval = log_interval
-
- super().__init__(buf)
- self.c_envs = binding.vec_init(
- self.observations, self.actions, self.rewards,
- self.terminals, self.truncations, num_envs, seed
- )
-
- def reset(self, seed=0):
- binding.vec_reset(self.c_envs, seed)
- self.tick = 0
- return self.observations, []
-
- def step(self, actions):
- self.tick += 1
-
- self.actions[:] = actions
- binding.vec_step(self.c_envs)
-
- info = []
- if self.tick % self.log_interval == 0:
- info.append(binding.vec_log(self.c_envs))
-
- return (
- self.observations, self.rewards,
- self.terminals, self.truncations, info
- )
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-if __name__ == '__main__':
- N = 128
-
- env = G2048(num_envs=N)
- env.reset()
- steps = 0
-
- CACHE = 1024
- actions = np.random.randint(0, 4, (CACHE, N))
-
- i = 0
- import time
- start = time.time()
- while time.time() - start < 10:
- env.step(actions[i % CACHE])
- steps += N
- i += 1
-
- print('2048 SPS:', int(steps / (time.time() - start)))
diff --git a/pufferlib/ocean/go/binding.c b/pufferlib/ocean/go/binding.c
deleted file mode 100644
index 272c0ba41..000000000
--- a/pufferlib/ocean/go/binding.c
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "go.h"
-#define Env CGo
-#include "../env_binding.h"
-
-static int my_init(Env* env, PyObject* args, PyObject* kwargs) {
- env->width = unpack(kwargs, "width");
- env->height = unpack(kwargs, "height");
- env->grid_size = unpack(kwargs, "grid_size");
- env->board_width = unpack(kwargs, "board_width");
- env->board_height = unpack(kwargs, "board_height");
- env->grid_square_size = unpack(kwargs, "grid_square_size");
- env->moves_made = unpack(kwargs, "moves_made");
- env->komi = unpack(kwargs, "komi");
- env->score = unpack(kwargs, "score");
- env->last_capture_position = unpack(kwargs, "last_capture_position");
- env->reward_move_pass = unpack(kwargs, "reward_move_pass");
- env->reward_move_invalid = unpack(kwargs, "reward_move_invalid");
- env->reward_move_valid = unpack(kwargs, "reward_move_valid");
- env->reward_player_capture = unpack(kwargs, "reward_player_capture");
- env->reward_opponent_capture = unpack(kwargs, "reward_opponent_capture");
-
- init(env);
- return 0;
-}
-
-static int my_log(PyObject* dict, Log* log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "episode_length", log->episode_length);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "n", log->n);
- return 0;
-}
diff --git a/pufferlib/ocean/go/go.c b/pufferlib/ocean/go/go.c
deleted file mode 100644
index fcd6614ea..000000000
--- a/pufferlib/ocean/go/go.c
+++ /dev/null
@@ -1,229 +0,0 @@
-#include
-#include "go.h"
-#include "puffernet.h"
-
-typedef struct GoNet GoNet;
-struct GoNet {
- int num_agents;
- float* obs_2d;
- float* obs_1d;
- Conv2D* conv1;
- ReLU* relu1;
- Conv2D* conv2;
- Linear* flat;
- CatDim1* cat;
- Linear* proj;
- ReLU* relu3;
- LSTM* lstm;
- Linear* actor;
- Linear* value_fn;
- Multidiscrete* multidiscrete;
-};
-GoNet* init_gonet(Weights* weights, int num_agents, int grid_size) {
- GoNet* net = calloc(1, sizeof(GoNet));
- int hidden_size = 128;
- int cnn_channels = 64;
- int conv1_output_size = grid_size - 2;
- int output_size = grid_size - 4;
- int cnn_flat_size = cnn_channels * output_size * output_size;
-
- net->num_agents = num_agents;
- net->obs_2d = calloc(num_agents * grid_size * grid_size * 2, sizeof(float)); // 2 channels for player and opponent
- net->obs_1d = calloc(num_agents * 2, sizeof(float)); // 2 additional features
-
- net->conv1 = make_conv2d(weights, num_agents, grid_size, grid_size, 2, cnn_channels, 3, 1);
- net->relu1 = make_relu(num_agents, cnn_channels * conv1_output_size * conv1_output_size);
- net->conv2 = make_conv2d(weights, num_agents, conv1_output_size, conv1_output_size, cnn_channels, cnn_channels, 3, 1);
- net->flat = make_linear(weights, num_agents, 2, 32);
- net->cat = make_cat_dim1(num_agents, cnn_flat_size, 32);
- net->proj = make_linear(weights, num_agents, cnn_flat_size + 32, hidden_size);
- net->relu3 = make_relu(num_agents, hidden_size);
- net->actor = make_linear(weights, num_agents, hidden_size, grid_size*grid_size + 1); // +1 for pass move
- net->value_fn = make_linear(weights, num_agents, hidden_size, 1);
- net->lstm = make_lstm(weights, num_agents, hidden_size, 128);
- int logit_sizes[6] = {grid_size*grid_size+1};
- net->multidiscrete = make_multidiscrete(num_agents, logit_sizes, 1);
- return net;
-}
-
-void free_gonet(GoNet* net) {
- free(net->obs_2d);
- free(net->obs_1d);
- free(net->conv1);
- free(net->relu1);
- free(net->conv2);
- free(net->flat);
- free(net->cat);
- free(net->relu3);
- free(net->proj);
- free(net->lstm);
- free(net->actor);
- free(net->value_fn);
- free(net);
-}
-
-void forward(GoNet* net, float* observations, int* actions, int grid_size) {
- int full_board = grid_size * grid_size;
- // Clear previous observations
- memset(net->obs_2d, 0, net->num_agents * grid_size * grid_size * 2 * sizeof(float));
- memset(net->obs_1d, 0, net->num_agents * 2 * sizeof(float));
-
- // Reshape observations into 2D boards and additional features
- float (*obs_2d)[2][grid_size][grid_size] = (float (*)[2][grid_size][grid_size])net->obs_2d;
- float (*obs_1d)[2] = (float (*)[2])net->obs_1d;
-
- for (int b = 0; b < net->num_agents; b++) {
- int b_offset = b * (full_board * 2 + 2); // offset for each batch
-
- // Process black stones board
- for (int i = 0; i < grid_size; i++) {
- for (int j = 0; j < grid_size; j++) {
- obs_2d[b][0][i][j] = observations[b_offset + i*grid_size + j];
- }
- }
-
- // Process white stones board
- for (int i = 0; i < grid_size; i++) {
- for (int j = 0; j < grid_size; j++) {
- obs_2d[b][1][i][j] = observations[b_offset + full_board + i*grid_size + j];
- }
- }
-
- // Process additional features
- obs_1d[b][0] = observations[b_offset + full_board * 2];
- obs_1d[b][1] = observations[b_offset + full_board * 2 + 1];
- }
-
- // Forward pass through the network
- conv2d(net->conv1, net->obs_2d);
- relu(net->relu1, net->conv1->output);
- conv2d(net->conv2, net->relu1->output);
-
- linear(net->flat, net->obs_1d);
-
- cat_dim1(net->cat, net->conv2->output, net->flat->output);
- linear(net->proj, net->cat->output);
- relu(net->relu3, net->proj->output);
-
- lstm(net->lstm, net->relu3->output);
- linear(net->actor, net->lstm->state_h);
- linear(net->value_fn, net->lstm->state_h);
-
- // Get action by taking argmax of actor output
- softmax_multidiscrete(net->multidiscrete, net->actor->output, actions);
-
-}
-
-void demo(int grid_size) {
-
- CGo env = {
- .width = 950,
- .height = 64*(grid_size+1),
- .grid_size = grid_size,
- .board_width = 64*(grid_size+1) + 400,
- .board_height = 64*(grid_size+1),
- .grid_square_size = 64,
- .moves_made = 0,
- .komi = 7.5,
- .reward_move_pass = -0.25,
- .reward_move_invalid = -0.1,
- .reward_move_valid = 0.1
- };
-
- Weights* weights = load_weights("resources/go/go_weights.bin", 254867);
- GoNet* net = init_gonet(weights, 1, grid_size);
- allocate(&env);
- c_reset(&env);
- c_render(&env);
-
- int tick = 0;
- while (!WindowShouldClose()) {
- // User can take control of the paddle
- if(tick % 12 == 0) {
- tick = 0;
- int human_action = env.actions[0];
- forward(net, env.observations, env.actions, grid_size);
- if (IsKeyDown(KEY_LEFT_SHIFT)) {
- env.actions[0] = human_action;
- }
- c_step(&env);
- if (IsKeyDown(KEY_LEFT_SHIFT)) {
- env.actions[0] = -1;
- }
- }
- tick++;
- if (IsKeyDown(KEY_LEFT_SHIFT)) {
- if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
- Vector2 mousePos = GetMousePosition();
-
- // Calculate the offset for the board
- int boardOffsetX = env.grid_square_size;
- int boardOffsetY = env.grid_square_size;
-
- // Adjust mouse position relative to the board
- int relativeX = mousePos.x - boardOffsetX;
- int relativeY = mousePos.y - boardOffsetY;
-
- // Calculate cell indices for the corners
- int cellX = (relativeX + env.grid_square_size / 2) / env.grid_square_size;
- int cellY = (relativeY + env.grid_square_size / 2) / env.grid_square_size;
-
- // Ensure the click is within the game board
- if (cellX >= 0 && cellX <= env.grid_size && cellY >= 0 && cellY <= env.grid_size) {
- // Calculate the point index (1-19) based on the click position
- int pointIndex = cellY * (env.grid_size) + cellX + 1;
- env.actions[0] = (unsigned short)pointIndex;
- }
- // Check if pass button is clicked
- int passButtonX = env.width - 300;
- int passButtonY = 200;
- int passButtonWidth = 100;
- int passButtonHeight = 50;
-
- if (mousePos.x >= passButtonX && mousePos.x <= passButtonX + passButtonWidth &&
- mousePos.y >= passButtonY && mousePos.y <= passButtonY + passButtonHeight) {
- env.actions[0] = 0; // Send action 0 for pass
- }
- }
- }
- c_render(&env);
- }
- //close_client(client);
- free_allocated(&env);
-}
-
-void performance_test() {
- long test_time = 10;
- CGo env = {
- .width = 1000,
- .height = 800,
- .grid_size = 9,
- .board_width = 600,
- .board_height = 600,
- .grid_square_size = 600/9,
- .moves_made = 0,
- .komi = 7.5,
- .reward_move_pass = -0.25,
- .reward_move_invalid = -0.1,
- .reward_move_valid = 0.1
- };
- allocate(&env);
- c_reset(&env);
-
- long start = time(NULL);
- int i = 0;
- while (time(NULL) - start < test_time) {
- env.actions[0] = rand() % (env.grid_size)*(env.grid_size);
- c_step(&env);
- i++;
- }
- long end = time(NULL);
- printf("SPS: %ld\n", i / (end - start));
- free_allocated(&env);
-}
-
-int main() {
- demo(7);
- // performance_test();
- return 0;
-}
diff --git a/pufferlib/ocean/go/go.h b/pufferlib/ocean/go/go.h
deleted file mode 100644
index f96864ae0..000000000
--- a/pufferlib/ocean/go/go.h
+++ /dev/null
@@ -1,810 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include "raylib.h"
-
-#define NOOP 0
-#define MOVE_MIN 1
-#define TICK_RATE 1.0f/60.0f
-#define NUM_DIRECTIONS 4
-#define ENV_WIN -1
-#define PLAYER_WIN 1
-static const int DIRECTIONS[NUM_DIRECTIONS][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
-// LD_LIBRARY_PATH=raylib/lib ./go
-
-typedef struct Log Log;
-struct Log {
- float perf;
- float score;
- float episode_return;
- float episode_length;
- float n;
-};
-
-typedef struct Group Group;
-struct Group {
- int parent;
- int rank;
- int size;
- int liberties;
-};
-
-int find(Group* groups, int x) {
- if (groups[x].parent != x)
- groups[x].parent = find(groups, groups[x].parent);
- return groups[x].parent;
-}
-
-void union_groups(Group* groups, int pos1, int pos2) {
- pos1 = find(groups, pos1);
- pos2 = find(groups, pos2);
-
- if (pos1 == pos2) return;
-
- if (groups[pos1].rank < groups[pos2].rank) {
- groups[pos1].parent = pos2;
- groups[pos2].size += groups[pos1].size;
- groups[pos2].liberties += groups[pos1].liberties;
- } else if (groups[pos1].rank > groups[pos2].rank) {
- groups[pos2].parent = pos1;
- groups[pos1].size += groups[pos2].size;
- groups[pos1].liberties += groups[pos2].liberties;
- } else {
- groups[pos2].parent = pos1;
- groups[pos1].rank++;
- groups[pos1].size += groups[pos2].size;
- groups[pos1].liberties += groups[pos2].liberties;
- }
-}
-
-typedef struct Client Client;
-typedef struct CGo CGo;
-struct CGo {
- Client* client;
- float* observations;
- int* actions;
- float* rewards;
- unsigned char* terminals;
- Log log;
- float score;
- int width;
- int height;
- int* board_x;
- int* board_y;
- int board_width;
- int board_height;
- int grid_square_size;
- int grid_size;
- int* board_states;
- int* previous_board_state;
- int last_capture_position;
- int* temp_board_states;
- int moves_made;
- int* capture_count;
- float komi;
- int* visited;
- Group* groups;
- Group* temp_groups;
- float reward_move_pass;
- float reward_move_invalid;
- float reward_move_valid;
- float reward_player_capture;
- float reward_opponent_capture;
- float tick;
-};
-
-void add_log(CGo* env) {
- env->log.episode_length += env->tick;
-
- // Calculate perf as a win rate (1.0 if win, 0.0 if loss)
- float win_value = 0.0;
- if (env->score > 0) {
- win_value = 1.0; // Win
- }
- else if (env->score < 0) {
- win_value = 0.0; // Loss
- }
- else {
- win_value = 0.0; // Tie
- }
-
- env->log.perf = (env->log.perf * env->log.n + win_value) / (env->log.n + 1.0);
-
- env->log.score += env->score;
- env->log.episode_return += env->rewards[0];
- env->log.n += 1.0;
-}
-
-void generate_board_positions(CGo* env) {
- for (int i = 0; i < (env->grid_size-1) * (env->grid_size-1); i++) {
- int row = i / (env->grid_size-1);
- int col = i % (env->grid_size-1);
- env->board_x[i] = col * (env->grid_square_size-1);
- env->board_y[i] = row * (env->grid_square_size-1);
- }
-}
-
-void init_groups(CGo* env) {
- for (int i = 0; i < (env->grid_size)*(env->grid_size); i++) {
- env->groups[i].parent = i;
- env->groups[i].rank = 0;
- env->groups[i].size = 1;
- env->groups[i].liberties = 0;
- }
-}
-
-void init(CGo* env) {
- int board_render_size = (env->grid_size-1)*(env->grid_size-1);
- int grid_size = env->grid_size*env->grid_size;
- env->board_x = (int*)calloc(board_render_size, sizeof(int));
- env->board_y = (int*)calloc(board_render_size, sizeof(int));
- env->board_states = (int*)calloc(grid_size, sizeof(int));
- env->visited = (int*)calloc(grid_size, sizeof(int));
- env->previous_board_state = (int*)calloc(grid_size, sizeof(int));
- env->temp_board_states = (int*)calloc(grid_size, sizeof(int));
- env->capture_count = (int*)calloc(2, sizeof(int));
- env->groups = (Group*)calloc(grid_size, sizeof(Group));
- env->temp_groups = (Group*)calloc(grid_size, sizeof(Group));
- generate_board_positions(env);
- init_groups(env);
-}
-
-void allocate(CGo* env) {
- init(env);
- env->observations = (float*)calloc((env->grid_size)*(env->grid_size)*2 + 2, sizeof(float));
- env->actions = (int*)calloc(1, sizeof(int));
- env->rewards = (float*)calloc(1, sizeof(float));
- env->terminals = (unsigned char*)calloc(1, sizeof(unsigned char));
-}
-
-void c_close(CGo* env) {
- free(env->board_x);
- free(env->board_y);
- free(env->board_states);
- free(env->visited);
- free(env->previous_board_state);
- free(env->temp_board_states);
- free(env->capture_count);
- free(env->temp_groups);
- free(env->groups);
-}
-
-void free_allocated(CGo* env) {
- free(env->actions);
- free(env->observations);
- free(env->terminals);
- free(env->rewards);
- c_close(env);
-}
-
-void compute_observations(CGo* env) {
- int observation_indx=0;
- for (int i = 0; i < (env->grid_size)*(env->grid_size); i++) {
- if(env->board_states[i] ==1 ){
- env->observations[observation_indx] = 1.0;
- }
- else {
- env->observations[observation_indx] = 0.0;
- }
- observation_indx++;
- }
- for (int i = 0; i < (env->grid_size)*(env->grid_size); i++) {
- if(env->board_states[i] ==2 ){
- env->observations[observation_indx] = 1.0;
- }
- else {
- env->observations[observation_indx] = 0.0;
- }
- observation_indx++;
- }
- env->observations[observation_indx] = env->capture_count[0];
- env->observations[observation_indx+1] = env->capture_count[1];
-
-}
-
-int is_valid_position(CGo* env, int x, int y) {
- return (x >= 0 && x < env->grid_size && y >= 0 && y < env->grid_size);
-}
-
-void reset_visited(CGo* env) {
- memset(env->visited, 0, sizeof(int) * (env->grid_size) * (env->grid_size));
-}
-
-void flood_fill(CGo* env, int x, int y, int* territory, int player) {
- if (!is_valid_position(env, x, y)) {
- return;
- }
-
- int pos = y * (env->grid_size) + x;
- if (env->visited[pos] || env->board_states[pos] != 0) {
- return;
- }
- env->visited[pos] = 1;
- territory[player]++;
- // Check adjacent positions
- for (int i = 0; i < 4; i++) {
- flood_fill(env, x + DIRECTIONS[i][0], y + DIRECTIONS[i][1], territory, player);
- }
-}
-
-void compute_score_tromp_taylor(CGo* env) {
- int player_score = 0;
- int opponent_score = 0;
- reset_visited(env);
-
- // Queue for BFS
- int queue_size = (env->grid_size) * (env->grid_size);
- int queue[queue_size];
-
- // First count stones
- for (int i = 0; i < queue_size; i++) {
- if (env->board_states[i] == 1) {
- player_score++;
- } else if (env->board_states[i] == 2) {
- opponent_score++;
- }
- }
-
- // Then process empty territories
- for (int start_pos = 0; start_pos < queue_size; start_pos++) {
- // Skip if not empty or already visited
- if (env->board_states[start_pos] != 0 || env->visited[start_pos]) {
- continue;
- }
-
- // Initialize BFS
- int front = 0, rear = 0;
- int territory_size = 0;
- int bordering_player = 0; // 0=neutral, 1=player1, 2=player2, 3=mixed
-
- queue[rear++] = start_pos;
- env->visited[start_pos] = 1;
-
- // Process connected empty points
- while (front < rear) {
- int pos = queue[front++];
- territory_size++;
- int x = pos % env->grid_size;
- int y = pos / env->grid_size;
-
- // Check all adjacent positions
- for (int i = 0; i < 4; i++) {
- int nx = x + DIRECTIONS[i][0];
- int ny = y + DIRECTIONS[i][1];
-
- if (!is_valid_position(env, nx, ny)) {
- continue;
- }
-
- int npos = ny * env->grid_size + nx;
-
- if (env->board_states[npos] == 0 && !env->visited[npos]) {
- // Add unvisited empty points to queue
- queue[rear++] = npos;
- env->visited[npos] = 1;
- } else if (bordering_player == 0) {
- bordering_player = env->board_states[npos];
- } else if (bordering_player != env->board_states[npos]) {
- bordering_player = 3; // Mixed territory
- }
- }
- }
-
- // Assign territory points
- if (bordering_player == 1) {
- player_score += territory_size;
- } else if (bordering_player == 2) {
- opponent_score += territory_size;
- }
- // Mixed territories (bordering_player == 3) are neutral and not counted
- }
-
- env->score = (float)player_score - (float)opponent_score - env->komi;
-}
-
-int find_in_group(int* group, int group_size, int value) {
- for (int i = 0; i < group_size; i++) {
- if (group[i] == value) {
- return 1; // Found
- }
- }
- return 0; // Not found
-}
-
-
-void capture_group(CGo* env, int* board, int root, int* affected_groups, int* affected_count) {
- // Reset visited array
- reset_visited(env);
-
- // Use a queue for BFS
- int queue_size = (env->grid_size) * (env->grid_size);
- int queue[queue_size];
- int front = 0, rear = 0;
-
- int captured_player = board[root]; // Player whose stones are being captured
- int capturing_player = 3 - captured_player; // Player who captures
-
- queue[rear++] = root;
- env->visited[root] = 1;
-
- while (front != rear) {
- int pos = queue[front++];
- board[pos] = 0; // Remove stone
- env->capture_count[capturing_player - 1]++; // Update capturing player's count
- if(capturing_player-1 == 0){
- env->rewards[0] += env->reward_player_capture;
- env->log.episode_return += env->reward_player_capture;
- } else{
- env->rewards[0] += env->reward_opponent_capture;
- env->log.episode_return += env->reward_opponent_capture;
- }
- int x = pos % (env->grid_size);
- int y = pos / (env->grid_size);
-
- for (int i = 0; i < 4; i++) {
- int nx = x + DIRECTIONS[i][0];
- int ny = y + DIRECTIONS[i][1];
- int npos = ny * (env->grid_size) + nx;
-
- if (!is_valid_position(env, nx, ny)) {
- continue;
- }
-
- if (board[npos] == captured_player && !env->visited[npos]) {
- env->visited[npos] = 1;
- queue[rear++] = npos;
- }
- else if (board[npos] == capturing_player) {
- int adj_root = find(env->temp_groups, npos);
- if (find_in_group(affected_groups, *affected_count, adj_root)) {
- continue;
- }
- affected_groups[(*affected_count)] = adj_root;
- (*affected_count)++;
- }
- }
- }
-}
-
-
-int count_liberties(CGo* env, int root, int* queue) {
- reset_visited(env);
- int liberties = 0;
- int front = 0;
- int rear = 0;
-
- queue[rear++] = root;
- env->visited[root] = 1;
- while (front < rear) {
- int pos = queue[front++];
- int x = pos % (env->grid_size);
- int y = pos / (env->grid_size);
-
- for (int i = 0; i < 4; i++) {
- int nx = x + DIRECTIONS[i][0];
- int ny = y + DIRECTIONS[i][1];
- if (!is_valid_position(env, nx, ny)) {
- continue;
- }
-
- int npos = ny * (env->grid_size) + nx;
- if (env->visited[npos]) {
- continue;
- }
-
- int temp_npos = env->temp_board_states[npos];
- if (temp_npos == 0) {
- liberties++;
- env->visited[npos] = 1;
- } else if (temp_npos == env->temp_board_states[root]) {
- queue[rear++] = npos;
- env->visited[npos] = 1;
- }
- }
- }
- return liberties;
-}
-
-int is_ko(CGo* env) {
- for (int i = 0; i < (env->grid_size) * (env->grid_size); i++) {
- if (env->temp_board_states[i] != env->previous_board_state[i]) {
- return 0; // Not a ko
- }
- }
- return 1; // Is a ko
-}
-
-int make_move(CGo* env, int pos, int player){
- int x = pos % (env->grid_size);
- int y = pos / (env->grid_size);
- // cannot place stone on occupied tile
- if (env->board_states[pos] != 0) {
- return 0 ;
- }
- // temp structures
- memcpy(env->temp_board_states, env->board_states, sizeof(int) * (env->grid_size) * (env->grid_size));
- memcpy(env->temp_groups, env->groups, sizeof(Group) * (env->grid_size) * (env->grid_size));
- // create new group
- env->temp_board_states[pos] = player;
- env->temp_groups[pos].parent = pos;
- env->temp_groups[pos].rank = 0;
- env->temp_groups[pos].size = 1;
- env->temp_groups[pos].liberties = 0;
-
- int max_affected_groups = (env->grid_size) * (env->grid_size);
- int affected_groups[max_affected_groups];
- int affected_count = 0;
- affected_groups[affected_count++] = pos;
-
- int queue[(env->grid_size) * (env->grid_size)];
-
- // Perform unions and track affected groups
- for (int i = 0; i < 4; i++) {
- int nx = x + DIRECTIONS[i][0];
- int ny = y + DIRECTIONS[i][1];
- int npos = ny * (env->grid_size) + nx;
- if (!is_valid_position(env, nx, ny)) {
- continue;
- }
- if (env->temp_board_states[npos] == player) {
- union_groups(env->temp_groups, pos, npos);
- affected_groups[affected_count++] = npos;
- } else if (env->temp_board_states[npos] == 3 - player) {
- affected_groups[affected_count++] = npos;
- }
- }
-
- // Recalculate liberties only for affected groups
- for (int i = 0; i < affected_count; i++) {
- int root = find(env->temp_groups, affected_groups[i]);
- env->temp_groups[root].liberties = count_liberties(env, root, queue);
- }
-
- // Check for captures
- bool captured = false;
- for (int i = 0; i < affected_count; i++) {
- int root = find(env->temp_groups, affected_groups[i]);
- if (env->temp_board_states[root] == 3 - player && env->temp_groups[root].liberties == 0) {
- capture_group(env, env->temp_board_states, root, affected_groups, &affected_count);
- captured = true;
- }
- }
- // If captures occurred, recalculate liberties again
- if (captured) {
- for (int i = 0; i < affected_count; i++) {
- int root = find(env->temp_groups, affected_groups[i]);
- env->temp_groups[root].liberties = count_liberties(env, root, queue);
- }
- // Check for ko rule violation
- if(is_ko(env)) {
- return 0;
- }
- }
- // self capture
- int root = find(env->temp_groups, pos);
- if (env->temp_groups[root].liberties == 0) {
- return 0;
- }
- memcpy(env->board_states, env->temp_board_states, sizeof(int) * (env->grid_size) * (env->grid_size));
- memcpy(env->groups, env->temp_groups, sizeof(Group) * (env->grid_size) * (env->grid_size));
- return 1;
-
-}
-
-
-void enemy_random_move(CGo* env){
- int num_positions = (env->grid_size)*(env->grid_size);
- int positions[num_positions];
- int count = 0;
-
- // Collect all empty positions
- for(int i = 0; i < num_positions; i++){
- if(env->board_states[i] == 0){
- positions[count++] = i;
- }
- }
- // Shuffle the positions
- for(int i = count - 1; i > 0; i--){
- int j = rand() % (i + 1);
- int temp = positions[i];
- positions[i] = positions[j];
- positions[j] = temp;
- }
- // Try to make a move in a random empty position
- for(int i = 0; i < count; i++){
- if(make_move(env, positions[i], 2)){
- return;
- }
- }
- // If no move is possible, pass or end the game
- env->terminals[0] = 1;
-}
-
-int find_group_liberty(CGo* env, int root){
- reset_visited(env);
- int queue[(env->grid_size)*(env->grid_size)];
- int front = 0, rear = 0;
- queue[rear++] = root;
- env->visited[root] = 1;
-
- while(front < rear){
- int pos = queue[front++];
- int x = pos % (env->grid_size);
- int y = pos / (env->grid_size);
-
- for(int i = 0; i < 4; i++){
- int nx = x + DIRECTIONS[i][0];
- int ny = y + DIRECTIONS[i][1];
- int npos = ny * (env->grid_size) + nx;
- if(!is_valid_position(env, nx, ny)){
- continue;
- }
- if(env->board_states[npos] == 0){
- return npos; // Found a liberty
- } else if(env->board_states[npos] == env->board_states[root] && !env->visited[npos]){
- env->visited[npos] = 1;
- queue[rear++] = npos;
- }
- }
- }
- return -1; // Should not happen if liberties > 0
-}
-
-void enemy_greedy_hard(CGo* env){
- // Attempt to capture opponent stones in atari
- int liberties[4][(env->grid_size) * (env->grid_size)];
- int liberty_counts[4] = {0};
- for(int i = 0; i < (env->grid_size)*(env->grid_size); i++){
- if(env->board_states[i]==0){
- continue;
- }
- if (env->board_states[i]==1){
- int root = find(env->groups, i);
- int group_liberties = env->groups[root].liberties;
- if (group_liberties >= 1 && group_liberties <= 4) {
- int liberty = find_group_liberty(env, root);
- liberties[group_liberties - 1][liberty_counts[group_liberties - 1]++] = liberty;
- }
- } else if (env->board_states[i]==2){
- int root = find(env->groups, i);
- int group_liberties = env->groups[root].liberties;
- if (group_liberties==1) {
- int liberty = find_group_liberty(env, root);
- liberties[group_liberties - 1][liberty_counts[group_liberties - 1]++] = liberty;
- }
- }
- }
- // make move to attack or defend
- for (int priority = 0; priority < 4; priority++) {
- for (int i = 0; i < liberty_counts[priority]; i++) {
- if (make_move(env, liberties[priority][i], 2)) {
- return;
- }
- }
- }
- // random move
- enemy_random_move(env);
-}
-
-void enemy_greedy_easy(CGo* env){
- // Attempt to capture opponent stones in atari
- for(int i = 0; i < (env->grid_size)*(env->grid_size); i++){
- if(env->board_states[i] != 1){
- continue;
- }
- int root = find(env->groups, i);
- if(env->groups[root].liberties == 1){
- int liberty = find_group_liberty(env, root);
- if(make_move(env, liberty, 2)){
- return; // Successful capture
- }
- }
- }
- // Protect own stones in atari
- for(int i = 0; i < (env->grid_size)*(env->grid_size); i++){
- if(env->board_states[i] != 2){
- continue;
- }
- // Enemy's own stones
- int root = find(env->groups, i);
- if(env->groups[root].liberties == 1){
- int liberty = find_group_liberty(env, root);
- if(make_move(env, liberty, 2)){
- return; // Successful defense
- }
- }
- }
- // Play a random legal move
- enemy_random_move(env);
-}
-
-void c_reset(CGo* env) {
- env->tick = 0;
- // We don't reset the log struct - leave it accumulating like in Pong
- env->terminals[0] = 0;
- env->score = 0;
- for (int i = 0; i < (env->grid_size)*(env->grid_size); i++) {
- env->board_states[i] = 0;
- env->temp_board_states[i] = 0;
- env->visited[i] = 0;
- env->previous_board_state[i] = 0;
- env->groups[i].parent = i;
- env->groups[i].rank = 0;
- env->groups[i].size = 0;
- env->groups[i].liberties = 0;
- }
- env->capture_count[0] = 0;
- env->capture_count[1] = 0;
- env->last_capture_position = -1;
- env->moves_made = 0;
- compute_observations(env);
-}
-
-void end_game(CGo* env){
- compute_score_tromp_taylor(env);
- if (env->score > 0) {
- env->rewards[0] = 1.0;
- }
- else if (env->score < 0) {
- env->rewards[0] = -1.0;
- }
- else {
- env->rewards[0] = 0.0;
- }
- add_log(env);
- c_reset(env);
-}
-
-void c_step(CGo* env) {
- env->tick += 1;
- env->rewards[0] = 0.0;
- int action = (int)env->actions[0];
- // useful for training , can prob be a hyper param. Recommend to increase with larger board size
- float max_moves = 3 * env->grid_size * env->grid_size;
- if (env->tick > max_moves) {
- env->terminals[0] = 1;
- end_game(env);
- compute_observations(env);
- return;
- }
- if(action == NOOP){
- env->rewards[0] = env->reward_move_pass;
- env->log.episode_return += env->reward_move_pass;
- enemy_greedy_hard(env);
- if (env->terminals[0] == 1) {
- end_game(env);
- return;
- }
- compute_observations(env);
- return;
- }
- if (action >= MOVE_MIN && action <= (env->grid_size)*(env->grid_size)) {
- memcpy(env->previous_board_state, env->board_states, sizeof(int) * (env->grid_size) * (env->grid_size));
- if(make_move(env, action-1, 1)) {
- env->moves_made++;
- env->rewards[0] = env->reward_move_valid;
- env->log.episode_return += env->reward_move_valid;
- enemy_greedy_hard(env);
-
- } else {
- env->rewards[0] = env->reward_move_invalid;
- env->log.episode_return += env->reward_move_invalid;
- }
- compute_observations(env);
- }
-
- if(env->rewards[0] > 1){
- env->rewards[0] = 1;
- }
- if(env->rewards[0] < -1){
- env->rewards[0] = -1;
- }
-
- if (env->terminals[0] == 1) {
- end_game(env);
- return;
- }
-
- compute_observations(env);
-}
-
-const Color STONE_GRAY = (Color){80, 80, 80, 255};
-const Color PUFF_RED = (Color){187, 0, 0, 255};
-const Color PUFF_CYAN = (Color){0, 187, 187, 255};
-const Color PUFF_WHITE = (Color){241, 241, 241, 241};
-const Color PUFF_BACKGROUND = (Color){6, 24, 24, 255};
-const Color PUFF_BACKGROUND2 = (Color){18, 72, 72, 255};
-
-struct Client {
- float width;
- float height;
-};
-
-Client* make_client(int width, int height) {
- Client* client = (Client*)calloc(1, sizeof(Client));
- client->width = width;
- client->height = height;
- InitWindow(width, height, "PufferLib Ray Go");
- SetTargetFPS(60);
- return client;
-}
-
-void c_render(CGo* env) {
- if (env->client == NULL) {
- env->client = make_client(env->width, env->height);
- }
-
- if (IsKeyDown(KEY_ESCAPE)) {
- exit(0);
- }
-
- BeginDrawing();
- ClearBackground(PUFF_BACKGROUND);
-
- int board_size = (env->grid_size + 1) * env->grid_square_size;
- DrawRectangle(0, 0, board_size, board_size, PUFF_BACKGROUND);
- DrawRectangle(
- env->grid_square_size,
- env->grid_square_size,
- board_size - 2*env->grid_square_size,
- board_size - 2*env->grid_square_size,
- PUFF_BACKGROUND2
- );
- int start = env->grid_square_size;
- int end = board_size - env->grid_square_size;
- for (int i = 1; i <= env->grid_size; i++) {
- DrawLineEx(
- (Vector2){start, i*start},
- (Vector2){end, i*start},
- 4, PUFF_BACKGROUND
- );
- DrawLineEx(
- (Vector2){i*start, start},
- (Vector2){i*start, end},
- 4, PUFF_BACKGROUND
- );
- }
-
- for (int i = 0; i < (env->grid_size) * (env->grid_size); i++) {
- int position_state = env->board_states[i];
- int row = i / (env->grid_size);
- int col = i % (env->grid_size);
- int x = col * env->grid_square_size;
- int y = row * env->grid_square_size;
- // Calculate the circle position based on the grid
- int circle_x = x + env->grid_square_size;
- int circle_y = y + env->grid_square_size;
- // if player draw circle tile for black
- int inner = (env->grid_square_size / 2) - 4;
- int outer = (env->grid_square_size / 2) - 2;
- if (position_state == 1) {
- DrawCircleGradient(circle_x, circle_y, outer, STONE_GRAY, BLACK);
- }
- // if enemy draw circle tile for white
- if (position_state == 2) {
- DrawCircleGradient(circle_x, circle_y, inner, WHITE, GRAY);
- }
- }
- // design a pass button
- int left = (env->grid_size + 1)*env->grid_square_size;
- int top = env->grid_square_size;
- DrawRectangle(left, top + 90, 100, 50, GRAY);
- DrawText("Pass", left + 25, top + 105, 20, PUFF_WHITE);
-
- // show capture count for both players
- DrawText(
- TextFormat("Player 1 Capture Count: %d", env->capture_count[0]),
- left, top, 20, PUFF_WHITE
- );
- DrawText(
- TextFormat("Player 2 Capture Count: %d", env->capture_count[1]),
- left, top + 40, 20, PUFF_WHITE
- );
- EndDrawing();
-}
-void close_client(Client* client) {
- CloseWindow();
- free(client);
-}
diff --git a/pufferlib/ocean/go/go.py b/pufferlib/ocean/go/go.py
deleted file mode 100644
index 06b87155d..000000000
--- a/pufferlib/ocean/go/go.py
+++ /dev/null
@@ -1,92 +0,0 @@
-'''High-perf Pong
-
-Inspired from https://gist.github.com/Yttrmin/18ecc3d2d68b407b4be1
-& https://jair.org/index.php/jair/article/view/10819/25823
-& https://www.youtube.com/watch?v=PSQt5KGv7Vk
-'''
-
-import numpy as np
-import gymnasium
-
-import pufferlib
-from pufferlib.ocean.go import binding
-
-class Go(pufferlib.PufferEnv):
- def __init__(self, num_envs=1, render_mode=None, log_interval=1,
- width=950, height=800,
- grid_size=7,
- board_width=600, board_height=600,
- grid_square_size=600/9,
- moves_made=0,
- komi=7.5,
- score = 0.0,
- last_capture_position=-1,
- reward_move_pass = -0.25,
- reward_move_invalid = -0.1,
- reward_move_valid = 0.1,
- reward_player_capture = 0.25,
- reward_opponent_capture = -0.25,
- buf = None, seed=0):
-
- # env
- self.num_agents = num_envs
- self.render_mode = render_mode
- self.log_interval = log_interval
- self.tick = 0
- self.num_obs = (grid_size) * (grid_size)*2 + 2
- self.num_act = (grid_size) * (grid_size) + 1
- self.single_observation_space = gymnasium.spaces.Box(low=0, high=1,
- shape=(self.num_obs,), dtype=np.float32)
- self.single_action_space = gymnasium.spaces.Discrete(self.num_act)
-
- super().__init__(buf=buf)
- height = 64*(grid_size+1)
- self.c_envs = binding.vec_init(self.observations, self.actions, self.rewards,
- self.terminals, self.truncations, num_envs, seed, width=width, height=height, grid_size=grid_size,
- board_width=board_width, board_height=board_height, grid_square_size=grid_square_size,
- moves_made=moves_made, komi=komi, score=score, last_capture_position=last_capture_position,
- reward_move_pass=reward_move_pass, reward_move_invalid=reward_move_invalid,
- reward_move_valid=reward_move_valid, reward_player_capture=reward_player_capture,
- reward_opponent_capture=reward_opponent_capture)
-
- def reset(self, seed=None):
- binding.vec_reset(self.c_envs, seed)
- self.tick = 0
- return self.observations, []
-
- def step(self, actions):
- self.actions[:] = actions
- binding.vec_step(self.c_envs)
- self.tick += 1
- info = []
- if self.tick % self.log_interval == 0:
- info.append(binding.vec_log(self.c_envs))
-
- return (self.observations, self.rewards,
- self.terminals, self.truncations, info)
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-def test_performance(timeout=10, atn_cache=1024):
- num_envs=1000
- env = Go(num_envs=num_envs)
- env.reset()
- tick = 0
-
- actions = np.random.randint(0, env.single_action_space.n, (atn_cache, num_envs))
-
- import time
- start = time.time()
- while time.time() - start < timeout:
- atn = actions[tick % atn_cache]
- env.step(atn)
- tick += 1
-
- sps = num_envs * tick / (time.time() - start)
- print(f'SPS: {sps:,}')
-if __name__ == '__main__':
- test_performance()
diff --git a/pufferlib/ocean/grid/__init__.py b/pufferlib/ocean/grid/__init__.py
deleted file mode 100644
index e69de29bb..000000000
diff --git a/pufferlib/ocean/grid/binding.c b/pufferlib/ocean/grid/binding.c
deleted file mode 100644
index 449a8a587..000000000
--- a/pufferlib/ocean/grid/binding.c
+++ /dev/null
@@ -1,71 +0,0 @@
-#include "grid.h"
-
-#define Env Grid
-#define MY_SHARED
-#include "../env_binding.h"
-
-static PyObject* my_shared(PyObject* self, PyObject* args, PyObject* kwargs) {
- int num_maps = unpack(kwargs, "num_maps");
- int max_size = unpack(kwargs, "max_size");
- int size = unpack(kwargs, "size");
- State* levels = calloc(num_maps, sizeof(State));
-
- if (max_size <= 5) {
- PyErr_SetString(PyExc_ValueError, "max_size must be >5");
- return NULL;
- }
-
- // Temporary env used to gen maps
- Grid env;
- env.max_size = max_size;
- init_grid(&env);
-
- srand(time(NULL));
- int start_seed = rand();
- for (int i = 0; i < num_maps; i++) {
- int sz = size;
- if (size == -1) {
- sz = 5 + (rand() % (max_size-5));
- }
-
- if (sz % 2 == 0) {
- sz -= 1;
- }
-
- float difficulty = (float)rand()/(float)(RAND_MAX);
- create_maze_level(&env, sz, sz, difficulty, start_seed + i);
- init_state(&levels[i], max_size, 1);
- get_state(&env, &levels[i]);
- }
-
- return PyLong_FromVoidPtr(levels);
-}
-
-static int my_init(Env* env, PyObject* args, PyObject* kwargs) {
- env->max_size = unpack(kwargs, "max_size");
- env->num_maps = unpack(kwargs, "num_maps");
- init_grid(env);
-
- PyObject* handle_obj = PyDict_GetItemString(kwargs, "state");
- if (!PyObject_TypeCheck(handle_obj, &PyLong_Type)) {
- PyErr_SetString(PyExc_TypeError, "state handle must be an integer");
- return 1;
- }
-
- State* levels = (State*)PyLong_AsVoidPtr(handle_obj);
- if (!levels) {
- PyErr_SetString(PyExc_ValueError, "Invalid state handle");
- return 1;
- }
-
- env->levels = levels;
- return 0;
-}
-
-static int my_log(PyObject* dict, Log* log) {
- assign_to_dict(dict, "perf", log->perf);
- assign_to_dict(dict, "score", log->score);
- assign_to_dict(dict, "episode_return", log->episode_return);
- assign_to_dict(dict, "episode_length", log->episode_length);
- return 0;
-}
diff --git a/pufferlib/ocean/grid/c_grid.pyx b/pufferlib/ocean/grid/c_grid.pyx
deleted file mode 100644
index 64c720a89..000000000
--- a/pufferlib/ocean/grid/c_grid.pyx
+++ /dev/null
@@ -1,206 +0,0 @@
-# distutils: define_macros=NPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION
-# cython: language_level=3
-# cython: boundscheck=False
-# cython: initializedcheck=False
-# cython: wraparound=False
-# cython: cdivision=True
-# cython: nonecheck=False
-# cython: profile=False
-
-from libc.stdlib cimport rand
-
-cdef:
- int EMPTY = 0
- int FOOD = 1
- int WALL = 2
- int AGENT_1 = 3
- int AGENT_2 = 4
- int AGENT_3 = 5
- int AGENT_4 = 6
-
- int PASS = 0
- int NORTH = 1
- int SOUTH = 2
- int EAST = 3
- int WEST = 4
-
-cdef class Environment:
- cdef:
- int width
- int height
- int num_agents
- int horizon
- int vision_range
- float agent_speed
- bint discretize
- float food_reward
- int expected_lifespan
- int obs_size
-
- unsigned char[:, :] grid
- unsigned char[:, :, :] observations
- float[:] rewards
- float[:, :] agent_positions
- float[:, :] spawn_position_cands
- int[:] agent_colors
-
- def __init__(self, grid, agent_positions, spawn_position_cands, agent_colors,
- observations, rewards, int width, int height, int num_agents, int horizon,
- int vision_range, float agent_speed, bint discretize, float food_reward,
- int expected_lifespan):
- self.width = width
- self.height = height
- self.num_agents = num_agents
- self.horizon = horizon
- self.vision_range = vision_range
- self.agent_speed = agent_speed
- self.discretize = discretize
- self.food_reward = food_reward
- self.expected_lifespan = expected_lifespan
- self.obs_size = 2*self.vision_range + 1
-
- self.grid = grid
- self.observations = observations
- self.rewards = rewards
- self.agent_positions = agent_positions
- self.spawn_position_cands = spawn_position_cands
- self.agent_colors = agent_colors
-
- cdef void compute_observations(self):
- cdef:
- float y
- float x
- int r
- int c
- int agent_idx
-
- for agent_idx in range(self.num_agents):
- y = self.agent_positions[agent_idx, 0]
- x = self.agent_positions[agent_idx, 1]
- r = int(y)
- c = int(x)
- self.observations[agent_idx, :] = self.grid[
- r-self.vision_range:r+self.vision_range+1,
- c-self.vision_range:c+self.vision_range+1
- ]
-
- cdef void spawn_food(self):
- cdef int r, c, tile
- while True:
- r = rand() % (self.height - 1)
- c = rand() % (self.width - 1)
- tile = self.grid[r, c]
- if tile == EMPTY:
- self.grid[r, c] = FOOD
- return
-
- cdef void spawn_agent(self, int agent_idx):
- cdef int old_r, old_c, r, c, tile
-
- # Delete agent from old position
- old_r = int(self.agent_positions[agent_idx, 0])
- old_c = int(self.agent_positions[agent_idx, 1])
- self.grid[old_r, old_c] = EMPTY
-
- r = rand() % (self.height - 1)
- c = rand() % (self.width - 1)
- tile = self.grid[r, c]
- if tile == EMPTY:
- # Spawn agent in new position
- self.grid[r, c] = self.agent_colors[agent_idx]
- self.agent_positions[agent_idx, 0] = r
- self.agent_positions[agent_idx, 1] = c
- return
-
- def reset(self, seed=0):
- # Add borders
- cdef int left = int(self.agent_speed * self.vision_range)
- cdef int right = self.width - int(self.agent_speed*self.vision_range) - 1
- cdef int bottom = self.height - int(self.agent_speed*self.vision_range) - 1
- self.grid[:left, :] = WALL
- self.grid[:, :left] = WALL
- self.grid[bottom:, :] = WALL
- self.grid[:, right:] = WALL
-
- # Agent spawning
- cdef:
- int spawn_idx
- float y
- float x
- int disc_y
- int disc_x
- int agent_idx = 0
-
- for spawn_idx in range(self.width*self.height):
- y = self.spawn_position_cands[spawn_idx, 0]
- x = self.spawn_position_cands[spawn_idx, 1]
- disc_y = int(y)
- disc_x = int(x)
-
- if self.grid[disc_y, disc_x] == EMPTY:
- self.grid[disc_y, disc_x] = self.agent_colors[agent_idx]
- self.agent_positions[agent_idx, 0] = y
- self.agent_positions[agent_idx, 1] = x
- agent_idx += 1
- if agent_idx == self.num_agents:
- break
-
- self.compute_observations()
-
- def step(self, np_actions):
- cdef:
- float[:, :] actions_continuous
- unsigned int[:, :] actions_discrete
- int agent_idx
- float y
- float x
- float vel_y
- float vel_x
- int disc_y
- int disc_x
- int disc_dest_y
- int disc_dest_x
-
- if self.discretize:
- actions_discrete = np_actions
- else:
- actions_continuous = np_actions
-
- for agent_idx in range(self.num_agents):
- if self.discretize:
- # Convert [0, 1, 2] to [-1, 0, 1]
- vel_y = float(actions_discrete[agent_idx, 0]) - 1.0
- vel_x = float(actions_discrete[agent_idx, 1]) - 1.0
- else:
- vel_y = actions_continuous[agent_idx, 0]
- vel_x = actions_continuous[agent_idx, 1]
-
- y = self.agent_positions[agent_idx, 0]
- x = self.agent_positions[agent_idx, 1]
- dest_y = y + self.agent_speed * vel_y
- dest_x = x + self.agent_speed * vel_x
-
- # Discretize
- disc_y = int(y)
- disc_x = int(x)
- disc_dest_y = int(dest_y)
- disc_dest_x = int(dest_x)
-
- if self.grid[disc_dest_y, disc_dest_x] == FOOD:
- self.grid[disc_dest_y, disc_dest_x] = EMPTY
- self.rewards[agent_idx] = self.food_reward
- self.spawn_food()
-
- if self.grid[disc_dest_y, disc_dest_x] == 0:
- self.grid[disc_y, disc_x] = EMPTY
- self.grid[disc_dest_y, disc_dest_x] = self.agent_colors[agent_idx]
-
- # Continuous position update
- self.agent_positions[agent_idx, 0] = dest_y
- self.agent_positions[agent_idx, 1] = dest_x
-
- # Randomly respawn agents
- if rand() % self.expected_lifespan == 0:
- self.spawn_agent(agent_idx)
-
- self.compute_observations()
diff --git a/pufferlib/ocean/grid/cy_grid.pyx b/pufferlib/ocean/grid/cy_grid.pyx
deleted file mode 100644
index bfafe25c2..000000000
--- a/pufferlib/ocean/grid/cy_grid.pyx
+++ /dev/null
@@ -1,186 +0,0 @@
-# distutils: define_macros=NPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION
-# cython: language_level=3
-# cython: boundscheck=False
-# cython: initializedcheck=False
-# cython: wraparound=False
-# cython: cdivision=True
-# cython: nonecheck=False
-# cython: profile=True
-
-from libc.stdlib cimport calloc, free, rand
-
-cdef extern from "grid.h":
- int LOG_BUFFER_SIZE
-
- ctypedef struct Log:
- float episode_return;
- float episode_length;
- float score;
-
- ctypedef struct LogBuffer
- LogBuffer* allocate_logbuffer(int)
- void free_logbuffer(LogBuffer*)
- Log aggregate_and_clear(LogBuffer*)
-
- ctypedef struct Agent:
- float y;
- float x;
- float prev_y;
- float prev_x;
- float spawn_y;
- float spawn_x;
- int color;
- float direction;
- int held;
-
- ctypedef struct Grid:
- int width;
- int height;
- int num_agents;
- int horizon;
- int vision;
- float speed;
- int obs_size;
- int max_size;
- bint discretize;
- Log log;
- LogBuffer* log_buffer;
- Agent* agents;
- unsigned char* grid;
- int* counts;
- unsigned char* observations;
- float* actions;
- float* rewards;
- unsigned char* dones;
-
- ctypedef struct State:
- int width;
- int height;
- int num_agents;
- Agent* agents;
- unsigned char* grid;
-
- cdef:
- void create_maze_level(Grid* env, int width, int height, float difficulty, int seed)
- void load_locked_room_env(unsigned char* observations,
- unsigned int* actions, float* rewards, float* dones)
- void init_grid(Grid* env)
- void reset(Grid* env, int seed)
- void compute_observations(Grid* env)
- bint step(Grid* env)
- ctypedef struct Renderer
- Renderer* init_renderer(int cell_size, int width, int height)
- void render_global(Renderer*erenderer, Grid* env, float frac, float overlay)
- void clear_overlay(Renderer* renderer)
- void close_renderer(Renderer* renderer)
- void init_state(State* state, int max_size, int num_agents)
- void free_state(State* state)
- void get_state(Grid* env, State* state)
- void set_state(Grid* env, State* state)
-
-import numpy as np
-cimport numpy as cnp
-
-cdef class CGrid:
- cdef:
- Grid* envs
- State* levels
- Renderer* client
- LogBuffer* logs
- int num_envs
- int num_maps
- int max_size
-
- def __init__(self, unsigned char[:, :] observations, float[:] actions,
- float[:] rewards, unsigned char[:] terminals, int num_envs, int num_maps,
- int size, int max_size):
-
- self.num_envs = num_envs
- self.num_maps = num_maps
- if size > max_size:
- max_size = size
-
- self.max_size = max_size
-
- self.client = NULL
- self.levels = calloc(num_maps, sizeof(State))
- self.envs = calloc(num_envs, sizeof(Grid))
- self.logs = allocate_logbuffer(LOG_BUFFER_SIZE)
-
- cdef int i
- for i in range(num_envs):
- self.envs[i] = Grid(
- observations = &observations[i, 0],
- actions = &actions[i],
- rewards = &rewards[i],
- dones = &terminals[i],
- log_buffer = self.logs,
- max_size = max_size,
- num_agents = 1,
- vision = 5,
- speed = 1,
- discretize = True,
- )
- init_grid(&self.envs[i])
-
- cdef float difficulty
- cdef int sz
- for i in range(num_maps):
-
- # RNG or fixed size
- if size == -1:
- sz = np.random.randint(5, max_size)
- else:
- sz = size
-
- if sz % 2 == 0:
- sz -= 1
-
- difficulty = np.random.rand()
- create_maze_level(&self.envs[0], sz, sz, difficulty, i)
- init_state(&self.levels[i], max_size, 1)
- get_state(&self.envs[0], &self.levels[i])
-
- def reset(self):
- cdef int i, idx
- for i in range(self.num_envs):
- idx = rand() % self.num_maps
- reset(&self.envs[i], i)
- set_state(&self.envs[i], &self.levels[idx])
- compute_observations(&self.envs[i])
-
- def step(self):
- cdef:
- int i, idx
- bint done
-
- for i in range(self.num_envs):
- done = step(&self.envs[i])
- if done:
- idx = rand() % self.num_maps
- reset(&self.envs[i], i)
- set_state(&self.envs[i], &self.levels[idx])
-
- if i == 0 and self.client != NULL:
- clear_overlay(self.client)
-
- def render(self, int cell_size=16, float overlay=0.0):
- if self.client == NULL:
- import os
- cwd = os.getcwd()
- os.chdir(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
- self.client = init_renderer(cell_size, self.max_size, self.max_size)
- os.chdir(cwd)
-
- render_global(self.client, &self.envs[0], 0, overlay)
-
- def log(self):
- cdef Log log = aggregate_and_clear(self.logs)
- return log
-
- def close(self):
- if self.client != NULL:
- close_renderer(self.client)
- self.client = NULL
-
- #free_envs(self.envs, self.num_envs)
diff --git a/pufferlib/ocean/grid/grid.c b/pufferlib/ocean/grid/grid.c
deleted file mode 100644
index 3a267a313..000000000
--- a/pufferlib/ocean/grid/grid.c
+++ /dev/null
@@ -1,93 +0,0 @@
-#include "grid.h"
-
-int main() {
- int max_size = 32;
- int width = 32;
- int height = 32;
- int num_agents = 1;
- int horizon = 128;
- float speed = 1;
- int vision = 5;
- bool discretize = true;
-
- int render_cell_size = 32;
- int seed = 0;
-
- Grid* env = allocate_grid(max_size, num_agents, horizon,
- vision, speed, discretize);
-
- //env->width = 32;
- //env->height = 32; env->agents[0].spawn_x = 16;
- //env->agents[0].spawn_y = 16;
- //env->agents[0].color = 6;
- //reset(env, seed);
- //load_locked_room_preset(env);
-
-
- State* levels = calloc(1, sizeof(State));
-
- create_maze_level(env, 31, 31, 0.85, seed);
- init_state(levels, max_size, num_agents);
- get_state(env, levels);
- env->num_maps = 1;
- env->levels = levels;
- //generate_locked_room(env);
- //State state;
- //init_state(&state, env->max_size, env->num_agents);
- //get_state(env, &state);
-
- /*
- width = height = 31;
- env->width=31;
- env->height=31;
- env->agents[0].spawn_x = 1;
- env->agents[0].spawn_y = 1;
- reset(env, seed);
- generate_growing_tree_maze(env->grid, env->width, env->height, max_size, 0.85, 0);
- env->grid[(env->height-2)*env->max_size + (env->width - 2)] = GOAL;
- */
-
- int tick = 0;
- c_render(env);
- while (!WindowShouldClose()) {
- // User can take control of the first agent
- env->actions[0] = ATN_FORWARD;
- Agent* agent = &env->agents[0];
-
- // TODO: Why are up and down flipped?
- if (IsKeyDown(KEY_LEFT_SHIFT)) {
- if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)){
- //env->actions[0] = ATN_FORWARD;
- agent->direction = 3.0*PI/2.0;
- } else if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)) {
- //env->actions[0] = ATN_BACK;
- agent->direction = PI/2.0;
- } else if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) {
- //env->actions[0] = ATN_LEFT;
- agent->direction = PI;
- } else if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) {
- //env->actions[0] = ATN_RIGHT;
- agent->direction = 0;
- } else {
- env->actions[0] = ATN_PASS;
- }
- } else {
- for (int i = 0; i < num_agents; i++) {
- env->actions[i] = rand() % 5;
- }
- }
-
- //env->actions[0] = actions[t];
- tick = (tick + 1)%12;
- bool done = false;
- if (tick % 1 == 0) {
- c_step(env);
- //printf("direction: %f\n", env->agents[0].direction);
-
- }
- c_render(env);
- }
- free_allocated_grid(env);
- return 0;
-}
-
diff --git a/pufferlib/ocean/grid/grid.h b/pufferlib/ocean/grid/grid.h
deleted file mode 100644
index c82001d75..000000000
--- a/pufferlib/ocean/grid/grid.h
+++ /dev/null
@@ -1,767 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include "raylib.h"
-
-#define TWO_PI 2.0*PI
-#define MAX_SIZE 40
-
-#define ATN_PASS 0
-#define ATN_FORWARD 1
-#define ATN_LEFT 2
-#define ATN_RIGHT 3
-#define ATN_BACK 4
-
-#define DIR_WEST 0.0;
-#define DIR_NORTH PI/2.0;
-#define DIR_EAST PI;
-#define DIR_SOUTH 3.0*PI/2.0;
-
-#define EMPTY 0
-#define WALL 1
-#define LAVA 2
-#define GOAL 3
-#define REWARD 4
-#define OBJECT 5
-#define AGENT 6
-#define KEY 14
-#define DOOR_LOCKED 20
-#define DOOR_OPEN 26
-
-#define LOG_BUFFER_SIZE 4096
-
-typedef struct Log Log;
-struct Log {
- float perf;
- float score;
- float episode_return;
- float episode_length;
- float n;
-};
-
-// 8 unique agents
-bool is_agent(int idx) {
- return idx >= AGENT && idx < AGENT + 8;
-}
-int rand_color() {
- return AGENT + rand()%8;
-}
-
-// 6 unique keys and doors
-bool is_key(int idx) {
- return idx >= KEY && idx < KEY + 6;
-}
-bool is_locked_door(int idx) {
- return idx >= DOOR_LOCKED && idx < DOOR_LOCKED + 6;
-}
-bool is_open_door(int idx) {
- return idx >= DOOR_OPEN && idx <= DOOR_OPEN + 6;
-}
-bool is_correct_key(int key, int door) {
- return key == door - 6;
-}
-
-typedef struct Agent Agent;
-struct Agent {
- float y;
- float x;
- float prev_y;
- float prev_x;
- float spawn_y;
- float spawn_x;
- int color;
- float direction;
- int held;
-};
-
-typedef struct Renderer Renderer;
-typedef struct State State;
-typedef struct Grid Grid;
-struct Grid{
- Renderer* renderer;
- State* levels;
- int num_maps;
- int width;
- int height;
- int num_agents;
- int horizon;
- int vision;
- int tick;
- float speed;
- int obs_size;
- int max_size;
- bool discretize;
- Log log;
- Agent* agents;
- unsigned char* grid;
- int* counts;
- unsigned char* observations;
- float* actions;
- float* rewards;
- unsigned char* terminals;
-};
-
-void init_grid(Grid* env) {
- env->num_agents = 1;
- env->vision = 5;
- env->speed = 1;
- env->discretize = true;
- env->obs_size = 2*env->vision + 1;
- int env_mem= env->max_size * env->max_size;
- env->grid = calloc(env_mem, sizeof(unsigned char));
- env->counts = calloc(env_mem, sizeof(int));
- env->agents = calloc(env->num_agents, sizeof(Agent));
-}
-
-Grid* allocate_grid(int max_size, int num_agents, int horizon,
- int vision, float speed, bool discretize) {
- Grid* env = (Grid*)calloc(1, sizeof(Grid));
- env->max_size = max_size;
- env->num_agents = num_agents;
- env->horizon = horizon;
- env->vision = vision;
- env->speed = speed;
- env->discretize = discretize;
- int obs_size = 2*vision + 1;
- env->observations = calloc(
- num_agents*obs_size*obs_size, sizeof(unsigned char));
- env->actions = calloc(num_agents, sizeof(float));
- env->rewards = calloc(num_agents, sizeof(float));
- env->terminals = calloc(num_agents, sizeof(unsigned char));
- init_grid(env);
- return env;
-}
-
-void c_close(Grid* env) {
- free(env->grid);
- free(env->counts);
- free(env->agents);
- free(env);
-}
-
-void free_allocated_grid(Grid* env) {
- free(env->observations);
- free(env->actions);
- free(env->rewards);
- free(env->terminals);
- c_close(env);
-}
-
-bool in_bounds(Grid* env, int y, int c) {
- return (y >= 0 && y <= env->height
- && c >= 0 && c <= env->width);
-}
-
-int grid_offset(Grid* env, int y, int x) {
- return y*env->max_size + x;
-}
-
-void add_log(Grid* env, int idx) {
- env->log.perf += env->rewards[idx];
- env->log.score += env->rewards[idx];
- env->log.episode_return += env->rewards[idx];
- env->log.episode_length += env->tick;
- env->log.n += 1.0;
-}
-
-void compute_observations(Grid* env) {
- memset(env->observations, 0, env->obs_size*env->obs_size*env->num_agents);
- for (int agent_idx = 0; agent_idx < env->num_agents; agent_idx++) {
- Agent* agent = &env->agents[agent_idx];
- float y = agent->y;
- float x = agent->x;
- int start_r = y - env->vision;
- if (start_r < 0) {
- start_r = 0;
- }
-
- int start_c = x - env->vision;
- if (start_c < 0) {
- start_c = 0;
- }
-
- int end_r = y + env->vision;
- if (end_r >= env->max_size) {
- end_r = env->max_size - 1;
- }
-
- int end_c = x + env->vision;
- if (end_c >= env->max_size) {
- end_c = env->max_size - 1;
- }
-
- int obs_offset = agent_idx*env->obs_size*env->obs_size;
- for (int r = start_r; r <= end_r; r++) {
- for (int c = start_c; c <= end_c; c++) {
- int r_idx = r - y + env->vision;
- int c_idx = c - x + env->vision;
- int obs_adr = obs_offset + r_idx*env->obs_size + c_idx;
- int adr = grid_offset(env, r, c);
- env->observations[obs_adr] = env->grid[adr];
- }
- }
- /*
- int obs_adr = 0;
- for (int r = 0; r < env->obs_size; r++) {
- for (int c = 0; c < env->obs_size; c++) {
- printf("%d ", env->observations[obs_adr]);
- obs_adr++;
- }
- printf("\n");
- }
- */
- }
-}
-
-void make_border(Grid*env) {
- for (int r = 0; r < env->height; r++) {
- int adr = grid_offset(env, r, 0);
- env->grid[adr] = WALL;
- adr = grid_offset(env, r, env->width-1);
- env->grid[adr] = WALL;
- }
- for (int c = 0; c < env->width; c++) {
- int adr = grid_offset(env, 0, c);
- env->grid[adr] = WALL;
- adr = grid_offset(env, env->height-1, c);
- env->grid[adr] = WALL;
- }
-}
-
-void spawn_agent(Grid* env, int idx, int x, int y) {
- Agent* agent = &env->agents[idx];
- int spawn_y = y;
- int spawn_x = x;
- assert(in_bounds(env, spawn_y, spawn_x));
- int adr = grid_offset(env, spawn_y, spawn_x);
- assert(env->grid[adr] == EMPTY);
- agent->spawn_y = spawn_y;
- agent->spawn_x = spawn_x;
- agent->y = agent->spawn_y;
- agent->x = agent->spawn_x;
- agent->prev_y = agent->y;
- agent->prev_x = agent->x;
- env->grid[adr] = agent->color;
- agent->direction = 0;
- agent->held = -1;
- agent->color = AGENT;
-}
-
-struct State {
- int width;
- int height;
- int num_agents;
- Agent* agents;
- unsigned char* grid;
-};
-
-void init_state(State* state, int max_size, int num_agents) {
- state->agents = calloc(num_agents, sizeof(Agent));
- state->grid = calloc(max_size*max_size, sizeof(unsigned char));
-}
-
-void free_state(State* state) {
- free(state->agents);
- free(state->grid);
- free(state);
-}
-
-void get_state(Grid* env, State* state) {
- state->width = env->width;
- state->height = env->height;
- state->num_agents = env->num_agents;
- memcpy(state->agents, env->agents, env->num_agents*sizeof(Agent));
- memcpy(state->grid, env->grid, env->max_size*env->max_size);
-}
-
-void set_state(Grid* env, State* state) {
- env->width = state->width;
- env->height = state->height;
- env->horizon = 2*env->width*env->height;
- env->num_agents = state->num_agents;
- memcpy(env->agents, state->agents, env->num_agents*sizeof(Agent));
- memcpy(env->grid, state->grid, env->max_size*env->max_size);
-}
-
-void c_reset(Grid* env) {
- memset(env->grid, 0, env->max_size*env->max_size);
- memset(env->counts, 0, env->max_size*env->max_size*sizeof(int));
- env->tick = 0;
- int idx = rand() % env->num_maps;
- set_state(env, &env->levels[idx]);
- compute_observations(env);
-}
-
-int move_to(Grid* env, int agent_idx, float y, float x) {
- Agent* agent = &env->agents[agent_idx];
- if (!in_bounds(env, y, x)) {
- return 1;
- }
-
- int adr = grid_offset(env, round(y), round(x));
- int dest = env->grid[adr];
- if (dest == WALL) {
- return 1;
- } else if (dest == REWARD || dest == GOAL) {
- env->rewards[agent_idx] = 1.0;
- env->terminals[agent_idx] = 1;
- add_log(env, agent_idx);
- } else if (is_key(dest)) {
- if (agent->held != -1) {
- return 1;
- }
- agent->held = dest;
- } else if (is_locked_door(dest)) { if (!is_correct_key(agent->held, dest)) { return 1;
- }
- agent->held = -1;
- env->grid[adr] = EMPTY;
- }
-
- int start_y = round(agent->y);
- int start_x = round(agent->x);
- int start_adr = grid_offset(env, start_y, start_x);
- env->grid[start_adr] = EMPTY;
-
- env->grid[adr] = agent->color;
- agent->y = y;
- agent->x = x;
- return 0;
-}
-
-bool step_agent(Grid* env, int idx) {
- Agent* agent = &env->agents[idx];
- agent->prev_y = agent->y;
- agent->prev_x = agent->x;
-
- float atn = env->actions[idx];
- float direction = agent->direction;
-
- if (env->discretize) {
- int iatn = (int)atn;
- if (iatn == ATN_PASS) {
- return true;
- } else if (iatn == ATN_FORWARD) {
- } else if (iatn == ATN_LEFT) {
- direction -= PI/2.0;
- } else if (iatn == ATN_RIGHT) {
- direction += PI/2.0;
- } else if (iatn == ATN_BACK) {
- direction += PI;
- } else {
- printf("Invalid action: %f\n", atn);
- exit(1);
- }
- if (direction < 0) {
- direction += TWO_PI;
- } else if (direction >= TWO_PI) {
- direction -= TWO_PI;
- }
- } else {
- assert(atn >= -1.0);
- assert(atn <= 1.0);
- direction += PI*atn;
- }
-
- float x = agent->x;
- float y = agent->y;
- float dx = env->speed*cos(direction);
- float dy = env->speed*sin(direction);
- agent->direction = direction;
- if (env->discretize) {
- float dest_x = x + dx;
- float dest_y = y + dy;
- if (!in_bounds(env, dest_y, dest_x)) {
- return false;
- }
- int err = move_to(env, idx, dest_y, dest_x);
- if (err) {
- return false;
- }
- } else {
- for (int substep = 1; substep <= 4; substep++) {
- float dest_x = x + dx/(float)substep;
- float dest_y = y + dy/(float)substep;
- int err = move_to(env, idx, dest_y, dest_x);
- if (!err) {
- continue;
- } else if (substep == 1) {
- return false;
- } else {
- break;
- }
- }
- }
-
- int x_int = agent->x;
- int y_int = agent->y;
- int adr = grid_offset(env, y_int, x_int);
- env->counts[adr]++;
- //env->rewards[idx] += 0.01 / (float)env->counts[adr];
- //env->log.episode_return += 0.01 / (float)env->counts[adr];
- return true;
-}
-
-void c_step(Grid* env) {
- memset(env->terminals, 0, env->num_agents);
- memset(env->rewards, 0, env->num_agents*sizeof(float));
- env->tick++;
-
- for (int i = 0; i < env->num_agents; i++) {
- step_agent(env, i);
- }
- compute_observations(env);
-
- bool done = true;
- for (int i = 0; i < env->num_agents; i++) {
- if (!env->terminals[i]) {
- done = false;
- break;
- }
- }
-
- if (env->tick >= env->horizon) {
- done = true;
- add_log(env, 0);
- }
-
- if (done) {
- c_reset(env);
- int idx = rand() % env->num_maps;
- set_state(env, &env->levels[idx]);
- compute_observations(env);
- }
-}
-
-// Raylib client
-Color COLORS[] = {
- (Color){6, 24, 24, 255},
- (Color){0, 0, 255, 255},
- (Color){0, 128, 255, 255},
- (Color){128, 128, 128, 255},
- (Color){255, 0, 0, 255},
- (Color){255, 255, 255, 255},
- (Color){255, 85, 85, 255},
- (Color){170, 170, 170, 255},
- (Color){0, 255, 255, 255},
- (Color){255, 255, 0, 255},
-};
-
-Rectangle UV_COORDS[7] = {
- (Rectangle){0, 0, 0, 0},
- (Rectangle){512, 0, 128, 128},
- (Rectangle){0, 0, 0, 0},
- (Rectangle){0, 0, 128, 128},
- (Rectangle){128, 0, 128, 128},
- (Rectangle){256, 0, 128, 128},
- (Rectangle){384, 0, 128, 128},
-};
-
-struct Renderer {
- int cell_size;
- int width;
- int height;
- Texture2D puffer;
- float* overlay;
-};
-
-Renderer* init_renderer(int cell_size, int width, int height) {
- Renderer* renderer = (Renderer*)calloc(1, sizeof(Renderer));
- renderer->cell_size = cell_size;
- renderer->width = width;
- renderer->height = height;
-
- renderer->overlay = (float*)calloc(width*height, sizeof(float));
-
- InitWindow(width*cell_size, height*cell_size, "PufferLib Grid");
- SetTargetFPS(60);
-
- renderer->puffer = LoadTexture("resources/shared/puffers_128.png");
- return renderer;
-}
-
-void clear_overlay(Renderer* renderer) {
- memset(renderer->overlay, 0, renderer->width*renderer->height*sizeof(float));
-}
-
-void close_renderer(Renderer* renderer) {
- CloseWindow();
- free(renderer->overlay);
- free(renderer);
-}
-
-void c_render(Grid* env) {
- // TODO: fractional rendering
- float frac = 0.0;
- float overlay = 0.0;
- if (env->renderer == NULL) {
- env->renderer = init_renderer(16, env->max_size, env->max_size);
- }
- Renderer* renderer = env->renderer;
-
- if (IsKeyDown(KEY_ESCAPE)) {
- exit(0);
- }
-
- Agent* agent = &env->agents[0];
- int r = agent->y;
- int c = agent->x;
- int adr = grid_offset(env, r, c);
- //renderer->overlay[adr] = overlay;
- //renderer->overlay[adr] -= 0.1;
- //renderer->overlay[adr] = -1 + 1.0/(float)env->counts[adr];
-
- BeginDrawing();
- ClearBackground((Color){6, 24, 24, 255});
-
- int ts = renderer->cell_size;
- for (int r = 0; r < env->height; r++) {
- for (int c = 0; c < env->width; c++){
- adr = grid_offset(env, r, c);
- int tile = env->grid[adr];
- if (tile == EMPTY) {
- continue;
- overlay = renderer->overlay[adr];
- if (overlay == 0) {
- continue;
- }
- Color color;
- if (overlay < 0) {
- overlay = -fmaxf(-1.0, overlay);
- color = (Color){255.0*overlay, 0, 0, 255};
- } else {
- overlay = fminf(1.0, overlay);
- color = (Color){0, 255.0*overlay, 0, 255};
- }
- DrawRectangle(c*ts, r*ts, ts, ts, color);
- }
-
- Color color;
- if (tile == WALL) {
- color = (Color){128, 128, 128, 255};
- } else if (tile == GOAL) {
- color = GREEN;
- } else if (is_locked_door(tile)) {
- int weight = 40*(tile - DOOR_LOCKED);
- color = (Color){weight, 0, 0, 255};
- } else if (is_open_door(tile)) {
- int weight = 40*(tile - DOOR_OPEN);
- color = (Color){0, weight, 0, 255};
- } else if (is_key(tile)) {
- int weight = 40*(tile - KEY);
- color = (Color){0, 0, weight, 255};
- } else {
- continue;
- }
-
- DrawRectangle(c*ts, r*ts, ts, ts, color);
- }
- }
-
- for (int i = 0; i < env->num_agents; i++) {
- agent = &env->agents[0];
- float y = agent->y + (frac - 1)*(agent->y - agent->prev_y);
- float x = agent->x + (frac - 1)*(agent->x - agent->prev_x);
- int u = 0;
- int v = 0;
- Rectangle source_rect = (Rectangle){u, v, 128, 128};
- Rectangle dest_rect = (Rectangle){x*ts, y*ts, ts, ts};
- DrawTexturePro(renderer->puffer, source_rect, dest_rect,
- (Vector2){0, 0}, 0, WHITE);
- }
-
- EndDrawing();
-}
-
-void generate_locked_room(Grid* env) {
- assert(env->max_size >= 19);
- env->width = 19;
- env->height = 19;
- env->num_agents = 1;
- env->horizon = 1000;
- env->speed = 1;
- env->vision = 3;
- env->discretize = true;
-
- Agent* agent = &env->agents[0];
- agent->x = 9;
- agent->y = 9;
- agent->prev_x = 9;
- agent->prev_y = 9;
- agent->spawn_y = 9;
- agent->spawn_x = 9;
- agent->color = 6;
- agent->held = -1;
-
- make_border(env);
-
- for (int r = 0; r < env->height; r++) {
- int adr = grid_offset(env, r, 7);
- env->grid[adr] = WALL;
- adr = grid_offset(env, r, 11);
- env->grid[adr] = WALL;
- }
- for (int c = 0; c < 7; c++) {
- int adr = grid_offset(env, 6, c);
- env->grid[adr] = WALL;
- adr = grid_offset(env, 12, c);
- env->grid[adr] = WALL;
- }
- for (int c = 11; c < env->width; c++) {
- int adr = grid_offset(env, 6, c);
- env->grid[adr] = WALL;
- adr = grid_offset(env, 12, c);
- env->grid[adr] = WALL;
- }
- int adr = grid_offset(env, 3, 7);
- env->grid[adr] = DOOR_OPEN;
- adr = grid_offset(env, 9, 7);
- env->grid[adr] = DOOR_OPEN + 1;
- adr = grid_offset(env, 15, 7);
- env->grid[adr] = DOOR_OPEN + 2;
- adr = grid_offset(env, 3, 11);
- env->grid[adr] = DOOR_OPEN + 3;
- adr = grid_offset(env, 9, 11);
- env->grid[adr] = DOOR_OPEN + 4;
- adr = grid_offset(env, 15, 11);
- env->grid[adr] = DOOR_LOCKED + 5;
-
- adr = grid_offset(env, 4, 15);
- env->grid[adr] = KEY + 5;
-
- adr = grid_offset(env, 16, 17);
- env->grid[adr] = GOAL;
-}
-
-void generate_growing_tree_maze(unsigned char* grid,
- int width, int height, int max_size, float difficulty, int seed) {
- srand(seed);
- int dx[4] = {-1, 0, 1, 0};
- int dy[4] = {0, 1, 0, -1};
- int dirs[4] = {0, 1, 2, 3};
- int cells[2*width*height];
- int num_cells = 1;
-
- bool visited[width*height];
- memset(visited, false, width*height);
-
- memset(grid, WALL, max_size*height);
- for (int r = 0; r < height; r++) {
- for (int c = 0; c < width; c++) {
- int adr = r*max_size + c;
- if (r % 2 == 1 && c % 2 == 1) {
- grid[adr] = EMPTY;
- }
- }
- }
-
- int x_init = rand() % (width - 1);
- int y_init = rand() % (height - 1);
-
- if (x_init % 2 == 0) {
- x_init++;
- }
- if (y_init % 2 == 0) {
- y_init++;
- }
-
- int adr = y_init*height + x_init;
- visited[adr] = true;
- cells[0] = x_init;
- cells[1] = y_init;
-
- //int cell = 32;
- //InitWindow(width*cell, height*cell, "PufferLib Ray Grid");
- //SetTargetFPS(60);
-
- while (num_cells > 0) {
- if (rand() % 1000 > 1000*difficulty) {
- int i = rand() % num_cells;
- int tmp_x = cells[2*num_cells - 2];
- int tmp_y = cells[2*num_cells - 1];
- cells[2*num_cells - 2] = cells[2*i];
- cells[2*num_cells - 1] = cells[2*i + 1];
- cells[2*i] = tmp_x;
- cells[2*i + 1] = tmp_y;
-
- }
-
- int x = cells[2*num_cells - 2];
- int y = cells[2*num_cells - 1];
-
- int nx, ny;
-
- // In-place direction shuffle
- for (int i = 0; i < 4; i++) {
- int ii = i + rand() % (4 - i);
- int tmp = dirs[i];
- dirs[i] = dirs[ii];
- dirs[ii] = tmp;
- }
-
- bool made_path = false;
- for (int dir_i = 0; dir_i < 4; dir_i++) {
- int dir = dirs[dir_i];
- nx = x + 2*dx[dir];
- ny = y + 2*dy[dir];
-
- if (nx <= 0 || nx >= width-1 || ny <= 0 || ny >= height-1) {
- continue;
- }
-
- int visit_adr = ny*width + nx;
- if (visited[visit_adr]) {
- continue;
- }
-
- visited[visit_adr] = true;
- cells[2*num_cells] = nx;
- cells[2*num_cells + 1] = ny;
-
- nx = x + dx[dir];
- ny = y + dy[dir];
-
- int adr = ny*max_size + nx;
- grid[adr] = EMPTY;
- num_cells++;
-
- made_path = true;
-
- /*
- if (IsKeyPressed(KEY_ESCAPE)) {
- exit(0);
- }
- BeginDrawing();
- ClearBackground((Color){6, 24, 24, 255});
- Color color = (Color){128, 128, 128, 255};
- for (int r = 0; r < height; r++) {
- for (int c = 0; c < width; c++){
- int adr = r*max_size + c;
- int tile = grid[adr];
- if (tile == WALL) {
- DrawRectangle(c*cell, r*cell, cell, cell, color);
- }
- }
- }
- EndDrawing();
- */
-
- break;
- }
- if (!made_path) {
- num_cells--;
- }
- }
-}
-
-void create_maze_level(Grid* env, int width, int height, float difficulty, int seed) {
- env->width = width;
- env->height = height;
- generate_growing_tree_maze(env->grid, width, height, env->max_size, difficulty, seed);
- make_border(env);
- spawn_agent(env, 0, 1, 1);
- int goal_adr = grid_offset(env, env->height - 2, env->width - 2);
- env->grid[goal_adr] = GOAL;
-}
diff --git a/pufferlib/ocean/grid/grid.py b/pufferlib/ocean/grid/grid.py
deleted file mode 100644
index 0229d6fe7..000000000
--- a/pufferlib/ocean/grid/grid.py
+++ /dev/null
@@ -1,67 +0,0 @@
-import numpy as np
-import os
-
-import gymnasium
-
-import pufferlib
-from pufferlib.ocean.grid import binding
-
-class Grid(pufferlib.PufferEnv):
- def __init__(self, render_mode='raylib', vision_range=5,
- num_envs=4096, num_maps=1000, map_size=-1, max_size=9,
- report_interval=128, buf=None, seed=0):
- assert map_size <= max_size
- self.obs_size = 2*vision_range + 1
- self.single_observation_space = gymnasium.spaces.Box(low=0, high=255,
- shape=(self.obs_size*self.obs_size,), dtype=np.uint8)
- self.single_action_space = gymnasium.spaces.Discrete(5)
- self.render_mode = render_mode
- self.num_agents = num_envs
- self.report_interval = report_interval
- super().__init__(buf=buf)
- self.float_actions = np.zeros_like(self.actions).astype(np.float32)
- self.c_state = binding.shared(num_maps=num_maps, max_size=max_size, size=map_size)
- self.c_envs = binding.vec_init(self.observations, self.float_actions,
- self.rewards, self.terminals, self.truncations, num_envs, seed,
- state=self.c_state, max_size=max_size, num_maps=num_maps)
- pass
-
- def reset(self, seed=None):
- self.tick = 0
- binding.vec_reset(self.c_envs, seed)
- return self.observations, []
-
- def step(self, actions):
- self.float_actions[:] = actions
- binding.vec_step(self.c_envs)
-
- info = []
- if self.tick % self.report_interval == 0:
- info.append(binding.vec_log(self.c_envs))
-
- self.tick += 1
- return (self.observations, self.rewards,
- self.terminals, self.truncations, info)
-
- def render(self, overlay=0):
- binding.vec_render(self.c_envs, overlay)
-
- def close(self):
- pass
- #binding.vec_close(self.c_envs)
-
-def test_performance(timeout=10, atn_cache=1024):
- env = CGrid(num_envs=1000)
- env.reset()
- tick = 0
-
- actions = np.random.randint(0, 2, (atn_cache, env.num_envs))
-
- import time
- start = time.time()
- while time.time() - start < timeout:
- atn = actions[tick % atn_cache]
- env.step(atn)
- tick += 1
-
- print(f'SPS: %f', env.num_envs * tick / (time.time() - start))
diff --git a/pufferlib/ocean/impulse_wars/.clang-format b/pufferlib/ocean/impulse_wars/.clang-format
deleted file mode 100644
index d9ba19d3d..000000000
--- a/pufferlib/ocean/impulse_wars/.clang-format
+++ /dev/null
@@ -1,229 +0,0 @@
----
-Language: Cpp
-AccessModifierOffset: -2
-AlignAfterOpenBracket: BlockIndent
-AlignArrayOfStructures: None
-AlignConsecutiveAssignments:
- Enabled: false
- AcrossEmptyLines: false
- AcrossComments: false
- AlignCompound: false
- AlignFunctionPointers: false
- PadOperators: true
-AlignConsecutiveBitFields:
- Enabled: false
- AcrossEmptyLines: false
- AcrossComments: false
- AlignCompound: false
- AlignFunctionPointers: false
- PadOperators: false
-AlignConsecutiveDeclarations:
- Enabled: false
- AcrossEmptyLines: false
- AcrossComments: false
- AlignCompound: false
- AlignFunctionPointers: false
- PadOperators: false
-AlignConsecutiveMacros:
- Enabled: false
- AcrossEmptyLines: false
- AcrossComments: false
- AlignCompound: false
- AlignFunctionPointers: false
- PadOperators: false
-AlignConsecutiveShortCaseStatements:
- Enabled: false
- AcrossEmptyLines: false
- AcrossComments: false
- AlignCaseColons: false
-AlignEscapedNewlines: Right
-AlignOperands: Align
-AlignTrailingComments:
- Kind: Always
- OverEmptyLines: 0
-AllowAllArgumentsOnNextLine: true
-AllowAllParametersOfDeclarationOnNextLine: true
-AllowBreakBeforeNoexceptSpecifier: Never
-AllowShortBlocksOnASingleLine: Never
-AllowShortCaseLabelsOnASingleLine: false
-AllowShortCompoundRequirementOnASingleLine: true
-AllowShortEnumsOnASingleLine: true
-AllowShortFunctionsOnASingleLine: All
-AllowShortIfStatementsOnASingleLine: Never
-AllowShortLambdasOnASingleLine: All
-AllowShortLoopsOnASingleLine: false
-AlwaysBreakAfterDefinitionReturnType: None
-AlwaysBreakAfterReturnType: None
-AlwaysBreakBeforeMultilineStrings: false
-AlwaysBreakTemplateDeclarations: MultiLine
-AttributeMacros:
- - __capability
-BinPackArguments: false
-BinPackParameters: false
-BitFieldColonSpacing: Both
-BraceWrapping:
- AfterCaseLabel: false
- AfterClass: false
- AfterControlStatement: Never
- AfterEnum: false
- AfterExternBlock: false
- AfterFunction: false
- AfterNamespace: false
- AfterObjCDeclaration: false
- AfterStruct: false
- AfterUnion: false
- BeforeCatch: false
- BeforeElse: false
- BeforeLambdaBody: false
- BeforeWhile: false
- IndentBraces: false
- SplitEmptyFunction: true
- SplitEmptyRecord: true
- SplitEmptyNamespace: true
-BreakAdjacentStringLiterals: true
-BreakAfterAttributes: Leave
-BreakAfterJavaFieldAnnotations: false
-BreakArrays: true
-BreakBeforeBinaryOperators: None
-BreakBeforeClosingBracket: Always
-BreakBeforeConceptDeclarations: Always
-BreakBeforeBraces: Custom
-BreakBeforeInlineASMColon: OnlyMultiline
-BreakBeforeTernaryOperators: true
-BreakConstructorInitializers: BeforeColon
-BreakInheritanceList: BeforeColon
-BreakStringLiterals: true
-ColumnLimit: 0
-CommentPragmas: '^ IWYU pragma:'
-CompactNamespaces: false
-ConstructorInitializerIndentWidth: 4
-ContinuationIndentWidth: 4
-Cpp11BracedListStyle: true
-DerivePointerAlignment: false
-DisableFormat: false
-EmptyLineAfterAccessModifier: Never
-EmptyLineBeforeAccessModifier: LogicalBlock
-ExperimentalAutoDetectBinPacking: false
-FixNamespaceComments: false
-IfMacros:
- - KJ_IF_MAYBE
-IncludeBlocks: Preserve
-IncludeIsMainRegex: '(Test)?$'
-IncludeIsMainSourceRegex: ''
-IndentAccessModifiers: false
-IndentCaseBlocks: false
-IndentCaseLabels: false
-IndentExternBlock: AfterExternBlock
-IndentGotoLabels: true
-IndentPPDirectives: None
-IndentRequiresClause: true
-IndentWidth: 4
-IndentWrappedFunctionNames: false
-InsertBraces: true
-InsertNewlineAtEOF: false
-InsertTrailingCommas: Wrapped
-IntegerLiteralSeparator:
- Binary: 0
- BinaryMinDigits: 0
- Decimal: 0
- DecimalMinDigits: 0
- Hex: 0
- HexMinDigits: 0
-JavaScriptQuotes: Leave
-JavaScriptWrapImports: true
-KeepEmptyLinesAtTheStartOfBlocks: true
-KeepEmptyLinesAtEOF: false
-LambdaBodyIndentation: Signature
-LineEnding: DeriveLF
-MacroBlockBegin: ''
-MacroBlockEnd: ''
-MaxEmptyLinesToKeep: 1
-NamespaceIndentation: None
-ObjCBinPackProtocolList: Auto
-ObjCBlockIndentWidth: 2
-ObjCBreakBeforeNestedBlockParam: true
-ObjCSpaceAfterProperty: false
-ObjCSpaceBeforeProtocolList: true
-PackConstructorInitializers: Never
-PenaltyBreakAssignment: 2
-PenaltyBreakBeforeFirstCallParameter: 19
-PenaltyBreakComment: 300
-PenaltyBreakFirstLessLess: 120
-PenaltyBreakOpenParenthesis: 0
-PenaltyBreakScopeResolution: 500
-PenaltyBreakString: 1000
-PenaltyBreakTemplateDeclaration: 10
-PenaltyExcessCharacter: 1000000
-PenaltyIndentedWhitespace: 0
-PenaltyReturnTypeOnItsOwnLine: 60
-PointerAlignment: Right
-PPIndentWidth: -1
-QualifierAlignment: Leave
-ReferenceAlignment: Pointer
-ReflowComments: true
-RemoveBracesLLVM: false
-RemoveParentheses: Leave
-RemoveSemicolon: false
-RequiresClausePosition: OwnLine
-RequiresExpressionIndentation: OuterScope
-SeparateDefinitionBlocks: Leave
-ShortNamespaceLines: 1
-SkipMacroDefinitionBody: false
-SortIncludes: CaseSensitive
-SortJavaStaticImport: Before
-SortUsingDeclarations: LexicographicNumeric
-SpaceAfterCStyleCast: false
-SpaceAfterLogicalNot: false
-SpaceAfterTemplateKeyword: true
-SpaceAroundPointerQualifiers: Default
-SpaceBeforeAssignmentOperators: true
-SpaceBeforeCaseColon: false
-SpaceBeforeCpp11BracedList: false
-SpaceBeforeCtorInitializerColon: true
-SpaceBeforeInheritanceColon: true
-SpaceBeforeJsonColon: false
-SpaceBeforeParens: ControlStatements
-SpaceBeforeParensOptions:
- AfterControlStatements: true
- AfterForeachMacros: true
- AfterFunctionDefinitionName: false
- AfterFunctionDeclarationName: false
- AfterIfMacros: true
- AfterOverloadedOperator: false
- AfterPlacementOperator: true
- AfterRequiresInClause: false
- AfterRequiresInExpression: false
- BeforeNonEmptyParentheses: false
-SpaceBeforeRangeBasedForLoopColon: true
-SpaceBeforeSquareBrackets: false
-SpaceInEmptyBlock: false
-SpacesBeforeTrailingComments: 1
-SpacesInAngles: Never
-SpacesInContainerLiterals: true
-SpacesInLineCommentPrefix:
- Minimum: 1
- Maximum: -1
-SpacesInParens: Never
-SpacesInParensOptions:
- InCStyleCasts: false
- InConditionalStatements: false
- InEmptyParentheses: false
- Other: false
-SpacesInSquareBrackets: false
-Standard: Latest
-StatementAttributeLikeMacros:
- - Q_EMIT
-StatementMacros:
- - Q_UNUSED
- - QT_REQUIRE_VERSION
-TabWidth: 4
-UseTab: Never
-VerilogBreakBetweenInstancePorts: true
-WhitespaceSensitiveMacros:
- - BOOST_PP_STRINGIZE
- - CF_SWIFT_NAME
- - NS_SWIFT_NAME
- - PP_STRINGIZE
- - STRINGIZE
-...
-
diff --git a/pufferlib/ocean/impulse_wars/CMakeLists.txt b/pufferlib/ocean/impulse_wars/CMakeLists.txt
deleted file mode 100644
index fec78fa53..000000000
--- a/pufferlib/ocean/impulse_wars/CMakeLists.txt
+++ /dev/null
@@ -1,138 +0,0 @@
-# 3.22 was released on Nov 2021, should be widely available
-cmake_minimum_required(VERSION 3.22)
-include(FetchContent)
-
-project(
- impulse-wars
- DESCRIPTION "Impulse Wars"
- LANGUAGES C
-)
-
-message(INFO " C Compiler: ${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_VERSION} ${CMAKE_C_COMPILER_ID}")
-
-# use ccache if available to speed up subsequent builds
-find_program(CCACHE_FOUND "ccache")
-if(CCACHE_FOUND)
- set(CMAKE_C_COMPILER_LAUNCHER "ccache")
-endif()
-
-# enable some C23 features, the c2x standard is a WIP standard supported
-# by gcc since 9 (May 2019) and clang since 9 (Sep 2019)
-set(CMAKE_C_FLAGS_INIT " -std=c2x")
-
-# force position independent code everywhere to prevent some rare
-# linker errors depending on what compiler is used
-add_compile_options("-fPIC")
-
-if(CMAKE_BUILD_TYPE MATCHES Debug)
- # leak detection doesn't work correctly when the code is called by
- # Python, so disable it
- if(DEFINED BUILD_PYTHON_MODULE)
- add_compile_options("-fno-omit-frame-pointer" "-fsanitize=address,undefined,bounds,pointer-overflow")
- add_link_options("-shared-libasan" "-fno-omit-frame-pointer" "-fsanitize=address,undefined,bounds,pointer-overflow")
- else()
- add_compile_options("-fno-omit-frame-pointer" "-fsanitize=address,undefined,bounds,pointer-overflow,leak")
- add_link_options("-fno-omit-frame-pointer" "-fsanitize=address,undefined,bounds,pointer-overflow,leak")
- endif()
-
- # mold is an extremely fast linker, use it if available
- # only use mold in debug mode, link time optimization currently doesn't
- # work with mold and provides large speedups
- find_program(MOLD_FOUND "mold")
- if(MOLD_FOUND)
- add_link_options("-fuse-ld=mold")
- endif()
-else()
- add_compile_options("-flto" "-fno-math-errno")
- if (NOT DEFINED EMSCRIPTEN)
- # emscripten doesn't support -march=native, it doesn't make sense
- # for WASM anyway
- add_compile_options("-march=native")
- else()
- # tell emscripten to generate an HTML file that can be used to
- # test the WASM, and ensure necessary code is transformed to be
- # async friendly; it allows the game to be run much more smoothly
- set(CMAKE_EXECUTABLE_SUFFIX ".html")
- add_link_options("-sASYNCIFY")
- endif()
- # ensure the linker used is from the same compiler toolchain, or else
- # link time optimization will probably fail; if we're using
- # emscripten it will use it's own linker
- if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT DEFINED EMSCRIPTEN)
- add_link_options("-fuse-ld=lld")
- endif()
-
- # add_compile_options("-pg")
- # add_link_options("-pg")
-endif()
-
-set_property(GLOBAL PROPERTY USE_FOLDERS ON)
-set(FETCHCONTENT_QUIET FALSE)
-
-# fetch and configure dependencies
-FetchContent_Declare(
- raylib
- URL https://github.com/raysan5/raylib/archive/c1ab645ca298a2801097931d1079b10ff7eb9df8.zip # 5.5
-)
-set(BUILD_SHARED_LIBS OFF CACHE BOOL "Statically link raylib" FORCE)
-set(WITH_PIC "Compile static library as position-independent code" ON)
-set(CUSTOMIZE_BUILD ON CACHE BOOL "Customize raylib build settings" FORCE)
-set(USE_AUDIO OFF CACHE BOOL "Don't build unused audio module" FORCE)
-FetchContent_MakeAvailable(raylib)
-
-# if box2d is fetched first installing built python module will fail
-# for reasons unbeknownst to mere mortals
-# maybe due to install prefix schenanigans?
-FetchContent_Declare(
- box2d
- URL https://github.com/capnspacehook/box2d/archive/df25d747be0ab2fd9425eece022d2ec897c2028d.zip
-)
-set(BOX2D_ENABLE_SIMD ON CACHE BOOL "Enable SIMD math (faster)" FORCE)
-set(BOX2D_AVX2 ON CACHE BOOL "Enable AVX2 (faster)" FORCE)
-add_compile_definitions(B2_MAX_WORLDS=65534)
-FetchContent_MakeAvailable(box2d)
-# this is set to off by box2d to enable cross platform determinism, but
-# I don't care about that and want the small speedup instead
-target_compile_options(box2d PRIVATE "-ffp-contract=fast")
-
-function(configure_target target_name)
- target_include_directories(
- ${target_name} PRIVATE
- "${CMAKE_CURRENT_SOURCE_DIR}"
- "${CMAKE_CURRENT_SOURCE_DIR}/include"
- )
-
- # Mark box2d as a system include directory to suppress warnings from it
- target_include_directories(${target_name} SYSTEM PRIVATE "${box2d_SOURCE_DIR}/src")
-
- target_link_libraries(${target_name} PRIVATE raylib box2d)
-
- target_compile_options(${target_name} PRIVATE
- "-Werror" "-Wall" "-Wextra" "-Wpedantic"
- "-Wno-implicit-fallthrough" "-Wno-variadic-macros" "-Wno-strict-prototypes" "-Wno-gnu-statement-expression"
- )
-endfunction()
-
-if(DEFINED BUILD_PYTHON_MODULE)
- find_package(
- Python
- COMPONENTS Interpreter Development.Module NumPy
- REQUIRED
- )
-
- python_add_library(binding MODULE binding.c WITH_SOABI)
-
- target_include_directories(binding PRIVATE
- ${Python_NumPy_INCLUDE_DIRS}
- )
-
- configure_target(binding)
-
- install(TARGETS binding DESTINATION .)
-elseif(DEFINED BUILD_DEMO)
- add_executable(demo "${CMAKE_CURRENT_SOURCE_DIR}/impulse_wars.c")
- configure_target(demo)
-elseif(DEFINED BUILD_BENCHMARK)
- add_executable(benchmark "${CMAKE_CURRENT_SOURCE_DIR}/benchmark.c")
- configure_target(benchmark)
-endif()
diff --git a/pufferlib/ocean/impulse_wars/Makefile b/pufferlib/ocean/impulse_wars/Makefile
deleted file mode 100644
index ce593669d..000000000
--- a/pufferlib/ocean/impulse_wars/Makefile
+++ /dev/null
@@ -1,61 +0,0 @@
-RELEASE_PYTHON_MODULE_DIR := python-module-release
-DEBUG_PYTHON_MODULE_DIR := python-module-debug
-DEBUG_DIR := debug-demo
-RELEASE_DIR := release-demo
-RELEASE_WEB_DIR := release-demo-web
-BENCHMARK_DIR := benchmark
-
-DEBUG_BUILD_TYPE := Debug
-RELEASE_BUILD_TYPE := Release
-
-# install build dependencies if this is a fresh build, Python won't
-# install build dependencies when --no-build-isolation is passed
-# build with no isolation so that builds can be cached and/or incremental
-
-# build Python module in release mode
-.PHONY: python-module-release
-python-module-release:
- @test -d $(RELEASE_PYTHON_MODULE_DIR) || pip install scikit-build-core autopxd2 cython
- @pip install --no-build-isolation --config-settings=editable.rebuild=true -Cbuild-dir=$(RELEASE_PYTHON_MODULE_DIR) -v .
-
-# build Python module in debug mode
-.PHONY: python-module-debug
-python-module-debug:
- @test -d $(DEBUG_PYTHON_MODULE_DIR) || pip install scikit-build-core autopxd2 cython
- @pip install --no-build-isolation --config-settings=editable.rebuild=true --config-settings=cmake.build-type="Debug" -Cbuild-dir=$(DEBUG_PYTHON_MODULE_DIR) -v .
-
-# build C demo in debug mode
-.PHONY: debug-demo
-debug-demo:
- @mkdir -p $(DEBUG_DIR)
- @cd $(DEBUG_DIR) && \
- cmake -GNinja -DCMAKE_BUILD_TYPE=$(DEBUG_BUILD_TYPE) -DBUILD_DEMO=true -DCMAKE_C_COMPILER=clang-20 .. && \
- cmake --build .
-
-# build C demo in release mode
-.PHONY: release-demo
-release-demo:
- @mkdir -p $(RELEASE_DIR)
- @cd $(RELEASE_DIR) && \
- cmake -GNinja -DCMAKE_BUILD_TYPE=$(RELEASE_BUILD_TYPE) -DBUILD_DEMO=true -DCMAKE_C_COMPILER=clang-20 .. && \
- cmake --build .
-
-# build C demo in release mode for web
-.PHONY: release-demo-web
-release-demo-web:
- @mkdir -p $(RELEASE_WEB_DIR)
- @cd $(RELEASE_WEB_DIR) && \
- emcmake cmake -GNinja -DCMAKE_BUILD_TYPE=$(RELEASE_BUILD_TYPE) -DPLATFORM=Web -DBUILD_DEMO=true .. && \
- cmake --build .
-
-# build C benchmark
-.PHONY: benchmark
-benchmark:
- @mkdir -p $(BENCHMARK_DIR)
- @cd $(BENCHMARK_DIR) && \
- cmake -GNinja -DCMAKE_BUILD_TYPE=$(RELEASE_BUILD_TYPE) -DBUILD_BENCHMARK=true -DCMAKE_C_COMPILER=clang-20 .. && \
- cmake --build .
-
-.PHONY: clean
-clean:
- @rm -rf build $(RELEASE_PYTHON_MODULE_DIR) $(DEBUG_PYTHON_MODULE_DIR) $(DEBUG_DIR) $(RELEASE_DIR) $(RELEASE_WEB_DIR) $(BENCHMARK_DIR)
diff --git a/pufferlib/ocean/impulse_wars/README.md b/pufferlib/ocean/impulse_wars/README.md
deleted file mode 100644
index accca7438..000000000
--- a/pufferlib/ocean/impulse_wars/README.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# Impulse Wars
-
-To build, you need to have the following:
-- cmake
-- make
-- ninja
-- raylib required deps installed: https://github.com/raysan5/raylib/wiki/Working-on-GNU-Linux
-
-Run `make && cp python-module-release/binding.*.so .` to build the python module in release mode.
-`puffer_impulse_wars` env should now be trainable.
-
-When watching evaluations, you need to set all instances of `is_training = False` and `render = True` in the config file.
diff --git a/pufferlib/ocean/impulse_wars/benchmark.c b/pufferlib/ocean/impulse_wars/benchmark.c
deleted file mode 100644
index 3071bf91b..000000000
--- a/pufferlib/ocean/impulse_wars/benchmark.c
+++ /dev/null
@@ -1,64 +0,0 @@
-#include "env.h"
-
-void randActions(iwEnv *e) {
- // e->lastRandState = e->randState;
- uint8_t actionOffset = 0;
- for (uint8_t i = 0; i < e->numDrones; i++) {
- e->actions[actionOffset + 0] = randFloat(&e->randState, -1.0f, 1.0f);
- e->actions[actionOffset + 1] = randFloat(&e->randState, -1.0f, 1.0f);
- e->actions[actionOffset + 2] = randFloat(&e->randState, -1.0f, 1.0f);
- e->actions[actionOffset + 3] = randFloat(&e->randState, -1.0f, 1.0f);
- e->actions[actionOffset + 4] = randFloat(&e->randState, -1.0f, 1.0f);
- e->actions[actionOffset + 5] = randFloat(&e->randState, -1.0f, 1.0f);
- e->actions[actionOffset + 6] = randFloat(&e->randState, -1.0f, 1.0f);
-
- actionOffset += CONTINUOUS_ACTION_SIZE;
- }
-}
-
-void perfTest(const uint32_t numSteps) {
- const uint8_t NUM_DRONES = 2;
-
- iwEnv *e = fastCalloc(1, sizeof(iwEnv));
-
- posix_memalign((void **)&e->observations, sizeof(void *), alignedSize(NUM_DRONES * obsBytes(NUM_DRONES), sizeof(float)));
- e->rewards = fastCalloc(NUM_DRONES, sizeof(float));
- e->actions = fastCalloc(NUM_DRONES * CONTINUOUS_ACTION_SIZE, sizeof(float));
- e->masks = fastCalloc(NUM_DRONES, sizeof(uint8_t));
- e->terminals = fastCalloc(NUM_DRONES, sizeof(uint8_t));
- e->truncations = fastCalloc(NUM_DRONES, sizeof(uint8_t));
-
- // rayClient *client = createRayClient();
- // e->client = client;
-
- uint64_t seed = time(NULL);
- printf("seed: %lu\n", seed);
- initEnv(e, NUM_DRONES, 0, -1, seed, false, false, true, false);
- initMaps(e);
-
- // randActions(e);
- setupEnv(e);
- stepEnv(e);
-
- uint32_t steps = 0;
- while (steps != numSteps) {
- // randActions(e);
- stepEnv(e);
- steps++;
- }
-
- destroyEnv(e);
- destroyMaps();
- free(e->observations);
- fastFree(e->actions);
- fastFree(e->rewards);
- fastFree(e->masks);
- fastFree(e->terminals);
- fastFree(e->truncations);
- fastFree(e);
-}
-
-int main(void) {
- perfTest(2500000);
- return 0;
-}
diff --git a/pufferlib/ocean/impulse_wars/binding.c b/pufferlib/ocean/impulse_wars/binding.c
deleted file mode 100644
index d51837b73..000000000
--- a/pufferlib/ocean/impulse_wars/binding.c
+++ /dev/null
@@ -1,157 +0,0 @@
-#include
-
-#include "env.h"
-
-static PyObject *get_consts(PyObject *self, PyObject *args);
-
-#define Env iwEnv
-#define MY_SHARED
-#define MY_METHODS {"get_consts", get_consts, METH_VARARGS, "Get constants"}
-
-#include "../env_binding.h"
-
-#define setDictVal(dict, key, val) \
- if (PyDict_SetItemString(dict, key, PyLong_FromLong(val)) < 0) { \
- PyErr_SetString(PyExc_RuntimeError, "Failed to set " key " in dict"); \
- return NULL; \
- }
-
-static PyObject *get_consts(PyObject *self, PyObject *args) {
- PyObject *dronesArg = PyTuple_GetItem(args, 0);
- if (!PyObject_TypeCheck(dronesArg, &PyLong_Type)) {
- PyErr_SetString(PyExc_TypeError, "num_drones must be an integer");
- return NULL;
- }
- const uint8_t numDrones = (uint8_t)PyLong_AsLong(dronesArg);
-
- PyObject *dict = PyDict_New();
- if (PyErr_Occurred()) {
- return NULL;
- }
-
- const uint16_t droneObsOffset = ENEMY_DRONE_OBS_OFFSET + ((numDrones - 1) * ENEMY_DRONE_OBS_SIZE);
-
- setDictVal(dict, "obsBytes", obsBytes(numDrones));
- setDictVal(dict, "mapObsSize", MAP_OBS_SIZE);
- setDictVal(dict, "discreteObsSize", discreteObsSize(numDrones));
- setDictVal(dict, "continuousObsSize", continuousObsSize(numDrones));
- setDictVal(dict, "continuousObsBytes", continuousObsSize(numDrones) * sizeof(float));
- setDictVal(dict, "wallTypes", NUM_WALL_TYPES);
- setDictVal(dict, "weaponTypes", NUM_WEAPONS + 1);
- setDictVal(dict, "mapObsRows", MAP_OBS_ROWS);
- setDictVal(dict, "mapObsColumns", MAP_OBS_COLUMNS);
- setDictVal(dict, "continuousObsOffset", alignedSize(MAP_OBS_SIZE, sizeof(float)));
- setDictVal(dict, "numNearWallObs", NUM_NEAR_WALL_OBS);
- setDictVal(dict, "nearWallTypesObsOffset", NEAR_WALL_TYPES_OBS_OFFSET);
- setDictVal(dict, "nearWallPosObsSize", NEAR_WALL_POS_OBS_SIZE);
- setDictVal(dict, "nearWallObsSize", NEAR_WALL_OBS_SIZE);
- setDictVal(dict, "nearWallPosObsOffset", NEAR_WALL_POS_OBS_OFFSET);
- setDictVal(dict, "numFloatingWallObs", NUM_FLOATING_WALL_OBS);
- setDictVal(dict, "floatingWallTypesObsOffset", FLOATING_WALL_TYPES_OBS_OFFSET);
- setDictVal(dict, "floatingWallInfoObsSize", FLOATING_WALL_INFO_OBS_SIZE);
- setDictVal(dict, "floatingWallObsSize", FLOATING_WALL_OBS_SIZE);
- setDictVal(dict, "floatingWallInfoObsOffset", FLOATING_WALL_INFO_OBS_OFFSET);
- setDictVal(dict, "numWeaponPickupObs", NUM_WEAPON_PICKUP_OBS);
- setDictVal(dict, "weaponPickupTypesObsOffset", WEAPON_PICKUP_WEAPONS_OBS_OFFSET);
- setDictVal(dict, "weaponPickupPosObsSize", WEAPON_PICKUP_POS_OBS_SIZE);
- setDictVal(dict, "weaponPickupObsSize", WEAPON_PICKUP_OBS_SIZE);
- setDictVal(dict, "weaponPickupPosObsOffset", WEAPON_PICKUP_POS_OBS_OFFSET);
- setDictVal(dict, "numProjectileObs", NUM_PROJECTILE_OBS);
- setDictVal(dict, "projectileDroneObsOffset", PROJECTILE_DRONE_OBS_OFFSET);
- setDictVal(dict, "projectileTypesObsOffset", PROJECTILE_WEAPONS_OBS_OFFSET);
- setDictVal(dict, "projectileInfoObsSize", PROJECTILE_INFO_OBS_SIZE);
- setDictVal(dict, "projectileObsSize", PROJECTILE_OBS_SIZE);
- setDictVal(dict, "projectileInfoObsOffset", PROJECTILE_INFO_OBS_OFFSET);
- setDictVal(dict, "enemyDroneWeaponsObsOffset", ENEMY_DRONE_WEAPONS_OBS_OFFSET);
- setDictVal(dict, "enemyDroneObsOffset", ENEMY_DRONE_OBS_OFFSET);
- setDictVal(dict, "enemyDroneObsSize", ENEMY_DRONE_OBS_SIZE);
- setDictVal(dict, "droneObsOffset", droneObsOffset);
- setDictVal(dict, "droneObsSize", DRONE_OBS_SIZE);
- setDictVal(dict, "miscObsSize", MISC_OBS_SIZE);
- setDictVal(dict, "miscObsOffset", droneObsOffset + DRONE_OBS_SIZE);
-
- setDictVal(dict, "maxDrones", MAX_DRONES);
- setDictVal(dict, "contActionsSize", CONTINUOUS_ACTION_SIZE);
-
- return dict;
-}
-
-static PyObject *my_shared(PyObject *self, PyObject *args, PyObject *kwargs) {
- VecEnv *ve = unpack_vecenv(args);
- initMaps(ve->envs[0]);
-
- for (uint16_t i = 0; i < ve->num_envs; i++) {
- iwEnv *e = (iwEnv *)ve->envs[i];
- setupEnv(e);
- }
-
- return Py_None;
-}
-
-static int my_init(iwEnv *e, PyObject *args, PyObject *kwargs) {
- initEnv(
- e,
- (uint8_t)unpack(kwargs, "num_drones"),
- (uint8_t)unpack(kwargs, "num_agents"),
- (int8_t)unpack(kwargs, "map_idx"),
- (uint64_t)unpack(kwargs, "seed"),
- (bool)unpack(kwargs, "enable_teams"),
- (bool)unpack(kwargs, "sitting_duck"),
- (bool)unpack(kwargs, "is_training"),
- (bool)unpack(kwargs, "continuous")
- );
- return 0;
-}
-
-#define _LOG_BUF_SIZE 128
-
-char *droneLog(char *buf, const uint8_t droneIdx, const char *name) {
- snprintf(buf, _LOG_BUF_SIZE, "drone_%d_%s", droneIdx, name);
- return buf;
-}
-
-char *weaponLog(char *buf, const uint8_t droneIdx, const uint8_t weaponIdx, const char *name) {
- snprintf(buf, _LOG_BUF_SIZE, "drone_%d_%s_%s", droneIdx, weaponNames[weaponIdx], name);
- return buf;
-}
-
-static int my_log(PyObject *dict, Log *log) {
- assign_to_dict(dict, "episode_length", log->length);
- assign_to_dict(dict, "ties", log->ties);
-
- assign_to_dict(dict, "perf", log->stats[0].wins);
- assign_to_dict(dict, "score", log->stats[0].wins);
-
- char buf[_LOG_BUF_SIZE] = {0};
- for (uint8_t i = 0; i < MAX_DRONES; i++) {
- assign_to_dict(dict, droneLog(buf, i, "returns"), log->stats[i].returns);
- assign_to_dict(dict, droneLog(buf, i, "distance_traveled"), log->stats[i].distanceTraveled);
- assign_to_dict(dict, droneLog(buf, i, "abs_distance_traveled"), log->stats[i].absDistanceTraveled);
- assign_to_dict(dict, droneLog(buf, i, "brake_time"), log->stats[i].brakeTime);
- assign_to_dict(dict, droneLog(buf, i, "total_bursts"), log->stats[i].totalBursts);
- assign_to_dict(dict, droneLog(buf, i, "bursts_hit"), log->stats[i].burstsHit);
- assign_to_dict(dict, droneLog(buf, i, "energy_emptied"), log->stats[i].energyEmptied);
- assign_to_dict(dict, droneLog(buf, i, "wins"), log->stats[i].wins);
-
- // useful for debugging weapon balance, but really slows down
- // sweeps due to adding a ton of extra logging data
- //
- // for (uint8_t j = 0; j < _NUM_WEAPONS; j++) {
- // assign_to_dict(dict, weaponLog(buf, i, j, "shots_fired"), log->stats[i].shotsFired[j]);
- // assign_to_dict(dict, weaponLog(buf, i, j, "shots_hit"), log->stats[i].shotsHit[j]);
- // assign_to_dict(dict, weaponLog(buf, i, j, "shots_taken"), log->stats[i].shotsTaken[j]);
- // assign_to_dict(dict, weaponLog(buf, i, j, "own_shots_taken"), log->stats[i].ownShotsTaken[j]);
- // assign_to_dict(dict, weaponLog(buf, i, j, "picked_up"), log->stats[i].weaponsPickedUp[j]);
- // assign_to_dict(dict, weaponLog(buf, i, j, "shot_distances"), log->stats[i].shotDistances[j]);
- // }
-
- assign_to_dict(dict, droneLog(buf, i, "total_shots_fired"), log->stats[i].totalShotsFired);
- assign_to_dict(dict, droneLog(buf, i, "total_shots_hit"), log->stats[i].totalShotsHit);
- assign_to_dict(dict, droneLog(buf, i, "total_shots_taken"), log->stats[i].totalShotsTaken);
- assign_to_dict(dict, droneLog(buf, i, "total_own_shots_taken"), log->stats[i].totalOwnShotsTaken);
- assign_to_dict(dict, droneLog(buf, i, "total_picked_up"), log->stats[i].totalWeaponsPickedUp);
- assign_to_dict(dict, droneLog(buf, i, "total_shot_distances"), log->stats[i].totalShotDistances);
- }
-
- return 0;
-}
diff --git a/pufferlib/ocean/impulse_wars/env.h b/pufferlib/ocean/impulse_wars/env.h
deleted file mode 100644
index 33a220e8c..000000000
--- a/pufferlib/ocean/impulse_wars/env.h
+++ /dev/null
@@ -1,1256 +0,0 @@
-#ifndef IMPULSE_WARS_ENV_H
-#define IMPULSE_WARS_ENV_H
-
-#ifdef __EMSCRIPTEN__
-#include
-
-double lastFrameTime = 0.0;
-double accumulator = 0.0;
-#endif
-
-#include "game.h"
-#include "map.h"
-#include "render.h"
-#include "scripted_agent.h"
-#include "settings.h"
-#include "types.h"
-
-const uint8_t THREE_BIT_MASK = 0x7;
-const uint8_t FOUR_BIT_MASK = 0xf;
-
-// pufferlib compatibility
-#define c_step stepEnv
-#define c_reset resetEnv
-#define c_render setupRayClient
-#define c_close destroyEnv
-
-// returns a cell index that is closest to pos that isn't cellIdx
-uint16_t findNearestCell(const iwEnv *e, const b2Vec2 pos, const uint16_t cellIdx) {
- uint16_t closestCell = cellIdx;
- float minDistance = FLT_MAX;
- const uint8_t cellCol = cellIdx / e->map->columns;
- const uint8_t cellRow = cellIdx % e->map->columns;
- for (uint8_t i = 0; i < 8; i++) {
- const int8_t newCellCol = cellCol + cellOffsets[i][0];
- if (newCellCol < 0 || newCellCol >= e->map->columns) {
- continue;
- }
- const int8_t newCellRow = cellRow + cellOffsets[i][1];
- if (newCellRow < 0 || newCellRow >= e->map->rows) {
- continue;
- }
- const int16_t newCellIdx = cellIndex(e, newCellCol, newCellRow);
- const mapCell *cell = safe_array_get_at(e->cells, newCellIdx);
- if (minDistance != min(minDistance, b2DistanceSquared(pos, cell->pos))) {
- closestCell = newCellIdx;
- }
- }
-
- return closestCell;
-}
-
-// normalize a drone's ammo count, setting infinite ammo as no ammo
-static inline float scaleAmmo(const iwEnv *e, const droneEntity *drone) {
- int8_t maxAmmo = weaponAmmo(e->defaultWeapon->type, drone->weaponInfo->type);
- float scaledAmmo = 0;
- if (drone->ammo != INFINITE) {
- scaledAmmo = scaleValue(drone->ammo, maxAmmo, true);
- }
- return scaledAmmo;
-}
-
-// fills a small 2D grid centered around the agent with discretized
-// walls, floating walls, weapon pickups, and drone positions
-void computeMapObs(iwEnv *e, const uint8_t agentIdx, const uint16_t obsStartOffset) {
- droneEntity *drone = safe_array_get_at(e->drones, agentIdx);
- const uint8_t droneCellCol = drone->mapCellIdx % e->map->columns;
- const uint8_t droneCellRow = drone->mapCellIdx / e->map->columns;
-
- const int8_t obsStartCol = droneCellCol - (MAP_OBS_COLUMNS / 2);
- const int8_t startCol = max(obsStartCol, 0);
- const int8_t obsStartRow = droneCellRow - (MAP_OBS_ROWS / 2);
- const int8_t startRow = max(obsStartRow, 0);
-
- const int8_t obsEndCol = droneCellCol + (MAP_OBS_COLUMNS / 2);
- const int8_t endCol = min(obsEndCol, e->map->columns - 1);
- const int8_t endRow = min(droneCellRow + (MAP_OBS_ROWS / 2), e->map->rows - 1);
-
- const int8_t obsColOffset = startCol - obsStartCol;
- const int8_t obsRowOffset = startRow - obsStartRow;
- uint16_t startOffset = obsStartOffset;
- if (obsColOffset == 0 && obsRowOffset != 0) {
- startOffset += obsRowOffset * MAP_OBS_COLUMNS;
- } else if (obsColOffset != 0 && obsRowOffset == 0) {
- startOffset += obsColOffset;
- } else if (obsColOffset != 0 && obsRowOffset != 0) {
- startOffset += obsColOffset + (obsRowOffset * MAP_OBS_COLUMNS);
- }
- uint16_t offset = startOffset;
-
- // compute map layout, and discretized positions of weapon pickups
- if (!e->suddenDeathWallsPlaced) {
- // copy precomputed map layout if sudden death walls haven't been placed
- const int8_t numCols = endCol - startCol + 1;
- for (int8_t row = startRow; row <= endRow; row++) {
- const int16_t cellIdx = cellIndex(e, startCol, row);
- memcpy(e->observations + offset, e->map->packedLayout + cellIdx, numCols * sizeof(uint8_t));
- offset += MAP_OBS_COLUMNS;
- }
-
- // compute discretized location of weapon pickups on grid
- for (size_t i = 0; i < cc_array_size(e->pickups); i++) {
- const weaponPickupEntity *pickup = safe_array_get_at(e->pickups, i);
- const uint8_t cellCol = pickup->mapCellIdx % e->map->columns;
- if (cellCol < startCol || cellCol > endCol) {
- continue;
- }
- const uint8_t cellRow = pickup->mapCellIdx / e->map->columns;
- if (cellRow < startRow || cellRow > endRow) {
- continue;
- }
-
- offset = startOffset + ((cellCol - startCol) + ((cellRow - startRow) * MAP_OBS_COLUMNS));
- ASSERTF(offset <= startOffset + MAP_OBS_SIZE, "offset: %d", offset);
- e->observations[offset] |= 1 << 3;
- }
- } else {
- // sudden death walls have been placed so compute may layout manually
- const int8_t colPadding = obsColOffset + (obsEndCol - endCol);
- for (int8_t row = startRow; row <= endRow; row++) {
- for (int8_t col = startCol; col <= endCol; col++) {
- const int16_t cellIdx = cellIndex(e, col, row);
- const mapCell *cell = safe_array_get_at(e->cells, cellIdx);
- if (cell->ent == NULL) {
- offset++;
- continue;
- }
-
- if (entityTypeIsWall(cell->ent->type)) {
- e->observations[offset] = ((cell->ent->type + 1) & TWO_BIT_MASK) << 5;
- } else if (cell->ent->type == WEAPON_PICKUP_ENTITY) {
- e->observations[offset] |= 1 << 3;
- }
-
- offset++;
- }
- offset += colPadding;
- }
- ASSERTF(offset <= startOffset + MAP_OBS_SIZE, "offset %u startOffset %u", offset, startOffset);
- }
-
- // compute discretized locations of floating walls on grid
- for (size_t i = 0; i < cc_array_size(e->floatingWalls); i++) {
- const wallEntity *wall = safe_array_get_at(e->floatingWalls, i);
- const uint8_t cellCol = wall->mapCellIdx % e->map->columns;
- if (cellCol < startCol || cellCol > endCol) {
- continue;
- }
- const uint8_t cellRow = wall->mapCellIdx / e->map->columns;
- if (cellRow < startRow || cellRow > endRow) {
- continue;
- }
-
- offset = startOffset + ((cellCol - startCol) + ((cellRow - startRow) * MAP_OBS_COLUMNS));
- ASSERTF(offset <= startOffset + MAP_OBS_SIZE, "offset: %d", offset);
- e->observations[offset] = ((wall->type + 1) & TWO_BIT_MASK) << 5;
- e->observations[offset] |= 1 << 4;
- }
-
- // compute discretized location and index of drones on grid
- uint8_t newDroneIdx = 1;
- uint16_t droneCells[e->numDrones];
- memset(droneCells, 0x0, sizeof(droneCells));
- for (uint8_t i = 0; i < cc_array_size(e->drones); i++) {
- if (i == agentIdx) {
- continue;
- }
-
- // ensure drones do not share cells in the observation
- droneEntity *otherDrone = safe_array_get_at(e->drones, i);
- if (i != 0) {
- for (uint8_t j = 0; j < i; j++) {
- if (droneCells[j] == otherDrone->mapCellIdx) {
- otherDrone->mapCellIdx = findNearestCell(e, otherDrone->pos, otherDrone->mapCellIdx);
- break;
- }
- }
- }
- const uint8_t cellCol = otherDrone->mapCellIdx % e->map->columns;
- if (cellCol < startCol || cellCol > endCol) {
- continue;
- }
- const uint8_t cellRow = otherDrone->mapCellIdx / e->map->columns;
- if (cellRow < startRow || cellRow > endRow) {
- continue;
- }
- droneCells[i] = otherDrone->mapCellIdx;
-
- offset = startOffset + ((cellCol - startCol) + ((cellRow - startRow) * MAP_OBS_COLUMNS));
- ASSERTF(offset <= startOffset + MAP_OBS_SIZE, "offset: %d", offset);
- e->observations[offset] |= (newDroneIdx++ & THREE_BIT_MASK);
- }
-}
-
-// computes observations for N nearest walls, floating walls, and weapon pickups
-void computeNearObs(iwEnv *e, const droneEntity *drone, const uint16_t discreteObsStart, float *continuousObs) {
- nearEntity nearWalls[NUM_NEAR_WALL_OBS];
- findNearWalls(e, drone, nearWalls, NUM_NEAR_WALL_OBS);
-
- uint16_t offset;
-
- // compute type and position of N nearest walls
- for (uint8_t i = 0; i < NUM_NEAR_WALL_OBS; i++) {
- const wallEntity *wall = nearWalls[i].entity;
-
- offset = discreteObsStart + NEAR_WALL_TYPES_OBS_OFFSET + i;
- ASSERTF(offset <= discreteObsStart + FLOATING_WALL_TYPES_OBS_OFFSET, "offset: %d", offset);
- e->observations[offset] = wall->type;
-
- // DEBUG_LOGF("wall %d cell %d", i, wall->mapCellIdx);
-
- offset = NEAR_WALL_POS_OBS_OFFSET + (i * NEAR_WALL_POS_OBS_SIZE);
- ASSERTF(offset <= FLOATING_WALL_INFO_OBS_OFFSET, "offset: %d", offset);
- const b2Vec2 wallRelPos = b2Sub(wall->pos, drone->pos);
-
- continuousObs[offset++] = scaleValue(wallRelPos.x, MAX_X_POS, false);
- continuousObs[offset] = scaleValue(wallRelPos.y, MAX_Y_POS, false);
- }
-
- if (cc_array_size(e->floatingWalls) != 0) {
- // find N nearest floating walls
- nearEntity nearFloatingWalls[MAX_FLOATING_WALLS] = {0};
- for (uint8_t i = 0; i < cc_array_size(e->floatingWalls); i++) {
- wallEntity *wall = safe_array_get_at(e->floatingWalls, i);
- const nearEntity nearEnt = {
- .entity = wall,
- .distanceSquared = b2DistanceSquared(wall->pos, drone->pos),
- };
- nearFloatingWalls[i] = nearEnt;
- }
- insertionSort(nearFloatingWalls, cc_array_size(e->floatingWalls));
-
- // compute type, position, angle and velocity of N nearest floating walls
- for (uint8_t i = 0; i < cc_array_size(e->floatingWalls); i++) {
- if (i == NUM_FLOATING_WALL_OBS) {
- break;
- }
- const wallEntity *wall = nearFloatingWalls[i].entity;
-
- const b2Transform wallTransform = b2Body_GetTransform(wall->bodyID);
- const b2Vec2 wallRelPos = b2Sub(wallTransform.p, drone->pos);
- const float angle = b2Rot_GetAngle(wallTransform.q);
-
- offset = discreteObsStart + FLOATING_WALL_TYPES_OBS_OFFSET + i;
- ASSERTF(offset <= discreteObsStart + PROJECTILE_DRONE_OBS_OFFSET, "offset: %d", offset);
- e->observations[offset] = wall->type + 1;
-
- // DEBUG_LOGF("floating wall %d cell %d", i, wall->mapCellIdx);
-
- offset = FLOATING_WALL_INFO_OBS_OFFSET + (i * FLOATING_WALL_INFO_OBS_SIZE);
- ASSERTF(offset <= WEAPON_PICKUP_POS_OBS_OFFSET, "offset: %d", offset);
- continuousObs[offset++] = scaleValue(wallRelPos.x, MAX_X_POS, false);
- continuousObs[offset++] = scaleValue(wallRelPos.y, MAX_Y_POS, false);
- continuousObs[offset++] = scaleValue(angle, MAX_ANGLE, false);
- continuousObs[offset++] = scaleValue(wall->velocity.x, MAX_SPEED, false);
- continuousObs[offset] = scaleValue(wall->velocity.y, MAX_SPEED, false);
- }
- }
-
- if (cc_array_size(e->pickups) != 0) {
- // find N nearest weapon pickups
- nearEntity nearPickups[MAX_WEAPON_PICKUPS] = {0};
- for (uint8_t i = 0; i < cc_array_size(e->pickups); i++) {
- weaponPickupEntity *pickup = safe_array_get_at(e->pickups, i);
- const nearEntity nearEnt = {
- .entity = pickup,
- .distanceSquared = b2DistanceSquared(pickup->pos, drone->pos),
- };
- nearPickups[i] = nearEnt;
- }
- insertionSort(nearPickups, cc_array_size(e->pickups));
-
- // compute type and location of N nearest weapon pickups
- for (uint8_t i = 0; i < cc_array_size(e->pickups); i++) {
- if (i == NUM_WEAPON_PICKUP_OBS) {
- break;
- }
- const weaponPickupEntity *pickup = nearPickups[i].entity;
-
- offset = discreteObsStart + WEAPON_PICKUP_WEAPONS_OBS_OFFSET + i;
- ASSERTF(offset <= discreteObsStart + ENEMY_DRONE_WEAPONS_OBS_OFFSET, "offset: %d", offset);
- e->observations[offset] = pickup->weapon + 1;
-
- // DEBUG_LOGF("pickup %d cell %d", i, pickup->mapCellIdx);
-
- offset = WEAPON_PICKUP_POS_OBS_OFFSET + (i * WEAPON_PICKUP_POS_OBS_SIZE);
- ASSERTF(offset <= PROJECTILE_INFO_OBS_OFFSET, "offset: %d", offset);
- const b2Vec2 pickupRelPos = b2Sub(pickup->pos, drone->pos);
- continuousObs[offset++] = scaleValue(pickupRelPos.x, MAX_X_POS, false);
- continuousObs[offset] = scaleValue(pickupRelPos.y, MAX_Y_POS, false);
- }
- }
-}
-
-void computeObs(iwEnv *e) {
- for (uint8_t agentIdx = 0; agentIdx < e->numAgents; agentIdx++) {
- droneEntity *agentDrone = safe_array_get_at(e->drones, agentIdx);
- // if the drone is dead, only compute observations if it died
- // this step and it isn't out of bounds
- if (agentDrone->livesLeft == 0 && (!agentDrone->diedThisStep || agentDrone->mapCellIdx == -1)) {
- continue;
- }
-
- // compute discrete map observations
- const uint16_t discreteObsStart = e->obsBytes * agentIdx;
- memset(e->observations + discreteObsStart, 0x0, e->obsBytes);
- computeMapObs(e, agentIdx, discreteObsStart);
-
- // compute continuous observations
- uint16_t discreteObsOffset;
- uint16_t continuousObsOffset;
- const uint16_t continuousObsStart = discreteObsStart + e->discreteObsBytes;
- float *continuousObs = (float *)(e->observations + continuousObsStart);
-
- computeNearObs(e, agentDrone, discreteObsStart, continuousObs);
-
- // sort projectiles by distance to the current agent
- const b2Vec2 agentPos = agentDrone->pos;
- const size_t numProjectiles = cc_array_size(e->projectiles);
- if (numProjectiles > 0) {
- projectileEntity *sortedProjectiles[numProjectiles];
- memcpy(sortedProjectiles, e->projectiles->buffer, numProjectiles * sizeof(projectileEntity *));
-
- for (int16_t i = 1; i < (int64_t)numProjectiles; i++) {
- projectileEntity *key = sortedProjectiles[i];
- const float keyDistance = b2DistanceSquared(agentPos, key->pos);
- int16_t j = i - 1;
-
- while (j >= 0 && b2DistanceSquared(agentPos, sortedProjectiles[j]->pos) > keyDistance) {
- sortedProjectiles[j + 1] = sortedProjectiles[j];
- j = j - 1;
- }
-
- sortedProjectiles[j + 1] = key;
- }
-
- // compute type and location of N projectiles
- for (size_t i = 0; i < numProjectiles; i++) {
- if (i == NUM_PROJECTILE_OBS) {
- break;
- }
- const projectileEntity *projectile = sortedProjectiles[i];
-
- discreteObsOffset = discreteObsStart + PROJECTILE_DRONE_OBS_OFFSET + i;
- ASSERTF(discreteObsOffset <= discreteObsStart + PROJECTILE_WEAPONS_OBS_OFFSET, "offset: %d", discreteObsOffset);
- e->observations[discreteObsOffset] = projectile->droneIdx + 1;
-
- discreteObsOffset = discreteObsStart + PROJECTILE_WEAPONS_OBS_OFFSET + i;
- ASSERTF(discreteObsOffset <= discreteObsStart + WEAPON_PICKUP_WEAPONS_OBS_OFFSET, "offset: %d", discreteObsOffset);
- e->observations[discreteObsOffset] = projectile->weaponInfo->type + 1;
-
- continuousObsOffset = PROJECTILE_INFO_OBS_OFFSET + (i * PROJECTILE_INFO_OBS_SIZE);
- ASSERTF(continuousObsOffset <= ENEMY_DRONE_OBS_OFFSET, "offset: %d", continuousObsOffset);
- const b2Vec2 projectileRelPos = b2Sub(projectile->pos, agentDrone->pos);
- continuousObs[continuousObsOffset++] = scaleValue(projectileRelPos.x, MAX_X_POS, false);
- continuousObs[continuousObsOffset++] = scaleValue(projectileRelPos.y, MAX_Y_POS, false);
- continuousObs[continuousObsOffset++] = scaleValue(projectile->velocity.x, MAX_SPEED, false);
- continuousObs[continuousObsOffset] = scaleValue(projectile->velocity.y, MAX_SPEED, false);
- }
- }
-
- // compute enemy drone observations
- bool hitShot = false;
- bool tookShot = false;
- uint8_t processedDrones = 0;
- for (uint8_t i = 0; i < e->numDrones; i++) {
- if (i == agentIdx) {
- continue;
- }
-
- if (agentDrone->stepInfo.shotHit[i]) {
- hitShot = true;
- }
- if (agentDrone->stepInfo.shotTaken[i]) {
- tookShot = true;
- }
-
- droneEntity *enemyDrone = safe_array_get_at(e->drones, i);
- if (enemyDrone->livesLeft == 0) {
- processedDrones++;
- continue;
- }
-
- const b2Vec2 enemyDroneRelPos = b2Sub(enemyDrone->pos, agentDrone->pos);
- const float enemyDroneDistance = b2Distance(enemyDrone->pos, agentDrone->pos);
- const b2Vec2 enemyDroneAccel = b2Sub(enemyDrone->velocity, enemyDrone->lastVelocity);
- const b2Vec2 enemyDroneRelNormPos = b2Normalize(b2Sub(enemyDrone->pos, agentDrone->pos));
- const float enemyDroneAimAngle = atan2f(enemyDrone->lastAim.y, enemyDrone->lastAim.x);
- float enemyDroneBraking = 0.0f;
- if (enemyDrone->braking) {
- enemyDroneBraking = 1.0f;
- }
-
- discreteObsOffset = discreteObsStart + ENEMY_DRONE_WEAPONS_OBS_OFFSET + processedDrones;
- e->observations[discreteObsOffset] = enemyDrone->weaponInfo->type + 1;
-
- continuousObsOffset = ENEMY_DRONE_OBS_OFFSET + (e->numDrones - 1) + (processedDrones * ENEMY_DRONE_OBS_SIZE);
- continuousObs[continuousObsOffset++] = enemyDrone->team == agentDrone->team;
- continuousObs[continuousObsOffset++] = scaleValue(enemyDroneRelPos.x, MAX_X_POS, false);
- continuousObs[continuousObsOffset++] = scaleValue(enemyDroneRelPos.y, MAX_Y_POS, false);
- continuousObs[continuousObsOffset++] = scaleValue(enemyDroneDistance, MAX_DISTANCE, true);
- continuousObs[continuousObsOffset++] = scaleValue(enemyDrone->velocity.x, MAX_SPEED, false);
- continuousObs[continuousObsOffset++] = scaleValue(enemyDrone->velocity.y, MAX_SPEED, false);
- continuousObs[continuousObsOffset++] = scaleValue(enemyDroneAccel.x, MAX_ACCEL, false);
- continuousObs[continuousObsOffset++] = scaleValue(enemyDroneAccel.y, MAX_ACCEL, false);
- continuousObs[continuousObsOffset++] = scaleValue(enemyDroneRelNormPos.x, 1.0f, false);
- continuousObs[continuousObsOffset++] = scaleValue(enemyDroneRelNormPos.y, 1.0f, false);
- continuousObs[continuousObsOffset++] = scaleValue(enemyDrone->lastAim.x, 1.0f, false);
- continuousObs[continuousObsOffset++] = scaleValue(enemyDrone->lastAim.y, 1.0f, false);
- continuousObs[continuousObsOffset++] = scaleValue(enemyDroneAimAngle, PI, false);
- continuousObs[continuousObsOffset++] = scaleAmmo(e, enemyDrone);
- continuousObs[continuousObsOffset++] = scaleValue(enemyDrone->weaponCooldown, enemyDrone->weaponInfo->coolDown, true);
- continuousObs[continuousObsOffset++] = scaleValue(enemyDrone->weaponCharge, enemyDrone->weaponInfo->charge, true);
- continuousObs[continuousObsOffset++] = scaleValue(enemyDrone->energyLeft, DRONE_ENERGY_MAX, true);
- continuousObs[continuousObsOffset++] = (float)enemyDrone->energyFullyDepleted;
- continuousObs[continuousObsOffset++] = enemyDroneBraking;
- continuousObs[continuousObsOffset++] = scaleValue(enemyDrone->burstCooldown, DRONE_BURST_COOLDOWN, true);
- continuousObs[continuousObsOffset++] = (float)enemyDrone->chargingBurst;
- continuousObs[continuousObsOffset++] = scaleValue(enemyDrone->burstCharge, DRONE_ENERGY_MAX, true);
- continuousObs[continuousObsOffset++] = scaleValue(enemyDrone->livesLeft, DRONE_LIVES, true);
- continuousObs[continuousObsOffset++] = !enemyDrone->dead;
-
- processedDrones++;
- ASSERTF(continuousObsOffset == ENEMY_DRONE_OBS_OFFSET + (e->numDrones - 1) + (processedDrones * ENEMY_DRONE_OBS_SIZE), "offset: %d", continuousObsOffset);
- }
-
- // compute active drone observations
- continuousObsOffset = ENEMY_DRONE_OBS_OFFSET + ((e->numDrones - 1) * ENEMY_DRONE_OBS_SIZE);
- const b2Vec2 agentDroneAccel = b2Sub(agentDrone->velocity, agentDrone->lastVelocity);
- float agentDroneBraking = 0.0f;
- if (agentDrone->braking) {
- agentDroneBraking = 1.0f;
- }
-
- discreteObsOffset = discreteObsStart + ENEMY_DRONE_WEAPONS_OBS_OFFSET + e->numDrones - 1;
- e->observations[discreteObsOffset] = agentDrone->weaponInfo->type + 1;
-
- continuousObs[continuousObsOffset++] = scaleValue(agentDrone->pos.x, MAX_X_POS, false);
- continuousObs[continuousObsOffset++] = scaleValue(agentDrone->pos.y, MAX_Y_POS, false);
- continuousObs[continuousObsOffset++] = scaleValue(agentDrone->velocity.x, MAX_SPEED, false);
- continuousObs[continuousObsOffset++] = scaleValue(agentDrone->velocity.y, MAX_SPEED, false);
- continuousObs[continuousObsOffset++] = scaleValue(agentDroneAccel.x, MAX_ACCEL, false);
- continuousObs[continuousObsOffset++] = scaleValue(agentDroneAccel.y, MAX_ACCEL, false);
- continuousObs[continuousObsOffset++] = scaleValue(agentDrone->lastAim.x, 1.0f, false);
- continuousObs[continuousObsOffset++] = scaleValue(agentDrone->lastAim.y, 1.0f, false);
- continuousObs[continuousObsOffset++] = scaleAmmo(e, agentDrone);
- continuousObs[continuousObsOffset++] = scaleValue(agentDrone->weaponCooldown, agentDrone->weaponInfo->coolDown, true);
- continuousObs[continuousObsOffset++] = scaleValue(agentDrone->weaponCharge, agentDrone->weaponInfo->charge, true);
- continuousObs[continuousObsOffset++] = scaleValue(agentDrone->energyLeft, DRONE_ENERGY_MAX, true);
- continuousObs[continuousObsOffset++] = (float)agentDrone->energyFullyDepleted;
- continuousObs[continuousObsOffset++] = agentDroneBraking;
- continuousObs[continuousObsOffset++] = scaleValue(agentDrone->burstCooldown, DRONE_BURST_COOLDOWN, true);
- continuousObs[continuousObsOffset++] = (float)agentDrone->chargingBurst;
- continuousObs[continuousObsOffset++] = scaleValue(agentDrone->burstCharge, DRONE_ENERGY_MAX, true);
- continuousObs[continuousObsOffset++] = hitShot;
- continuousObs[continuousObsOffset++] = tookShot;
- continuousObs[continuousObsOffset++] = agentDrone->stepInfo.ownShotTaken;
- continuousObs[continuousObsOffset++] = scaleValue(agentDrone->livesLeft, DRONE_LIVES, true);
- continuousObs[continuousObsOffset++] = !agentDrone->dead;
-
- ASSERTF(continuousObsOffset == ENEMY_DRONE_OBS_OFFSET + ((e->numDrones - 1) * ENEMY_DRONE_OBS_SIZE) + DRONE_OBS_SIZE, "offset: %d", continuousObsOffset);
- continuousObs[continuousObsOffset] = scaleValue(e->stepsLeft, e->totalSteps, true);
- }
-}
-
-void setupEnv(iwEnv *e) {
- e->needsReset = false;
-
- e->stepsLeft = e->totalSteps;
- e->suddenDeathSteps = e->totalSuddenDeathSteps;
- e->suddenDeathWallCounter = 0;
-
- e->lastSpawnQuad = -1;
-
- int8_t mapIdx = e->pinnedMapIdx;
- if (e->pinnedMapIdx == -1) {
- uint8_t firstMap = 0;
- // don't evaluate on the boring empty map
- if (!e->isTraining) {
- firstMap = 1;
- }
- mapIdx = randInt(&e->randState, firstMap, NUM_MAPS - 1);
- }
- DEBUG_LOGF("setting up map %d", mapIdx);
- setupMap(e, mapIdx);
-
- DEBUG_LOG("creating drones");
- for (uint8_t i = 0; i < e->numDrones; i++) {
- createDrone(e, i);
- }
-
- DEBUG_LOG("placing floating walls");
- placeRandFloatingWalls(e, mapIdx);
-
- DEBUG_LOG("creating weapon pickups");
- // start spawning pickups in a random quadrant
- e->lastSpawnQuad = randInt(&e->randState, 0, 3);
- for (uint8_t i = 0; i < maps[mapIdx]->weaponPickups; i++) {
- createWeaponPickup(e);
- }
-
- if (e->client != NULL) {
- setupEnvCamera(e);
- renderEnv(e, true, false, -1, -1);
- }
-
- computeObs(e);
-}
-
-// sets the timing related variables for the environment depending on
-// the frame rate
-void setEnvFrameRate(iwEnv *e) {
- float frameRate = TRAINING_FRAME_RATE;
- e->box2dSubSteps = TRAINING_BOX2D_SUBSTEPS;
- // set a higher frame rate and physics substeps when evaluating
- // to make it more enjoyable to play
- if (!e->isTraining) {
- frameRate = EVAL_FRAME_RATE;
- e->box2dSubSteps = EVAL_BOX2D_SUBSTEPS;
- }
-
- e->frameRate = frameRate;
- e->deltaTime = 1.0f / (float)frameRate;
- e->frameSkip = frameRate / TRAINING_ACTIONS_PER_SECOND;
-
- e->totalSteps = ROUND_STEPS * frameRate;
- e->totalSuddenDeathSteps = SUDDEN_DEATH_STEPS * frameRate;
-}
-
-iwEnv *initEnv(iwEnv *e, uint8_t numDrones, uint8_t numAgents, int8_t mapIdx, uint64_t seed, bool enableTeams, bool sittingDuck, bool isTraining, bool continuousActions) {
- DEBUG_LOGF("seed: %lu", seed);
-
- e->numDrones = numDrones;
- e->numAgents = numAgents;
- e->teamsEnabled = enableTeams;
- e->numTeams = numDrones;
- if (e->teamsEnabled) {
- e->numTeams = 2;
- }
- e->sittingDuck = sittingDuck;
- e->isTraining = isTraining;
-
- e->obsBytes = obsBytes(e->numDrones);
- e->discreteObsBytes = alignedSize(discreteObsSize(e->numDrones) * sizeof(uint8_t), sizeof(float));
-
- e->continuousActions = continuousActions;
-
- // TODO: remove when puffer bindings add truncations
- e->truncations = fastCalloc(numDrones, sizeof(uint8_t));
-
- setEnvFrameRate(e);
- e->randState = seed;
- e->needsReset = false;
-
- b2WorldDef worldDef = b2DefaultWorldDef();
- worldDef.gravity = (b2Vec2){.x = 0.0f, .y = 0.0f};
- e->worldID = b2CreateWorld(&worldDef);
- e->pinnedMapIdx = mapIdx;
- e->mapIdx = -1;
-
- e->idPool = b2CreateIdPool();
- create_array(&e->entities, 128);
-
- create_array(&e->cells, 512);
- create_array(&e->walls, 128);
- create_array(&e->floatingWalls, MAX_FLOATING_WALLS);
- create_array(&e->drones, e->numDrones);
- create_array(&e->pickups, MAX_WEAPON_PICKUPS);
- create_array(&e->projectiles, 64);
- create_array(&e->explosions, 8);
- create_array(&e->explodingProjectiles, 8);
- create_array(&e->dronePieces, 16);
-
- e->mapPathing = fastCalloc(NUM_MAPS, sizeof(pathingInfo));
- for (uint8_t i = 0; i < NUM_MAPS; i++) {
- const mapEntry *map = maps[i];
- pathingInfo *info = &e->mapPathing[i];
- info->paths = fastMalloc(map->rows * map->columns * map->rows * map->columns * sizeof(uint8_t));
- memset(info->paths, UINT8_MAX, map->rows * map->columns * map->rows * map->columns * sizeof(uint8_t));
- info->pathBuffer = fastCalloc(3 * 8 * map->rows * map->columns, sizeof(int8_t));
- }
-
- e->humanInput = false;
- e->humanDroneInput = 0;
- e->connectedControllers = 0;
-
- return e;
-}
-
-void clearEnv(iwEnv *e) {
- // rewards get cleared in stepEnv every step
- // memset(e->masks, 1, e->numAgents * sizeof(uint8_t));
- memset(e->terminals, 0x0, e->numAgents * sizeof(uint8_t));
- memset(e->truncations, 0x0, e->numAgents * sizeof(uint8_t));
-
- e->episodeLength = 0;
- memset(e->stats, 0x0, sizeof(e->stats));
-
- for (uint8_t i = 0; i < e->numDrones; i++) {
- droneEntity *drone = safe_array_get_at(e->drones, i);
- destroyDrone(e, drone);
- }
-
- for (size_t i = 0; i < cc_array_size(e->floatingWalls); i++) {
- wallEntity *wall = safe_array_get_at(e->floatingWalls, i);
- destroyWall(e, wall, false);
- }
-
- for (size_t i = 0; i < cc_array_size(e->pickups); i++) {
- weaponPickupEntity *pickup = safe_array_get_at(e->pickups, i);
- destroyWeaponPickup(e, pickup);
- }
-
- for (size_t i = 0; i < cc_array_size(e->projectiles); i++) {
- projectileEntity *p = safe_array_get_at(e->projectiles, i);
- destroyProjectile(e, p, false, false);
- }
-
- for (size_t i = 0; i < cc_array_size(e->explosions); i++) {
- explosionInfo *explosion = safe_array_get_at(e->explosions, i);
- fastFree(explosion);
- }
-
- for (size_t i = 0; i < cc_array_size(e->dronePieces); i++) {
- dronePieceEntity *piece = safe_array_get_at(e->dronePieces, i);
- destroyDronePiece(e, piece);
- }
-
- cc_array_remove_all(e->drones);
- cc_array_remove_all(e->floatingWalls);
- cc_array_remove_all(e->pickups);
- cc_array_remove_all(e->projectiles);
- cc_array_remove_all(e->explodingProjectiles);
- cc_array_remove_all(e->explosions);
- cc_array_remove_all(e->dronePieces);
-}
-
-void destroyEnv(iwEnv *e) {
- clearEnv(e);
-
- for (uint8_t i = 0; i < NUM_MAPS; i++) {
- pathingInfo *info = &e->mapPathing[i];
- fastFree(info->paths);
- fastFree(info->pathBuffer);
- }
- fastFree(e->mapPathing);
-
- for (size_t i = 0; i < cc_array_size(e->walls); i++) {
- wallEntity *wall = safe_array_get_at(e->walls, i);
- destroyWall(e, wall, false);
- }
-
- for (size_t i = 0; i < cc_array_size(e->cells); i++) {
- mapCell *cell = safe_array_get_at(e->cells, i);
- fastFree(cell);
- }
-
- for (size_t i = 0; i < cc_array_size(e->entities); i++) {
- entity *ent = safe_array_get_at(e->entities, i);
- fastFree(ent->id);
- fastFree(ent);
- }
- b2DestroyIdPool(&e->idPool);
-
- cc_array_destroy(e->entities);
- cc_array_destroy(e->cells);
- cc_array_destroy(e->walls);
- cc_array_destroy(e->drones);
- cc_array_destroy(e->floatingWalls);
- cc_array_destroy(e->pickups);
- cc_array_destroy(e->projectiles);
- cc_array_destroy(e->explosions);
- cc_array_destroy(e->explodingProjectiles);
- cc_array_destroy(e->dronePieces);
-
- b2DestroyWorld(e->worldID);
-}
-
-void resetEnv(iwEnv *e) {
- clearEnv(e);
- setupEnv(e);
-}
-
-float computeShotReward(const droneEntity *drone, const weaponInformation *weaponInfo) {
- const float weaponForce = weaponInfo->fireMagnitude * weaponInfo->invMass;
- const float scaledForce = (weaponForce * (weaponForce * SHOT_HIT_REWARD_COEF)) + 0.25f;
- return scaledForce + computeHitStrength(drone);
-}
-
-float computeExplosionReward(const droneEntity *drone) {
- return computeHitStrength(drone) * EXPLOSION_HIT_REWARD_COEF;
-}
-
-float computeReward(iwEnv *e, droneEntity *drone) {
- float reward = 0.0f;
-
- if (drone->energyFullyDepleted && drone->energyRefillWait == DRONE_ENERGY_REFILL_EMPTY_WAIT) {
- reward += ENERGY_EMPTY_PUNISHMENT;
- }
-
- // only reward picking up a weapon if the standard weapon was
- // previously held; every weapon is better than the standard
- // weapon, but other weapons are situational better so don't
- // reward switching a non-standard weapon
- if (drone->stepInfo.pickedUpWeapon && drone->stepInfo.prevWeapon == STANDARD_WEAPON) {
- reward += WEAPON_PICKUP_REWARD;
- }
-
- for (uint8_t i = 0; i < e->numDrones; i++) {
- if (i == drone->idx) {
- continue;
- }
- droneEntity *enemyDrone = safe_array_get_at(e->drones, i);
- const bool onTeam = drone->team == enemyDrone->team;
-
- if (drone->stepInfo.shotHit[i] != 0 && !onTeam) {
- // subtract 1 from the weapon type because 1 is added so we
- // can use 0 as no shot was hit
- const weaponInformation *weaponInfo = weaponInfos[drone->stepInfo.shotHit[i] - 1];
- reward += computeShotReward(enemyDrone, weaponInfo);
- }
- if (drone->stepInfo.explosionHit[i] && !onTeam) {
- reward += computeExplosionReward(enemyDrone);
- }
-
- if (e->numAgents == e->numDrones) {
- if (drone->stepInfo.shotTaken[i] != 0 && !onTeam) {
- const weaponInformation *weaponInfo = weaponInfos[drone->stepInfo.shotTaken[i] - 1];
- reward -= computeShotReward(drone, weaponInfo) * 0.5f;
- }
- if (drone->stepInfo.explosionTaken[i] && !onTeam) {
- reward -= computeExplosionReward(drone) * 0.5f;
- }
- }
-
- if (enemyDrone->dead && enemyDrone->diedThisStep) {
- if (!onTeam) {
- reward += ENEMY_DEATH_REWARD;
- if (drone->killed[i]) {
- reward += ENEMY_KILL_REWARD;
- }
- } else {
- reward += TEAMMATE_DEATH_PUNISHMENT;
- if (drone->killed[i]) {
- reward += TEAMMATE_KILL_PUNISHMENT;
- }
- }
- continue;
- }
-
- const b2Vec2 enemyDirection = b2Normalize(b2Sub(enemyDrone->pos, drone->pos));
- const float velocityToEnemy = b2Dot(drone->lastVelocity, enemyDirection);
- const float enemyDistance = b2Distance(enemyDrone->pos, drone->pos);
- // stop rewarding approaching an enemy if they're very close
- // to avoid constant clashing; always reward approaching when
- // the current weapon is the shotgun, it greatly benefits from
- // being close to enemies
- if (velocityToEnemy > 0.1f && (drone->weaponInfo->type == SHOTGUN_WEAPON || enemyDistance > DISTANCE_CUTOFF)) {
- reward += APPROACH_REWARD;
- }
- }
-
- return reward;
-}
-
-const float REWARD_EPS = 1.0e-6f;
-
-void computeRewards(iwEnv *e, const bool roundOver, const int8_t winner, const int8_t winningTeam) {
- if (roundOver && winner != -1 && winner < e->numAgents) {
- e->rewards[winner] += WIN_REWARD;
- }
-
- for (uint8_t i = 0; i < e->numDrones; i++) {
- float reward = 0.0f;
- droneEntity *drone = safe_array_get_at(e->drones, i);
- if (!drone->dead) {
- reward = computeReward(e, drone);
- if (roundOver && winningTeam == drone->team) {
- reward += WIN_REWARD;
- }
- } else if (drone->diedThisStep) {
- reward = DEATH_PUNISHMENT;
- if (drone->killedBy == drone->idx) {
- reward += SELF_KILL_PUNISHMENT;
- }
- }
- if (i < e->numAgents) {
- e->rewards[i] += reward;
- }
- e->stats[i].returns += reward;
- }
-}
-
-static inline bool isActionNoop(const b2Vec2 action) {
- return b2Length(action) < ACTION_NOOP_MAGNITUDE;
-}
-
-agentActions _computeActions(iwEnv *e, droneEntity *drone, const agentActions *manualActions) {
- agentActions actions = {0};
-
- const uint8_t offset = drone->idx * CONTINUOUS_ACTION_SIZE;
- if (manualActions == NULL) {
- actions.move = (b2Vec2){.x = e->actions[offset + 0], .y = e->actions[offset + 1]};
- actions.aim = (b2Vec2){.x = e->actions[offset + 2], .y = e->actions[offset + 3]};
- if (e->continuousActions) {
- actions.move.x = tanhf(actions.move.x);
- actions.move.y = tanhf(actions.move.y);
- actions.aim.x = tanhf(actions.aim.x);
- actions.aim.y = tanhf(actions.aim.y);
- }
- actions.chargingWeapon = e->actions[offset + 4] > 0.0f;
- actions.shoot = actions.chargingWeapon;
- if (!actions.chargingWeapon && drone->chargingWeapon) {
- actions.shoot = true;
- }
- actions.brake = e->actions[offset + 5] > 0.0f;
- actions.chargingBurst = e->actions[offset + 6] > 0.0f;
- } else {
- actions.move = manualActions->move;
- actions.aim = manualActions->aim;
- actions.chargingWeapon = manualActions->chargingWeapon;
- actions.shoot = manualActions->shoot;
- actions.brake = manualActions->brake;
- actions.chargingBurst = manualActions->chargingBurst;
- actions.discardWeapon = manualActions->discardWeapon;
- }
-
- // cap movement magnitude to 1.0
- if (b2Length(actions.move) > 1.0f) {
- actions.move = b2Normalize(actions.move);
- } else if (isActionNoop(actions.move)) {
- actions.move = b2Vec2_zero;
- }
-
- if (isActionNoop(actions.aim)) {
- actions.aim = b2Vec2_zero;
- } else {
- actions.aim = b2Normalize(actions.aim);
- }
-
- return actions;
-}
-
-agentActions computeActions(iwEnv *e, droneEntity *drone, const agentActions *manualActions) {
- const agentActions actions = _computeActions(e, drone, manualActions);
- drone->lastMove = actions.move;
- if (!b2VecEqual(actions.aim, b2Vec2_zero)) {
- drone->lastAim = actions.aim;
- }
- return actions;
-}
-
-void updateConnectedControllers(iwEnv *e) {
- for (uint8_t i = 0; i < e->numDrones; i++) {
- if (IsGamepadAvailable(i)) {
- e->connectedControllers++;
- }
- }
-}
-
-void updateHumanInputToggle(iwEnv *e) {
- if (IsKeyPressed(KEY_LEFT_CONTROL)) {
- e->humanInput = !e->humanInput;
- if (!e->humanInput) {
- e->connectedControllers = 0;
- }
- }
- if (e->humanInput && e->connectedControllers == 0) {
- updateConnectedControllers(e);
- }
- if (e->connectedControllers > 1) {
- e->humanDroneInput = e->numDrones - e->connectedControllers;
- return;
- }
-
- if (IsKeyPressed(KEY_ONE) || IsKeyPressed(KEY_KP_1)) {
- e->humanDroneInput = 0;
- }
- if (IsKeyPressed(KEY_TWO) || IsKeyPressed(KEY_KP_2)) {
- e->humanDroneInput = 1;
- }
- if (e->numDrones >= 3 && (IsKeyPressed(KEY_THREE) || IsKeyPressed(KEY_KP_3))) {
- e->humanDroneInput = 2;
- }
- if (e->numDrones >= 4 && (IsKeyPressed(KEY_FOUR) || IsKeyPressed(KEY_KP_4))) {
- e->humanDroneInput = 3;
- }
-}
-
-agentActions getPlayerInputs(iwEnv *e, droneEntity *drone, uint8_t gamepadIdx) {
- if (IsKeyPressed(KEY_R)) {
- e->needsReset = true;
- }
-
- agentActions actions = {0};
-
- bool controllerConnected = false;
- if (IsGamepadAvailable(gamepadIdx)) {
- controllerConnected = true;
- }
- if (controllerConnected) {
- float lStickX = GetGamepadAxisMovement(gamepadIdx, GAMEPAD_AXIS_LEFT_X);
- float lStickY = GetGamepadAxisMovement(gamepadIdx, GAMEPAD_AXIS_LEFT_Y);
- float rStickX = GetGamepadAxisMovement(gamepadIdx, GAMEPAD_AXIS_RIGHT_X);
- float rStickY = GetGamepadAxisMovement(gamepadIdx, GAMEPAD_AXIS_RIGHT_Y);
-
- if (IsGamepadButtonDown(gamepadIdx, GAMEPAD_BUTTON_RIGHT_TRIGGER_2)) {
- actions.chargingWeapon = true;
- actions.shoot = true;
- } else if (drone->chargingWeapon && IsGamepadButtonUp(gamepadIdx, GAMEPAD_BUTTON_RIGHT_TRIGGER_2)) {
- actions.shoot = true;
- }
-
- if (IsGamepadButtonDown(gamepadIdx, GAMEPAD_BUTTON_LEFT_TRIGGER_2)) {
- actions.brake = true;
- }
-
- if (IsGamepadButtonDown(gamepadIdx, GAMEPAD_BUTTON_RIGHT_TRIGGER_1) || IsGamepadButtonDown(gamepadIdx, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) {
- actions.chargingBurst = true;
- }
-
- if (IsGamepadButtonPressed(gamepadIdx, GAMEPAD_BUTTON_RIGHT_FACE_LEFT)) {
- actions.discardWeapon = true;
- }
-
- actions.move = (b2Vec2){.x = lStickX, .y = lStickY};
- actions.aim = (b2Vec2){.x = rStickX, .y = rStickY};
- return computeActions(e, drone, &actions);
- }
- if (!controllerConnected && drone->idx != e->humanDroneInput) {
- return actions;
- }
-
- b2Vec2 move = b2Vec2_zero;
- if (IsKeyDown(KEY_W)) {
- move.y += -1.0f;
- }
- if (IsKeyDown(KEY_S)) {
- move.y += 1.0f;
- }
- if (IsKeyDown(KEY_A)) {
- move.x += -1.0f;
- }
- if (IsKeyDown(KEY_D)) {
- move.x += 1.0f;
- }
- actions.move = b2Normalize(move);
-
- Vector2 mousePos = (Vector2){.x = (float)GetMouseX(), .y = (float)GetMouseY()};
- actions.aim = b2Normalize(b2Sub(rayVecToB2Vec(e, mousePos), drone->pos));
-
- if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
- actions.chargingWeapon = true;
- actions.shoot = true;
- } else if (drone->chargingWeapon && IsMouseButtonUp(MOUSE_BUTTON_LEFT)) {
- actions.shoot = true;
- }
- if (IsKeyDown(KEY_SPACE)) {
- actions.brake = true;
- }
- if (IsMouseButtonDown(MOUSE_BUTTON_RIGHT)) {
- actions.chargingBurst = true;
- }
-
- return computeActions(e, drone, &actions);
-}
-
-bool droneControlledByHuman(const iwEnv *e, uint8_t i) {
- if (!e->humanInput) {
- return false;
- }
- return (e->connectedControllers > 1 && i >= e->humanDroneInput) || (e->connectedControllers <= 1 && i == e->humanDroneInput);
-}
-
-void addLog(iwEnv *e, Log *log) {
- e->log.length += log->length;
- e->log.ties += log->ties;
-
- for (uint8_t j = 0; j < e->numDrones; j++) {
- e->log.stats[j].returns += log->stats[j].returns;
- e->log.stats[j].wins += log->stats[j].wins;
-
- e->log.stats[j].distanceTraveled += log->stats[j].distanceTraveled;
- e->log.stats[j].absDistanceTraveled += log->stats[j].absDistanceTraveled;
- e->log.stats[j].brakeTime += log->stats[j].brakeTime;
- e->log.stats[j].totalBursts += log->stats[j].totalBursts;
- e->log.stats[j].burstsHit += log->stats[j].burstsHit;
- e->log.stats[j].energyEmptied += log->stats[j].energyEmptied;
-
- for (uint8_t k = 0; k < NUM_WEAPONS; k++) {
- e->log.stats[j].shotsFired[k] += log->stats[j].shotsFired[k];
- e->log.stats[j].shotsHit[k] += log->stats[j].shotsHit[k];
- e->log.stats[j].shotsTaken[k] += log->stats[j].shotsTaken[k];
- e->log.stats[j].ownShotsTaken[k] += log->stats[j].ownShotsTaken[k];
- e->log.stats[j].weaponsPickedUp[k] += log->stats[j].weaponsPickedUp[k];
- e->log.stats[j].shotDistances[k] += log->stats[j].shotDistances[k];
- }
-
- e->log.stats[j].totalShotsFired += log->stats[j].totalShotsFired;
- e->log.stats[j].totalShotsHit += log->stats[j].totalShotsHit;
- e->log.stats[j].totalShotsTaken += log->stats[j].totalShotsTaken;
- e->log.stats[j].totalOwnShotsTaken += log->stats[j].totalOwnShotsTaken;
- e->log.stats[j].totalWeaponsPickedUp += log->stats[j].totalWeaponsPickedUp;
- e->log.stats[j].totalShotDistances += log->stats[j].totalShotDistances;
- }
-
- e->log.n += 1.0f;
-}
-
-void stepEnv(iwEnv *e) {
- if (e->needsReset) {
- DEBUG_LOG("Resetting environment");
- resetEnv(e);
-
-#ifdef __EMSCRIPTEN__
- lastFrameTime = emscripten_get_now();
- accumulator = 0.0;
-#endif
- }
-
- agentActions stepActions[e->numDrones];
- memset(stepActions, 0x0, e->numDrones * sizeof(agentActions));
-
- // preprocess agent actions for the next frameSkip steps
- for (uint8_t i = 0; i < e->numDrones; i++) {
- droneEntity *drone = safe_array_get_at(e->drones, i);
- if (drone->dead || droneControlledByHuman(e, i)) {
- continue;
- }
-
- if (i < e->numAgents) {
- stepActions[i] = computeActions(e, drone, NULL);
- } else {
- const agentActions scriptedActions = scriptedAgentActions(e, drone);
- stepActions[i] = computeActions(e, drone, &scriptedActions);
- }
- }
-
- // reset reward buffer
- memset(e->rewards, 0x0, e->numAgents * sizeof(float));
-
- for (int i = 0; i < e->frameSkip; i++) {
-#ifdef __EMSCRIPTEN__
- // running at a fixed frame rate doesn't seem to work well in
- // the browser, so we need to adjust to handle a variable frame
- // rate; see https://www.gafferongames.com/post/fix_your_timestep/
- const double curTime = emscripten_get_now();
- const double deltaTime = (curTime - lastFrameTime) / 1000.0;
- lastFrameTime = curTime;
-
- accumulator += deltaTime;
- while (accumulator >= e->deltaTime) {
- if (e->needsReset) {
- break;
- }
-#endif
- e->episodeLength++;
-
- // handle actions
- if (e->client != NULL) {
- updateHumanInputToggle(e);
- }
-
- for (uint8_t i = 0; i < e->numDrones; i++) {
- droneEntity *drone = safe_array_get_at(e->drones, i);
- memset(&drone->stepInfo, 0x0, sizeof(droneStepInfo));
- if (drone->dead) {
- drone->diedThisStep = false;
- }
- memset(&drone->killed, 0x0, sizeof(drone->killed));
- }
-
- for (uint8_t i = 0; i < e->numDrones; i++) {
- droneEntity *drone = safe_array_get_at(e->drones, i);
- if (drone->dead) {
- continue;
- }
-
- agentActions actions;
- // take inputs from humans every frame
- if (droneControlledByHuman(e, i)) {
- actions = getPlayerInputs(e, drone, i - e->humanDroneInput);
- } else {
- actions = stepActions[i];
- }
-
- if (actions.discardWeapon) {
- droneDiscardWeapon(e, drone);
- }
- if (actions.shoot) {
- droneShoot(e, drone, actions.aim, actions.chargingWeapon);
- }
- if (actions.chargingBurst) {
- droneChargeBurst(e, drone);
- } else if (drone->chargingBurst) {
- droneBurst(e, drone);
- }
- if (!b2VecEqual(actions.move, b2Vec2_zero)) {
- droneMove(e, drone, actions.move);
- }
- droneBrake(e, drone, actions.brake);
-
- // update shield velocity if its active
- if (drone->shield != NULL) {
- b2Body_SetLinearVelocity(drone->shield->bodyID, b2Body_GetLinearVelocity(drone->bodyID));
- }
- }
-
- b2World_Step(e->worldID, e->deltaTime, e->box2dSubSteps);
-
- // update dynamic body positions and velocities
- handleBodyMoveEvents(e);
-
- // handle collisions
- handleContactEvents(e);
- handleSensorEvents(e);
-
- // handle sudden death
- e->stepsLeft = max(e->stepsLeft - 1, 0);
- if ((!e->isTraining || e->numDrones == e->numAgents) && e->stepsLeft == 0) {
- e->suddenDeathSteps = max(e->suddenDeathSteps - 1, 0);
- if (e->suddenDeathSteps == 0) {
- DEBUG_LOG("placing sudden death walls");
- handleSuddenDeath(e);
- e->suddenDeathSteps = e->totalSuddenDeathSteps;
- }
- }
-
- projectilesStep(e);
-
- int8_t lastAlive = -1;
- int8_t lastAliveTeam = -1;
- bool allAliveOnSameTeam = false;
- bool roundOver = false;
- uint8_t deadDrones = 0;
- for (uint8_t i = 0; i < e->numDrones; i++) {
- droneEntity *drone = safe_array_get_at(e->drones, i);
- if (drone->livesLeft != 0) {
- if (!droneStep(e, drone)) {
- // couldn't find a respawn position, end the round
- deadDrones++;
- roundOver = true;
- }
- lastAlive = i;
-
- if (e->teamsEnabled) {
- if (lastAliveTeam == -1) {
- lastAliveTeam = drone->team;
- allAliveOnSameTeam = true;
- } else if (drone->team != lastAliveTeam) {
- allAliveOnSameTeam = false;
- }
- }
- } else {
- deadDrones++;
- if (i < e->numAgents) {
- if (drone->diedThisStep) {
- e->terminals[i] = 1;
- }
- // else {
- // e->masks[i] = 0;
- // }
- }
- }
- }
-
- weaponPickupsStep(e);
-
- if (!roundOver) {
- roundOver = deadDrones >= e->numDrones - 1;
- }
- if (e->teamsEnabled && allAliveOnSameTeam) {
- roundOver = true;
- lastAlive = -1;
- }
- // if the enemy drone(s) are scripted don't enable sudden death
- // so that the agent has to work for victories
- if (e->isTraining && e->numDrones != e->numAgents && e->stepsLeft == 0) {
- roundOver = true;
- lastAliveTeam = -1;
- }
- if (roundOver && deadDrones < e->numDrones - 1) {
- lastAlive = -1;
- }
- computeRewards(e, roundOver, lastAlive, lastAliveTeam);
-
- if (e->client != NULL) {
- renderEnv(e, false, roundOver, lastAlive, lastAliveTeam);
- }
-
- if (roundOver) {
- if (e->numDrones != e->numAgents && e->stepsLeft == 0) {
- DEBUG_LOG("truncating episode");
- memset(e->truncations, 1, e->numAgents * sizeof(uint8_t));
- } else {
- DEBUG_LOG("terminating episode");
- memset(e->terminals, 1, e->numAgents * sizeof(uint8_t));
- }
-
- Log log = {0};
- log.length = e->episodeLength;
- if (lastAlive != -1) {
- e->stats[lastAlive].wins = 1.0f;
- } else if (!e->teamsEnabled || (e->teamsEnabled && lastAliveTeam == -1)) {
- log.ties = 1.0f;
- }
-
- for (uint8_t i = 0; i < e->numDrones; i++) {
- const droneEntity *drone = safe_array_get_at(e->drones, i);
- if (!drone->dead && e->teamsEnabled && drone->team == lastAliveTeam) {
- e->stats[i].wins = 1.0f;
- }
- // set absolute distance traveled of agent drones
- e->stats[i].absDistanceTraveled = b2Distance(drone->initalPos, drone->pos);
- }
-
- memcpy(log.stats, e->stats, sizeof(e->stats));
- addLog(e, &log);
-
- e->needsReset = true;
- break;
- }
-#ifdef __EMSCRIPTEN__
- accumulator -= e->deltaTime;
- }
-
- if (e->needsReset) {
- break;
- }
-#endif
- }
-
-#ifndef NDEBUG
- bool gotReward = false;
- for (uint8_t i = 0; i < e->numDrones; i++) {
- if (e->rewards[i] > REWARD_EPS || e->rewards[i] < -REWARD_EPS) {
- gotReward = true;
- break;
- }
- }
- if (gotReward) {
- DEBUG_RAW_LOG("!!! rewards: [");
- for (uint8_t i = 0; i < e->numDrones; i++) {
- const float reward = e->rewards[i];
- DEBUG_RAW_LOGF("%f", reward);
- if (i < e->numDrones - 1) {
- DEBUG_RAW_LOG(", ");
- }
- }
- DEBUG_RAW_LOGF("] step %d\n", e->totalSteps - e->stepsLeft);
- }
-#endif
-
- computeObs(e);
-}
-
-#endif
diff --git a/pufferlib/ocean/impulse_wars/game.h b/pufferlib/ocean/impulse_wars/game.h
deleted file mode 100644
index 7a8260d23..000000000
--- a/pufferlib/ocean/impulse_wars/game.h
+++ /dev/null
@@ -1,2854 +0,0 @@
-#ifndef IMPULSE_WARS_GAME_H
-#define IMPULSE_WARS_GAME_H
-
-#include "helpers.h"
-#include "settings.h"
-#include "types.h"
-
-// these functions call each other so need to be forward declared
-void destroyProjectile(iwEnv *e, projectileEntity *projectile, const bool processExplosions, const bool full);
-void createExplosion(iwEnv *e, droneEntity *drone, const projectileEntity *projectile, const b2ExplosionDef *def);
-
-void updateTrailPoints(trailPoints *tp, const uint8_t maxLen, const b2Vec2 pos);
-
-entity *createEntity(iwEnv *e, enum entityType type, void *entityData) {
- int32_t id = b2AllocId(&e->idPool);
- entity *ent = NULL;
- if (id == (int64_t)cc_array_size(e->entities)) {
- ent = fastCalloc(1, sizeof(entity));
- ent->id = fastCalloc(1, sizeof(entityID));
- cc_array_add(e->entities, ent);
- } else {
- ent = safe_array_get_at(e->entities, id);
- }
-
- ent->generation += 1;
- ent->type = type;
- ent->entity = entityData;
- ent->id->id = id + 1,
- ent->id->generation = ent->generation;
-
- return ent;
-}
-
-void destroyEntity(iwEnv *e, entity *ent) {
- b2FreeId(&e->idPool, ent->id->id - 1);
- ent->id->id = 0;
-}
-
-// will return a pointer to an entity or NULL if the given entity ID is
-// invalid or orphaned
-entity *getEntityByID(const iwEnv *e, const entityID *id) {
- if (id->id < 1 || (int64_t)cc_array_size(e->entities) < id->id) {
- // invalid index
- return NULL;
- }
- entity *ent = safe_array_get_at(e->entities, id->id - 1);
- if (ent->id->id == 0 || ent->generation != id->generation) {
- // orphaned entity
- return NULL;
- }
- return ent;
-}
-
-static inline bool entityTypeIsWall(const enum entityType type) {
- // walls are the first 3 entity types
- return type <= DEATH_WALL_ENTITY;
-}
-
-static inline int16_t cellIndex(const iwEnv *e, const int8_t col, const int8_t row) {
- return col + (row * e->map->columns);
-}
-
-// discretizes an entity's position into a cell index; -1 is returned if
-// the position is out of bounds of the map
-static inline int16_t entityPosToCellIdx(const iwEnv *e, const b2Vec2 pos) {
- const float cellX = pos.x + (((float)e->map->columns * WALL_THICKNESS) / 2.0f);
- const float cellY = pos.y + (((float)e->map->rows * WALL_THICKNESS) / 2.0f);
- const int8_t cellCol = cellX / WALL_THICKNESS;
- const int8_t cellRow = cellY / WALL_THICKNESS;
- const int16_t cellIdx = cellIndex(e, cellCol, cellRow);
- // set the cell to -1 if it's out of bounds
- if (cellIdx < 0 || (uint16_t)cellIdx >= cc_array_size(e->cells)) {
- DEBUG_LOGF("invalid cell index: %d from position: (%f, %f)", cellIdx, pos.x, pos.y);
- return -1;
- }
- return cellIdx;
-}
-
-typedef struct overlapAABBCtx {
- bool overlaps;
-} overlapAABBCtx;
-
-bool overlapAABBCallback(b2ShapeId shapeID, void *context) {
- if (!b2Shape_IsValid(shapeID)) {
- return true;
- }
-
- overlapAABBCtx *ctx = context;
- ctx->overlaps = true;
- return true;
-}
-
-// returns true if the given position overlaps with shapes in a bounding
-// box with a height and width of distance
-bool isOverlappingAABB(const iwEnv *e, const b2Vec2 pos, const float distance, const b2QueryFilter filter) {
- b2AABB bounds = {
- .lowerBound = {.x = pos.x - distance, .y = pos.y - distance},
- .upperBound = {.x = pos.x + distance, .y = pos.y + distance},
- };
- overlapAABBCtx ctx = {.overlaps = false};
- b2World_OverlapAABB(e->worldID, bounds, filter, overlapAABBCallback, &ctx);
- return ctx.overlaps;
-}
-
-// TODO: store a shape proxy in entities?
-b2ShapeProxy makeDistanceProxyFromType(const enum entityType type, bool *isCircle) {
- b2ShapeProxy proxy = {0};
- switch (type) {
- case DRONE_ENTITY:
- *isCircle = true;
- proxy.count = 1;
- proxy.radius = DRONE_RADIUS;
- break;
- case SHIELD_ENTITY:
- *isCircle = true;
- proxy.count = 1;
- proxy.radius = DRONE_SHIELD_RADIUS;
- break;
- case WEAPON_PICKUP_ENTITY:
- proxy.count = 4;
- proxy.points[0] = (b2Vec2){.x = -PICKUP_THICKNESS / 2.0f, .y = -PICKUP_THICKNESS / 2.0f};
- proxy.points[1] = (b2Vec2){.x = -PICKUP_THICKNESS / 2.0f, .y = +PICKUP_THICKNESS / 2.0f};
- proxy.points[2] = (b2Vec2){.x = +PICKUP_THICKNESS / 2.0f, .y = -PICKUP_THICKNESS / 2.0f};
- proxy.points[3] = (b2Vec2){.x = +PICKUP_THICKNESS / 2.0f, .y = +PICKUP_THICKNESS / 2.0f};
- break;
- case STANDARD_WALL_ENTITY:
- case BOUNCY_WALL_ENTITY:
- case DEATH_WALL_ENTITY:
- proxy.count = 4;
- proxy.points[0] = (b2Vec2){.x = -FLOATING_WALL_THICKNESS / 2.0f, .y = -FLOATING_WALL_THICKNESS / 2.0f};
- proxy.points[1] = (b2Vec2){.x = -FLOATING_WALL_THICKNESS / 2.0f, .y = +FLOATING_WALL_THICKNESS / 2.0f};
- proxy.points[2] = (b2Vec2){.x = +FLOATING_WALL_THICKNESS / 2.0f, .y = -FLOATING_WALL_THICKNESS / 2.0f};
- proxy.points[3] = (b2Vec2){.x = +FLOATING_WALL_THICKNESS / 2.0f, .y = +FLOATING_WALL_THICKNESS / 2.0f};
- break;
- default:
- ERRORF("unknown entity type for shape distance: %d", type);
- }
-
- return proxy;
-}
-
-b2ShapeProxy makeDistanceProxy(const entity *ent, bool *isCircle) {
- if (ent->type == PROJECTILE_ENTITY) {
- *isCircle = true;
- b2ShapeProxy proxy = {0};
- const projectileEntity *proj = ent->entity;
- proxy.count = 1;
- proxy.radius = proj->weaponInfo->radius;
- return proxy;
- }
-
- return makeDistanceProxyFromType(ent->type, isCircle);
-}
-
-b2Transform entityTransform(const entity *ent) {
- b2Transform transform;
- wallEntity *wall;
- projectileEntity *proj;
- droneEntity *drone;
-
- switch (ent->type) {
- case STANDARD_WALL_ENTITY:
- case BOUNCY_WALL_ENTITY:
- case DEATH_WALL_ENTITY:
- wall = ent->entity;
- transform.p = wall->pos;
- transform.q = wall->rot;
- return transform;
- case PROJECTILE_ENTITY:
- proj = ent->entity;
- transform.p = proj->pos;
- transform.q = b2Rot_identity;
- return transform;
- case DRONE_ENTITY:
- drone = ent->entity;
- transform.p = drone->pos;
- transform.q = b2Rot_identity;
- return transform;
- default:
- ERRORF("unknown entity type: %d", ent->type);
- }
-}
-
-// returns the closest points between two entities
-b2DistanceOutput closestPoint(const entity *srcEnt, const entity *dstEnt) {
- bool isCircle = false;
- b2DistanceInput input;
- input.proxyA = makeDistanceProxy(srcEnt, &isCircle);
- input.proxyB = makeDistanceProxy(dstEnt, &isCircle);
- input.transformA = entityTransform(srcEnt);
- input.transformB = entityTransform(dstEnt);
- if (input.proxyA.radius != 0.0f && input.proxyB.radius != 0.0f) {
- b2DistanceOutput output = {0};
- output.distance = b2Distance(input.transformB.p, input.transformA.p) - input.proxyA.radius - input.proxyB.radius;
- output.normal = b2Normalize(b2Sub(input.transformB.p, input.transformA.p));
- output.pointA = b2MulAdd(input.transformA.p, input.proxyA.radius, output.normal);
- output.pointB = b2MulAdd(input.transformB.p, input.proxyB.radius, output.normal);
- return output;
- }
-
- input.useRadii = isCircle;
-
- b2SimplexCache cache = {0};
- return b2ShapeDistance(&input, &cache, NULL, 0);
-}
-
-typedef struct behindWallContext {
- const entity *dstEnt;
- const enum entityType *targetType;
- bool hit;
-} behindWallContext;
-
-float posBehindWallCallback(b2ShapeId shapeID, b2Vec2 point, b2Vec2 normal, float fraction, void *context) {
- // these are unused but required by the b2CastResultFcn callback prototype
- MAYBE_UNUSED(point);
- MAYBE_UNUSED(normal);
- MAYBE_UNUSED(fraction);
-
- behindWallContext *ctx = context;
- const entity *ent = b2Shape_GetUserData(shapeID);
- if (ent == ctx->dstEnt || (ctx->targetType != NULL && ent->type == *ctx->targetType)) {
- return -1;
- }
- ctx->hit = true;
- return 0;
-}
-
-// returns true if there are shapes that match filter between startPos and endPos
-bool posBehindWall(const iwEnv *e, const b2Vec2 srcPos, const b2Vec2 dstPos, const entity *dstEnt, const b2QueryFilter filter, const enum entityType *targetType) {
- const float rayDistance = b2Distance(srcPos, dstPos);
- // if the two points are extremely close we can safely assume the
- // entity isn't behind a wall
- if (rayDistance <= 1.0f) {
- return false;
- }
-
- const b2Vec2 translation = b2Sub(dstPos, srcPos);
- behindWallContext ctx = {
- .dstEnt = dstEnt,
- .targetType = targetType,
- .hit = false,
- };
- b2World_CastRay(e->worldID, srcPos, translation, filter, posBehindWallCallback, &ctx);
- return ctx.hit;
-}
-
-typedef struct overlapCircleCtx {
- const iwEnv *e;
- const entity *ent;
- const enum entityType *targetType;
- const b2QueryFilter filter;
- bool overlaps;
-} overlapCircleCtx;
-
-bool isOverlappingCircleCallback(b2ShapeId shapeID, void *context) {
- if (!b2Shape_IsValid(shapeID)) {
- return true;
- }
-
- overlapCircleCtx *ctx = context;
- const entity *overlappingEnt = b2Shape_GetUserData(shapeID);
- if (ctx->targetType != NULL && overlappingEnt->type != *ctx->targetType) {
- return true;
- }
-
- const b2DistanceOutput output = closestPoint(ctx->ent, overlappingEnt);
- const bool behind = posBehindWall(ctx->e, output.pointA, output.pointB, ctx->ent, ctx->filter, ctx->targetType);
- if (!behind) {
- ctx->overlaps = true;
- } else if (ctx->ent->type == PROJECTILE_ENTITY) {
- projectileEntity *proj = ctx->ent->entity;
- droneEntity *drone = overlappingEnt->entity;
- proj->dronesBehindWalls[proj->numDronesBehindWalls++] = drone->idx;
- }
- return behind;
-}
-
-bool isOverlappingCircleInLineOfSight(const iwEnv *e, const entity *ent, const b2Vec2 startPos, const float radius, const b2QueryFilter filter, const enum entityType *targetType) {
- const b2ShapeProxy cirProxy = b2MakeProxy(&startPos, 1, radius);
- overlapCircleCtx ctx = {
- .e = e,
- .ent = ent,
- .targetType = targetType,
- .filter = (b2QueryFilter){
- .categoryBits = filter.categoryBits,
- .maskBits = WALL_SHAPE | FLOATING_WALL_SHAPE,
- },
- .overlaps = false,
- };
- b2World_OverlapShape(e->worldID, &cirProxy, filter, isOverlappingCircleCallback, &ctx);
- return ctx.overlaps;
-}
-
-uint8_t cellOffsets[8][2] = {
- {-1, 0}, // left
- {1, 0}, // right
- {0, -1}, // up
- {0, 1}, // down
- {-1, -1}, // top-left
- {1, -1}, // top-right
- {-1, 1}, // bottom-left
- {1, 1}, // bottom-right
-};
-
-// returns true and sets emptyPos to the position of an empty cell
-// that is an appropriate distance away from other entities if one exists;
-// if quad is set to -1 a random valid position from anywhere on the map
-// will be returned, otherwise a position within the specified quadrant
-// will be returned
-bool findOpenPos(iwEnv *e, const enum shapeCategory shapeType, b2Vec2 *emptyPos, int8_t quad) {
- uint8_t checkedCells[BITNSLOTS(MAX_CELLS)] = {0};
- const size_t nCells = cc_array_size(e->cells) - 1;
- uint16_t attempts = 0;
- bool laxDroneDistanceChecks = false;
- float minSpawnDistance = MIN_SPAWN_DISTANCE;
-
- while (true) {
- if (attempts == nCells) {
- // if we're trying to find a position for a drone and sudden
- // death walls have been placed, try again this time ignoring
- // distance checks; the drone must be spawned next
- // to a death wall in this case
- if (shapeType == DRONE_SHAPE && e->suddenDeathWallsPlaced && !laxDroneDistanceChecks) {
- attempts = 0;
- memset(checkedCells, 0x0, BITNSLOTS(MAX_CELLS));
- laxDroneDistanceChecks = true;
- minSpawnDistance = MIN_SD_SPAWN_DISTANCE;
- continue;
- }
- return false;
- }
-
- uint16_t cellIdx;
- if (quad == -1) {
- cellIdx = randInt(&e->randState, 0, nCells);
- } else {
- const float minX = e->map->spawnQuads[quad].min.x;
- const float minY = e->map->spawnQuads[quad].min.y;
- const float maxX = e->map->spawnQuads[quad].max.x;
- const float maxY = e->map->spawnQuads[quad].max.y;
-
- b2Vec2 randPos = {.x = randFloat(&e->randState, minX, maxX), .y = randFloat(&e->randState, minY, maxY)};
- cellIdx = entityPosToCellIdx(e, randPos);
- }
- if (bitTest(checkedCells, cellIdx)) {
- continue;
- }
- bitSet(checkedCells, cellIdx);
- attempts++;
-
- const mapCell *cell = safe_array_get_at(e->cells, cellIdx);
- if (cell->ent != NULL) {
- continue;
- }
-
- bool tooClose = false;
- switch (shapeType) {
- case WEAPON_PICKUP_SHAPE:
- // ensure pickups don't spawn too close to other pickups
- for (uint8_t i = 0; i < cc_array_size(e->pickups); i++) {
- const weaponPickupEntity *pickup = safe_array_get_at(e->pickups, i);
- if (b2DistanceSquared(cell->pos, pickup->pos) < PICKUP_SPAWN_DISTANCE_SQUARED) {
- tooClose = true;
- break;
- }
- }
- if (tooClose) {
- continue;
- }
- break;
- case DRONE_SHAPE:
- if (e->suddenDeathWallsPlaced) {
- if (!laxDroneDistanceChecks) {
- // if sudden death walls have been placed, ignore the
- // spawn points as they may be covered by death walls;
- // instead just try and find a cell that doesn't neighbor
- // a death wall
- const uint8_t cellCol = cellIdx / e->map->columns;
- const uint8_t cellRow = cellIdx % e->map->columns;
- bool deathWallNeighboring = false;
- for (uint8_t i = 0; i < 8; i++) {
- const int8_t col = cellCol + cellOffsets[i][0];
- const int8_t row = cellRow + cellOffsets[i][1];
- if (row < 0 || row >= e->map->rows || col < 0 || col >= e->map->columns) {
- continue;
- }
- const int16_t testCellIdx = cellIndex(e, col, row);
- const mapCell *testCell = safe_array_get_at(e->cells, testCellIdx);
- if (testCell->ent != NULL && testCell->ent->type == DEATH_WALL_ENTITY) {
- deathWallNeighboring = true;
- break;
- }
- }
- if (deathWallNeighboring) {
- continue;
- }
- }
-
- // ensure drones aren't spawning on top of each other
- for (uint8_t i = 0; i < cc_array_size(e->drones); i++) {
- const droneEntity *drone = safe_array_get_at(e->drones, i);
- if (drone->dead) {
- continue;
- }
- if (b2DistanceSquared(cell->pos, drone->pos) == 0.0f) {
- tooClose = true;
- break;
- }
- }
- if (tooClose) {
- continue;
- }
- } else {
- if (!e->map->droneSpawns[cellIdx]) {
- continue;
- }
-
- // ensure drones don't spawn too close to other drones
- for (uint8_t i = 0; i < cc_array_size(e->drones); i++) {
- const droneEntity *drone = safe_array_get_at(e->drones, i);
- if (drone->dead) {
- continue;
- }
- if (b2DistanceSquared(cell->pos, drone->pos) < DRONE_DRONE_SPAWN_DISTANCE_SQUARED) {
- tooClose = true;
- break;
- }
- }
- if (tooClose) {
- continue;
- }
- }
- break;
- default:
- break;
- }
-
- uint64_t maskBits = FLOATING_WALL_SHAPE | WEAPON_PICKUP_SHAPE | DRONE_SHAPE;
- if (shapeType != FLOATING_WALL_SHAPE && !laxDroneDistanceChecks) {
- maskBits &= ~shapeType;
- }
- const b2QueryFilter filter = {
- .categoryBits = shapeType,
- .maskBits = maskBits,
- };
- if (!isOverlappingAABB(e, cell->pos, minSpawnDistance, filter)) {
- *emptyPos = cell->pos;
- return true;
- }
- }
-}
-
-entity *createWall(iwEnv *e, const b2Vec2 pos, const float width, const float height, int16_t cellIdx, const enum entityType type, const bool floating) {
- ASSERT(cellIdx != -1);
- ASSERT(entityTypeIsWall(type));
-
- b2BodyDef wallBodyDef = b2DefaultBodyDef();
- wallBodyDef.position = pos;
- if (floating) {
- wallBodyDef.type = b2_dynamicBody;
- wallBodyDef.linearDamping = FLOATING_WALL_DAMPING;
- wallBodyDef.angularDamping = FLOATING_WALL_DAMPING;
- wallBodyDef.isAwake = false;
- }
- b2BodyId wallBodyID = b2CreateBody(e->worldID, &wallBodyDef);
-
- b2Vec2 extent = {.x = width / 2.0f, .y = height / 2.0f};
- b2ShapeDef wallShapeDef = b2DefaultShapeDef();
- wallShapeDef.invokeContactCreation = false;
- wallShapeDef.density = WALL_DENSITY;
- wallShapeDef.material.restitution = STANDARD_WALL_RESTITUTION;
- wallShapeDef.material.friction = STANDARD_WALL_FRICTION;
- wallShapeDef.filter.categoryBits = WALL_SHAPE;
- wallShapeDef.filter.maskBits = FLOATING_WALL_SHAPE | PROJECTILE_SHAPE | DRONE_SHAPE | SHIELD_SHAPE | DRONE_PIECE_SHAPE;
- if (floating) {
- wallShapeDef.filter.categoryBits = FLOATING_WALL_SHAPE;
- wallShapeDef.filter.maskBits |= WALL_SHAPE | WEAPON_PICKUP_SHAPE;
- wallShapeDef.enableSensorEvents = true;
- }
-
- if (type == BOUNCY_WALL_ENTITY) {
- wallShapeDef.material.restitution = BOUNCY_WALL_RESTITUTION;
- wallShapeDef.material.friction = 0.0f;
- } else if (type == DEATH_WALL_ENTITY) {
- wallShapeDef.enableContactEvents = true;
- }
-
- wallEntity *wall = fastCalloc(1, sizeof(wallEntity));
- wall->bodyID = wallBodyID;
- wall->pos = pos;
- wall->rot = b2Rot_identity;
- wall->velocity = b2Vec2_zero;
- wall->extent = extent;
- wall->mapCellIdx = cellIdx;
- wall->isFloating = floating;
- wall->type = type;
- wall->isSuddenDeath = e->suddenDeathWallsPlaced;
-
- entity *ent = createEntity(e, type, wall);
- wall->ent = ent;
-
- wallShapeDef.userData = ent;
- const b2Polygon wallPolygon = b2MakeBox(extent.x, extent.y);
- wall->shapeID = b2CreatePolygonShape(wallBodyID, &wallShapeDef, &wallPolygon);
- b2Body_SetUserData(wall->bodyID, ent);
-
- if (floating) {
- cc_array_add(e->floatingWalls, wall);
- } else {
- cc_array_add(e->walls, wall);
- }
-
- return ent;
-}
-
-void destroyWall(iwEnv *e, wallEntity *wall, const bool full) {
- destroyEntity(e, wall->ent);
-
- if (full) {
- mapCell *cell = safe_array_get_at(e->cells, wall->mapCellIdx);
- cell->ent = NULL;
- }
-
- b2DestroyBody(wall->bodyID);
- fastFree(wall);
-}
-
-enum weaponType randWeaponPickupType(iwEnv *e) {
- // spawn weapon pickups according to their spawn weights and how many
- // pickups are currently spawned with different weapons
- float totalWeight = 0.0f;
- float spawnWeights[_NUM_WEAPONS - 1] = {0};
- for (uint8_t i = 1; i < NUM_WEAPONS; i++) {
- if (i == e->defaultWeapon->type) {
- continue;
- }
- spawnWeights[i - 1] = weaponInfos[i]->spawnWeight / ((e->spawnedWeaponPickups[i] + 1) * 2.0f);
- totalWeight += spawnWeights[i - 1];
- }
-
- const float randPick = randFloat(&e->randState, 0.0f, totalWeight);
- float cumulativeWeight = 0.0f;
- enum weaponType type = STANDARD_WEAPON;
- for (uint8_t i = 1; i < NUM_WEAPONS; i++) {
- if (i == e->defaultWeapon->type) {
- continue;
- }
- cumulativeWeight += spawnWeights[i - 1];
- if (randPick < cumulativeWeight) {
- type = i;
- break;
- }
- }
- ASSERT(type != STANDARD_WEAPON && type != e->defaultWeapon->type);
- e->spawnedWeaponPickups[type]++;
-
- return type;
-}
-
-void createWeaponPickupBodyShape(const iwEnv *e, weaponPickupEntity *pickup) {
- pickup->bodyDestroyed = false;
-
- b2BodyDef pickupBodyDef = b2DefaultBodyDef();
- pickupBodyDef.position = pickup->pos;
- pickupBodyDef.userData = pickup->ent;
- pickup->bodyID = b2CreateBody(e->worldID, &pickupBodyDef);
-
- b2ShapeDef pickupShapeDef = b2DefaultShapeDef();
- pickupShapeDef.filter.categoryBits = WEAPON_PICKUP_SHAPE;
- pickupShapeDef.filter.maskBits = FLOATING_WALL_SHAPE | DRONE_SHAPE;
- pickupShapeDef.isSensor = true;
- pickupShapeDef.enableSensorEvents = true;
- pickupShapeDef.userData = pickup->ent;
- const b2Polygon pickupPolygon = b2MakeBox(PICKUP_THICKNESS / 2.0f, PICKUP_THICKNESS / 2.0f);
- pickup->shapeID = b2CreatePolygonShape(pickup->bodyID, &pickupShapeDef, &pickupPolygon);
-}
-
-void createWeaponPickup(iwEnv *e) {
- // ensure weapon pickups are initially spawned somewhat uniformly
- b2Vec2 pos;
- e->lastSpawnQuad = (e->lastSpawnQuad + 1) % 4;
- if (!findOpenPos(e, WEAPON_PICKUP_SHAPE, &pos, e->lastSpawnQuad)) {
- ERROR("no open position for weapon pickup");
- }
-
- weaponPickupEntity *pickup = fastCalloc(1, sizeof(weaponPickupEntity));
- pickup->weapon = randWeaponPickupType(e);
- pickup->respawnWait = 0.0f;
- pickup->floatingWallsTouching = 0;
- pickup->pos = pos;
-
- entity *ent = createEntity(e, WEAPON_PICKUP_ENTITY, pickup);
- pickup->ent = ent;
-
- const int16_t cellIdx = entityPosToCellIdx(e, pos);
- if (cellIdx == -1) {
- ERRORF("invalid position for weapon pickup spawn: (%f, %f)", pos.x, pos.y);
- }
- pickup->mapCellIdx = cellIdx;
- mapCell *cell = safe_array_get_at(e->cells, cellIdx);
- cell->ent = ent;
-
- createWeaponPickupBodyShape(e, pickup);
-
- cc_array_add(e->pickups, pickup);
-}
-
-void destroyWeaponPickup(iwEnv *e, weaponPickupEntity *pickup) {
- destroyEntity(e, pickup->ent);
-
- mapCell *cell = safe_array_get_at(e->cells, pickup->mapCellIdx);
- cell->ent = NULL;
-
- if (!pickup->bodyDestroyed) {
- b2DestroyBody(pickup->bodyID);
- }
-
- fastFree(pickup);
-}
-
-// destroys the pickup body and shape while the pickup is waiting to
-// respawn to avoid spurious sensor overlap checks; enabling/disabling
-// a body is almost as expensive and creating a new body in box2d, and
-// manually moving (teleporting) it is expensive as well so destroying
-// the body now and re-creating it later is the fastest
-void disableWeaponPickup(iwEnv *e, weaponPickupEntity *pickup) {
- DEBUG_LOGF("disabling weapon pickup at cell %d (%f, %f)", pickup->mapCellIdx, pickup->pos.x, pickup->pos.y);
-
- pickup->respawnWait = PICKUP_RESPAWN_WAIT;
- if (e->suddenDeathWallsPlaced) {
- pickup->respawnWait = SUDDEN_DEATH_PICKUP_RESPAWN_WAIT;
- }
- b2DestroyBody(pickup->bodyID);
- pickup->bodyDestroyed = true;
-
- mapCell *cell = safe_array_get_at(e->cells, pickup->mapCellIdx);
- ASSERT(cell->ent != NULL);
- cell->ent = NULL;
-
- e->spawnedWeaponPickups[pickup->weapon]--;
-}
-
-void createDroneShield(iwEnv *e, droneEntity *drone, const int8_t groupIdx) {
- // the shield is comprised of 2 shapes over 2 bodies:
- // 1. a kinematic body that allows the parent drone to be unaffected
- // by collisions since kinematic bodies have essentially infinite mass
- // 2. a shape on the drone body that collides with walls and other
- // shields, since kinematic bodies don't collide with other kinematic
- // bodies or static bodies
-
- b2BodyDef shieldBodyDef = b2DefaultBodyDef();
- shieldBodyDef.type = b2_kinematicBody;
- shieldBodyDef.motionLocks = (b2MotionLocks){.angularZ = true};
- shieldBodyDef.position = drone->pos;
- b2BodyId shieldBodyID = b2CreateBody(e->worldID, &shieldBodyDef);
-
- b2ShapeDef shieldShapeDef = b2DefaultShapeDef();
- shieldShapeDef.filter.categoryBits = SHIELD_SHAPE;
- shieldShapeDef.filter.maskBits = PROJECTILE_SHAPE | DRONE_SHAPE;
- shieldShapeDef.filter.groupIndex = groupIdx;
- shieldShapeDef.enableContactEvents = true;
-
- b2ShapeDef shieldBufferShapeDef = b2DefaultShapeDef();
- shieldBufferShapeDef.density = 0.0f;
- shieldBufferShapeDef.material.friction = DRONE_FRICTION;
- shieldBufferShapeDef.material.restitution = DRONE_RESTITUTION;
- shieldBufferShapeDef.filter.categoryBits = SHIELD_SHAPE;
- shieldBufferShapeDef.filter.maskBits = WALL_SHAPE | FLOATING_WALL_SHAPE | SHIELD_SHAPE;
- shieldBufferShapeDef.filter.groupIndex = groupIdx;
-
- shieldEntity *shield = fastCalloc(1, sizeof(shieldEntity));
- shield->drone = drone;
- shield->bodyID = shieldBodyID;
- shield->pos = drone->pos;
- shield->health = DRONE_SHIELD_HEALTH;
- float duration = DRONE_SHIELD_START_DURATION;
- if (drone->livesLeft != DRONE_LIVES) {
- duration = DRONE_SHIELD_RESPAWN_DURATION;
- }
- shield->duration = duration;
-
- entity *ent = createEntity(e, SHIELD_ENTITY, shield);
- shield->ent = ent;
-
- shieldShapeDef.userData = ent;
- const b2Circle shieldCircle = {.center = b2Vec2_zero, .radius = DRONE_SHIELD_RADIUS};
- shield->shapeID = b2CreateCircleShape(shieldBodyID, &shieldShapeDef, &shieldCircle);
- b2Body_SetUserData(shield->bodyID, ent);
-
- shieldBufferShapeDef.userData = ent;
- shield->bufferShapeID = b2CreateCircleShape(drone->bodyID, &shieldBufferShapeDef, &shieldCircle);
-
- drone->shield = shield;
-}
-
-void createDrone(iwEnv *e, const uint8_t idx) {
- const int8_t groupIdx = -(idx + 1);
- b2BodyDef droneBodyDef = b2DefaultBodyDef();
- droneBodyDef.type = b2_dynamicBody;
-
- int8_t spawnQuad = -1;
- if (!e->isTraining) {
- // spawn drones in diagonal quadrants from each other so that
- // they're more likely to be further apart if we're not training;
- // doing this while training will result in much slower learning
- // due to drones starting much farther apart
- if (e->lastSpawnQuad == -1) {
- spawnQuad = randInt(&e->randState, 0, 3);
- } else if (e->numDrones == 2) {
- spawnQuad = 3 - e->lastSpawnQuad;
- } else {
- spawnQuad = (e->lastSpawnQuad + 1) % 4;
- }
- e->lastSpawnQuad = spawnQuad;
- }
- if (!findOpenPos(e, DRONE_SHAPE, &droneBodyDef.position, spawnQuad)) {
- ERROR("no open position for drone");
- }
-
- droneBodyDef.motionLocks = (b2MotionLocks){.angularZ = true};
- droneBodyDef.linearDamping = DRONE_LINEAR_DAMPING;
- b2BodyId droneBodyID = b2CreateBody(e->worldID, &droneBodyDef);
- b2ShapeDef droneShapeDef = b2DefaultShapeDef();
- droneShapeDef.density = DRONE_DENSITY;
- droneShapeDef.material.friction = DRONE_FRICTION;
- droneShapeDef.material.restitution = DRONE_RESTITUTION;
- droneShapeDef.filter.categoryBits = DRONE_SHAPE;
- droneShapeDef.filter.maskBits = WALL_SHAPE | FLOATING_WALL_SHAPE | WEAPON_PICKUP_SHAPE | PROJECTILE_SHAPE | DRONE_SHAPE | SHIELD_SHAPE;
- droneShapeDef.filter.groupIndex = groupIdx;
- droneShapeDef.enableContactEvents = true;
- droneShapeDef.enableSensorEvents = true;
- const b2Circle droneCircle = {.center = b2Vec2_zero, .radius = DRONE_RADIUS};
-
- droneEntity *drone = fastCalloc(1, sizeof(droneEntity));
- drone->bodyID = droneBodyID;
- drone->weaponInfo = e->defaultWeapon;
- drone->ammo = weaponAmmo(e->defaultWeapon->type, drone->weaponInfo->type);
- drone->energyLeft = DRONE_ENERGY_MAX;
- drone->idx = idx;
- drone->team = idx;
- if (e->teamsEnabled) {
- drone->team = idx / (e->numDrones / 2);
- }
- drone->initalPos = droneBodyDef.position;
- drone->pos = droneBodyDef.position;
- drone->mapCellIdx = entityPosToCellIdx(e, droneBodyDef.position);
- drone->lastAim = (b2Vec2){.x = 0.0f, .y = -1.0f};
- drone->livesLeft = DRONE_LIVES;
- create_array(&drone->brakeTrailPoints, 64);
- drone->respawnGuideLifetime = UINT16_MAX;
- memset(&drone->stepInfo, 0x0, sizeof(droneStepInfo));
- create_array(&drone->physicsTracking, 128);
- drone->killedBy = -1;
-
- entity *ent = createEntity(e, DRONE_ENTITY, drone);
- drone->ent = ent;
-
- droneShapeDef.userData = ent;
- drone->shapeID = b2CreateCircleShape(droneBodyID, &droneShapeDef, &droneCircle);
- b2Body_SetUserData(drone->bodyID, ent);
-
- cc_array_add(e->drones, drone);
-
- createDroneShield(e, drone, groupIdx);
-}
-
-void droneAddEnergy(droneEntity *drone, float energy) {
- // if a burst is charging, add the energy to the burst charge
- if (drone->chargingBurst) {
- drone->burstCharge = clamp(drone->burstCharge + energy);
- } else {
- drone->energyLeft = clamp(drone->energyLeft + energy);
- }
-}
-
-void createDronePiece(iwEnv *e, droneEntity *drone, const bool fromShield) {
- const float distance = randFloat(&e->randState, DRONE_PIECE_MIN_DISTANCE, DRONE_PIECE_MAX_DISTANCE);
- const b2Vec2 direction = {.x = randFloat(&e->randState, -1.0f, 1.0f), .y = randFloat(&e->randState, -1.0f, 1.0f)};
- const b2Vec2 pos = b2MulAdd(drone->pos, distance, direction);
- const b2Rot rot = b2MakeRot(randFloat(&e->randState, -PI, PI));
-
- dronePieceEntity *piece = fastCalloc(1, sizeof(dronePieceEntity));
- piece->droneIdx = drone->idx;
- piece->pos = pos;
- piece->rot = rot;
- piece->isShieldPiece = fromShield;
- piece->lifetime = UINT16_MAX;
-
- entity *ent = createEntity(e, DRONE_PIECE_ENTITY, piece);
- piece->ent = ent;
-
- b2BodyDef pieceBodyDef = b2DefaultBodyDef();
- pieceBodyDef.type = b2_dynamicBody;
-
- pieceBodyDef.position = pos;
- pieceBodyDef.rotation = rot;
- pieceBodyDef.linearDamping = DRONE_PIECE_LINEAR_DAMPING;
- pieceBodyDef.angularDamping = DRONE_PIECE_ANGULAR_DAMPING;
- const float bonus = 1.0f + min(b2Length(drone->velocity) / 15.0f, 5.0f);
- const float speed = randFloat(&e->randState, DRONE_PIECE_MIN_SPEED, DRONE_PIECE_MAX_SPEED) * bonus;
- pieceBodyDef.linearVelocity = b2MulSV(speed, direction);
- pieceBodyDef.angularVelocity = randFloat(&e->randState, -PI, PI);
- pieceBodyDef.userData = ent;
- piece->bodyID = b2CreateBody(e->worldID, &pieceBodyDef);
-
- b2ShapeDef pieceShapeDef = b2DefaultShapeDef();
- pieceShapeDef.filter.categoryBits = DRONE_PIECE_SHAPE;
- pieceShapeDef.filter.maskBits = WALL_SHAPE | FLOATING_WALL_SHAPE | DRONE_PIECE_SHAPE;
- pieceShapeDef.density = 1.0f;
- pieceShapeDef.material.friction = 0.5f;
- pieceShapeDef.userData = ent;
-
- // make pieces from the shield a bit smaller
- if (fromShield) {
- piece->vertices[0] = (b2Vec2){.x = 0.0f, .y = -1.0f};
- piece->vertices[1] = (b2Vec2){.x = -0.5f, .y = 0.0f};
- piece->vertices[2] = (b2Vec2){.x = 0.5f, .y = 0.0f};
- } else {
- piece->vertices[0] = (b2Vec2){.x = 0.0f, .y = -1.5f};
- piece->vertices[1] = (b2Vec2){.x = -0.75f, .y = 0.0f};
- piece->vertices[2] = (b2Vec2){.x = 0.75f, .y = 0.0f};
- }
-
- const b2Hull pieceHull = b2ComputeHull(piece->vertices, 3);
- const b2Polygon piecePolygon = b2MakePolygon(&pieceHull, 0.0f);
- piece->shapeID = b2CreatePolygonShape(piece->bodyID, &pieceShapeDef, &piecePolygon);
-
- cc_array_add(e->dronePieces, piece);
-}
-
-void destroyDronePiece(iwEnv *e, dronePieceEntity *piece) {
- b2DestroyBody(piece->bodyID);
- destroyEntity(e, piece->ent);
- fastFree(piece);
-}
-
-void destroyDroneShield(iwEnv *e, shieldEntity *shield, const bool createPieces) {
- droneEntity *drone = shield->drone;
- const float health = shield->health;
- if (health <= 0.0f) {
- droneAddEnergy(drone, DRONE_SHIELD_BREAK_ENERGY_COST);
- }
- drone->shield = NULL;
-
- b2DestroyBody(shield->bodyID);
- b2DestroyShape(shield->bufferShapeID, false);
- destroyEntity(e, shield->ent);
- fastFree(shield);
-
- if (!createPieces || health > 0.0f) {
- return;
- }
-
- // only create pieces if the shield was broken early
- for (uint8_t i = 0; i < DRONE_PIECE_COUNT; i++) {
- createDronePiece(e, drone, true);
- }
-}
-
-void destroyDrone(iwEnv *e, droneEntity *drone) {
- for (size_t i = 0; i < cc_array_size(drone->brakeTrailPoints); i++) {
- brakeTrailPoint *trailPoint = safe_array_get_at(drone->brakeTrailPoints, i);
- fastFree(trailPoint);
- }
- cc_array_destroy(drone->brakeTrailPoints);
- for (size_t i = 0; i < cc_array_size(drone->physicsTracking); i++) {
- physicsStepInfo *physicsStep = safe_array_get_at(drone->physicsTracking, i);
- fastFree(physicsStep);
- }
- cc_array_destroy(drone->physicsTracking);
-
- destroyEntity(e, drone->ent);
-
- shieldEntity *shield = drone->shield;
- if (shield != NULL) {
- destroyDroneShield(e, shield, false);
- }
-
- b2DestroyBody(drone->bodyID);
- fastFree(drone);
-}
-
-void droneApplyForce(const iwEnv *e, const droneEntity *drone, const b2Vec2 force, const uint8_t srcIdx) {
- b2Body_ApplyForceToCenter(drone->bodyID, force, true);
-
- physicsStepInfo *physicsStep = fastCalloc(1, sizeof(physicsStepInfo));
- physicsStep->srcIdx = srcIdx;
- physicsStep->force = force;
- physicsStep->step = e->episodeLength;
- cc_array_add(drone->physicsTracking, physicsStep);
-}
-
-void droneTrackImpulse(const iwEnv *e, const droneEntity *drone, const b2Vec2 impulse, const uint8_t srcIdx) {
- physicsStepInfo *physicsStep = fastCalloc(1, sizeof(physicsStepInfo));
- physicsStep->srcIdx = srcIdx;
- physicsStep->impulse = impulse;
- physicsStep->step = e->episodeLength;
- cc_array_add(drone->physicsTracking, physicsStep);
-}
-
-void droneApplyImpulse(const iwEnv *e, const droneEntity *drone, const b2Vec2 impulse, const uint8_t srcIdx) {
- b2Body_ApplyLinearImpulseToCenter(drone->bodyID, impulse, true);
- droneTrackImpulse(e, drone, impulse, srcIdx);
-}
-
-void droneTrackBrake(const iwEnv *e, const droneEntity *drone) {
- physicsStepInfo *physicsStep = fastCalloc(1, sizeof(physicsStepInfo));
- physicsStep->brakeToggled = true;
- physicsStep->step = e->episodeLength;
- cc_array_add(drone->physicsTracking, physicsStep);
-}
-
-void droneChangeWeapon(const iwEnv *e, droneEntity *drone, const enum weaponType newWeapon) {
- // top up ammo but change nothing else if the weapon is the same
- if (drone->weaponInfo->type != newWeapon || drone->dead) {
- drone->weaponInfo = weaponInfos[newWeapon];
- drone->weaponCooldown = 0.0f;
- drone->weaponCharge = 0.0f;
- drone->heat = 0;
- }
- drone->ammo = weaponAmmo(e->defaultWeapon->type, drone->weaponInfo->type);
-}
-
-void findDroneKiller(const iwEnv *e, droneEntity *drone) {
- b2Vec2 contrib[e->numDrones];
- memset(contrib, 0x0, e->numDrones * sizeof(b2Vec2));
- uint16_t step = 0;
- bool braking = false;
- float droneDamping = DRONE_LINEAR_DAMPING;
-
- // calculate the contribution of forces and impulses of each drone
- for (size_t i = 0; i < cc_array_size(drone->physicsTracking); i++) {
- physicsStepInfo *physicsStep = safe_array_get_at(drone->physicsTracking, i);
- // if the step has changed, apply damping to contributions
- if (physicsStep->step != step) {
- const uint16_t stepDiff = physicsStep->step - step;
- const float damp = 1.0f / (1.0f + (droneDamping * (e->deltaTime * stepDiff)));
- for (uint8_t k = 0; k < e->numDrones; k++) {
- contrib[k] = b2MulSV(damp, contrib[k]);
- }
-
- step = physicsStep->step;
- }
-
- if (physicsStep->brakeToggled) {
- braking = !braking;
- if (braking) {
- droneDamping = DRONE_BRAKE_DAMPING_COEF;
- } else {
- droneDamping = DRONE_LINEAR_DAMPING;
- }
- }
-
- const b2Vec2 invForce = b2MulSV(DRONE_INV_MASS, physicsStep->force);
- contrib[physicsStep->srcIdx] = b2MulAdd(contrib[physicsStep->srcIdx], e->deltaTime, invForce);
- contrib[physicsStep->srcIdx] = b2MulAdd(contrib[physicsStep->srcIdx], DRONE_INV_MASS, physicsStep->impulse);
-
- // DEBUG_LOGF("# step %d drone %d contrib %f (%f, %f)", physicsStep->step, physicsStep->srcIdx, b2Length(contrib[physicsStep->srcIdx]), contrib[physicsStep->srcIdx].x, contrib[physicsStep->srcIdx].y);
- }
-
- // determine the killer by finding the drone that pushed the dead
- // drone towards the wall that killed it the most
- const b2Vec2 deathNormal = b2Normalize(drone->lastVelocity);
- DEBUG_LOGF("> death normal (%f, %f) velocity (%f, %f)", deathNormal.x, deathNormal.y, drone->lastVelocity.x, drone->lastVelocity.y);
- float maxContrib = -FLT_MAX;
- int8_t killer = -1;
- for (uint8_t i = 0; i < e->numDrones; i++) {
- DEBUG_LOGF("---\n> src drone contrib %d %f (%f, %f)", i, b2Length(contrib[i]), contrib[i].x, contrib[i].y);
- if (b2VecEqual(contrib[i], b2Vec2_zero)) {
- continue;
- }
-
- const b2Vec2 normContrib = b2Normalize(contrib[i]);
- const float dot = b2Dot(normContrib, deathNormal);
- DEBUG_LOGF("> > src drone %d norm contrib (%f, %f)", i, normContrib.x, normContrib.y);
- DEBUG_LOGF("> src drone %d death normal dot %f", i, dot);
- const float totalContrib = b2Length(contrib[i]) * dot;
- DEBUG_LOGF("> src drone %d total contrib %f", i, totalContrib);
- if (totalContrib > maxContrib) {
- maxContrib = totalContrib;
- killer = i;
- }
- }
- if (killer == -1) {
- return;
- }
-
- DEBUG_LOGF(">>> drone %d killed by drone %d", drone->idx, killer);
-
- drone->killedBy = killer;
- droneEntity *killerDrone = safe_array_get_at(e->drones, killer);
- killerDrone->killed[drone->idx] = true;
-}
-
-void killDrone(iwEnv *e, droneEntity *drone) {
- if (drone->dead || drone->livesLeft == 0) {
- return;
- }
- DEBUG_LOGF("drone %d died", drone->idx);
-
- findDroneKiller(e, drone);
-
- drone->livesLeft--;
- drone->dead = true;
- drone->diedThisStep = true;
- drone->respawnWait = DRONE_RESPAWN_WAIT;
-
- for (uint8_t i = 0; i < DRONE_PIECE_COUNT; i++) {
- createDronePiece(e, drone, false);
- }
-
- b2Body_Disable(drone->bodyID);
- droneChangeWeapon(e, drone, e->defaultWeapon->type);
- drone->braking = false;
- drone->chargingBurst = false;
- drone->energyFullyDepleted = false;
- drone->shotThisStep = false;
- drone->velocity = b2Vec2_zero;
- drone->lastVelocity = b2Vec2_zero;
-}
-
-bool respawnDrone(iwEnv *e, droneEntity *drone) {
- b2Vec2 pos;
- if (!findOpenPos(e, DRONE_SHAPE, &pos, -1)) {
- return false;
- }
- b2Body_SetTransform(drone->bodyID, pos, b2Rot_identity);
- b2Body_Enable(drone->bodyID);
- b2Body_SetLinearDamping(drone->bodyID, DRONE_LINEAR_DAMPING);
-
- drone->dead = false;
- drone->pos = pos;
- drone->respawnGuideLifetime = UINT16_MAX;
- drone->killedBy = -1;
-
- droneAddEnergy(drone, DRONE_ENERGY_RESPAWN_REFILL);
-
- createDroneShield(e, drone, -(drone->idx + 1));
-
- if (e->client != NULL) {
- drone->trailPoints.length = 0;
- }
-
- return true;
-}
-
-void createProjectile(iwEnv *e, droneEntity *drone, const b2Vec2 normAim) {
- ASSERT_VEC_NORMALIZED(normAim);
-
- const float radius = drone->weaponInfo->radius;
- float droneRadius = DRONE_RADIUS;
- if (drone->shield != NULL) {
- droneRadius = DRONE_SHIELD_RADIUS;
- }
- // spawn the projectile just outside the drone so they don't
- // immediately collide
- b2Vec2 pos = b2MulAdd(drone->pos, droneRadius + (radius * 1.5f), normAim);
- // if the projectile is inside a wall or out of the map, move the
- // projectile to be just outside the wall
- bool projectileInWall = false;
- int16_t cellIdx = entityPosToCellIdx(e, pos);
- if (cellIdx == -1) {
- projectileInWall = true;
- } else {
- const mapCell *cell = safe_array_get_at(e->cells, cellIdx);
- if (cell->ent != NULL && entityTypeIsWall(cell->ent->type)) {
- projectileInWall = true;
- }
- }
- if (projectileInWall) {
- const b2Vec2 rayEnd = b2MulAdd(drone->pos, droneRadius + (radius * 2.5f), normAim);
- const b2Vec2 translation = b2Sub(rayEnd, drone->pos);
- const b2QueryFilter filter = {.categoryBits = PROJECTILE_SHAPE, .maskBits = WALL_SHAPE};
- const b2RayResult rayRes = b2World_CastRayClosest(e->worldID, drone->pos, translation, filter);
- if (rayRes.hit) {
- const b2Vec2 invNormAim = b2MulSV(-1.0f, normAim);
- pos = b2MulAdd(rayRes.point, radius * 1.5f, invNormAim);
- }
- }
-
- b2BodyDef projectileBodyDef = b2DefaultBodyDef();
- projectileBodyDef.type = b2_dynamicBody;
- projectileBodyDef.isBullet = drone->weaponInfo->isPhysicsBullet;
- projectileBodyDef.linearDamping = drone->weaponInfo->damping;
- projectileBodyDef.enableSleep = drone->weaponInfo->canSleep;
- projectileBodyDef.position = pos;
- b2BodyId projectileBodyID = b2CreateBody(e->worldID, &projectileBodyDef);
- b2ShapeDef projectileShapeDef = b2DefaultShapeDef();
- projectileShapeDef.enableContactEvents = true;
- projectileShapeDef.density = drone->weaponInfo->density;
- projectileShapeDef.material.restitution = 1.0f;
- projectileShapeDef.material.friction = 0.0f;
- projectileShapeDef.filter.categoryBits = PROJECTILE_SHAPE;
- projectileShapeDef.filter.maskBits = WALL_SHAPE | FLOATING_WALL_SHAPE | PROJECTILE_SHAPE | DRONE_SHAPE | SHIELD_SHAPE;
- const b2Circle projectileCircle = {.center = b2Vec2_zero, .radius = radius};
-
- b2ShapeId projectileShapeID = b2CreateCircleShape(projectileBodyID, &projectileShapeDef, &projectileCircle);
-
- // add a bit of lateral drone velocity to projectile
- b2Vec2 forwardVel = b2MulSV(b2Dot(drone->velocity, normAim), normAim);
- b2Vec2 lateralVel = b2Sub(drone->velocity, forwardVel);
- lateralVel = b2MulSV(projectileShapeDef.density * DRONE_MOVE_AIM_COEF, lateralVel);
- b2Vec2 aim = weaponAdjustAim(&e->randState, drone->weaponInfo->type, drone->heat, normAim);
- b2Vec2 fire = b2MulAdd(lateralVel, weaponFire(&e->randState, drone->weaponInfo->type), aim);
- b2Body_ApplyLinearImpulseToCenter(projectileBodyID, fire, true);
-
- projectileEntity *projectile = fastCalloc(1, sizeof(projectileEntity));
- projectile->droneIdx = drone->idx;
- projectile->bodyID = projectileBodyID;
- projectile->shapeID = projectileShapeID;
- projectile->weaponInfo = drone->weaponInfo;
- projectile->pos = projectileBodyDef.position;
- projectile->lastPos = projectileBodyDef.position;
- projectile->velocity = b2Body_GetLinearVelocity(projectileBodyID);
- projectile->lastVelocity = projectile->velocity;
- projectile->speed = b2Length(projectile->velocity);
- projectile->lastSpeed = projectile->speed;
- if (projectile->weaponInfo->type == BLACK_HOLE_WEAPON) {
- create_array(&projectile->entsInBlackHole, 4);
- }
- cc_array_add(e->projectiles, projectile);
-
- entity *ent = createEntity(e, PROJECTILE_ENTITY, projectile);
- projectile->ent = ent;
- b2Body_SetUserData(projectile->bodyID, ent);
- b2Shape_SetUserData(projectile->shapeID, ent);
-
- // create a sensor shape if needed
- if (projectile->weaponInfo->hasSensor) {
- projectile->sensorID = weaponSensor(projectile->bodyID, projectile->weaponInfo->type);
- b2Shape_SetUserData(projectile->sensorID, ent);
- }
-}
-
-// compute value generally from 0-1 based off of how much a projectile(s)
-// or explosion(s) caused the hit drone to change velocity
-float computeHitStrength(const droneEntity *hitDrone) {
- const float prevSpeed = b2Length(hitDrone->lastVelocity);
- const float curSpeed = b2Length(hitDrone->velocity);
- return fabsf(curSpeed - prevSpeed) / MAX_SPEED;
-}
-
-// simplified and copied from box2d/src/shape.c
-float getShapeProjectedPerimeter(const b2ShapeId shapeID, const b2Vec2 line) {
- if (b2Shape_GetType(shapeID) == b2_circleShape) {
- const b2Circle circle = b2Shape_GetCircle(shapeID);
- return circle.radius * 2.0f;
- }
-
- const b2Polygon polygon = b2Shape_GetPolygon(shapeID);
- const b2Vec2 *points = polygon.vertices;
- int count = polygon.count;
- B2_ASSERT(count > 0);
- float value = b2Dot(points[0], line);
- float lower = value;
- float upper = value;
- for (int i = 1; i < count; ++i) {
- value = b2Dot(points[i], line);
- lower = b2MinFloat(lower, value);
- upper = b2MaxFloat(upper, value);
- }
-
- return upper - lower;
-}
-
-// explodes projectile and ensures any other projectiles that are caught
-// in the explosion are also destroyed if necessary
-void createProjectileExplosion(iwEnv *e, projectileEntity *projectile, const bool initalProjectile) {
- if (projectile->needsToBeDestroyed) {
- return;
- }
- projectile->needsToBeDestroyed = true;
- cc_array_add(e->explodingProjectiles, projectile);
-
- b2ExplosionDef explosion;
- weaponExplosion(projectile->weaponInfo->type, &explosion);
- explosion.position = projectile->pos;
- explosion.maskBits = FLOATING_WALL_SHAPE | PROJECTILE_SHAPE | DRONE_SHAPE;
- droneEntity *parentDrone = safe_array_get_at(e->drones, projectile->droneIdx);
- createExplosion(e, parentDrone, projectile, &explosion);
-
- if (e->client != NULL) {
- explosionInfo *explInfo = fastCalloc(1, sizeof(explosionInfo));
- explInfo->def = explosion;
- explInfo->renderSteps = UINT16_MAX;
- cc_array_add(e->explosions, explInfo);
- }
- if (!initalProjectile) {
- return;
- }
-
- // if we're not destroying the projectiles now, we need to remove the initial projectile
- // from the list of exploding projectiles so it's not destroyed twice
- const enum cc_stat res = cc_array_remove_fast(e->explodingProjectiles, projectile, NULL);
- MAYBE_UNUSED(res);
- ASSERT(res == CC_OK);
-}
-
-// ensures projectiles don't slow down when an impluse is applied to them
-void fixProjectileSpeed(projectileEntity *projectile) {
- b2Vec2 newVel = b2Body_GetLinearVelocity(projectile->bodyID);
- float newSpeed = b2Length(newVel);
- if (newSpeed < projectile->lastSpeed) {
- newSpeed = projectile->lastSpeed;
- newVel = b2MulSV(newSpeed, b2Normalize(newVel));
- b2Body_SetLinearVelocity(projectile->bodyID, newVel);
- }
-
- projectile->velocity = newVel;
- projectile->lastSpeed = newSpeed;
- projectile->speed = newSpeed;
-}
-
-#define MAX_WALL_HITS 8
-
-typedef struct wallBurstImpulse {
- float distance;
- b2Vec2 direction;
- float magnitude;
- uint16_t wallCellIdx;
-} wallBurstImpulse;
-
-typedef struct explosionCtx {
- iwEnv *e;
- const bool isBurst;
- droneEntity *parentDrone;
- const projectileEntity *projectile;
- const b2ExplosionDef *def;
-
- wallBurstImpulse wallImpulses[MAX_WALL_HITS];
- int8_t closestWallIdx;
- uint8_t wallsHit;
-} explosionCtx;
-
-const float COS_85_DEGREES = 0.087155743f;
-
-// b2World_Explode doesn't support filtering on shapes of the same category,
-// so we have to do it manually
-// mostly copied from box2d/src/world.c
-bool explodeCallback(b2ShapeId shapeID, void *context) {
- if (!b2Shape_IsValid(shapeID)) {
- return true;
- }
-
- explosionCtx *ctx = context;
- const entity *entity = b2Shape_GetUserData(shapeID);
- projectileEntity *projectile = NULL;
- droneEntity *drone = NULL;
- wallEntity *wall = NULL;
- bool isStaticWall = false;
- b2Transform transform;
-
- switch (entity->type) {
- case PROJECTILE_ENTITY:
- // don't explode the parent projectile
- projectile = entity->entity;
- if (ctx->projectile != NULL && (ctx->projectile == projectile || projectile->needsToBeDestroyed)) {
- return true;
- }
- transform.p = projectile->pos;
- transform.q = b2Rot_identity;
- break;
- case DRONE_ENTITY:
- drone = entity->entity;
- // the explosion shouldn't affect the parent drone if this is a burst
- if (drone->idx == ctx->parentDrone->idx) {
- if (ctx->isBurst) {
- return true;
- }
-
- drone->stepInfo.ownShotTaken = true;
- ctx->e->stats[drone->idx].ownShotsTaken[ctx->projectile->weaponInfo->type]++;
- ctx->e->stats[drone->idx].totalOwnShotsTaken++;
- DEBUG_LOGF("drone %d hit itself with explosion from weapon %d", drone->idx, ctx->projectile->weaponInfo->type);
- }
- ctx->parentDrone->stepInfo.explosionHit[drone->idx] = true;
- if (ctx->isBurst) {
- DEBUG_LOGF("drone %d hit drone %d with burst", ctx->parentDrone->idx, drone->idx);
- ctx->e->stats[ctx->parentDrone->idx].burstsHit++;
- DEBUG_LOGF("drone %d hit by burst from drone %d", drone->idx, ctx->parentDrone->idx);
- } else {
- DEBUG_LOGF("drone %d hit drone %d with explosion from weapon %d", ctx->parentDrone->idx, drone->idx, ctx->projectile->weaponInfo->type);
- ctx->e->stats[ctx->parentDrone->idx].shotsHit[ctx->projectile->weaponInfo->type]++;
- ctx->e->stats[ctx->parentDrone->idx].totalShotsHit++;
- DEBUG_LOGF("drone %d hit by explosion from weapon %d from drone %d", drone->idx, ctx->projectile->weaponInfo->type, ctx->parentDrone->idx);
- }
- drone->stepInfo.explosionTaken[ctx->parentDrone->idx] = true;
- transform.p = drone->pos;
- transform.q = b2Rot_identity;
- break;
- case STANDARD_WALL_ENTITY:
- case BOUNCY_WALL_ENTITY:
- case DEATH_WALL_ENTITY:
- wall = entity->entity;
- isStaticWall = !wall->isFloating;
- // normal explosions don't affect static walls
- if (!ctx->isBurst && isStaticWall) {
- return true;
- }
- transform.p = wall->pos;
- transform.q = wall->rot;
- break;
- default:
- ERRORF("invalid entity type %d to explode", entity->type);
- }
-
- // find the closest point from the entity to the explosion center
- const b2BodyId bodyID = b2Shape_GetBody(shapeID);
- ASSERT(b2Body_IsValid(bodyID));
-
- bool isCircle = false;
- b2DistanceInput input;
- input.proxyA = makeDistanceProxy(entity, &isCircle);
- input.proxyB = b2MakeProxy(&ctx->def->position, 1, 0.0f);
- input.transformA = transform;
- input.transformB = b2Transform_identity;
- input.useRadii = isCircle;
-
- b2SimplexCache cache = {0};
- const b2DistanceOutput output = b2ShapeDistance(&input, &cache, NULL, 0);
- if (output.distance > ctx->def->radius) {
- return true;
- }
-
- // don't explode the entity if it's behind a static or floating wall,
- // but always consider floating walls for implosions
- const bool isImplosion = ctx->def->impulsePerLength < 0.0f;
- b2QueryFilter filter = {.categoryBits = PROJECTILE_SHAPE, .maskBits = WALL_SHAPE};
- if (!isImplosion) {
- filter.maskBits |= FLOATING_WALL_SHAPE;
- }
- if (posBehindWall(ctx->e, ctx->def->position, output.pointA, entity, filter, NULL)) {
- return true;
- }
-
- const b2Vec2 closestPoint = output.pointA;
- b2Vec2 direction;
- if (isStaticWall) {
- direction = b2Normalize(b2Sub(ctx->def->position, closestPoint));
- } else {
- direction = b2Normalize(b2Sub(closestPoint, ctx->def->position));
- }
- // if the direction is zero, the magnitude cannot be calculated
- // correctly so set the direction randomly
- if (b2VecEqual(direction, b2Vec2_zero)) {
- direction.x = randFloat(&ctx->e->randState, -1.0f, 1.0f);
- direction.y = randFloat(&ctx->e->randState, -1.0f, 1.0f);
- direction = b2Normalize(direction);
- }
-
- b2Vec2 localLine = b2Vec2_zero;
- if (entityTypeIsWall(entity->type)) {
- // the localLine isn't used in perimeter calculations for circles
- localLine = b2InvRotateVector(transform.q, b2LeftPerp(direction));
- }
- float perimeter = getShapeProjectedPerimeter(shapeID, localLine);
- const float relDistance = output.distance / ctx->def->radius;
- const float scale = 1.0f - (SQUARED(relDistance) * relDistance);
-
- // the parent drone or projecile's velocity affects the direction
- // and magnitude of the explosion
- b2Vec2 parentVelocity;
- float parentSpeed;
- if (ctx->projectile != NULL) {
- // use the projectile's last velocity and speed if it is in
- // contact with another body, as the current velocity will be
- // the velocity after the projectile rebounds which is not
- // what we want
- if (ctx->projectile->contacts != 0) {
- parentVelocity = ctx->projectile->lastVelocity;
- parentSpeed = ctx->projectile->lastSpeed;
- } else {
- parentVelocity = ctx->projectile->velocity;
- parentSpeed = ctx->projectile->speed;
- }
- if (isImplosion) {
- parentSpeed *= -1.0f;
- }
- } else {
- parentVelocity = ctx->parentDrone->lastVelocity;
- parentSpeed = b2Length(parentVelocity);
- }
- const b2Vec2 parentDirection = b2Normalize(parentVelocity);
-
- // scale the parent speed by how close the movement direction of
- // the parent is to where the entity is to the parent, except if
- // we're bursting off of a wall to make it more predictable and
- // to prevent taking a log of a negative number
- if (!isStaticWall) {
- parentSpeed *= b2Dot(direction, parentDirection);
- }
- // the parent entity's velocity affects the direction of the impulse
- // depending on the speed
- const b2Vec2 baseImpulse = b2MulSV(fabsf(ctx->def->impulsePerLength), direction);
- direction = b2Normalize(b2Add(baseImpulse, parentVelocity));
-
- float shieldReduction = 1.0f;
- if (drone != NULL && drone->shield != NULL) {
- shieldReduction = DRONE_SHIELD_EXPLOSION_REDUCTION;
- }
-
- float magnitude = (ctx->def->impulsePerLength + parentSpeed) * perimeter * scale * shieldReduction;
- if (isStaticWall) {
- // ensure this wall faces at least 85 degrees away from the
- // closest hit wall to prevent multiple walls facing roughly
- // the same direction greatly increasing the impulse magnitude
- if (ctx->closestWallIdx == -1) {
- ctx->closestWallIdx = 0;
- } else {
- const float closestWallDistance = ctx->wallImpulses[ctx->closestWallIdx].distance;
- if (output.distance < closestWallDistance) {
- ctx->closestWallIdx = ctx->wallsHit;
-
- for (int8_t i = 0; i < ctx->wallsHit; i++) {
- const wallBurstImpulse impulse = ctx->wallImpulses[i];
- if (impulse.distance != output.distance && b2Dot(impulse.direction, direction) > COS_85_DEGREES) {
- ctx->wallImpulses[i] = ctx->wallImpulses[--ctx->wallsHit];
- i--;
- }
- }
- }
- }
-
- // reduce the magnitude when pushing a drone away from a wall
- magnitude = log2f(magnitude) * (5.0f + (25.0f * ctx->parentDrone->burstCharge));
-
- ctx->wallImpulses[ctx->wallsHit++] = (wallBurstImpulse){
- .distance = output.distance,
- .direction = direction,
- .magnitude = magnitude,
- .wallCellIdx = wall->mapCellIdx,
- };
- return true;
- }
- const b2Vec2 impulse = b2MulSV(magnitude, direction);
- ASSERT(b2IsValidVec2(impulse));
-
- switch (entity->type) {
- case STANDARD_WALL_ENTITY:
- case BOUNCY_WALL_ENTITY:
- case DEATH_WALL_ENTITY:
- b2Body_ApplyLinearImpulse(bodyID, impulse, output.pointA, true);
- wall->velocity = b2Body_GetLinearVelocity(wall->bodyID);
- break;
- case PROJECTILE_ENTITY:
- b2Body_ApplyLinearImpulseToCenter(bodyID, impulse, true);
- // mine launcher projectiles explode when caught in another
- // explosion, explode this mine only once
- if (projectile->weaponInfo->type == MINE_LAUNCHER_WEAPON && ctx->def->impulsePerLength > 0.0f) {
- createProjectileExplosion(ctx->e, projectile, false);
- break;
- }
-
- fixProjectileSpeed(projectile);
-
- break;
- case DRONE_ENTITY:
- droneApplyImpulse(ctx->e, drone, impulse, ctx->parentDrone->idx);
- drone->lastVelocity = drone->velocity;
- drone->velocity = b2Body_GetLinearVelocity(drone->bodyID);
-
- shieldEntity *shield = drone->shield;
-
- // add energy to the drone that fired the projectile that is
- // currently exploding if it hit another drone
- if (!ctx->isBurst && drone->team != ctx->parentDrone->team && shield == NULL) {
- const float energyRefill = computeHitStrength(drone) * EXPLOSION_ENERGY_REFILL_COEF;
- droneAddEnergy(ctx->parentDrone, energyRefill);
- } else if (shield != NULL && shield->health > 0.0f) {
- const float damage = fabsf(magnitude) * DRONE_SHIELD_HEALTH_EXPLOSION_COEF;
- DEBUG_LOGF("shield explosion damage: %f", damage);
- shield->health -= damage;
- if (shield->health <= 0.0f) {
- droneAddEnergy(ctx->parentDrone, DRONE_SHIELD_BREAK_ENERGY_REFILL);
- }
- }
-
- break;
- default:
- ERRORF("unknown entity type for burst impulse %d", entity->type);
- }
-
- return true;
-}
-
-void applyDroneBurstImpulse(iwEnv *e, explosionCtx *ctx, const droneEntity *drone) {
- wallBurstImpulse *hitWalls = ctx->wallImpulses;
- uint8_t wallsHit = ctx->wallsHit;
-
- // sort by distance
- for (int8_t i = 1; i < wallsHit; i++) {
- wallBurstImpulse key = hitWalls[i];
- int j = i - 1;
-
- while (j >= 0 && hitWalls[j].distance > key.distance) {
- hitWalls[j + 1] = hitWalls[j];
- j = j - 1;
- }
-
- hitWalls[j + 1] = key;
- }
-
- for (uint8_t i = 0; i < wallsHit; i++) {
- const wallBurstImpulse impulseA = hitWalls[i];
- if (impulseA.distance == FLT_MAX) {
- continue;
- }
- for (uint8_t j = 0; j < wallsHit; j++) {
- if (j == i) {
- continue;
- }
- wallBurstImpulse impulseB = hitWalls[j];
- if (impulseB.distance == FLT_MAX) {
- continue;
- }
- const uint8_t cellIdxDiff = abs(impulseB.wallCellIdx - impulseA.wallCellIdx);
- if (cellIdxDiff == e->map->columns) {
- hitWalls[j].distance = FLT_MAX;
- continue;
- }
- if (cellIdxDiff == 1) {
- int8_t colA = impulseA.wallCellIdx / e->map->columns;
- int8_t colB = impulseB.wallCellIdx / e->map->columns;
- if (colA == colB) {
- hitWalls[j].distance = FLT_MAX;
- }
- }
- }
- }
-
- uint8_t wallsUsed = 0;
- float magnitude = 0.0f;
- b2Vec2 direction = b2Vec2_zero;
- for (uint8_t i = 0; i < wallsHit; i++) {
- const wallBurstImpulse impulse = hitWalls[i];
- if (impulse.distance == FLT_MAX) {
- continue;
- }
-
- wallsUsed++;
- magnitude += impulse.magnitude;
- direction = b2Add(direction, impulse.direction);
- }
-
- if (wallsUsed > 2) {
- DEBUG_LOG("more than 2 walls used");
- }
-
- DEBUG_LOGF("walls used: %d magnitude: %f final: %f", wallsUsed, magnitude, magnitude / (float)wallsUsed);
- const b2Vec2 finalImpulse = b2MulSV(magnitude / (float)wallsUsed, b2Normalize(direction));
- ASSERT(b2IsValidVec2(finalImpulse));
- droneApplyImpulse(e, drone, finalImpulse, drone->idx);
-}
-
-void createExplosion(iwEnv *e, droneEntity *drone, const projectileEntity *projectile, const b2ExplosionDef *def) {
- b2AABB aabb = {
- .lowerBound.x = def->position.x - def->radius,
- .lowerBound.y = def->position.y - def->radius,
- .upperBound.x = def->position.x + def->radius,
- .upperBound.y = def->position.y + def->radius,
- };
-
- b2QueryFilter filter = b2DefaultQueryFilter();
- filter.categoryBits = PROJECTILE_SHAPE;
- filter.maskBits = def->maskBits;
-
- const bool isBurst = projectile == NULL;
- explosionCtx ctx = {
- .e = e,
- .isBurst = isBurst,
- .parentDrone = drone,
- .projectile = projectile,
- .def = def,
- .wallImpulses = {{0}},
- .closestWallIdx = -1,
- .wallsHit = 0,
- };
- b2World_OverlapAABB(e->worldID, aabb, filter, explodeCallback, &ctx);
-
- uint8_t wallsHit = ctx.wallsHit;
- if (isBurst && wallsHit != 0) {
- applyDroneBurstImpulse(e, &ctx, drone);
- }
-}
-
-void destroyProjectile(iwEnv *e, projectileEntity *projectile, const bool processExplosions, const bool full) {
- // explode projectile if necessary
- if (processExplosions && projectile->weaponInfo->explosive) {
- createProjectileExplosion(e, projectile, true);
- }
-
- destroyEntity(e, projectile->ent);
-
- b2DestroyBody(projectile->bodyID);
-
- if (full) {
- enum cc_stat res = cc_array_remove_fast(e->projectiles, projectile, NULL);
- MAYBE_UNUSED(res);
- ASSERT(res == CC_OK);
- }
-
- e->stats[projectile->droneIdx].shotDistances[projectile->weaponInfo->type] += projectile->distance;
- e->stats[projectile->droneIdx].totalShotDistances += projectile->distance;
-
- if (projectile->entsInBlackHole != NULL) {
- for (uint8_t i = 0; i < cc_array_size(projectile->entsInBlackHole); i++) {
- entityID *id = safe_array_get_at(projectile->entsInBlackHole, i);
- fastFree(id);
- }
- cc_array_destroy(projectile->entsInBlackHole);
- }
-
- fastFree(projectile);
-}
-
-// destroy projectiles that were caught in an explosion; projectiles
-// can't be destroyed in explodeCallback because box2d assumes all shapes
-// and bodies are valid for the lifetime of an AABB query
-static inline void destroyExplodedProjectiles(iwEnv *e) {
- if (cc_array_size(e->explodingProjectiles) == 0) {
- return;
- }
-
- CC_ArrayIter iter;
- cc_array_iter_init(&iter, e->explodingProjectiles);
- projectileEntity *projectile;
- while (cc_array_iter_next(&iter, (void **)&projectile) != CC_ITER_END) {
- destroyProjectile(e, projectile, false, false);
- const enum cc_stat res = cc_array_remove_fast(e->projectiles, projectile, NULL);
- MAYBE_UNUSED(res);
- ASSERT(res == CC_OK);
- }
- cc_array_remove_all(e->explodingProjectiles);
-}
-
-void createSuddenDeathWalls(iwEnv *e, const b2Vec2 startPos, const b2Vec2 size) {
- int16_t endIdx;
- uint8_t indexIncrement;
- if (size.y == WALL_THICKNESS) {
- // horizontal walls
- const b2Vec2 endPos = (b2Vec2){.x = startPos.x + size.x, .y = startPos.y};
- endIdx = entityPosToCellIdx(e, endPos);
- if (endIdx == -1) {
- ERRORF("invalid position for sudden death wall: (%f, %f)", endPos.x, endPos.y);
- }
- indexIncrement = 1;
- } else {
- // vertical walls
- const b2Vec2 endPos = (b2Vec2){.x = startPos.x, .y = startPos.y + size.y};
- endIdx = entityPosToCellIdx(e, endPos);
- if (endIdx == -1) {
- ERRORF("invalid position for sudden death wall: (%f, %f)", endPos.x, endPos.y);
- }
- indexIncrement = e->map->columns;
- }
- const int16_t startIdx = entityPosToCellIdx(e, startPos);
- if (startIdx == -1) {
- ERRORF("invalid position for sudden death wall: (%f, %f)", startPos.x, startPos.y);
- }
- for (uint16_t i = startIdx; i <= endIdx; i += indexIncrement) {
- mapCell *cell = safe_array_get_at(e->cells, i);
- if (cell->ent != NULL) {
- if (cell->ent->type == WEAPON_PICKUP_ENTITY) {
- weaponPickupEntity *pickup = cell->ent->entity;
- disableWeaponPickup(e, pickup);
- } else {
- continue;
- }
- }
- entity *ent = createWall(e, cell->pos, WALL_THICKNESS, WALL_THICKNESS, i, DEATH_WALL_ENTITY, false);
- cell->ent = ent;
- }
-}
-
-void handleSuddenDeath(iwEnv *e) {
- ASSERT(e->suddenDeathSteps == 0);
- if (e->suddenDeathWallCounter >= e->map->maxSuddenDeathWalls) {
- return;
- }
-
- // create new walls that will close in on the arena
- e->suddenDeathWallCounter++;
- e->suddenDeathWallsPlaced = true;
-
- const float leftX = (e->suddenDeathWallCounter - 1) * WALL_THICKNESS;
- const float yOffset = (WALL_THICKNESS * (e->suddenDeathWallCounter - 1)) + (WALL_THICKNESS / 2);
- const float xWidth = WALL_THICKNESS * (e->map->columns - (e->suddenDeathWallCounter * 2) - 1);
-
- // top walls
- createSuddenDeathWalls(
- e,
- (b2Vec2){
- .x = e->map->bounds.min.x + leftX,
- .y = e->map->bounds.min.y + yOffset,
- },
- (b2Vec2){
- .x = xWidth,
- .y = WALL_THICKNESS,
- }
- );
- // bottom walls
- createSuddenDeathWalls(
- e,
- (b2Vec2){
- .x = e->map->bounds.min.x + leftX,
- .y = e->map->bounds.max.y - yOffset,
- },
- (b2Vec2){
- .x = xWidth,
- .y = WALL_THICKNESS,
- }
- );
- // left walls
- createSuddenDeathWalls(
- e,
- (b2Vec2){
- .x = e->map->bounds.min.x + leftX,
- .y = e->map->bounds.min.y + (e->suddenDeathWallCounter * WALL_THICKNESS),
- },
- (b2Vec2){
- .x = WALL_THICKNESS,
- .y = WALL_THICKNESS * (e->map->rows - (e->suddenDeathWallCounter * 2) - 2),
- }
- );
- // right walls
- createSuddenDeathWalls(
- e,
- (b2Vec2){
- .x = e->map->bounds.min.x + ((e->map->columns - e->suddenDeathWallCounter - 2) * WALL_THICKNESS),
- .y = e->map->bounds.min.y + (e->suddenDeathWallCounter * WALL_THICKNESS),
- },
- (b2Vec2){
- .x = WALL_THICKNESS,
- .y = WALL_THICKNESS * (e->map->rows - (e->suddenDeathWallCounter * 2) - 2),
- }
- );
-
- // mark drones as dead if they touch a newly placed wall
- for (uint8_t i = 0; i < e->numDrones; i++) {
- droneEntity *drone = safe_array_get_at(e->drones, i);
- const b2QueryFilter filter = {
- .categoryBits = DRONE_SHAPE,
- .maskBits = WALL_SHAPE,
- };
- if (isOverlappingAABB(e, drone->pos, DRONE_RADIUS, filter)) {
- killDrone(e, drone);
- }
- }
-
- // make floating walls static bodies if they are now overlapping with
- // a newly placed wall, but destroy them if they are fully inside a wall
- CC_ArrayIter floatingWallIter;
- cc_array_iter_init(&floatingWallIter, e->floatingWalls);
- wallEntity *wall;
- while (cc_array_iter_next(&floatingWallIter, (void **)&wall) != CC_ITER_END) {
- const mapCell *cell = safe_array_get_at(e->cells, wall->mapCellIdx);
- if (cell->ent != NULL && entityTypeIsWall(cell->ent->type)) {
- // floating wall is overlapping with a wall, destroy it
- const enum cc_stat res = cc_array_iter_remove_fast(&floatingWallIter, NULL);
- MAYBE_UNUSED(res);
- ASSERT(res == CC_OK);
-
- const b2Vec2 wallPos = wall->pos;
- MAYBE_UNUSED(wallPos);
- destroyWall(e, wall, false);
- DEBUG_LOGF("destroyed floating wall at %f, %f", wallPos.x, wallPos.y);
- continue;
- }
- }
-
- // detroy all projectiles that are now overlapping with a newly placed wall
- CC_ArrayIter projectileIter;
- cc_array_iter_init(&projectileIter, e->projectiles);
- projectileEntity *projectile;
- while (cc_array_iter_next(&projectileIter, (void **)&projectile) != CC_ITER_END) {
- const mapCell *cell = safe_array_get_at(e->cells, projectile->mapCellIdx);
- if (cell->ent != NULL && entityTypeIsWall(cell->ent->type)) {
- cc_array_iter_remove_fast(&projectileIter, NULL);
- destroyProjectile(e, projectile, false, false);
- }
- }
-}
-
-void droneMove(const iwEnv *e, droneEntity *drone, b2Vec2 direction) {
- ASSERT_VEC_BOUNDED(direction);
-
- // if energy is fully depleted halve movement until energy starts
- // to refill again
- if (drone->energyFullyDepleted && drone->energyRefillWait != 0.0f) {
- direction = b2MulSV(0.5f, direction);
- drone->lastMove = direction;
- }
- const b2Vec2 force = b2MulSV(DRONE_MOVE_MAGNITUDE, direction);
- droneApplyForce(e, drone, force, drone->idx);
-}
-
-void droneShoot(iwEnv *e, droneEntity *drone, const b2Vec2 aim, const bool chargingWeapon) {
- ASSERT(drone->ammo != 0);
-
- drone->shotThisStep = true;
- // TODO: rework heat to only increase when projectiles are fired,
- // and only cool down after the next shot was skipped
- drone->heat++;
- if (drone->weaponCooldown != 0.0f) {
- return;
- }
- const bool weaponNeedsCharge = drone->weaponInfo->charge != 0.0f;
- if (weaponNeedsCharge) {
- if (chargingWeapon) {
- drone->chargingWeapon = true;
- drone->weaponCharge = min(drone->weaponCharge + e->deltaTime, drone->weaponInfo->charge);
- } else if (drone->weaponCharge < drone->weaponInfo->charge) {
- drone->chargingWeapon = false;
- drone->weaponCharge = max(drone->weaponCharge - e->deltaTime, 0.0f);
- }
- }
- // if the weapon needs to be charged, only fire the weapon if it's
- // fully charged and the agent released the trigger
- if (weaponNeedsCharge && (chargingWeapon || drone->weaponCharge < drone->weaponInfo->charge)) {
- return;
- }
-
- if (drone->ammo != INFINITE) {
- drone->ammo--;
- }
- drone->weaponCooldown = drone->weaponInfo->coolDown;
- drone->chargingWeapon = false;
- drone->weaponCharge = 0.0f;
-
- b2Vec2 normAim = drone->lastAim;
- if (!b2VecEqual(aim, b2Vec2_zero)) {
- normAim = b2Normalize(aim);
- }
- ASSERT_VEC_NORMALIZED(normAim);
- b2Vec2 recoil = b2MulSV(-drone->weaponInfo->recoilMagnitude, normAim);
- droneApplyImpulse(e, drone, recoil, drone->idx);
-
- for (int i = 0; i < drone->weaponInfo->numProjectiles; i++) {
- createProjectile(e, drone, normAim);
-
- e->stats[drone->idx].shotsFired[drone->weaponInfo->type]++;
- e->stats[drone->idx].totalShotsFired++;
- }
- drone->stepInfo.firedShot = true;
-
- if (drone->ammo == 0) {
- droneChangeWeapon(e, drone, e->defaultWeapon->type);
- drone->weaponCooldown = drone->weaponInfo->coolDown;
- }
-}
-
-void droneBrake(iwEnv *e, droneEntity *drone, const bool brake) {
- if (drone->shield != NULL) {
- return;
- }
- // if the drone isn't braking or energy is fully depleted, return
- // unless the drone was braking during the last step
- if (!brake || drone->energyFullyDepleted) {
- if (drone->braking) {
- drone->braking = false;
- b2Body_SetLinearDamping(drone->bodyID, DRONE_LINEAR_DAMPING);
- if (drone->energyRefillWait == 0.0f && !drone->chargingBurst) {
- drone->energyRefillWait = DRONE_ENERGY_REFILL_WAIT;
- }
- droneTrackBrake(e, drone);
-
- if (e->client != NULL) {
- brakeTrailPoint *trailPoint = fastCalloc(1, sizeof(brakeTrailPoint));
- trailPoint->pos = drone->pos;
- trailPoint->lifetime = UINT16_MAX;
- trailPoint->isEnd = true;
- cc_array_add(drone->brakeTrailPoints, trailPoint);
- }
- }
- return;
- }
- ASSERT(!drone->energyFullyDepleted);
-
- // apply additional brake damping and decrease energy
- if (brake) {
- if (!drone->braking) {
- drone->braking = true;
- b2Body_SetLinearDamping(drone->bodyID, DRONE_LINEAR_DAMPING * DRONE_BRAKE_DAMPING_COEF);
- droneTrackBrake(e, drone);
- }
- drone->energyLeft = max(drone->energyLeft - (DRONE_BRAKE_DRAIN_RATE * e->deltaTime), 0.0f);
- e->stats[drone->idx].brakeTime += e->deltaTime;
- }
-
- // if energy is empty but burst is being charged, let burst functions
- // handle energy refill
- if (drone->energyLeft == 0.0f && !drone->chargingBurst) {
- drone->energyFullyDepleted = true;
- drone->energyFullyDepletedThisStep = true;
- drone->energyRefillWait = DRONE_ENERGY_REFILL_EMPTY_WAIT;
- e->stats[drone->idx].energyEmptied++;
- }
-
- if (e->client != NULL) {
- brakeTrailPoint *trailPoint = fastCalloc(1, sizeof(brakeTrailPoint));
- trailPoint->pos = drone->pos;
- trailPoint->lifetime = UINT16_MAX;
- cc_array_add(drone->brakeTrailPoints, trailPoint);
- }
-}
-
-void droneChargeBurst(iwEnv *e, droneEntity *drone) {
- if (drone->energyFullyDepleted || drone->burstCooldown != 0.0f || drone->shield != NULL || (!drone->chargingBurst && drone->energyLeft < DRONE_BURST_BASE_COST)) {
- return;
- }
-
- // take energy and put it into burst charge
- if (drone->chargingBurst) {
- drone->burstCharge = min(drone->burstCharge + (DRONE_BURST_CHARGE_RATE * e->deltaTime), DRONE_ENERGY_MAX);
- drone->energyLeft = max(drone->energyLeft - (DRONE_BURST_CHARGE_RATE * e->deltaTime), 0.0f);
- } else {
- drone->burstCharge = min(drone->burstCharge + DRONE_BURST_BASE_COST, DRONE_ENERGY_MAX);
- drone->energyLeft = max(drone->energyLeft - DRONE_BURST_BASE_COST, 0.0f);
- drone->chargingBurst = true;
- }
-
- if (drone->energyLeft == 0.0f) {
- drone->energyFullyDepleted = true;
- e->stats[drone->idx].energyEmptied++;
- }
-}
-
-void droneBurst(iwEnv *e, droneEntity *drone) {
- if (!drone->chargingBurst) {
- return;
- }
-
- const float radius = (DRONE_BURST_RADIUS_BASE * drone->burstCharge) + DRONE_BURST_RADIUS_MIN;
- b2ExplosionDef explosion = {
- .position = drone->pos,
- .radius = radius,
- .impulsePerLength = (DRONE_BURST_IMPACT_BASE * drone->burstCharge) + DRONE_BURST_IMPACT_MIN,
- .maskBits = WALL_SHAPE | FLOATING_WALL_SHAPE | PROJECTILE_SHAPE | DRONE_SHAPE,
- };
- createExplosion(e, drone, NULL, &explosion);
- destroyExplodedProjectiles(e);
-
- drone->chargingBurst = false;
- drone->burstCharge = 0.0f;
- drone->burstCooldown = DRONE_BURST_COOLDOWN;
- if (drone->energyLeft == 0.0f) {
- drone->energyFullyDepletedThisStep = true;
- drone->energyRefillWait = DRONE_ENERGY_REFILL_EMPTY_WAIT;
- } else {
- drone->energyRefillWait = DRONE_ENERGY_REFILL_WAIT;
- }
- e->stats[drone->idx].totalBursts++;
-
- if (e->client != NULL) {
- explosionInfo *explInfo = fastCalloc(1, sizeof(explosionInfo));
- explInfo->def = explosion;
- explInfo->isBurst = true;
- explInfo->droneIdx = drone->idx;
- explInfo->renderSteps = UINT16_MAX;
- cc_array_add(e->explosions, explInfo);
- }
-}
-
-void droneDiscardWeapon(iwEnv *e, droneEntity *drone) {
- if (drone->weaponInfo->type == e->defaultWeapon->type || (drone->energyFullyDepleted && !drone->chargingBurst)) {
- return;
- }
-
- droneChangeWeapon(e, drone, e->defaultWeapon->type);
- droneAddEnergy(drone, -WEAPON_DISCARD_COST);
- if (drone->chargingBurst) {
- return;
- }
-
- if (drone->energyLeft == 0.0f) {
- drone->energyFullyDepleted = true;
- drone->energyFullyDepletedThisStep = true;
- drone->energyRefillWait = DRONE_ENERGY_REFILL_EMPTY_WAIT;
- e->stats[drone->idx].energyEmptied++;
- } else {
- drone->energyRefillWait = DRONE_ENERGY_REFILL_WAIT;
- }
-}
-
-// update drone state, respawn the drone if necessary; false is returned
-// if no position could be found to respawn the drone at, and true otherwise
-bool droneStep(iwEnv *e, droneEntity *drone) {
- if (drone->dead) {
- drone->respawnWait -= e->deltaTime;
- if (drone->respawnWait <= 0.0f) {
- const bool foundPos = respawnDrone(e, drone);
- if (!foundPos) {
- return false;
- }
- }
- return true;
- }
-
- // manage weapon charge and heat
- if (drone->weaponCooldown != 0.0f) {
- drone->weaponCooldown = max(drone->weaponCooldown - e->deltaTime, 0.0f);
- }
- if (!drone->shotThisStep) {
- drone->weaponCharge = max(drone->weaponCharge - e->deltaTime, 0);
- drone->heat = max(drone->heat - 1, 0);
- } else {
- drone->shotThisStep = false;
- }
- ASSERT(!drone->shotThisStep);
-
- // manage drone energy
- if (drone->burstCooldown != 0.0f) {
- drone->burstCooldown = max(drone->burstCooldown - e->deltaTime, 0.0f);
- }
- if (drone->energyFullyDepletedThisStep) {
- drone->energyFullyDepletedThisStep = false;
- } else if (drone->energyRefillWait != 0.0f) {
- drone->energyRefillWait = max(drone->energyRefillWait - e->deltaTime, 0.0f);
- } else if (drone->energyLeft != DRONE_ENERGY_MAX && !drone->chargingBurst) {
- // don't start recharging energy until the burst charge is used
- drone->energyLeft = min(drone->energyLeft + (DRONE_ENERGY_REFILL_RATE * e->deltaTime), DRONE_ENERGY_MAX);
- }
- if (drone->energyLeft == DRONE_ENERGY_MAX) {
- drone->energyFullyDepleted = false;
- }
-
- const float distance = b2Distance(drone->lastPos, drone->pos);
- e->stats[drone->idx].distanceTraveled += distance;
-
- shieldEntity *shield = drone->shield;
- if (shield != NULL) {
- shield->duration -= e->deltaTime;
- if (shield->duration <= 0.0f || shield->health <= 0.0f) {
- destroyDroneShield(e, shield, true);
- }
- }
-
- return true;
-}
-
-void handleBlackHolePull(iwEnv *e, projectileEntity *projectile) {
- ASSERT(projectile->weaponInfo->type == BLACK_HOLE_WEAPON);
-
- CC_ArrayIter entIter;
- cc_array_iter_init(&entIter, projectile->entsInBlackHole);
- entityID *id;
- while (cc_array_iter_next(&entIter, (void **)&id) != CC_ITER_END) {
- // check if the entity is still valid
- const entity *ent = getEntityByID(e, id);
- if (ent == NULL) {
- fastFree(id);
- enum cc_stat res = cc_array_iter_remove_fast(&entIter, NULL);
- MAYBE_UNUSED(res);
- ASSERT(res == CC_OK);
- continue;
- }
- const b2DistanceOutput output = closestPoint(projectile->ent, ent);
- const b2QueryFilter filter = {.categoryBits = PROJECTILE_SHAPE, .maskBits = WALL_SHAPE | FLOATING_WALL_SHAPE};
- if (posBehindWall(e, projectile->pos, output.pointB, ent, filter, NULL)) {
- continue;
- }
-
- b2BodyId bodyID;
- b2ShapeId shapeID;
- b2Rot rot;
-
- wallEntity *wall;
- droneEntity *drone;
- projectileEntity *proj;
- bool hasShield = false;
-
- switch (ent->type) {
- case STANDARD_WALL_ENTITY:
- case BOUNCY_WALL_ENTITY:
- case DEATH_WALL_ENTITY:
- wall = ent->entity;
- bodyID = wall->bodyID;
- shapeID = wall->shapeID;
- rot = wall->rot;
- break;
- case DRONE_ENTITY:
- drone = ent->entity;
- bodyID = drone->bodyID;
- shapeID = drone->shapeID;
- hasShield = drone->shield != NULL;
- break;
- case PROJECTILE_ENTITY:
- proj = ent->entity;
- bodyID = proj->bodyID;
- shapeID = proj->shapeID;
- break;
- default:
- ERRORF("unknown entity type %d for black hole suck", ent->type);
- }
-
- b2Vec2 direction = b2Normalize(b2Sub(output.pointB, projectile->pos));
-
- b2Vec2 localLine = b2Vec2_zero;
- if (entityTypeIsWall(ent->type)) {
- // the localLine isn't used in perimeter calculations for circles
- localLine = b2InvRotateVector(rot, b2LeftPerp(direction));
- }
- const float perimeter = getShapeProjectedPerimeter(shapeID, localLine);
-
- const float scale = 1.0f - (output.distance / BLACK_HOLE_PROXIMITY_RADIUS);
-
- // the projecile's velocity affects the direction
- // and magnitude of the force
- b2Vec2 parentVelocity = projectile->velocity;
- float parentSpeed = projectile->speed;
- if (projectile->contacts != 0) {
- parentVelocity = projectile->lastVelocity;
- parentSpeed = projectile->lastSpeed;
- }
- const b2Vec2 parentDirection = b2Normalize(parentVelocity);
- parentSpeed *= b2Dot(direction, parentDirection);
- // the parent entity's velocity affects the direction of the force
- // depending on the speed
- const b2Vec2 baseForce = b2MulSV(-1.0f * BLACK_HOLE_PULL_MAGNITUDE, direction);
- direction = b2Normalize(b2Add(baseForce, parentVelocity));
-
- float magnitude = (BLACK_HOLE_PULL_MAGNITUDE + (-1.0f * parentSpeed)) * perimeter * scale;
- if (hasShield) {
- magnitude *= DRONE_SHIELD_EXPLOSION_REDUCTION;
- }
- const b2Vec2 force = b2MulSV(magnitude, direction);
-
- if (entityTypeIsWall(ent->type)) {
- b2Body_ApplyForce(bodyID, force, output.pointB, true);
- } else if (ent->type == DRONE_ENTITY) {
- droneEntity *drone = ent->entity;
- droneApplyForce(e, drone, force, projectile->droneIdx);
- } else {
- b2Body_ApplyForceToCenter(bodyID, force, true);
- }
- }
-}
-
-void projectilesStep(iwEnv *e) {
- CC_ArrayIter projIter;
- cc_array_iter_init(&projIter, e->projectiles);
- projectileEntity *projectile;
- while (cc_array_iter_next(&projIter, (void **)&projectile) != CC_ITER_END) {
- if (projectile->needsToBeDestroyed) {
- continue;
- }
- const float maxDistance = projectile->weaponInfo->maxDistance;
- const float distance = b2Distance(projectile->pos, projectile->lastPos);
- projectile->distance += distance;
-
- // if a drone is in a set mine's sensor range but behind a wall,
- // we need to check until the drone leaves the sensor range if
- // it's not behind the wall anymore as we normally only check if
- // we need to explode the mine when a drone touches the sensor
- if (projectile->numDronesBehindWalls != 0) {
- bool destroyed = false;
- for (uint8_t i = 0; i < projectile->numDronesBehindWalls; i++) {
- const uint8_t droneIdx = projectile->dronesBehindWalls[i];
- const droneEntity *drone = safe_array_get_at(e->drones, droneIdx);
- // TODO: do we need the closest point here?
- const b2DistanceOutput output = closestPoint(projectile->ent, drone->ent);
- const b2QueryFilter filter = {.categoryBits = PROJECTILE_SHAPE, .maskBits = WALL_SHAPE | FLOATING_WALL_SHAPE};
- if (posBehindWall(e, projectile->pos, output.pointB, NULL, filter, NULL)) {
- continue;
- }
-
- // we have to destroy the projectile using the iterator so
- // we can continue to iterate correctly
- destroyProjectile(e, projectile, true, false);
- enum cc_stat res = cc_array_iter_remove_fast(&projIter, NULL);
- MAYBE_UNUSED(res);
- ASSERT(res == CC_OK);
- destroyed = true;
- break;
- }
- if (destroyed) {
- continue;
- }
- }
-
- if (projectile->entsInBlackHole != NULL) {
- handleBlackHolePull(e, projectile);
- }
-
- if (maxDistance == INFINITE) {
- continue;
- }
- if (projectile->distance >= maxDistance) {
- // we have to destroy the projectile using the iterator so
- // we can continue to iterate correctly
- destroyProjectile(e, projectile, true, false);
- enum cc_stat res = cc_array_iter_remove_fast(&projIter, NULL);
- MAYBE_UNUSED(res);
- ASSERT(res == CC_OK);
- continue;
- }
- }
-
- destroyExplodedProjectiles(e);
-}
-
-void weaponPickupsStep(iwEnv *e) {
- CC_ArrayIter iter;
- cc_array_iter_init(&iter, e->pickups);
- weaponPickupEntity *pickup;
-
- // respawn weapon pickups at a random location as a random weapon type
- // once the respawn wait has elapsed
- while (cc_array_iter_next(&iter, (void **)&pickup) != CC_ITER_END) {
- if (pickup->respawnWait == 0.0f) {
- continue;
- }
- pickup->respawnWait = max(pickup->respawnWait - e->deltaTime, 0.0f);
- if (pickup->respawnWait != 0.0f) {
- continue;
- }
-
- b2Vec2 pos;
- if (!findOpenPos(e, WEAPON_PICKUP_SHAPE, &pos, -1)) {
- const enum cc_stat res = cc_array_iter_remove_fast(&iter, NULL);
- MAYBE_UNUSED(res);
- ASSERT(res == CC_OK);
- DEBUG_LOG("destroying weapon pickup");
- destroyWeaponPickup(e, pickup);
- continue;
- }
- pickup->pos = pos;
- pickup->weapon = randWeaponPickupType(e);
-
- const int16_t cellIdx = entityPosToCellIdx(e, pos);
- if (cellIdx == -1) {
- ERRORF("invalid position for weapon pickup spawn: (%f, %f)", pos.x, pos.y);
- }
- DEBUG_LOGF("respawned weapon pickup at cell %d (%f, %f)", cellIdx, pos.x, pos.y);
- pickup->mapCellIdx = cellIdx;
- createWeaponPickupBodyShape(e, pickup);
-
- mapCell *cell = safe_array_get_at(e->cells, cellIdx);
- cell->ent = pickup->ent;
- }
-}
-
-// only update positions and velocities of dynamic bodies if they moved
-// this step
-void handleBodyMoveEvents(iwEnv *e) {
- b2BodyEvents events = b2World_GetBodyEvents(e->worldID);
- for (int i = 0; i < events.moveCount; i++) {
- const b2BodyMoveEvent *event = events.moveEvents + i;
- if (!b2Body_IsValid(event->bodyId)) {
- continue;
- }
- ASSERT(b2IsValidVec2(event->transform.p));
- const b2Vec2 newPos = event->transform.p;
- entity *ent = event->userData;
- if (ent == NULL) {
- continue;
- }
-
- wallEntity *wall;
- projectileEntity *proj;
- droneEntity *drone;
- shieldEntity *shield;
- dronePieceEntity *piece;
- int16_t mapIdx;
-
- // if the new position is out of bounds, destroy the entity unless
- // a drone is out of bounds, then just kill it
- switch (ent->type) {
- case STANDARD_WALL_ENTITY:
- case BOUNCY_WALL_ENTITY:
- case DEATH_WALL_ENTITY:
- wall = ent->entity;
- mapIdx = entityPosToCellIdx(e, newPos);
- if (mapIdx == -1) {
- DEBUG_LOGF("invalid position for floating wall: (%f, %f) destroying", newPos.x, newPos.y);
- cc_array_remove_fast(e->floatingWalls, wall, NULL);
- destroyWall(e, wall, false);
- continue;
- }
- wall->mapCellIdx = mapIdx;
- wall->pos = newPos;
- wall->rot = event->transform.q;
- wall->velocity = b2Body_GetLinearVelocity(wall->bodyID);
- break;
- case PROJECTILE_ENTITY:
- proj = ent->entity;
- mapIdx = entityPosToCellIdx(e, newPos);
- if (mapIdx == -1) {
- DEBUG_LOGF("invalid position for projectile: (%f, %f) destroying", newPos.x, newPos.y);
- destroyProjectile(e, proj, false, true);
- continue;
- }
- proj->mapCellIdx = mapIdx;
- proj->lastPos = proj->pos;
- proj->pos = newPos;
- proj->lastVelocity = proj->velocity;
- proj->velocity = b2Body_GetLinearVelocity(proj->bodyID);
- // if the projectile doesn't have damping its speed will
- // only change when colliding with a dynamic body or getting
- // hit by an explosion, and if it's currently colliding with
- // something we don't care about the current speed
- if (proj->weaponInfo->damping != 0.0f && proj->contacts == 0) {
- proj->lastSpeed = proj->speed;
- proj->speed = b2Length(proj->velocity);
- }
-
- if (e->client != NULL) {
- updateTrailPoints(&proj->trailPoints, MAX_PROJECTLE_TRAIL_POINTS, newPos);
- }
- break;
- case DRONE_ENTITY:
- drone = ent->entity;
- mapIdx = entityPosToCellIdx(e, newPos);
- if (mapIdx == -1) {
- DEBUG_LOGF("invalid position for drone: (%f, %f) killing it", newPos.x, newPos.y);
- killDrone(e, drone);
- continue;
- }
- drone->mapCellIdx = mapIdx;
- drone->lastPos = drone->pos;
- drone->pos = newPos;
- drone->lastVelocity = drone->velocity;
- drone->velocity = b2Body_GetLinearVelocity(drone->bodyID);
-
- if (e->client != NULL) {
- updateTrailPoints(&drone->trailPoints, MAX_DRONE_TRAIL_POINTS, newPos);
- }
- break;
- case SHIELD_ENTITY:
- shield = ent->entity;
- shield->pos = newPos;
- break;
- case DRONE_PIECE_ENTITY:
- piece = ent->entity;
- piece->pos = newPos;
- piece->rot = event->transform.q;
- break;
- default:
- ERRORF("unknown entity type for move event %d", ent->type);
- }
- }
-}
-
-// destroy the projectile if it has traveled enough or has bounced enough
-// times, and update drone stats if a drone was hit
-uint8_t handleProjectileBeginContact(iwEnv *e, const entity *proj, const entity *ent, const b2ContactId contactID, const bool projIsShapeA) {
- projectileEntity *projectile = proj->entity;
- projectile->contacts++;
-
- // e (shape B in the collision) will be NULL if it's another
- // projectile that was just destroyed
- if (ent == NULL || ent->type == PROJECTILE_ENTITY) {
- // explode mines when hit by a projectile
- if (projectile->weaponInfo->type == MINE_LAUNCHER_WEAPON) {
- uint8_t numDestroyed = 1;
- if (ent != NULL) {
- const projectileEntity *projectile2 = ent->entity;
- // if both entities are mines both will be destroyed
- if (projectile2->weaponInfo->type == MINE_LAUNCHER_WEAPON) {
- numDestroyed = 2;
- }
- }
- destroyProjectile(e, projectile, true, true);
- destroyExplodedProjectiles(e);
- return numDestroyed;
- }
-
- // always allow all other projectiles to bounce off each other
- return false;
- } else if (ent->type == BOUNCY_WALL_ENTITY) {
- // always allow projectiles to bounce off bouncy walls
- return false;
- } else if (ent->type == SHIELD_ENTITY) {
- // always allow projectiles to bounce off shields, and update shield health
- shieldEntity *shield = ent->entity;
- if (shield->health <= 0.0f) {
- return false;
- }
-
- const float damage = projectile->lastSpeed * projectile->weaponInfo->mass * DRONE_SHIELD_HEALTH_IMPULSE_COEF;
- DEBUG_LOGF("shield projectile damage: %f", damage);
- shield->health -= damage;
- if (shield->health <= 0.0f) {
- droneEntity *parentDrone = safe_array_get_at(e->drones, projectile->droneIdx);
- droneAddEnergy(parentDrone, DRONE_SHIELD_BREAK_ENERGY_REFILL);
- }
-
- return false;
- }
-
- if (projectile->weaponInfo->type != BLACK_HOLE_WEAPON || ent->type != DRONE_ENTITY) {
- projectile->bounces++;
- }
- if (ent->type == DRONE_ENTITY) {
- droneEntity *hitDrone = ent->entity;
- if (b2Contact_IsValid(contactID)) {
- const b2Manifold manifold = b2Contact_GetData(contactID).manifold;
- ASSERT(manifold.pointCount == 1);
- b2Vec2 hitImpulse = b2MulSV(manifold.points[0].normalImpulse, manifold.normal);
- if (!projIsShapeA) {
- hitImpulse = b2Neg(hitImpulse);
- }
- droneTrackImpulse(e, hitDrone, hitImpulse, projectile->droneIdx);
- }
-
- if (projectile->droneIdx != hitDrone->idx) {
- droneEntity *shooterDrone = safe_array_get_at(e->drones, projectile->droneIdx);
-
- if (shooterDrone->team != hitDrone->team) {
- const float impulseEnergy = projectile->lastSpeed * projectile->weaponInfo->mass * projectile->weaponInfo->energyRefillCoef;
- droneAddEnergy(shooterDrone, impulseEnergy);
- }
- // add 1 so we can differentiate between no weapon and weapon 0
- shooterDrone->stepInfo.shotHit[hitDrone->idx] = projectile->weaponInfo->type + 1;
- e->stats[shooterDrone->idx].shotsHit[projectile->weaponInfo->type]++;
- e->stats[shooterDrone->idx].totalShotsHit++;
- DEBUG_LOGF("drone %d hit drone %d with weapon %d", shooterDrone->idx, hitDrone->idx, projectile->weaponInfo->type);
- hitDrone->stepInfo.shotTaken[shooterDrone->idx] = projectile->weaponInfo->type + 1;
- e->stats[hitDrone->idx].shotsTaken[projectile->weaponInfo->type]++;
- e->stats[hitDrone->idx].totalShotsTaken++;
- DEBUG_LOGF("drone %d hit by drone %d with weapon %d", hitDrone->idx, shooterDrone->idx, projectile->weaponInfo->type);
- } else {
- hitDrone->stepInfo.ownShotTaken = true;
- e->stats[hitDrone->idx].ownShotsTaken[projectile->weaponInfo->type]++;
- e->stats[hitDrone->idx].totalOwnShotsTaken++;
- DEBUG_LOGF("drone %d hit by own weapon %d", hitDrone->idx, projectile->weaponInfo->type);
- }
-
- if (projectile->weaponInfo->destroyedOnDroneHit) {
- destroyProjectile(e, projectile, projectile->weaponInfo->explodesOnDroneHit, true);
- destroyExplodedProjectiles(e);
- return 1;
- }
- } else if (projectile->weaponInfo->type == MINE_LAUNCHER_WEAPON && !projectile->setMine) {
- // if the mine is in explosion proximity of a drone now,
- // destroy it
- const b2QueryFilter filter = {
- .categoryBits = PROJECTILE_SHAPE,
- .maskBits = DRONE_SHAPE,
- };
- if (isOverlappingCircleInLineOfSight(e, projectile->ent, projectile->pos, MINE_LAUNCHER_PROXIMITY_RADIUS, filter, NULL)) {
- destroyProjectile(e, projectile, true, true);
- destroyExplodedProjectiles(e);
- return 1;
- }
-
- // create a weld joint to stick the mine to the wall
- ASSERT(entityTypeIsWall(ent->type));
- wallEntity *wall = ent->entity;
- ASSERT(b2Contact_IsValid(contactID));
- const b2Manifold manifold = b2Contact_GetData(contactID).manifold;
- ASSERT(manifold.pointCount == 1);
-
- b2WeldJointDef jointDef = b2DefaultWeldJointDef();
- const b2Rot projRot = b2Body_GetRotation(projectile->bodyID);
- if (projIsShapeA) {
- jointDef.base.bodyIdA = projectile->bodyID;
- jointDef.base.bodyIdB = wall->bodyID;
- const b2Rot relativeRot = b2MakeRot(b2RelativeAngle(wall->rot, projRot));
- jointDef.base.localFrameA.p = b2InvRotateVector(projRot, manifold.points[0].anchorB);
- jointDef.base.localFrameA.q = relativeRot;
- jointDef.base.localFrameB.p = b2InvRotateVector(wall->rot, manifold.points[0].anchorA);
- jointDef.base.localFrameB.q = relativeRot;
- } else {
- jointDef.base.bodyIdA = wall->bodyID;
- jointDef.base.bodyIdB = projectile->bodyID;
- const b2Rot relativeRot = b2MakeRot(b2RelativeAngle(projRot, wall->rot));
- jointDef.base.localFrameA.p = b2InvRotateVector(wall->rot, manifold.points[0].anchorA);
- jointDef.base.localFrameA.q = relativeRot;
- jointDef.base.localFrameB.p = b2InvRotateVector(projRot, manifold.points[0].anchorB);
- jointDef.base.localFrameB.q = relativeRot;
- }
- b2CreateWeldJoint(e->worldID, &jointDef);
- projectile->velocity = b2Vec2_zero;
- projectile->lastVelocity = b2Vec2_zero;
- projectile->speed = 0.0f;
- projectile->lastSpeed = 0.0f;
- projectile->setMine = true;
- }
-
- const uint8_t maxBounces = projectile->weaponInfo->maxBounces;
- if (projectile->bounces == maxBounces) {
- destroyProjectile(e, projectile, true, true);
- destroyExplodedProjectiles(e);
- return 1;
- }
-
- return 0;
-}
-
-// ensure speed is maintained when a projectile hits a dynamic body
-void handleProjectileEndContact(const entity *proj, const entity *ent) {
- projectileEntity *projectile = proj->entity;
- projectile->contacts--;
-
- // mines stick to walls, explode when hitting another projectile
- // and are destroyed when hitting a drone so no matter what we don't
- // need to do anything here
- if (projectile->weaponInfo->type == MINE_LAUNCHER_WEAPON) {
- return;
- }
-
- if (ent != NULL) {
- if (ent->type == PROJECTILE_ENTITY) {
- const projectileEntity *projectile2 = ent->entity;
- // allow projectile speeds to increase when two different
- // projectile types collide
- if (projectile->weaponInfo->type != projectile2->weaponInfo->type) {
- b2Vec2 newVel = b2Body_GetLinearVelocity(projectile->bodyID);
- float newSpeed = b2Length(newVel);
- if (newSpeed < projectile->lastSpeed) {
- newSpeed = projectile->lastSpeed;
- newVel = b2MulSV(newSpeed, b2Normalize(newVel));
- b2Body_SetLinearVelocity(projectile->bodyID, newVel);
- }
- projectile->velocity = newVel;
- projectile->speed = newSpeed;
- projectile->lastSpeed = newSpeed;
- return;
- }
- }
- }
-
- // the last speed is used here instead of the current speed because
- // the current speed will be the speed box2d set the projectile to
- // after a collision and we want to keep the speed consistent
- float newSpeed = projectile->lastSpeed;
- if (projectile->weaponInfo->type == ACCELERATOR_WEAPON) {
- newSpeed = min(projectile->lastSpeed * ACCELERATOR_BOUNCE_SPEED_COEF, ACCELERATOR_MAX_SPEED);
- projectile->speed = newSpeed;
- }
-
- // ensure the projectile's speed doesn't change after bouncing off
- // something
- b2Vec2 newVel = b2Body_GetLinearVelocity(projectile->bodyID);
- newVel = b2MulSV(newSpeed, b2Normalize(newVel));
- b2Body_SetLinearVelocity(projectile->bodyID, newVel);
- projectile->velocity = newVel;
- projectile->speed = newSpeed;
- projectile->lastSpeed = newSpeed;
-}
-
-// TODO: drone on drone collisions should reduce shield health
-void handleContactEvents(iwEnv *e) {
- b2ContactEvents events = b2World_GetContactEvents(e->worldID);
- for (int i = 0; i < events.beginCount; ++i) {
- const b2ContactBeginTouchEvent *event = events.beginEvents + i;
- entity *e1 = NULL;
- entity *e2 = NULL;
-
- if (b2Shape_IsValid(event->shapeIdA)) {
- e1 = b2Shape_GetUserData(event->shapeIdA);
- ASSERT(e1 != NULL);
- }
- if (b2Shape_IsValid(event->shapeIdB)) {
- e2 = b2Shape_GetUserData(event->shapeIdB);
- ASSERT(e2 != NULL);
- }
-
- if (e1 != NULL && e1->type == DRONE_ENTITY && e2 != NULL && e2->type == DRONE_ENTITY) {
- droneEntity *drone1 = e1->entity;
- droneEntity *drone2 = e2->entity;
-
- if (b2Contact_IsValid(event->contactId)) {
- const b2Manifold manifold = b2Contact_GetData(event->contactId).manifold;
- ASSERT(manifold.pointCount == 1);
- b2Vec2 hitImpulse = b2MulSV(manifold.points[0].normalImpulse, manifold.normal);
- droneTrackImpulse(e, drone2, hitImpulse, drone1->idx);
- droneTrackImpulse(e, drone1, b2Neg(hitImpulse), drone2->idx);
- }
- }
-
- if (e1 != NULL) {
- if (e1->type == PROJECTILE_ENTITY) {
- uint8_t numDestroyed = handleProjectileBeginContact(e, e1, e2, event->contactId, true);
- if (numDestroyed == 2) {
- continue;
- } else if (numDestroyed == 1) {
- e1 = NULL;
- }
-
- } else if (entityTypeIsWall(e1->type) && e2 != NULL) {
- if (e1->type == DEATH_WALL_ENTITY) {
- if (e2->type == DRONE_ENTITY) {
- droneEntity *drone = e2->entity;
- killDrone(e, drone);
- } else if (e2->type == SHIELD_ENTITY) {
- shieldEntity *shield = e2->entity;
- shield->health = 0.0f;
- destroyDroneShield(e, shield, true);
- e2 = NULL;
- }
- }
- }
- }
- if (e2 != NULL) {
- if (e2->type == PROJECTILE_ENTITY) {
- handleProjectileBeginContact(e, e2, e1, event->contactId, false);
- } else if (entityTypeIsWall(e2->type) && e1 != NULL) {
- if (e2->type == DEATH_WALL_ENTITY) {
- if (e1->type == DRONE_ENTITY) {
- droneEntity *drone = e1->entity;
- killDrone(e, drone);
- } else if (e1->type == SHIELD_ENTITY) {
- shieldEntity *shield = e1->entity;
- shield->health = 0.0f;
- destroyDroneShield(e, shield, true);
- }
- }
- }
- }
- }
-
- for (int i = 0; i < events.endCount; ++i) {
- const b2ContactEndTouchEvent *event = events.endEvents + i;
- entity *e1 = NULL;
- entity *e2 = NULL;
- if (b2Shape_IsValid(event->shapeIdA)) {
- e1 = b2Shape_GetUserData(event->shapeIdA);
- ASSERT(e1 != NULL);
- }
- if (b2Shape_IsValid(event->shapeIdB)) {
- e2 = b2Shape_GetUserData(event->shapeIdB);
- ASSERT(e2 != NULL);
- }
- if (e1 != NULL && e1->type == PROJECTILE_ENTITY) {
- handleProjectileEndContact(e1, e2);
- }
- if (e2 != NULL && e2->type == PROJECTILE_ENTITY) {
- handleProjectileEndContact(e2, e1);
- }
- }
-}
-
-// set pickup to respawn somewhere else randomly if a drone touched it,
-// mark the pickup as disabled if a floating wall is touching it
-void handleWeaponPickupBeginTouch(iwEnv *e, const entity *sensor, entity *visitor) {
- weaponPickupEntity *pickup = sensor->entity;
- if (pickup->floatingWallsTouching != 0) {
- return;
- }
-
- wallEntity *wall;
-
- switch (visitor->type) {
- case DRONE_ENTITY:
- disableWeaponPickup(e, pickup);
-
- droneEntity *drone = visitor->entity;
- drone->stepInfo.pickedUpWeapon = true;
- drone->stepInfo.prevWeapon = drone->weaponInfo->type;
- droneChangeWeapon(e, drone, pickup->weapon);
-
- e->stats[drone->idx].weaponsPickedUp[pickup->weapon]++;
- e->stats[drone->idx].totalWeaponsPickedUp++;
- DEBUG_LOGF("drone %d picked up weapon %d", drone->idx, pickup->weapon);
- break;
- case STANDARD_WALL_ENTITY:
- case BOUNCY_WALL_ENTITY:
- case DEATH_WALL_ENTITY:
- wall = visitor->entity;
- if (!wall->isFloating) {
- if (!wall->isSuddenDeath) {
- ERRORF("non sudden death wall type %d at cell %d touched weapon pickup", visitor->type, wall->mapCellIdx);
- }
- return;
- }
-
- pickup->floatingWallsTouching++;
- break;
- default:
- ERRORF("invalid weapon pickup begin touch visitor %d", visitor->type);
- }
-}
-
-// explode proximity detonating projectiles
-void handleProjectileBeginTouch(iwEnv *e, const entity *sensor, entity *visitor) {
- projectileEntity *projectile = sensor->entity;
-
- switch (projectile->weaponInfo->type) {
- case FLAK_CANNON_WEAPON:
- if (projectile->distance < FLAK_CANNON_SAFE_DISTANCE) {
- return;
- }
- destroyProjectile(e, projectile, true, true);
- destroyExplodedProjectiles(e);
- break;
- case MINE_LAUNCHER_WEAPON:
- if (!projectile->setMine) {
- return;
- }
-
- ASSERT(visitor->type == DRONE_ENTITY);
- const b2DistanceOutput output = closestPoint(sensor, visitor);
- const b2QueryFilter filter = {.categoryBits = PROJECTILE_SHAPE, .maskBits = WALL_SHAPE | FLOATING_WALL_SHAPE};
- if (posBehindWall(e, projectile->pos, output.pointB, NULL, filter, NULL)) {
- const droneEntity *drone = visitor->entity;
- projectile->dronesBehindWalls[projectile->numDronesBehindWalls++] = drone->idx;
- return;
- }
-
- destroyProjectile(e, projectile, true, true);
- destroyExplodedProjectiles(e);
- break;
- case BLACK_HOLE_WEAPON:
- if (visitor->type == DRONE_ENTITY) {
- const droneEntity *drone = visitor->entity;
- if (projectile->droneIdx == drone->idx && projectile->distance < BLACK_HOLE_PARENT_IGNORE_DISTANCE) {
- return;
- }
- }
-
- // copy the entity ID so it won't be changed if the entity is
- // destroyed and reused later
- const entityID *visitorID = visitor->id;
- entityID *id = fastCalloc(1, sizeof(entityID));
- id->id = visitorID->id;
- id->generation = visitorID->generation;
- cc_array_add(projectile->entsInBlackHole, id);
- break;
- default:
- ERRORF("invalid projectile type %d for begin touch event", sensor->type);
- }
-}
-
-// mark the pickup as enabled if no floating walls are touching it
-void handleWeaponPickupEndTouch(const entity *sensor, entity *visitor) {
- weaponPickupEntity *pickup = sensor->entity;
- if (pickup->respawnWait != 0.0f) {
- return;
- }
-
- wallEntity *wall;
-
- switch (visitor->type) {
- case DRONE_ENTITY:
- break;
- case STANDARD_WALL_ENTITY:
- case BOUNCY_WALL_ENTITY:
- case DEATH_WALL_ENTITY:
- wall = visitor->entity;
- if (!wall->isFloating) {
- return;
- }
-
- pickup->floatingWallsTouching--;
- break;
- default:
- ERRORF("invalid weapon pickup end touch visitor %d", visitor->type);
- }
-}
-
-void handleProjectileEndTouch(const entity *sensor, entity *visitor) {
- projectileEntity *projectile = sensor->entity;
-
- switch (projectile->weaponInfo->type) {
- case FLAK_CANNON_WEAPON:
- break;
- case MINE_LAUNCHER_WEAPON:
- if (projectile->numDronesBehindWalls == 0) {
- return;
- }
- projectile->numDronesBehindWalls--;
- break;
- case BLACK_HOLE_WEAPON:
- if (visitor == NULL) {
- return;
- }
-
- const entityID *visitorID = visitor->id;
- for (uint8_t i = 0; i < cc_array_size(projectile->entsInBlackHole); ++i) {
- entityID *id = safe_array_get_at(projectile->entsInBlackHole, i);
- if (id->id == visitorID->id) {
- fastFree(id);
- cc_array_remove_fast_at(projectile->entsInBlackHole, i, NULL);
- return;
- }
- }
- break;
- default:
- ERRORF("invalid projectile type %d for end touch event", projectile->weaponInfo->type);
- }
-}
-
-void handleSensorEvents(iwEnv *e) {
- b2SensorEvents events = b2World_GetSensorEvents(e->worldID);
- for (int i = 0; i < events.beginCount; ++i) {
- const b2SensorBeginTouchEvent *event = events.beginEvents + i;
- if (!b2Shape_IsValid(event->sensorShapeId)) {
- DEBUG_LOG("could not find sensor shape for begin touch event");
- continue;
- }
- entity *s = b2Shape_GetUserData(event->sensorShapeId);
- ASSERT(s != NULL);
-
- if (!b2Shape_IsValid(event->visitorShapeId)) {
- DEBUG_LOG("could not find visitor shape for begin touch event");
- continue;
- }
- entity *v = b2Shape_GetUserData(event->visitorShapeId);
- ASSERT(v != NULL);
-
- switch (s->type) {
- case WEAPON_PICKUP_ENTITY:
- handleWeaponPickupBeginTouch(e, s, v);
- break;
- case PROJECTILE_ENTITY:
- handleProjectileBeginTouch(e, s, v);
- break;
- default:
- ERRORF("unknown entity type %d for sensor begin touch event", s->type);
- }
- }
-
- for (int i = 0; i < events.endCount; ++i) {
- const b2SensorEndTouchEvent *event = events.endEvents + i;
- if (!b2Shape_IsValid(event->sensorShapeId)) {
- DEBUG_LOG("could not find sensor shape for end touch event");
- continue;
- }
- entity *s = b2Shape_GetUserData(event->sensorShapeId);
- ASSERT(s != NULL);
- entity *v = NULL;
- if (b2Shape_IsValid(event->visitorShapeId)) {
- v = b2Shape_GetUserData(event->visitorShapeId);
- ASSERT(v != NULL);
- }
-
- if (s->type == PROJECTILE_ENTITY) {
- handleProjectileEndTouch(s, v);
- continue;
- }
-
- if (v != NULL) {
- handleWeaponPickupEndTouch(s, v);
- }
- }
-}
-
-void findNearWalls(const iwEnv *e, const droneEntity *drone, nearEntity nearestWalls[], const uint8_t nWalls) {
- nearEntity nearWalls[MAX_NEAREST_WALLS];
-
- for (uint8_t i = 0; i < MAX_NEAREST_WALLS; ++i) {
- const uint32_t idx = (MAX_NEAREST_WALLS * drone->mapCellIdx) + i;
- const uint16_t wallIdx = e->map->nearestWalls[idx].idx;
- wallEntity *wall = safe_array_get_at(e->walls, wallIdx);
- nearWalls[i].entity = wall;
- nearWalls[i].distanceSquared = b2DistanceSquared(drone->pos, wall->pos);
- }
- insertionSort(nearWalls, MAX_NEAREST_WALLS);
- memcpy(nearestWalls, nearWalls, nWalls * sizeof(nearEntity));
-}
-
-#endif
diff --git a/pufferlib/ocean/impulse_wars/helpers.h b/pufferlib/ocean/impulse_wars/helpers.h
deleted file mode 100644
index 1692d6b9b..000000000
--- a/pufferlib/ocean/impulse_wars/helpers.h
+++ /dev/null
@@ -1,246 +0,0 @@
-#ifndef IMPULSE_WARS_HELPERS_H
-#define IMPULSE_WARS_HELPERS_H
-
-#include
-#include
-#include
-#include
-
-#include "box2d/box2d.h"
-
-#include "include/cc_array.h"
-
-#ifndef NDEBUG
-#define ON_ERROR __builtin_trap()
-#define _DEBUG_GET_TIMEINFO() \
- time_t _t = time(NULL); \
- struct tm *_timeinfo; \
- _timeinfo = localtime(&_t)
-#define DEBUG_RAW_LOG(msg) \
- do { \
- printf(msg); \
- fflush(stdout); \
- } while (0)
-#define DEBUG_RAW_LOGF(fmt, args...) \
- do { \
- printf(fmt, args); \
- fflush(stdout); \
- } while (0)
-#define DEBUG_LOGF(fmt, args...) \
- do { \
- _DEBUG_GET_TIMEINFO(); \
- printf(fmt " %d:%d:%d %s:%d\n", args, _timeinfo->tm_hour, _timeinfo->tm_min, _timeinfo->tm_sec, __FILE__, __LINE__); \
- fflush(stdout); \
- } while (0)
-#define DEBUG_LOG(msg) \
- do { \
- _DEBUG_GET_TIMEINFO(); \
- printf(msg " %d:%d:%d %s:%d\n", _timeinfo->tm_hour, _timeinfo->tm_min, _timeinfo->tm_sec, __FILE__, __LINE__); \
- fflush(stdout); \
- } while (0)
-
-#define ASSERT(condition) \
- do { \
- if (!(condition)) { \
- printf("\nASSERTION FAILED: %s at %s:%d\n\n", #condition, __FILE__, __LINE__); \
- fflush(stdout); \
- ON_ERROR; \
- } \
- } while (0)
-#define ASSERTF(condition, fmt, args...) \
- do { \
- if (!(condition)) { \
- printf("\nASSERTION FAILED: %s; " fmt "; at %s:%d\n\n", #condition, args, __FILE__, __LINE__); \
- fflush(stdout); \
- ON_ERROR; \
- } \
- } while (0)
-#else
-#define ON_ERROR abort()
-#define DEBUG_RAW_LOG(msg)
-#define DEBUG_RAW_LOGF(fmt, args...)
-#define DEBUG_LOGF(fmt, args...)
-#define DEBUG_LOG(msg)
-#define ASSERT(condition)
-#define ASSERTF(condition, fmt, args...)
-#endif
-
-#define ERRORF(fmt, args...) \
- fprintf(stderr, "FATAL: " fmt " %s:%d\n", args, __FILE__, __LINE__); \
- fflush(stderr); \
- ON_ERROR
-#define ERROR(msg) \
- fprintf(stderr, "FATAL: " msg " %s:%d\n", __FILE__, __LINE__); \
- fflush(stderr); \
- ON_ERROR
-
-// ignore compiler warnings about unused variables for variables that are
-// only used in debug builds
-#define MAYBE_UNUSED(x) (void)x
-
-#define SQUARED(x) ((x) * (x))
-
-#ifndef PI
-#define PI 3.14159265358979323846f
-#endif
-
-#ifndef RAD2DEG
-#define RAD2DEG (180.0f / PI)
-#endif
-
-#define MASS(density, radius) ((density) * PI * (radius) * (radius))
-#define INV_MASS(mass) (1.0f / (mass))
-// given a mass and radius, calculate the density such that the density
-// and radius will result in the same mass as what's given
-#define MATCHING_DENSITY(mass, radius) ((mass) / (PI * (radius) * (radius)))
-
-#define ASSERT_VEC_BOUNDED(vec) \
- ASSERTF(vec.x <= 1.0f, "vec.x: %f", vec.x); \
- ASSERTF(vec.x >= -1.0f, "vec.x: %f", vec.x); \
- ASSERTF(vec.y <= 1.0f, "vec.y: %f", vec.y); \
- ASSERTF(vec.y >= -1.0f, "vec.y: %f", vec.y)
-
-#define ASSERT_VEC_NORMALIZED(vec) \
- ASSERT_VEC_BOUNDED(vec); \
- do { \
- const b2Vec2 norm = b2Normalize(vec); \
- MAYBE_UNUSED(norm); \
- ASSERTF(fabs(vec.x - norm.x) < 0.000001f, "vec: %f, %f norm: %f, %f", vec.x, vec.y, norm.x, norm.y); \
- ASSERTF(fabs(vec.y - norm.y) < 0.000001f, "vec: %f, %f norm: %f, %f", vec.x, vec.y, norm.x, norm.y); \
- } while (0)
-
-// use malloc when debugging so the address sanitizer can find issues with
-// heap memory, use dlmalloc in release mode for performance; emscripten
-// uses dlmalloc by default so no need to change anything here; dlmalloc
-// sometimes won't compile on macOS so just use malloc and friends
-#if !defined(NDEBUG) || defined(__EMSCRIPTEN__) || defined(__APPLE__)
-#define fastMalloc(size) malloc(size)
-#define fastMallocFn malloc
-#define fastCalloc(nmemb, size) calloc(nmemb, size)
-#define fastCallocFn calloc
-#define fastFree(ptr) free(ptr)
-#define fastFreeFn free
-#else
-#include "include/dlmalloc.h"
-#define fastMalloc(size) dlmalloc(size)
-#define fastMallocFn dlmalloc
-#define fastCalloc(nmemb, size) dlcalloc(nmemb, size)
-#define fastCallocFn dlcalloc
-#define fastFree(ptr) dlfree(ptr)
-#define fastFreeFn dlfree
-#endif
-
-static inline void create_array(CC_Array **array, size_t initialCap) {
- CC_ArrayConf conf;
- cc_array_conf_init(&conf);
- conf.capacity = initialCap;
- conf.mem_alloc = fastMallocFn;
- conf.mem_calloc = fastCallocFn;
- conf.mem_free = fastFreeFn;
-
- cc_array_new_conf(&conf, array);
-}
-
-// automatically checks that the index is valid and returns the value
-// so callers can use it as a constant expression
-static inline void *safe_array_get_at(const CC_Array *const array, size_t index) {
- void *val;
- const enum cc_stat res = cc_array_get_at(array, index, &val);
- ASSERT(res == CC_OK);
- MAYBE_UNUSED(res);
- return val;
-}
-
-static inline bool b2VecEqual(const b2Vec2 v1, const b2Vec2 v2) {
- return v1.x == v2.x && v1.y == v2.y;
-}
-
-// from https://lemire.me/blog/2019/03/19/the-fastest-conventional-random-number-generator-that-can-pass-big-crush/
-// see also https://github.com/lemire/testingRNG
-uint64_t wyhash64(uint64_t *state) {
- *state += 0x60bee2bee120fc15;
- __uint128_t tmp;
- tmp = (__uint128_t)(*state) * 0xa3b195354a39b70d;
- uint64_t m1 = (tmp >> 64) ^ tmp;
- tmp = (__uint128_t)m1 * 0x1b03738712fad5c9;
- uint64_t m2 = (tmp >> 64) ^ tmp;
- return m2;
-}
-
-static inline float randFloat(uint64_t *state, const float min, const float max) {
- float n = wyhash64(state) / (float)UINT64_MAX;
- return min + n * (max - min);
-}
-
-static inline int randInt(uint64_t *state, const int min, const int max) {
- return min + wyhash64(state) % (max - min + 1);
-}
-
-static inline float logBasef(const float v, const float b) {
- return log2f(v) / log2(b);
-}
-
-#define min(a, b) \
- ({ \
- __typeof__(a) _a = (a); \
- __typeof__(b) _b = (b); \
- _a < _b ? _a : _b; \
- })
-
-#define max(a, b) \
- ({ \
- __typeof__(a) _a = (a); \
- __typeof__(b) _b = (b); \
- _a > _b ? _a : _b; \
- })
-
-// clamps between 0 and 1
-static inline float clamp(float f) {
- return min(max(f, 0.0f), 1.0f);
-}
-
-// normalize value to be between 0 and max, or -max and max;
-// minIsZero determines if the min value is 0 or -max
-static inline float scaleValue(const float v, const float max, const bool minIsZero) {
- ASSERTF(v <= max, "v: %f, max: %f", v, max);
- ASSERTF(!minIsZero || v >= 0, "v: %f", v);
- ASSERTF(minIsZero || v >= -max, "v: %f, -max: %f", v, -max);
-
- float scaled = v / max;
- if (minIsZero) {
- return max(min(scaled, max), 0.0f);
- } else {
- return max(min(scaled, max), -1.0f);
- }
-}
-
-static inline uint8_t oneHotEncode(float *obs, const uint16_t offset, const uint8_t val, const uint8_t max) {
- ASSERTF(val < max, "val: %d, max: %d", val, max);
- memset(obs + offset, 0x0, max * sizeof(float));
- obs[offset + val] = 1;
- return max;
-}
-
-static inline uint16_t alignedSize(const uint16_t size, const uint8_t align) {
- return (size + align - 1) & ~(align - 1);
-}
-
-#define BITNSLOTS(nb) ((nb + sizeof(uint8_t) - 1) / sizeof(uint8_t))
-
-static inline uint16_t bitMask(const uint16_t n) {
- return 1 << (n % sizeof(uint8_t));
-}
-
-static inline uint16_t bitSlot(const uint16_t n) {
- return n / sizeof(uint8_t);
-}
-
-static inline void bitSet(uint8_t *b, const uint16_t n) {
- b[bitSlot(n)] |= bitMask(n);
-}
-
-static inline bool bitTest(const uint8_t *b, const uint16_t n) {
- return b[bitSlot(n)] & bitMask(n);
-}
-
-#endif
diff --git a/pufferlib/ocean/impulse_wars/impulse_wars.c b/pufferlib/ocean/impulse_wars/impulse_wars.c
deleted file mode 100644
index 1dfbd1d5c..000000000
--- a/pufferlib/ocean/impulse_wars/impulse_wars.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#include "env.h"
-#include "render.h"
-
-#ifdef __EMSCRIPTEN__
-void emscriptenStep(void *e) {
- stepEnv((iwEnv *)e);
- return;
-}
-#endif
-
-int main(void) {
- const int NUM_DRONES = 2;
-
- iwEnv *e = fastCalloc(1, sizeof(iwEnv));
-
- posix_memalign((void **)&e->observations, sizeof(void *), alignedSize(NUM_DRONES * obsBytes(NUM_DRONES), sizeof(float)));
- e->rewards = fastCalloc(NUM_DRONES, sizeof(float));
- e->actions = fastCalloc(NUM_DRONES * CONTINUOUS_ACTION_SIZE, sizeof(float));
- e->masks = fastCalloc(NUM_DRONES, sizeof(uint8_t));
- e->terminals = fastCalloc(NUM_DRONES, sizeof(uint8_t));
- e->truncations = fastCalloc(NUM_DRONES, sizeof(uint8_t));
-
- rayClient *client = createRayClient();
- e->client = client;
-
- initEnv(e, NUM_DRONES, 0, -1, time(NULL), false, false, false, false);
- initMaps(e);
- setupEnv(e);
- // e->humanInput = true;
-
-#ifdef __EMSCRIPTEN__
- lastFrameTime = emscripten_get_now();
- emscripten_set_main_loop_arg(emscriptenStep, e, 0, true);
-#else
- while (!WindowShouldClose()) {
- stepEnv(e);
- }
-
- destroyEnv(e);
- destroyMaps();
- free(e->observations);
- fastFree(e->actions);
- fastFree(e->rewards);
- fastFree(e->masks);
- fastFree(e->terminals);
- fastFree(e->truncations);
- fastFree(e);
- destroyRayClient(client);
-#endif
- return 0;
-}
diff --git a/pufferlib/ocean/impulse_wars/impulse_wars.py b/pufferlib/ocean/impulse_wars/impulse_wars.py
deleted file mode 100644
index 0f958b8dc..000000000
--- a/pufferlib/ocean/impulse_wars/impulse_wars.py
+++ /dev/null
@@ -1,161 +0,0 @@
-from types import SimpleNamespace
-
-import gymnasium
-import numpy as np
-
-import pufferlib
-from pufferlib.ocean.impulse_wars import binding
-
-
-discMoveToContMove = np.array([
- [1.0, 0.707107, 0.0, -0.707107, -1.0, -0.707107, 0.0, 0.707107, 0.0],
- [0.0, 0.707107, 1.0, 0.707107, 0.0, -0.707107, -1.0, -0.707107, 0.0],
-], dtype=np.float32)
-discAimToContAim = np.array([
- [1.0, 0.92388, 0.707107, 0.382683, 0.0, -0.382683, -0.707107, -0.92388, -1.0, -0.92388, -0.707107, -0.382683, 0.0, 0.382683, 0.707107, 0.92388, 0.0],
- [0.0, 0.382683, 0.707107, 0.92388, 1.0, 0.92388, 0.707107, 0.382683, 0.0, -0.382683, -0.707107, -0.92388, -1.0, -0.92388, -0.707107, -0.382683, 0.0],
-], dtype=np.float32)
-
-
-class ImpulseWars(pufferlib.PufferEnv):
- def __init__(
- self,
- num_envs: int = 1,
- num_drones: int = 2,
- num_agents: int = 1,
- enable_teams: bool = False,
- sitting_duck: bool = False,
- continuous: bool = False,
- is_training: bool = True,
- human_control: bool = False,
- seed: int = 0,
- render: bool = False,
- report_interval: int = 64,
- buf = None,
- ):
- self.obsInfo = SimpleNamespace(**binding.get_consts(num_drones))
-
- if num_envs <= 0:
- raise ValueError("num_envs must be greater than 0")
- if num_drones > self.obsInfo.maxDrones or num_drones <= 0:
- raise ValueError(f"num_drones must greater than 0 and less than or equal to {self.obsInfo.maxDrones}")
- if num_agents > num_drones or num_agents <= 0:
- raise ValueError("num_agents must greater than 0 and less than or equal to num_drones")
- if enable_teams and (num_drones % 2 != 0 or num_drones <= 2):
- raise ValueError("enable_teams is only supported for even numbers of drones greater than 2")
-
- self.numDrones = num_drones
- self.continuous = continuous
-
- self.num_agents = num_agents * num_envs
- self.tick = 0
-
- # map observations are bit packed to save space, and scalar
- # observations need to be floats
- self.single_observation_space = gymnasium.spaces.Box(
- low=0, high=255, shape=(self.obsInfo.obsBytes,), dtype=np.uint8
- )
-
- if self.continuous:
- # action space is actually bounded by (-1, 1) but pufferlib
- # will check that actions are within the bounds of the action
- # space before actions get to the env, and we ensure the actions
- # are bounded there; so set bounds to (-inf, inf) here so
- # action bounds checks pass
- self.single_action_space = gymnasium.spaces.Box(
- low=float("-inf"), high=float("inf"), shape=(self.obsInfo.contActionsSize,), dtype=np.float32
- )
- else:
- self.single_action_space = gymnasium.spaces.MultiDiscrete(
- [
- 9, # move, noop + 8 directions
- 17, # aim, noop + 16 directions
- 2, # shoot or not
- 2, # brake or not
- 2, # burst
- ]
- )
-
- self.report_interval = report_interval
- self.render_mode = "human" if render else None
-
- super().__init__(buf)
- if not self.continuous:
- self.actions = np.zeros((self.num_agents, self.obsInfo.contActionsSize), dtype=np.float32)
-
- self.c_envs = binding.vec_init(
- self.observations,
- self.actions,
- self.rewards,
- self.terminals,
- self.truncations,
- num_envs,
- seed,
- num_drones=num_drones,
- num_agents=num_agents,
- map_idx=-1,
- enable_teams=enable_teams,
- sitting_duck=sitting_duck,
- is_training=is_training,
- continuous=continuous,
- )
-
- binding.shared(self.c_envs)
-
- def reset(self, seed=None):
- self.tick = 0
- if seed is None:
- binding.vec_reset(self.c_envs, 0)
- else:
- binding.vec_reset(self.c_envs, seed)
- return self.observations, []
-
- def step(self, actions):
- if self.continuous:
- self.actions[:] = actions
- else:
- contMove = discMoveToContMove[:, actions[:, 0]].T
- contAim = discAimToContAim[:, actions[:, 1]].T
- contRest = actions[:, 2:].astype(np.float32)
- self.actions[:] = np.concatenate([contMove, contAim, contRest], axis=1)
-
- self.tick += 1
- binding.vec_step(self.c_envs)
-
- infos = []
- if self.tick % self.report_interval == 0:
- infos.append(binding.vec_log(self.c_envs))
-
- return self.observations, self.rewards, self.terminals, self.truncations, infos
-
- def render(self):
- binding.vec_render(self.c_envs, 0)
-
- def close(self):
- binding.vec_close(self.c_envs)
-
-
-def testPerf(timeout, actionCache, numEnvs):
- env = ImpulseWars(numEnvs)
-
- import time
-
- np.random.seed(int(time.time()))
- actions = np.random.uniform(-1, 1, (actionCache, env.num_agents, 7))
-
- tick = 0
- start = time.time()
- while time.time() - start < timeout:
- action = actions[tick % actionCache]
- env.step(action)
- tick += 1
-
- sps = numEnvs * (tick / (time.time() - start))
- print(f"SPS: {sps:,}")
- print(f"Steps: {numEnvs * tick}")
-
- env.close()
-
-
-if __name__ == "__main__":
- testPerf(timeout=5, actionCache=1024, numEnvs=1)
diff --git a/pufferlib/ocean/impulse_wars/include/cc_array.h b/pufferlib/ocean/impulse_wars/include/cc_array.h
deleted file mode 100644
index 311f99122..000000000
--- a/pufferlib/ocean/impulse_wars/include/cc_array.h
+++ /dev/null
@@ -1,1410 +0,0 @@
-/*
- * Collections-C
- * Copyright (C) 2013-2015 Srđan Panić
- *
- * This file is part of Collections-C.
- *
- * Collections-C is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Collections-C is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Collections-C. If not, see .
- */
-
-#ifndef CC_ARRAY_H
-#define CC_ARRAY_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "cc_common.h"
-
-/**
- * A dynamic array that expands automatically as elements are
- * added. The array supports amortized constant time insertion
- * and removal of elements at the end of the array, as well as
- * constant time access.
- */
-typedef struct cc_array_s CC_Array;
-
-/**
- * Array configuration structure. Used to initialize a new Array
- * with specific values.
- */
-typedef struct cc_array_conf_s {
- /**
- * The initial capacity of the array */
- size_t capacity;
-
- /**
- * The rate at which the buffer expands (capacity * exp_factor). */
- float exp_factor;
-
- /**
- * Memory allocators used to allocate the Array structure and the
- * underlying data buffers. */
- void *(*mem_alloc)(size_t size);
- void *(*mem_calloc)(size_t blocks, size_t size);
- void (*mem_free)(void *block);
-} CC_ArrayConf;
-
-/**
- * Array iterator structure. Used to iterate over the elements of
- * the array in an ascending order. The iterator also supports
- * operations for safely adding and removing elements during
- * iteration.
- */
-typedef struct cc_array_iter_s {
- /**
- * The array associated with this iterator */
- CC_Array *ar;
-
- /**
- * The current position of the iterator.*/
- size_t index;
-
- /**
- * Set to true if the last returned element was removed. */
- bool last_removed;
-} CC_ArrayIter;
-
-/**
- * Array zip iterator structure. Used to iterate over the elements of two
- * arrays in lockstep in an ascending order until one of the Arrays is
- * exhausted. The iterator also supports operations for safely adding
- * and removing elements during iteration.
- */
-typedef struct array_zip_iter_s {
- CC_Array *ar1;
- CC_Array *ar2;
- size_t index;
- bool last_removed;
-} CC_ArrayZipIter;
-
-enum cc_stat cc_array_new(CC_Array **out);
-enum cc_stat cc_array_new_conf(CC_ArrayConf const *const conf, CC_Array **out);
-void cc_array_conf_init(CC_ArrayConf *conf);
-size_t cc_array_struct_size();
-
-void cc_array_destroy(CC_Array *ar);
-void cc_array_destroy_cb(CC_Array *ar, void (*cb)(void *));
-
-enum cc_stat cc_array_add(CC_Array *ar, void *element);
-enum cc_stat cc_array_add_at(CC_Array *ar, void *element, size_t index);
-enum cc_stat cc_array_replace_at(CC_Array *ar, void *element, size_t index, void **out);
-enum cc_stat cc_array_swap_at(CC_Array *ar, size_t index1, size_t index2);
-
-enum cc_stat cc_array_remove(CC_Array *ar, void *element, void **out);
-enum cc_stat cc_array_remove_fast(CC_Array *ar, void *element, void **out);
-enum cc_stat cc_array_remove_at(CC_Array *ar, size_t index, void **out);
-enum cc_stat cc_array_remove_fast_at(CC_Array *ar, size_t index, void **out);
-enum cc_stat cc_array_remove_last(CC_Array *ar, void **out);
-void cc_array_remove_all(CC_Array *ar);
-void cc_array_remove_all_free(CC_Array *ar);
-
-enum cc_stat cc_array_get_at(const CC_Array *ar, size_t index, void **out);
-enum cc_stat cc_array_get_last(const CC_Array *ar, void **out);
-
-enum cc_stat cc_array_subarray(CC_Array *ar, size_t from, size_t to, CC_Array **out);
-enum cc_stat cc_array_copy_shallow(CC_Array *ar, CC_Array **out);
-enum cc_stat cc_array_copy_deep(CC_Array *ar, void *(*cp)(void *), CC_Array **out);
-
-void cc_array_reverse(CC_Array *ar);
-enum cc_stat cc_array_trim_capacity(CC_Array *ar);
-
-size_t cc_array_contains(const CC_Array *ar, void *element);
-size_t cc_array_contains_value(const CC_Array *ar, void *element, int (*cmp)(const void *, const void *));
-size_t cc_array_size(const CC_Array *ar);
-size_t cc_array_capacity(const CC_Array *ar);
-
-enum cc_stat cc_array_index_of(const CC_Array *ar, void *element, size_t *index);
-void cc_array_sort(CC_Array *ar, int (*cmp)(const void *, const void *));
-
-void cc_array_map(CC_Array *ar, void (*fn)(void *));
-void cc_array_reduce(CC_Array *ar, void (*fn)(void *, void *, void *), void *result);
-
-enum cc_stat cc_array_filter_mut(CC_Array *ar, bool (*predicate)(const void *));
-enum cc_stat cc_array_filter(CC_Array *ar, bool (*predicate)(const void *), CC_Array **out);
-
-void cc_array_iter_init(CC_ArrayIter *iter, CC_Array *ar);
-enum cc_stat cc_array_iter_next(CC_ArrayIter *iter, void **out);
-enum cc_stat cc_array_iter_remove(CC_ArrayIter *iter, void **out);
-enum cc_stat cc_array_iter_remove_fast(CC_ArrayIter *iter, void **out);
-enum cc_stat cc_array_iter_add(CC_ArrayIter *iter, void *element);
-enum cc_stat cc_array_iter_replace(CC_ArrayIter *iter, void *element, void **out);
-size_t cc_array_iter_index(CC_ArrayIter *iter);
-
-void cc_array_zip_iter_init(CC_ArrayZipIter *iter, CC_Array *a1, CC_Array *a2);
-enum cc_stat cc_array_zip_iter_next(CC_ArrayZipIter *iter, void **out1, void **out2);
-enum cc_stat cc_array_zip_iter_add(CC_ArrayZipIter *iter, void *e1, void *e2);
-enum cc_stat cc_array_zip_iter_remove(CC_ArrayZipIter *iter, void **out1, void **out2);
-enum cc_stat cc_array_zip_iter_replace(CC_ArrayZipIter *iter, void *e1, void *e2, void **out1, void **out2);
-size_t cc_array_zip_iter_index(CC_ArrayZipIter *iter);
-
-const void *const *cc_array_get_buffer(CC_Array *ar);
-
-#define CC_ARRAY_FOREACH(val, array, body) \
- { \
- CC_ArrayIter cc_array_iter_53d46d2a04458e7b; \
- cc_array_iter_init(&cc_array_iter_53d46d2a04458e7b, array); \
- void *val; \
- while (cc_array_iter_next(&cc_array_iter_53d46d2a04458e7b, &val) != CC_ITER_END) \
- body \
- }
-
-#define CC_ARRAY_FOREACH_ZIP(val1, val2, array1, array2, body) \
- { \
- CC_ArrayZipIter cc_array_zip_iter_ea08d3e52f25883b3; \
- cc_array_zip_iter_init(&cc_array_zip_iter_ea08d3e52f25883b3, array1, array2); \
- void *val1; \
- void *val2; \
- while (cc_array_zip_iter_next(&cc_array_zip_iter_ea08d3e52f25883b3, &val1, &val2) != CC_ITER_END) \
- body \
- }
-
-#define DEFAULT_CAPACITY 8
-#define DEFAULT_EXPANSION_FACTOR 2
-
-struct cc_array_s {
- size_t size;
- size_t capacity;
- float exp_factor;
- void **buffer;
-
- void *(*mem_alloc)(size_t size);
- void *(*mem_calloc)(size_t blocks, size_t size);
- void (*mem_free)(void *block);
-};
-
-static enum cc_stat expand_array_capacity(CC_Array *ar);
-
-/**
- * Creates a new empty array and returns a status code.
- *
- * @param[out] out pointer to where the newly created CC_Array is to be stored
- *
- * @return CC_OK if the creation was successful, or CC_ERR_ALLOC if the
- * memory allocation for the new CC_Array structure failed.
- */
-enum cc_stat cc_array_new(CC_Array **out) {
- CC_ArrayConf c;
- cc_array_conf_init(&c);
- return cc_array_new_conf(&c, out);
-}
-
-/**
- * Creates a new empty CC_Array based on the specified CC_ArrayConf struct and
- * returns a status code.
- *
- * The CC_Array is allocated using the allocators specified in the CC_ArrayConf
- * struct. The allocation may fail if underlying allocator fails. It may also
- * fail if the values of exp_factor and capacity in the CC_ArrayConf do not meet
- * the following condition: exp_factor < (CC_MAX_ELEMENTS / capacity).
- *
- * @param[in] conf array configuration structure
- * @param[out] out pointer to where the newly created CC_Array is to be stored
- *
- * @return CC_OK if the creation was successful, CC_ERR_INVALID_CAPACITY if
- * the above mentioned condition is not met, or CC_ERR_ALLOC if the memory
- * allocation for the new CC_Array structure failed.
- */
-enum cc_stat cc_array_new_conf(CC_ArrayConf const *const conf, CC_Array **out) {
- float ex;
-
- /* The expansion factor must be greater than one for the
- * array to grow */
- if (conf->exp_factor <= 1) {
- ex = DEFAULT_EXPANSION_FACTOR;
- } else {
- ex = conf->exp_factor;
- }
-
- /* Needed to avoid an integer overflow on the first resize and
- * to easily check for any future overflows. */
- if (!conf->capacity || ex >= CC_MAX_ELEMENTS / conf->capacity) {
- return CC_ERR_INVALID_CAPACITY;
- }
-
- CC_Array *ar = (CC_Array *)conf->mem_calloc(1, sizeof(CC_Array));
-
- if (!ar) {
- return CC_ERR_ALLOC;
- }
-
- void **buff = (void **)conf->mem_alloc(conf->capacity * sizeof(void *));
-
- if (!buff) {
- conf->mem_free(ar);
- return CC_ERR_ALLOC;
- }
-
- ar->buffer = buff;
- ar->exp_factor = ex;
- ar->capacity = conf->capacity;
- ar->mem_alloc = conf->mem_alloc;
- ar->mem_calloc = conf->mem_calloc;
- ar->mem_free = conf->mem_free;
-
- *out = ar;
- return CC_OK;
-}
-
-/**
- * Initializes the fields of the CC_ArrayConf struct to default values.
- *
- * @param[in, out] conf CC_ArrayConf structure that is being initialized
- */
-void cc_array_conf_init(CC_ArrayConf *conf) {
- conf->exp_factor = DEFAULT_EXPANSION_FACTOR;
- conf->capacity = DEFAULT_CAPACITY;
- conf->mem_alloc = malloc;
- conf->mem_calloc = calloc;
- conf->mem_free = free;
-}
-
-/**
- * Destroys the CC_Array structure, but leaves the data it used to hold intact.
- *
- * @param[in] ar the array that is to be destroyed
- */
-void cc_array_destroy(CC_Array *ar) {
- ar->mem_free(ar->buffer);
- ar->mem_free(ar);
-}
-
-/**
- * Destroys the CC_Array structure along with all the data it holds.
- *
- * @note
- * This function should not be called on a array that has some of its elements
- * allocated on the stack.
- *
- * @param[in] ar the array that is being destroyed
- */
-void cc_array_destroy_cb(CC_Array *ar, void (*cb)(void *)) {
- size_t i;
- for (i = 0; i < ar->size; i++) {
- cb(ar->buffer[i]);
- }
-
- cc_array_destroy(ar);
-}
-
-/**
- * Adds a new element to the CC_Array. The element is appended to the array making
- * it the last element (the one with the highest index) of the CC_Array.
- *
- * @param[in] ar the array to which the element is being added
- * @param[in] element the element that is being added
- *
- * @return CC_OK if the element was successfully added, CC_ERR_ALLOC if the
- * memory allocation for the new element failed, or CC_ERR_MAX_CAPACITY if the
- * array is already at maximum capacity.
- */
-enum cc_stat cc_array_add(CC_Array *ar, void *element) {
- if (ar->size >= ar->capacity) {
- enum cc_stat status = expand_array_capacity(ar);
- if (status != CC_OK) {
- return status;
- }
- }
-
- ar->buffer[ar->size] = element;
- ar->size++;
-
- return CC_OK;
-}
-
-/**
- * Adds a new element to the array at a specified position by shifting all
- * subsequent elements by one. The specified index must be within the bounds
- * of the array. This function may also fail if the memory allocation for
- * the new element was unsuccessful.
- *
- * @param[in] ar the array to which the element is being added
- * @param[in] element the element that is being added
- * @param[in] index the position in the array at which the element is being
- * added
- *
- * @return CC_OK if the element was successfully added, CC_ERR_OUT_OF_RANGE if
- * the specified index was not in range, CC_ERR_ALLOC if the memory
- * allocation for the new element failed, or CC_ERR_MAX_CAPACITY if the
- * array is already at maximum capacity.
- */
-enum cc_stat cc_array_add_at(CC_Array *ar, void *element, size_t index) {
- if (index == ar->size) {
- return cc_array_add(ar, element);
- }
-
- if ((ar->size == 0 && index != 0) || index > (ar->size - 1)) {
- return CC_ERR_OUT_OF_RANGE;
- }
-
- if (ar->size >= ar->capacity) {
- enum cc_stat status = expand_array_capacity(ar);
- if (status != CC_OK) {
- return status;
- }
- }
-
- size_t shift = (ar->size - index) * sizeof(void *);
-
- memmove(&(ar->buffer[index + 1]),
- &(ar->buffer[index]),
- shift);
-
- ar->buffer[index] = element;
- ar->size++;
-
- return CC_OK;
-}
-
-/**
- * Replaces an array element at the specified index and optionally sets the out
- * parameter to the value of the replaced element. The specified index must be
- * within the bounds of the CC_Array.
- *
- * @param[in] ar array whose element is being replaced
- * @param[in] element replacement element
- * @param[in] index index at which the replacement element should be inserted
- * @param[out] out pointer to where the replaced element is stored, or NULL if
- * it is to be ignored
- *
- * @return CC_OK if the element was successfully replaced, or CC_ERR_OUT_OF_RANGE
- * if the index was out of range.
- */
-enum cc_stat cc_array_replace_at(CC_Array *ar, void *element, size_t index, void **out) {
- if (index >= ar->size) {
- return CC_ERR_OUT_OF_RANGE;
- }
-
- if (out) {
- *out = ar->buffer[index];
- }
-
- ar->buffer[index] = element;
-
- return CC_OK;
-}
-
-enum cc_stat cc_array_swap_at(CC_Array *ar, size_t index1, size_t index2) {
- void *tmp;
-
- if (index1 >= ar->size || index2 >= ar->size) {
- return CC_ERR_OUT_OF_RANGE;
- }
-
- tmp = ar->buffer[index1];
-
- ar->buffer[index1] = ar->buffer[index2];
- ar->buffer[index2] = tmp;
- return CC_OK;
-}
-
-/**
- * Removes the specified element from the CC_Array if such element exists and
- * optionally sets the out parameter to the value of the removed element.
- *
- * @param[in] ar array from which the element is being removed
- * @param[in] element element being removed
- * @param[out] out pointer to where the removed value is stored, or NULL
- * if it is to be ignored
- *
- * @return CC_OK if the element was successfully removed, or
- * CC_ERR_VALUE_NOT_FOUND if the element was not found.
- */
-enum cc_stat cc_array_remove(CC_Array *ar, void *element, void **out) {
- size_t index;
- enum cc_stat status = cc_array_index_of(ar, element, &index);
-
- if (status == CC_ERR_OUT_OF_RANGE) {
- return CC_ERR_VALUE_NOT_FOUND;
- }
-
- if (index != ar->size - 1) {
- size_t block_size = (ar->size - 1 - index) * sizeof(void *);
-
- memmove(&(ar->buffer[index]),
- &(ar->buffer[index + 1]),
- block_size);
- }
- ar->size--;
-
- if (out) {
- *out = element;
- }
-
- return CC_OK;
-}
-
-/**
- * Removes a CC_Array element without preserving order and optionally sets the
- * out parameter to the value of the removed element. The last element of the
- * array is moved to the index of the element being removed, and the last
- * element is removed.
- *
- * @param[in] ar the array whose last element is being removed
- * @param[out] out pointer to where the removed value is stored, or NULL if it is
- * to be ignored
- *
- * @return CC_OK if the element was successfully removed, or CC_ERR_OUT_OF_RANGE
- * if the CC_Array is already empty.
- */
-enum cc_stat cc_array_remove_fast(CC_Array *ar, void *element, void **out) {
- size_t index = 0;
- const enum cc_stat status = cc_array_index_of(ar, element, &index);
- if (status != CC_OK) {
- return status;
- }
-
- if (out) {
- *out = ar->buffer[index];
- }
-
- ar->buffer[index] = ar->buffer[ar->size - 1];
- ar->size--;
-
- return CC_OK;
-}
-
-/**
- * Removes an CC_Array element from the specified index and optionally sets the
- * out parameter to the value of the removed element. The index must be within
- * the bounds of the array.
- *
- * @param[in] ar the array from which the element is being removed
- * @param[in] index the index of the element being removed.
- * @param[out] out pointer to where the removed value is stored,
- * or NULL if it is to be ignored
- *
- * @return CC_OK if the element was successfully removed, or CC_ERR_OUT_OF_RANGE
- * if the index was out of range.
- */
-enum cc_stat cc_array_remove_at(CC_Array *ar, size_t index, void **out) {
- if (index >= ar->size) {
- return CC_ERR_OUT_OF_RANGE;
- }
-
- if (out) {
- *out = ar->buffer[index];
- }
-
- if (index != ar->size - 1) {
- size_t block_size = (ar->size - 1 - index) * sizeof(void *);
-
- memmove(&(ar->buffer[index]),
- &(ar->buffer[index + 1]),
- block_size);
- }
- ar->size--;
-
- return CC_OK;
-}
-
-/**
- * Removes a CC_Array element from the specified index and optionally sets the
- * out parameter to the value of the removed element without preserving ordering.
- * The last element of the array is moved to the index of the element being removed,
- * and the last element is removed. The index must be within the bounds of the array.
- *
- * @param[in] ar the array from which the element is being removed
- * @param[in] index the index of the element being removed.
- * @param[out] out pointer to where the removed value is stored,
- * or NULL if it is to be ignored
- *
- * @return CC_OK if the element was successfully removed, or CC_ERR_OUT_OF_RANGE
- * if the index was out of range.
- */
-enum cc_stat cc_array_remove_fast_at(CC_Array *ar, size_t index, void **out) {
- if (index >= ar->size) {
- return CC_ERR_OUT_OF_RANGE;
- }
-
- if (out) {
- *out = ar->buffer[index];
- }
-
- ar->buffer[index] = ar->buffer[ar->size - 1];
- ar->size--;
-
- return CC_OK;
-}
-
-/**
- * Removes an CC_Array element from the end of the array and optionally sets the
- * out parameter to the value of the removed element.
- *
- * @param[in] ar the array whose last element is being removed
- * @param[out] out pointer to where the removed value is stored, or NULL if it is
- * to be ignored
- *
- * @return CC_OK if the element was successfully removed, or CC_ERR_OUT_OF_RANGE
- * if the CC_Array is already empty.
- */
-enum cc_stat cc_array_remove_last(CC_Array *ar, void **out) {
- return cc_array_remove_at(ar, ar->size - 1, out);
-}
-
-/**
- * Removes all elements from the specified array. This function does not shrink
- * the array capacity.
- *
- * @param[in] ar array from which all elements are to be removed
- */
-void cc_array_remove_all(CC_Array *ar) {
- ar->size = 0;
-}
-
-/**
- * Removes and frees all elements from the specified array. This function does
- * not shrink the array capacity.
- *
- * @param[in] ar array from which all elements are to be removed
- */
-void cc_array_remove_all_free(CC_Array *ar) {
- size_t i;
- for (i = 0; i < ar->size; i++) {
- free(ar->buffer[i]);
- }
-
- cc_array_remove_all(ar);
-}
-
-/**
- * Gets an CC_Array element from the specified index and sets the out parameter to
- * its value. The specified index must be within the bounds of the array.
- *
- * @param[in] ar the array from which the element is being retrieved
- * @param[in] index the index of the array element
- * @param[out] out pointer to where the element is stored
- *
- * @return CC_OK if the element was found, or CC_ERR_OUT_OF_RANGE if the index
- * was out of range.
- */
-enum cc_stat cc_array_get_at(const CC_Array *ar, size_t index, void **out) {
- if (index >= ar->size) {
- return CC_ERR_OUT_OF_RANGE;
- }
-
- *out = ar->buffer[index];
- return CC_OK;
-}
-
-/**
- * Gets the last element of the array or the element at the highest index
- * and sets the out parameter to its value.
- *
- * @param[in] ar the array whose last element is being returned
- * @param[out] out pointer to where the element is stored
- *
- * @return CC_OK if the element was found, or CC_ERR_VALUE_NOT_FOUND if the
- * CC_Array is empty.
- */
-enum cc_stat cc_array_get_last(const CC_Array *ar, void **out) {
- if (ar->size == 0) {
- return CC_ERR_VALUE_NOT_FOUND;
- }
-
- return cc_array_get_at(ar, ar->size - 1, out);
-}
-
-/**
- * Returns the underlying array buffer.
- *
- * @note Any direct modification of the buffer may invalidate the CC_Array.
- *
- * @param[in] ar array whose underlying buffer is being returned
- *
- * @return array's internal buffer.
- */
-const void *const *cc_array_get_buffer(CC_Array *ar) {
- return (const void *const *)ar->buffer;
-}
-
-/**
- * Gets the index of the specified element. The returned index is the index
- * of the first occurrence of the element starting from the beginning of the
- * CC_Array.
- *
- * @param[in] ar array being searched
- * @param[in] element the element whose index is being looked up
- * @param[out] index pointer to where the index is stored
- *
- * @return CC_OK if the index was found, or CC_OUT_OF_RANGE if not.
- */
-enum cc_stat cc_array_index_of(const CC_Array *ar, void *element, size_t *index) {
- size_t i;
- for (i = 0; i < ar->size; i++) {
- if (ar->buffer[i] == element) {
- *index = i;
- return CC_OK;
- }
- }
- return CC_ERR_OUT_OF_RANGE;
-}
-
-/**
- * Creates a subarray of the specified CC_Array, ranging from b
- * index (inclusive) to e index (inclusive). The range indices
- * must be within the bounds of the CC_Array, while the e index
- * must be greater or equal to the b index.
- *
- * @note The new CC_Array is allocated using the original CC_Array's allocators
- * and it also inherits the configuration of the original CC_Array.
- *
- * @param[in] ar array from which the subarray is being created
- * @param[in] b the beginning index (inclusive) of the subarray that must be
- * within the bounds of the array and must not exceed the
- * the end index
- * @param[in] e the end index (inclusive) of the subarray that must be within
- * the bounds of the array and must be greater or equal to the
- * beginning index
- * @param[out] out pointer to where the new sublist is stored
- *
- * @return CC_OK if the subarray was successfully created, CC_ERR_INVALID_RANGE
- * if the specified index range is invalid, or CC_ERR_ALLOC if the memory allocation
- * for the new subarray failed.
- */
-enum cc_stat cc_array_subarray(CC_Array *ar, size_t b, size_t e, CC_Array **out) {
- if (b > e || e >= ar->size) {
- return CC_ERR_INVALID_RANGE;
- }
-
- CC_Array *sub_ar = (CC_Array *)ar->mem_calloc(1, sizeof(CC_Array));
-
- if (!sub_ar) {
- return CC_ERR_ALLOC;
- }
-
- /* Try to allocate the buffer */
- if (!(sub_ar->buffer = (void **)ar->mem_alloc(ar->capacity * sizeof(void *)))) {
- ar->mem_free(sub_ar);
- return CC_ERR_ALLOC;
- }
-
- sub_ar->mem_alloc = ar->mem_alloc;
- sub_ar->mem_calloc = ar->mem_calloc;
- sub_ar->mem_free = ar->mem_free;
- sub_ar->size = e - b + 1;
- sub_ar->capacity = sub_ar->size;
-
- memcpy(sub_ar->buffer,
- &(ar->buffer[b]),
- sub_ar->size * sizeof(void *));
-
- *out = sub_ar;
- return CC_OK;
-}
-
-/**
- * Creates a shallow copy of the specified CC_Array. A shallow copy is a copy of
- * the CC_Array structure, but not the elements it holds.
- *
- * @note The new CC_Array is allocated using the original CC_Array's allocators
- * and it also inherits the configuration of the original array.
- *
- * @param[in] ar the array to be copied
- * @param[out] out pointer to where the newly created copy is stored
- *
- * @return CC_OK if the copy was successfully created, or CC_ERR_ALLOC if the
- * memory allocation for the copy failed.
- */
-enum cc_stat cc_array_copy_shallow(CC_Array *ar, CC_Array **out) {
- CC_Array *copy = (CC_Array *)ar->mem_alloc(sizeof(CC_Array));
-
- if (!copy) {
- return CC_ERR_ALLOC;
- }
-
- if (!(copy->buffer = (void **)ar->mem_calloc(ar->capacity, sizeof(void *)))) {
- ar->mem_free(copy);
- return CC_ERR_ALLOC;
- }
- copy->exp_factor = ar->exp_factor;
- copy->size = ar->size;
- copy->capacity = ar->capacity;
- copy->mem_alloc = ar->mem_alloc;
- copy->mem_calloc = ar->mem_calloc;
- copy->mem_free = ar->mem_free;
-
- memcpy(copy->buffer,
- ar->buffer,
- copy->size * sizeof(void *));
-
- *out = copy;
- return CC_OK;
-}
-
-/**
- * Creates a deep copy of the specified CC_Array. A deep copy is a copy of
- * both the CC_Array structure and the data it holds.
- *
- * @note The new CC_Array is allocated using the original CC_Array's allocators
- * and it also inherits the configuration of the original CC_Array.
- *
- * @param[in] ar array to be copied
- * @param[in] cp the copy function that should return a pointer to the copy of
- * the data
- * @param[out] out pointer to where the newly created copy is stored
- *
- * @return CC_OK if the copy was successfully created, or CC_ERR_ALLOC if the
- * memory allocation for the copy failed.
- */
-enum cc_stat cc_array_copy_deep(CC_Array *ar, void *(*cp)(void *), CC_Array **out) {
- CC_Array *copy = (CC_Array *)ar->mem_alloc(sizeof(CC_Array));
-
- if (!copy) {
- return CC_ERR_ALLOC;
- }
-
- if (!(copy->buffer = (void **)ar->mem_calloc(ar->capacity, sizeof(void *)))) {
- ar->mem_free(copy);
- return CC_ERR_ALLOC;
- }
-
- copy->exp_factor = ar->exp_factor;
- copy->size = ar->size;
- copy->capacity = ar->capacity;
- copy->mem_alloc = ar->mem_alloc;
- copy->mem_calloc = ar->mem_calloc;
- copy->mem_free = ar->mem_free;
-
- size_t i;
- for (i = 0; i < copy->size; i++) {
- copy->buffer[i] = cp(ar->buffer[i]);
- }
-
- *out = copy;
-
- return CC_OK;
-}
-
-/**
- * Filters the CC_Array by modifying it. It removes all elements that don't
- * return true on pred(element).
- *
- * @param[in] ar array that is to be filtered
- * @param[in] pred predicate function which returns true if the element should
- * be kept in the CC_Array
- *
- * @return CC_OK if the CC_Array was filtered successfully, or CC_ERR_OUT_OF_RANGE
- * if the CC_Array is empty.
- */
-enum cc_stat cc_array_filter_mut(CC_Array *ar, bool (*pred)(const void *)) {
- if (ar->size == 0) {
- return CC_ERR_OUT_OF_RANGE;
- }
-
- size_t rm = 0;
- size_t keep = 0;
-
- /* Look for clusters of non matching elements before moving
- * in order to minimize the number of memmoves */
- for (size_t i = ar->size - 1; i != ((size_t)-1); i--) {
- if (!pred(ar->buffer[i])) {
- rm++;
- continue;
- }
- if (rm > 0) {
- if (keep > 0) {
- size_t block_size = keep * sizeof(void *);
- memmove(&(ar->buffer[i + 1]),
- &(ar->buffer[i + 1 + rm]),
- block_size);
- }
- ar->size -= rm;
- rm = 0;
- }
- keep++;
- }
- /* Remove any remaining elements*/
- if (rm > 0) {
- size_t block_size = keep * sizeof(void *);
- memmove(&(ar->buffer[0]),
- &(ar->buffer[rm]),
- block_size);
-
- ar->size -= rm;
- }
- return CC_OK;
-}
-
-/**
- * Filters the CC_Array by creating a new CC_Array that contains all elements from the
- * original CC_Array that return true on pred(element) without modifying the original
- * CC_Array.
- *
- * @param[in] ar array that is to be filtered
- * @param[in] pred predicate function which returns true if the element should
- * be kept in the filtered array
- * @param[out] out pointer to where the new filtered CC_Array is to be stored
- *
- * @return CC_OK if the CC_Array was filtered successfully, CC_ERR_OUT_OF_RANGE
- * if the CC_Array is empty, or CC_ERR_ALLOC if the memory allocation for the
- * new CC_Array failed.
- */
-enum cc_stat cc_array_filter(CC_Array *ar, bool (*pred)(const void *), CC_Array **out) {
- if (ar->size == 0) {
- return CC_ERR_OUT_OF_RANGE;
- }
-
- CC_Array *filtered = (CC_Array *)ar->mem_alloc(sizeof(CC_Array));
-
- if (!filtered) {
- return CC_ERR_ALLOC;
- }
-
- if (!(filtered->buffer = (void **)ar->mem_calloc(ar->capacity, sizeof(void *)))) {
- ar->mem_free(filtered);
- return CC_ERR_ALLOC;
- }
-
- filtered->exp_factor = ar->exp_factor;
- filtered->size = 0;
- filtered->capacity = ar->capacity;
- filtered->mem_alloc = ar->mem_alloc;
- filtered->mem_calloc = ar->mem_calloc;
- filtered->mem_free = ar->mem_free;
-
- size_t f = 0;
- for (size_t i = 0; i < ar->size; i++) {
- if (pred(ar->buffer[i])) {
- filtered->buffer[f++] = ar->buffer[i];
- filtered->size++;
- }
- }
- *out = filtered;
-
- return CC_OK;
-}
-
-/**
- * Reverses the order of elements in the specified array.
- *
- * @param[in] ar array that is being reversed
- */
-void cc_array_reverse(CC_Array *ar) {
- if (ar->size == 0) {
- return;
- }
-
- size_t i;
- size_t j;
- for (i = 0, j = ar->size - 1; i < ar->size / 2; i++, j--) {
- void *tmp = ar->buffer[i];
- ar->buffer[i] = ar->buffer[j];
- ar->buffer[j] = tmp;
- }
-}
-
-/**
- * Trims the array's capacity, in other words, it shrinks the capacity to match
- * the number of elements in the CC_Array, however the capacity will never shrink
- * below 1.
- *
- * @param[in] ar array whose capacity is being trimmed
- *
- * @return CC_OK if the capacity was trimmed successfully, or CC_ERR_ALLOC if
- * the reallocation failed.
- */
-enum cc_stat cc_array_trim_capacity(CC_Array *ar) {
- if (ar->size == ar->capacity) {
- return CC_OK;
- }
-
- void **new_buff = (void **)ar->mem_calloc(ar->size, sizeof(void *));
-
- if (!new_buff) {
- return CC_ERR_ALLOC;
- }
-
- size_t size = ar->size < 1 ? 1 : ar->size;
-
- memcpy(new_buff, ar->buffer, size * sizeof(void *));
- ar->mem_free(ar->buffer);
-
- ar->buffer = new_buff;
- ar->capacity = ar->size;
-
- return CC_OK;
-}
-
-/**
- * Returns the number of occurrences of the element within the specified CC_Array.
- *
- * @param[in] ar array that is being searched
- * @param[in] element the element that is being searched for
- *
- * @return the number of occurrences of the element.
- */
-size_t cc_array_contains(const CC_Array *ar, void *element) {
- size_t o = 0;
- size_t i;
- for (i = 0; i < ar->size; i++) {
- if (ar->buffer[i] == element) {
- o++;
- }
- }
- return o;
-}
-
-/**
- * Returns the number of occurrences of the value pointed to by e
- * within the specified CC_Array.
- *
- * @param[in] ar array that is being searched
- * @param[in] element the element that is being searched for
- * @param[in] cmp comparator function which returns 0 if the values passed to it are equal
- *
- * @return the number of occurrences of the value.
- */
-size_t cc_array_contains_value(const CC_Array *ar, void *element, int (*cmp)(const void *, const void *)) {
- size_t o = 0;
- size_t i;
- for (i = 0; i < ar->size; i++) {
- if (cmp(element, ar->buffer[i]) == 0) {
- o++;
- }
- }
- return o;
-}
-
-/**
- * Returns the size of the specified CC_Array. The size of the array is the
- * number of elements contained within the CC_Array.
- *
- * @param[in] ar array whose size is being returned
- *
- * @return the the number of element within the CC_Array.
- */
-size_t cc_array_size(const CC_Array *ar) {
- return ar->size;
-}
-
-/**
- * Returns the capacity of the specified CC_Array. The capacity of the CC_Array is
- * the maximum number of elements an CC_Array can hold before it has to be resized.
- *
- * @param[in] ar array whose capacity is being returned
- *
- * @return the capacity of the CC_Array.
- */
-size_t cc_array_capacity(const CC_Array *ar) {
- return ar->capacity;
-}
-
-/**
- * Sorts the specified array.
- *
- * @note
- * Pointers passed to the comparator function will be pointers to the array
- * elements that are of type (void*) ie. void**. So an extra step of
- * dereferencing will be required before the data can be used for comparison:
- * eg. my_type e = *(*((my_type**) ptr));.
- *
- * @code
- * enum cc_stat mycmp(const void *e1, const void *e2) {
- * MyType el1 = *(*((enum cc_stat**) e1));
- * MyType el2 = *(*((enum cc_stat**) e2));
- *
- * if (el1 < el2) return -1;
- * if (el1 > el2) return 1;
- * return 0;
- * }
- *
- * ...
- *
- * cc_array_sort(array, mycmp);
- * @endcode
- *
- * @param[in] ar array to be sorted
- * @param[in] cmp the comparator function that must be of type
- * enum cc_stat cmp(const void e1*, const void e2*) that
- * returns < 0 if the first element goes before the second,
- * 0 if the elements are equal and > 0 if the second goes
- * before the first
- */
-void cc_array_sort(CC_Array *ar, int (*cmp)(const void *, const void *)) {
- qsort(ar->buffer, ar->size, sizeof(void *), cmp);
-}
-
-/**
- * Expands the CC_Array capacity. This might fail if the the new buffer
- * cannot be allocated. In case the expansion would overflow the index
- * range, a maximum capacity buffer is allocated instead. If the capacity
- * is already at the maximum capacity, no new buffer is allocated.
- *
- * @param[in] ar array whose capacity is being expanded
- *
- * @return CC_OK if the buffer was expanded successfully, CC_ERR_ALLOC if
- * the memory allocation for the new buffer failed, or CC_ERR_MAX_CAPACITY
- * if the array is already at maximum capacity.
- */
-static enum cc_stat expand_array_capacity(CC_Array *ar) {
- if (ar->capacity == CC_MAX_ELEMENTS) {
- return CC_ERR_MAX_CAPACITY;
- }
-
- size_t new_capacity = (size_t)(ar->capacity * ar->exp_factor);
-
- /* As long as the capacity is greater that the expansion factor
- * at the point of overflow, this is check is valid. */
- if (new_capacity <= ar->capacity) {
- ar->capacity = CC_MAX_ELEMENTS;
- } else {
- ar->capacity = new_capacity;
- }
-
- void **new_buff = (void **)ar->mem_alloc(ar->capacity * sizeof(void *));
-
- if (!new_buff) {
- return CC_ERR_ALLOC;
- }
-
- memcpy(new_buff, ar->buffer, ar->size * sizeof(void *));
-
- ar->mem_free(ar->buffer);
- ar->buffer = new_buff;
-
- return CC_OK;
-}
-
-/**
- * Applies the function fn to each element of the CC_Array.
- *
- * @param[in] ar array on which this operation is performed
- * @param[in] fn operation function that is to be invoked on each CC_Array
- * element
- */
-void cc_array_map(CC_Array *ar, void (*fn)(void *e)) {
- size_t i;
- for (i = 0; i < ar->size; i++) {
- fn(ar->buffer[i]);
- }
-}
-
-/**
- * A fold/reduce function that collects all of the elements in the array
- * together. For example, if we have an array of [a,b,c...] the end result
- * will be (...((a+b)+c)+...).
- *
- * @param[in] ar the array on which this operation is performed
- * @param[in] fn the operation function that is to be invoked on each array
- * element
- * @param[in] result the pointer which will collect the end result
- */
-void cc_array_reduce(CC_Array *ar, void (*fn)(void *, void *, void *), void *result) {
- if (ar->size == 1) {
- fn(ar->buffer[0], NULL, result);
- return;
- }
- if (ar->size > 1) {
- fn(ar->buffer[0], ar->buffer[1], result);
- }
-
- for (size_t i = 2; i < ar->size; i++) {
- fn(result, ar->buffer[i], result);
- }
-}
-
-/**
- * Initializes the iterator.
- *
- * @param[in] iter the iterator that is being initialized
- * @param[in] ar the array to iterate over
- */
-void cc_array_iter_init(CC_ArrayIter *iter, CC_Array *ar) {
- iter->ar = ar;
- iter->index = 0;
- iter->last_removed = false;
-}
-
-/**
- * Advances the iterator and sets the out parameter to the value of the
- * next element in the sequence.
- *
- * @param[in] iter the iterator that is being advanced
- * @param[out] out pointer to where the next element is set
- *
- * @return CC_OK if the iterator was advanced, or CC_ITER_END if the
- * end of the CC_Array has been reached.
- */
-enum cc_stat cc_array_iter_next(CC_ArrayIter *iter, void **out) {
- if (iter->index >= iter->ar->size) {
- return CC_ITER_END;
- }
-
- *out = iter->ar->buffer[iter->index];
-
- iter->index++;
- iter->last_removed = false;
-
- return CC_OK;
-}
-
-/**
- * Removes the last returned element by cc_array_iter_next()
- * function without invalidating the iterator and optionally sets the out
- * parameter to the value of the removed element.
- *
- * @note This function should only ever be called after a call to
- * cc_array_iter_next().
-
- * @param[in] iter the iterator on which this operation is being performed
- * @param[out] out pointer to where the removed element is stored, or NULL
- * if it is to be ignored
- *
- * @return CC_OK if the element was successfully removed, or
- * CC_ERR_VALUE_NOT_FOUND.
- */
-enum cc_stat cc_array_iter_remove(CC_ArrayIter *iter, void **out) {
- enum cc_stat status = CC_ERR_VALUE_NOT_FOUND;
-
- if (!iter->last_removed) {
- status = cc_array_remove_at(iter->ar, iter->index - 1, out);
- if (status != CC_OK) {
- return status;
- }
-
- iter->last_removed = true;
- if (iter->index > 0) {
- iter->index--;
- }
- }
- return status;
-}
-
-/**
- * Removes the last returned element by cc_array_iter_next()
- * function without invalidating the iterator and optionally sets the out
- * parameter to the value of the removed element. The order of the array
- * is not preserved, the last element of the array is moved to the index
- * of the last returned element and the last element is removed.
- *
- * @note This function should only ever be called after a call to
- * cc_array_iter_next().
-
- * @param[in] iter the iterator on which this operation is being performed
- * @param[out] out pointer to where the removed element is stored, or NULL
- * if it is to be ignored
- *
- * @return CC_OK if the element was successfully removed, or
- * CC_ERR_VALUE_NOT_FOUND.
- */
-enum cc_stat cc_array_iter_remove_fast(CC_ArrayIter *iter, void **out) {
- enum cc_stat status = CC_ERR_VALUE_NOT_FOUND;
-
- if (!iter->last_removed) {
- status = cc_array_remove_fast_at(iter->ar, iter->index - 1, out);
- if (status != CC_OK) {
- return status;
- }
-
- iter->last_removed = true;
- if (iter->index > 0) {
- iter->index--;
- }
- }
- return status;
-}
-
-/**
- * Adds a new element to the CC_Array after the last returned element by
- * cc_array_iter_next() function without invalidating the
- * iterator.
- *
- * @note This function should only ever be called after a call to
- * cc_array_iter_next().
- *
- * @param[in] iter the iterator on which this operation is being performed
- * @param[in] element the element being added
- *
- * @return CC_OK if the element was successfully added, CC_ERR_ALLOC if the
- * memory allocation for the new element failed, or CC_ERR_MAX_CAPACITY if
- * the array is already at maximum capacity.
- */
-enum cc_stat cc_array_iter_add(CC_ArrayIter *iter, void *element) {
- return cc_array_add_at(iter->ar, element, iter->index++);
-}
-
-/**
- * Replaces the last returned element by cc_array_iter_next()
- * with the specified element and optionally sets the out parameter to
- * the value of the replaced element.
- *
- * @note This function should only ever be called after a call to
- * cc_array_iter_next().
- *
- * @param[in] iter the iterator on which this operation is being performed
- * @param[in] element the replacement element
- * @param[out] out pointer to where the replaced element is stored, or NULL
- * if it is to be ignored
- *
- * @return CC_OK if the element was replaced successfully, or
- * CC_ERR_OUT_OF_RANGE.
- */
-enum cc_stat cc_array_iter_replace(CC_ArrayIter *iter, void *element, void **out) {
- return cc_array_replace_at(iter->ar, element, iter->index - 1, out);
-}
-
-/**
- * Returns the index of the last returned element by cc_array_iter_next()
- * .
- *
- * @note
- * This function should not be called before a call to cc_array_iter_next()
- * .
- *
- * @param[in] iter the iterator on which this operation is being performed
- *
- * @return the index.
- */
-size_t cc_array_iter_index(CC_ArrayIter *iter) {
- return iter->index - 1;
-}
-
-/**
- * Initializes the zip iterator.
- *
- * @param[in] iter iterator that is being initialized
- * @param[in] ar1 first array
- * @param[in] ar2 second array
- */
-void cc_array_zip_iter_init(CC_ArrayZipIter *iter, CC_Array *ar1, CC_Array *ar2) {
- iter->ar1 = ar1;
- iter->ar2 = ar2;
- iter->index = 0;
- iter->last_removed = false;
-}
-
-/**
- * Outputs the next element pair in the sequence and advances the iterator.
- *
- * @param[in] iter iterator that is being advanced
- * @param[out] out1 output of the first array element
- * @param[out] out2 output of the second array element
- *
- * @return CC_OK if a next element pair is returned, or CC_ITER_END if the end of one
- * of the arrays has been reached.
- */
-enum cc_stat cc_array_zip_iter_next(CC_ArrayZipIter *iter, void **out1, void **out2) {
- if (iter->index >= iter->ar1->size || iter->index >= iter->ar2->size) {
- return CC_ITER_END;
- }
-
- *out1 = iter->ar1->buffer[iter->index];
- *out2 = iter->ar2->buffer[iter->index];
-
- iter->index++;
- iter->last_removed = false;
-
- return CC_OK;
-}
-
-/**
- * Removes and outputs the last returned element pair by cc_array_zip_iter_next()
- * without invalidating the iterator.
- *
- * @param[in] iter iterator on which this operation is being performed
- * @param[out] out1 output of the removed element from the first array
- * @param[out] out2 output of the removed element from the second array
- *
- * @return CC_OK if the element was successfully removed, CC_ERR_OUT_OF_RANGE if the
- * state of the iterator is invalid, or CC_ERR_VALUE_NOT_FOUND if the element was
- * already removed.
- */
-enum cc_stat cc_array_zip_iter_remove(CC_ArrayZipIter *iter, void **out1, void **out2) {
- if ((iter->index - 1) >= iter->ar1->size || (iter->index - 1) >= iter->ar2->size) {
- return CC_ERR_OUT_OF_RANGE;
- }
-
- if (!iter->last_removed) {
- cc_array_remove_at(iter->ar1, iter->index - 1, out1);
- cc_array_remove_at(iter->ar2, iter->index - 1, out2);
- iter->last_removed = true;
- return CC_OK;
- }
- return CC_ERR_VALUE_NOT_FOUND;
-}
-
-/**
- * Adds a new element pair to the arrays after the last returned element pair by
- * cc_array_zip_iter_next() and immediately before an element pair
- * that would be returned by a subsequent call to cc_array_zip_iter_next()
- * without invalidating the iterator.
- *
- * @param[in] iter iterator on which this operation is being performed
- * @param[in] e1 element added to the first array
- * @param[in] e2 element added to the second array
- *
- * @return CC_OK if the element pair was successfully added to the arrays, or
- * CC_ERR_ALLOC if the memory allocation for the new elements failed.
- */
-enum cc_stat cc_array_zip_iter_add(CC_ArrayZipIter *iter, void *e1, void *e2) {
- size_t index = iter->index++;
- CC_Array *ar1 = iter->ar1;
- CC_Array *ar2 = iter->ar2;
-
- /* Make sure both array buffers have room */
- if ((ar1->size == ar1->capacity && (expand_array_capacity(ar1) != CC_OK)) ||
- (ar2->size == ar2->capacity && (expand_array_capacity(ar2) != CC_OK))) {
- return CC_ERR_ALLOC;
- }
-
- cc_array_add_at(ar1, e1, index);
- cc_array_add_at(ar2, e2, index);
-
- return CC_OK;
-}
-
-/**
- * Replaces the last returned element pair by cc_array_zip_iter_next()
- * with the specified replacement element pair.
- *
- * @param[in] iter iterator on which this operation is being performed
- * @param[in] e1 first array's replacement element
- * @param[in] e2 second array's replacement element
- * @param[out] out1 output of the replaced element from the first array
- * @param[out] out2 output of the replaced element from the second array
- *
- * @return CC_OK if the element was successfully replaced, or CC_ERR_OUT_OF_RANGE.
- */
-enum cc_stat cc_array_zip_iter_replace(CC_ArrayZipIter *iter, void *e1, void *e2, void **out1, void **out2) {
- if ((iter->index - 1) >= iter->ar1->size || (iter->index - 1) >= iter->ar2->size) {
- return CC_ERR_OUT_OF_RANGE;
- }
-
- cc_array_replace_at(iter->ar1, e1, iter->index - 1, out1);
- cc_array_replace_at(iter->ar2, e2, iter->index - 1, out2);
-
- return CC_OK;
-}
-
-/**
- * Returns the index of the last returned element pair by cc_array_zip_iter_next().
- *
- * @param[in] iter iterator on which this operation is being performed
- *
- * @return current iterator index.
- */
-size_t cc_array_zip_iter_index(CC_ArrayZipIter *iter) {
- return iter->index - 1;
-}
-
-size_t cc_array_struct_size() {
- return sizeof(CC_Array);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/pufferlib/ocean/impulse_wars/include/cc_common.h b/pufferlib/ocean/impulse_wars/include/cc_common.h
deleted file mode 100644
index 174046064..000000000
--- a/pufferlib/ocean/impulse_wars/include/cc_common.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Collections-C
- * Copyright (C) 2013-2014 Srđan Panić
- *
- * This file is part of Collections-C.
- *
- * Collections-C is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Collections-C is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Collections-C. If not, see .
- */
-
-#ifndef CC_COMMON_H
-#define CC_COMMON_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include
-#include