From fe291c92824187fb072e5d8357ae633861790fa7 Mon Sep 17 00:00:00 2001 From: TPODAvia Date: Sun, 30 Mar 2025 23:05:36 +0300 Subject: [PATCH 1/5] Refactoring for easy to use in ros --- .gitmodules | 3 - README.md | 199 +- dependencies/OpenPlaceRecognition | 1 - docker/Dockerfile.jetson | 111 + .../{Dockerfile.devel => Dockerfile.x86_64} | 41 +- docker/{build.sh => build_jetson.sh} | 21 +- docker/build_x86_64.sh | 72 + docker/{start.sh => start_jetson.sh} | 0 docker/start_x86_64.sh | 64 + .../__init__.py => docs/SETUP_OPR.md | 0 open_place_recognition/CMakeLists.txt | 35 + .../configs/anno/ade20k.yaml | 0 .../configs/anno/oneformer.yaml | 0 .../aruco_localization_pipeline.yaml | 0 .../pipelines/localization_pipeline.yaml | 0 .../place_recognition/multimodal_pr.yaml | 5 +- .../multimodal_semantic_pr.yaml | 4 +- ...ltimodal_semantic_with_soc_outdoor_pr.yaml | 4 +- .../multimodal_with_soc_outdoor_pr.yaml | 4 +- .../place_recognition/text_labels_pr.yaml | 4 +- .../aruco_localization_pipeline.yaml | 0 .../localization_pipeline.yaml | 0 .../updated_pipelines/multimodal_pr.yaml | 0 .../multimodal_semantic_pr.yaml | 0 ...ltimodal_semantic_with_soc_outdoor_pr.yaml | 0 .../multimodal_with_soc_outdoor_pr.yaml | 0 .../updated_pipelines/text_labels_pr.yaml | 0 .../configs/sensors/husky.yaml | 0 .../launch/dataset_from_bag.launch.py | 36 + .../launch/dataset_from_rtabmap.launch.py | 43 + .../launch/dataset_publisher.launch.py | 158 + .../launch/dataset_train.launch.py | 43 + .../launch/localization.launch.py | 136 + .../launch/place_recognition.launch.py | 115 + .../launch/test_depth_estimation.launch.py | 26 +- .../launch/test_opr_odometry.launch.py | 37 + .../launch/test_visualizer.launch.py | 8 +- .../package.xml | 17 +- .../rviz}/depth_estimation_outdoor.rviz | 0 .../scripts/dataset_create.py | 388 +++ .../scripts/dataset_train.py | 95 + .../scripts/node_1_9_scan.pcd | 3069 +++++++++++++++++ .../scripts/read_scan copy.py | 59 + open_place_recognition/scripts/read_scan.py | 83 + .../src/dataset_from_rosbag_node.py | 314 ++ .../src/dataset_from_rtabmap_node.py | 274 ++ .../src/dataset_publisher_node.py | 372 ++ .../src/dataset_train_node.py | 61 + .../src/localization_node.py | 510 +++ .../src/place_recognition_node.py | 367 ++ .../src/test_depth_estimation_node.py | 1 + .../src/test_opr_odom_node.py | 40 + .../src/test_visualizer_node.py | 1 + .../CMakeLists.txt | 0 .../msg/DatabaseMatchIndex.msg | 0 .../package.xml | 0 .../launch/depth_estimation.launch.py | 22 - .../launch/localization_launch.py | 25 - .../launch/place_recognition_launch.py | 25 - .../open_place_recognition/localization.py | 397 --- .../place_recognition.py | 299 -- .../resource/open_place_recognition | 0 src/open_place_recognition/setup.cfg | 4 - src/open_place_recognition/setup.py | 32 - .../test/test_copyright.py | 25 - .../test/test_flake8.py | 25 - .../test/test_pep257.py | 23 - 67 files changed, 6696 insertions(+), 1002 deletions(-) delete mode 100644 .gitmodules delete mode 160000 dependencies/OpenPlaceRecognition create mode 100644 docker/Dockerfile.jetson rename docker/{Dockerfile.devel => Dockerfile.x86_64} (57%) rename docker/{build.sh => build_jetson.sh} (50%) create mode 100644 docker/build_x86_64.sh rename docker/{start.sh => start_jetson.sh} (100%) create mode 100644 docker/start_x86_64.sh rename src/open_place_recognition/open_place_recognition/__init__.py => docs/SETUP_OPR.md (100%) create mode 100644 open_place_recognition/CMakeLists.txt rename {src/open_place_recognition => open_place_recognition}/configs/anno/ade20k.yaml (100%) rename {src/open_place_recognition => open_place_recognition}/configs/anno/oneformer.yaml (100%) rename {src/open_place_recognition => open_place_recognition}/configs/pipelines/aruco_localization_pipeline.yaml (100%) rename {src/open_place_recognition => open_place_recognition}/configs/pipelines/localization_pipeline.yaml (100%) rename {src/open_place_recognition => open_place_recognition}/configs/pipelines/place_recognition/multimodal_pr.yaml (76%) rename {src/open_place_recognition => open_place_recognition}/configs/pipelines/place_recognition/multimodal_semantic_pr.yaml (84%) rename {src/open_place_recognition => open_place_recognition}/configs/pipelines/place_recognition/multimodal_semantic_with_soc_outdoor_pr.yaml (85%) rename {src/open_place_recognition => open_place_recognition}/configs/pipelines/place_recognition/multimodal_with_soc_outdoor_pr.yaml (82%) rename {src/open_place_recognition => open_place_recognition}/configs/pipelines/place_recognition/text_labels_pr.yaml (80%) rename {src/open_place_recognition => open_place_recognition}/configs/pipelines/updated_pipelines/aruco_localization_pipeline.yaml (100%) rename {src/open_place_recognition => open_place_recognition}/configs/pipelines/updated_pipelines/localization_pipeline.yaml (100%) rename {src/open_place_recognition => open_place_recognition}/configs/pipelines/updated_pipelines/multimodal_pr.yaml (100%) rename {src/open_place_recognition => open_place_recognition}/configs/pipelines/updated_pipelines/multimodal_semantic_pr.yaml (100%) rename {src/open_place_recognition => open_place_recognition}/configs/pipelines/updated_pipelines/multimodal_semantic_with_soc_outdoor_pr.yaml (100%) rename {src/open_place_recognition => open_place_recognition}/configs/pipelines/updated_pipelines/multimodal_with_soc_outdoor_pr.yaml (100%) rename {src/open_place_recognition => open_place_recognition}/configs/pipelines/updated_pipelines/text_labels_pr.yaml (100%) rename {src/open_place_recognition => open_place_recognition}/configs/sensors/husky.yaml (100%) create mode 100644 open_place_recognition/launch/dataset_from_bag.launch.py create mode 100644 open_place_recognition/launch/dataset_from_rtabmap.launch.py create mode 100644 open_place_recognition/launch/dataset_publisher.launch.py create mode 100644 open_place_recognition/launch/dataset_train.launch.py create mode 100644 open_place_recognition/launch/localization.launch.py create mode 100644 open_place_recognition/launch/place_recognition.launch.py rename src/open_place_recognition/launch/depth_estimation_new.launch.py => open_place_recognition/launch/test_depth_estimation.launch.py (62%) create mode 100644 open_place_recognition/launch/test_opr_odometry.launch.py rename src/open_place_recognition/launch/visualizer_launch.py => open_place_recognition/launch/test_visualizer.launch.py (58%) rename {src/open_place_recognition => open_place_recognition}/package.xml (53%) rename {rviz => open_place_recognition/rviz}/depth_estimation_outdoor.rviz (100%) create mode 100755 open_place_recognition/scripts/dataset_create.py create mode 100755 open_place_recognition/scripts/dataset_train.py create mode 100644 open_place_recognition/scripts/node_1_9_scan.pcd create mode 100644 open_place_recognition/scripts/read_scan copy.py create mode 100644 open_place_recognition/scripts/read_scan.py create mode 100755 open_place_recognition/src/dataset_from_rosbag_node.py create mode 100755 open_place_recognition/src/dataset_from_rtabmap_node.py create mode 100755 open_place_recognition/src/dataset_publisher_node.py create mode 100755 open_place_recognition/src/dataset_train_node.py create mode 100755 open_place_recognition/src/localization_node.py create mode 100755 open_place_recognition/src/place_recognition_node.py rename src/open_place_recognition/open_place_recognition/depth_estimation.py => open_place_recognition/src/test_depth_estimation_node.py (99%) mode change 100644 => 100755 create mode 100755 open_place_recognition/src/test_opr_odom_node.py rename src/open_place_recognition/open_place_recognition/visualizer.py => open_place_recognition/src/test_visualizer_node.py (99%) mode change 100644 => 100755 rename {src/opr_interfaces => opr_interfaces}/CMakeLists.txt (100%) rename {src/opr_interfaces => opr_interfaces}/msg/DatabaseMatchIndex.msg (100%) rename {src/opr_interfaces => opr_interfaces}/package.xml (100%) delete mode 100644 src/open_place_recognition/launch/depth_estimation.launch.py delete mode 100644 src/open_place_recognition/launch/localization_launch.py delete mode 100644 src/open_place_recognition/launch/place_recognition_launch.py delete mode 100644 src/open_place_recognition/open_place_recognition/localization.py delete mode 100644 src/open_place_recognition/open_place_recognition/place_recognition.py delete mode 100644 src/open_place_recognition/resource/open_place_recognition delete mode 100644 src/open_place_recognition/setup.cfg delete mode 100644 src/open_place_recognition/setup.py delete mode 100644 src/open_place_recognition/test/test_copyright.py delete mode 100644 src/open_place_recognition/test/test_flake8.py delete mode 100644 src/open_place_recognition/test/test_pep257.py diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 07acdcd..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "dependencies/OpenPlaceRecognition"] - path = dependencies/OpenPlaceRecognition - url = https://github.com/OPR-Project/OpenPlaceRecognition.git diff --git a/README.md b/README.md index 9171edc..81947d2 100644 --- a/README.md +++ b/README.md @@ -1,108 +1,187 @@ # OpenPlaceRecognition-ROS2 +Note: This project is the revisions for the Open PLace Recognition project for ROS2 Humble -The ROS2 wrapper is intended for: +# Installation -- 🔌 **Easy integration** of multimodal localization into robots and autonomous systems based on ROS2. -- 🚘 **Application in existing robotic platforms and autopilots** running ROS2. -- ⚙️ **Rapid deployment** of neural network-based global localization methods into real-world ROS2 projects. +## Prerequisites -> Check out out [OpenPlaceRecognition library](https://github.com/OPR-Project/OpenPlaceRecognition). -> It is a library for place recognition and localization, which includes a collection of datasets, including ITLP-Campus. -> The library provides a unified API for loading datasets, training and evaluating models, and performing place recognition tasks. -> The library is designed to be easy to use and extensible, allowing researchers and developers to quickly experiment with different models and datasets. +- [OpenPlaceRecognition](https://github.com/OPR-Project/OpenPlaceRecognition) recommended environment: + - Ubuntu 22.04 + - Python 3.10 + - CUDA 12.1.1 + - cuDNN 8 + - PyTorch 2.1.2 + - torhvision 0.16.2 + - MinkowskiEngine + - faiss +- ROS2 Humble -## Installation - -### Requirements - -#### Hardware - -- **CPU**: 6 or more physical cores -- **RAM**: at least 8 GB -- **GPU**: NVIDIA RTX 2060 or higher (to ensure adequate performance) -- **Video memory**: at least 4 GB -- **Storage**: SSD recommended for faster loading of data and models - -#### Software - -- **Operating System**: - - Any OS with support for Docker and CUDA >= 11.1. - *Ubuntu 20.04 or later is recommended.* - -- **Dependencies** (if not using Docker): - - Python >= 3.10 - - CUDA Toolkit >= 11.1 - - cuDNN >= 7.5 - - [OpenPlaceRecognition](https://github.com/OPR-Project/OpenPlaceRecognition) - - ROS2 Humble +It is highly recommended to use the provided Dockerfile to build the environment. +The scripts to build, run and enter the container are provided in the [docker/](./docker) directory. +You can use the following commands: -If you want to install all dependencies manually, please refer to the -[Advanced Installation section of the OpenPlaceRecognition documentation](https://openplacerecognition.readthedocs.io/en/latest/#installation) -for detailed instructions. +create a folder to store: -The only additional dependency is ROS2. Please refer to the -[ROS2 Humble installation guide](https://docs.ros.org/en/humble/Installation.html) -for instructions on how to install it. +cd ~/Downloads +mkdir OpenPlaceRecognition +cd OpenPlaceRecognition +git clone Datasets +git clone OpenPlaceRecognition -### Quick start -It is highly recommended to use the provided Dockerfile to build the environment. -The scripts to build, run and enter the container are provided in the [docker/](./docker) directory. -You can use the following commands: +To use [OpenPlaceRecognition](https://github.com/OPR-Project/OpenPlaceRecognition) library in the container, you need to install it first. ```bash -# 0. clone the repository and init submodules -git clone https://github.com/OPR-Project/OpenPlaceRecognition-ROS2.git -cd OpenPlaceRecognition-ROS2 -git submodule update --init --recursive - # 1. build the image -bash docker/build.sh +export OPR_PATH=$HOME/Downloads/OpenPlaceRecognition/OpenPlaceRecognition +export DATASETS_DIR=$HOME/Downloads/OpenPlaceRecognition/Datasets +export DISPLAY=:0 +bash docker/build_x86_64.sh # 2. start the container and mount the data directory -bash docker/start.sh [DATA_DIR] +bash docker/start_x86_64.sh # 3. enter the container bash docker/into.sh ``` -To use [OpenPlaceRecognition](https://github.com/OPR-Project/OpenPlaceRecognition) library in the container, you need to install it first. Run the following command inside the container: - ```bash -pip install -e ~/ros2_ws/dependencies/OpenPlaceRecognition +pip install -e ~/OpenPlaceRecognition +pip install -e ~/OpenPlaceRecognition/third_party/GeoTransformer +pip install -e ~/OpenPlaceRecognition/third_party/HRegNet +pip install -e ~/OpenPlaceRecognition/third_party/PointMamba ``` -## Running nodes +# Running nodes -### Build the workspace +## Build the workspace Inside `ros2_ws/` directory, run the following command: ```bash -colcon build --packages-select open_place_recognition opr_interfaces +cd ~/ros2_ws/ +colcon build --symlink-install ``` -### Run the nodes +## Run the nodes Open the new terminal and run: ```bash -source ros2_ws/install/setup.bash +source ~/ros2_ws/install/setup.bash ``` Run the place recognition node using launch file: ```bash -ros2 launch open_place_recognition place_recognition_launch.py +ros2 launch open_place_recognition database_publisher.launch.py +``` + +```bash +ros2 launch open_place_recognition place_recognition.launch.py ``` Run the visualizer node using launch file: ```bash -ros2 launch open_place_recognition visualizer_launch.py +ros2 launch open_place_recognition visualizer.launch.py +``` + + +## Package Overview + +The package includes three main nodes: + +1. **Dataset Creation Node (`dataset_create_node.py`)** + - Creates a dataset for a given map. + - Accepts parameters: + - `dataset_path`: Directory path to store or access the dataset. + - `map_name`: Name of the map for which the dataset is generated. + +2. **Dataset Training Node (`dataset_train_node.py`)** + - Simulates training on the created dataset using Torch. + - Accepts parameters: + - `dataset_path`: Directory path where the dataset is stored. + - `map_name`: Name of the map used for training. + +3. **Model Operation Node (`model_opr_node.py`)** + - Simulates reading a trained model and performing operations with it. + - Accepts parameters: + - `trained_model_path`: Directory path of the trained model. + - `map_name`: Name of the map used during training. + + +## Package Structure + +``` +open_place_recognition/ +├── launch/ +│ ├── dataset_create.launch.py +│ ├── dataset_train.launch.py +│ └── opr_odometry.launch.py +├── src/ +│ ├── dataset_create_node.py +│ ├── dataset_train_node.py +│ └── opr_odom_node.py +├── package.xml +└── README.md +``` + + +## Building the Package + +1. **Clone the repository into your ROS2 workspace's `src` directory:** + + ```bash + cd ~/ros2_ws/src + git clone open_place_recognition + ``` + +2. **Build the workspace using `colcon`:** + + ```bash + cd ~/ros2_ws + colcon build --packages-select open_place_recognition + ``` + +3. **Source your workspace:** + + ```bash + source install/setup.bash + ``` + +## Running the Nodes + +After building the package, you can launch the nodes using the provided launch files. + +### 1. Create Dataset + +```bash +ros2 launch open_place_recognition dataset_create.launch.py +``` + +This command starts the Dataset Creation Node using the parameters provided in the launch file (e.g., dataset path and map name). + +### 2. Train Dataset + +```bash +ros2 launch open_place_recognition dataset_train.launch.py ``` +This command starts the Dataset Training Node, which simulates training on the dataset created in the previous step. + +### 3. Operate on Trained Model + +```bash +ros2 launch open_place_recognition opr.launch.py +``` + +This command starts the Model Operation Node, which simulates reading the trained model and performing operations on it. + +export PATH=$PATH:$HOME/.local/bin +docker_opr_ros2@rover2:~/OpenPlaceRecognition/notebooks$ jupyter lab --ip=0.0.0.0 --port=8888 --allow-root + ## License -[Apache 2.0 license](./LICENSE) +[Apache 2.0 license](./LICENSE) \ No newline at end of file diff --git a/dependencies/OpenPlaceRecognition b/dependencies/OpenPlaceRecognition deleted file mode 160000 index 68eb76f..0000000 --- a/dependencies/OpenPlaceRecognition +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 68eb76f8697940a2928189405e0326e83a3c459e diff --git a/docker/Dockerfile.jetson b/docker/Dockerfile.jetson new file mode 100644 index 0000000..420c73c --- /dev/null +++ b/docker/Dockerfile.jetson @@ -0,0 +1,111 @@ +FROM open-place-recognition-jetson:r35.4.1-cu114-cp310 +ARG MAX_JOBS=4 + +ENV DEBIAN_FRONTEND noninteractive + +RUN add-apt-repository -y ppa:ubuntu-toolchain-r/test && \ + apt-get update && apt-get upgrade -y && apt-get install -y \ + openssh-server \ + g++-11 \ + unzip \ + zip \ + default-jdk \ + && rm -rf /var/lib/apt/lists/* + +RUN ln -s /usr/local/bin/python3 /usr/local/bin/python + +# upgrade pip +ARG PIP_VERSION=23.3.2 +ARG SETUPTOOLS_VERSION=69.0.3 +RUN pip install pip==${PIP_VERSION} setuptools==${SETUPTOOLS_VERSION} + +# install tensorrt bindings for python3.10 +# COPY docker/TensorRT /TensorRT +RUN git clone --branch=release/8.5 https://github.com/NVIDIA/TensorRT.git && \ + git submodule update --init --recursive +ENV TRT_OSSPATH=/TensorRT +ENV EXT_PATH=/external +RUN mkdir -p ${EXT_PATH} && cd ${EXT_PATH} && \ + git clone https://github.com/pybind/pybind11.git +RUN wget https://www.python.org/ftp/python/3.10.14/Python-3.10.14.tar.xz && \ + tar -xf Python-3.10.14.tar.xz && \ + mkdir ${EXT_PATH}/python3.10 && \ + cp -r Python-3.10.14/Include ${EXT_PATH}/python3.10/include && \ + cp /usr/include/aarch64-linux-gnu/python3.10/pyconfig.h ${EXT_PATH}/python3.10/include/. && \ + rm -rf Python-3.10.14.tar.xz Python-3.10.14 +RUN cd ${TRT_OSSPATH}/python && \ + PYTHON_MAJOR_VERSION=3 PYTHON_MINOR_VERSION=10 TARGET_ARCHITECTURE=aarch64 bash build.sh +RUN cd ${TRT_OSSPATH}/python/build/dist && \ + pip install tensorrt-*.whl + + +### install MinkowskiEngine +ARG NINJA_VERSION=1.11.1.1 +RUN pip install ninja==${NINJA_VERSION} +RUN git clone --recursive "https://github.com/alexmelekhin/MinkowskiEngine.git" && \ + cd MinkowskiEngine && \ + git checkout 4b628a7 && \ + python3 setup.py install --force_cuda --blas=openblas && \ + cd .. && \ + rm -rf MinkowskiEngine + +RUN pip install \ + numpy'<2.0.0' \ + opencv-python==4.10.0.84 + +### Install Torch-TensorRT. See: https://pytorch.org/TensorRT/getting_started/installation.html#compiling-from-source. + +WORKDIR / +RUN rm -rf /TensorRT +RUN git clone -b v2.2.0 https://github.com/pytorch/TensorRT.git + +# Install Bazel. +WORKDIR /TensorRT +RUN export BAZEL_VERSION=$(cat .bazelversion); \ + mkdir bazel; \ + cd bazel; \ + curl -fSsL -O https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel-${BAZEL_VERSION}-dist.zip; \ + unzip bazel-${BAZEL_VERSION}-dist.zip +WORKDIR /TensorRT/bazel +RUN bash ./compile.sh +RUN cp output/bazel /usr/local/bin/ + +# Install the torch_tensorrt package. +RUN pip install pyyaml +WORKDIR /TensorRT +# See: https://github.com/pytorch/TensorRT/issues/2623. +COPY docker/torch_tensorrt_workspace/WORKSPACE.jp51 /TensorRT/WORKSPACE +RUN python3 setup.py install --use-cxx11-abi + +# install onnx-runtime +RUN wget https://nvidia.box.com/shared/static/ndh4omnbyx9icnbwsizmivngnjo5kp1b.whl -O onnxruntime_gpu-1.18.0-cp310-cp310-linux_aarch64.whl && \ + pip install onnxruntime_gpu-1.18.0-cp310-cp310-linux_aarch64.whl && \ + rm onnxruntime_gpu-1.18.0-cp310-cp310-linux_aarch64.whl + +# COPY docker/Open3D /Open3D +RUN git clone https://github.com/isl-org/Open3D.git && cd Open3D && git checkout c8856fc +WORKDIR /Open3D +RUN bash util/install_deps_ubuntu.sh assume-yes && \ + rm -rf /var/lib/apt/lists/* +RUN mkdir build && cd build && \ + cmake \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_SHARED_LIBS=ON \ + -DGLIBCXX_USE_CXX11_ABI=ON \ + -DBUILD_CUDA_MODULE=ON \ + -DBUILD_PYTORCH_OPS=ON \ + -DBUILD_TENSORFLOW_OPS=OFF \ + -DPYTHON_EXECUTABLE=$(which python) \ + -DCMAKE_INSTALL_PREFIX=/usr/local \ + .. && \ + make -j1 && \ + make install -j1 +RUN pip install yapf==0.43.0 +ENV LD_PRELOAD=${LD_PRELOAD}:/usr/local/lib/libOpen3D.so +RUN cd build && make install-pip-package -j1 + +# install polygraphy +RUN pip install colored polygraphy --extra-index-url https://pypi.ngc.nvidia.com + +# install pytorch3d +RUN FORCE_CUDA=1 pip install "git+https://github.com/facebookresearch/pytorch3d.git@stable" diff --git a/docker/Dockerfile.devel b/docker/Dockerfile.x86_64 similarity index 57% rename from docker/Dockerfile.devel rename to docker/Dockerfile.x86_64 index 44c3f74..16b36c9 100644 --- a/docker/Dockerfile.devel +++ b/docker/Dockerfile.x86_64 @@ -1,9 +1,15 @@ FROM alexmelekhin/open-place-recognition:base -# to install "dvc[gdrive]" we need to install "distro" package first +# Install distro package as before. ARG DISTRO_VERSION=1.9.0 RUN pip install distro==${DISTRO_VERSION} +# OPR_PATH is provided as a relative path within the build context. +ARG OPR_PATH= + +# Copy the external OpenPlaceRecognition folder into /OpenPlaceRecognition inside the container. +COPY ${OPR_PATH} /OpenPlaceRecognition + # Set the locale RUN apt-get update && apt-get install -y locales && \ locale-gen en_US en_US.UTF-8 && \ @@ -17,38 +23,45 @@ RUN apt-get install -y software-properties-common && add-apt-repository universe # Install ROS2 RUN apt-get update && apt-get upgrade -y && apt-get install -y \ + nano \ ros-humble-desktop \ ros-dev-tools \ ros-humble-image-transport-plugins && \ rosdep init && rosdep update -COPY dependencies/OpenPlaceRecognition OpenPlaceRecognition +# Copy local ROS2 packages into the workspace source directory. +# These folders (open_place_recognition and opr_interfaces) are assumed to be in the repository (build context). +RUN mkdir -p /ros2_ws/src + +# Run additional setup steps from the external OPR folder. WORKDIR /OpenPlaceRecognition -RUN cd third_party/GeoTransformer && \ - bash setup.sh +RUN cd third_party/GeoTransformer && bash setup.sh WORKDIR / -RUN rm -rf OpenPlaceRecognition +RUN rm -rf /OpenPlaceRecognition -# add user and his password +# Add user and set password. ENV USER=docker_opr_ros2 ARG UID=1000 ARG GID=1000 -# default password ARG PW=user - RUN useradd -m ${USER} --uid=${UID} && echo "${USER}:${PW}" | chpasswd && adduser ${USER} sudo WORKDIR /home/${USER} -# create some directories for mounting volumes -RUN mkdir ros2_ws && chown -R ${UID}:${GID} /home/${USER} -RUN mkdir Datasets && chown -R ${UID}:${GID} /home/${USER} +# Create directories for mounting volumes. +RUN mkdir -p ros2_ws && chown -R ${UID}:${GID} /home/${USER} +RUN mkdir OpenPlaceRecognition && chown -R ${UID}:${GID} /home/${USER} USER ${UID}:${GID} RUN echo "source /opt/ros/humble/setup.bash" >> /home/${USER}/.bashrc -COPY dependencies/OpenPlaceRecognition/requirements.txt requirements.txt + +# Install pip requirements from the external folder. +COPY ${OPR_PATH}/requirements.txt requirements.txt RUN pip install --user -r requirements.txt && rm requirements.txt -COPY dependencies/OpenPlaceRecognition/requirements-dev.txt requirements-dev.txt +COPY ${OPR_PATH}/requirements-dev.txt requirements-dev.txt RUN pip install --user -r requirements-dev.txt && rm requirements-dev.txt -COPY dependencies/OpenPlaceRecognition/requirements-notebook.txt requirements-notebook.txt +COPY ${OPR_PATH}/requirements-notebook.txt requirements-notebook.txt RUN pip install --user -r requirements-notebook.txt && rm requirements-notebook.txt + +# Install Paddle packages via pip. +RUN pip install --user paddleocr paddlepaddle-gpu diff --git a/docker/build.sh b/docker/build_jetson.sh similarity index 50% rename from docker/build.sh rename to docker/build_jetson.sh index fbc6dd9..8fe7290 100644 --- a/docker/build.sh +++ b/docker/build_jetson.sh @@ -3,29 +3,26 @@ orange=`tput setaf 3` reset_color=`tput sgr0` + +echo "This architecture is still in development" +exit 1 + + ARCH=`uname -m` -if [ $ARCH != "x86_64" ]; then +if [ $ARCH != "aarch64" ]; then echo "${orange}${ARCH}${reset_color} architecture is not supported" exit 1 fi -if command -v nvidia-smi &> /dev/null; then - echo "Detected ${orange}CUDA${reset_color} hardware" - DOCKERFILE=Dockerfile.devel - DEVICE=cuda -else - echo "${orange}CPU-only${reset_color} build is not supported yet" - exit 1 -fi - -echo "Building for ${orange}${ARCH}${reset_color} with ${orange}${DEVICE}${reset_color}" +echo "Building for ${orange}${ARCH}${reset_color}" PROJECT_ROOT_DIR=$(cd ./"`dirname $0`"/.. || exit; pwd) +DOCKERFILE=Dockerfile.jetson docker build $PROJECT_ROOT_DIR \ --build-arg MAX_JOBS=4 \ --build-arg UID=$(id -u) \ --build-arg GID=$(id -g) \ -f $PROJECT_ROOT_DIR/docker/$DOCKERFILE \ - -t open-place-recognition-ros2:devel \ + -t open-place-recognition-jetson:base-r35.4.1-cu114-cp310 \ --network=host diff --git a/docker/build_x86_64.sh b/docker/build_x86_64.sh new file mode 100644 index 0000000..ec2146c --- /dev/null +++ b/docker/build_x86_64.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +orange=$(tput setaf 3) +reset_color=$(tput sgr0) + +ARCH=$(uname -m) +if [ "$ARCH" != "x86_64" ]; then + echo "${orange}${ARCH}${reset_color} architecture is not supported" + exit 1 +fi + +if command -v nvidia-smi &> /dev/null; then + echo "Detected ${orange}CUDA${reset_color} hardware" + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + DOCKERFILE_PATH="$SCRIPT_DIR/Dockerfile.x86_64" + DEVICE=cuda +else + echo "${orange}CPU-only${reset_color} build is not supported yet" + exit 1 +fi + +echo "Building for ${orange}${ARCH}${reset_color} with ${orange}${DEVICE}${reset_color}" + +# OPR_PATH must be provided as an absolute path. +if [ -z "$OPR_PATH" ]; then + echo "Error: Please set the OPR_PATH environment variable to your external OpenPlaceRecognition directory." + exit 1 +fi + +# Check if OPR_PATH exists. +if [ ! -d "$OPR_PATH" ]; then + echo "Error: OPR_PATH ($OPR_PATH) does not exist." + exit 1 +fi +echo "Using OpenPlaceRecognition path: ${orange}${OPR_PATH}${reset_color}" + +# Create a temporary build context directory (outside of your repository) +TMP_BUILD_CONTEXT=$(mktemp -d) +echo "Using temporary build context: ${orange}${TMP_BUILD_CONTEXT}${reset_color}" + +# Copy the Dockerfile into the temporary build context. +cp "$DOCKERFILE_PATH" "$TMP_BUILD_CONTEXT/" + +# Copy the external OPR directory into the temporary build context under a dedicated folder. +# This prevents polluting your repository. +mkdir -p "$TMP_BUILD_CONTEXT/OpenPlaceRecognition_external" +cp -r "$OPR_PATH" "$TMP_BUILD_CONTEXT/OpenPlaceRecognition_external" + +# The build argument OPR_PATH will be set to point to the external folder inside the temporary build context. +# For example, if OPR_PATH=/home/rover2/Downloads/OpenPlaceRecognition/OpenPlaceRecognition, +# then $(basename "$OPR_PATH") will be "OpenPlaceRecognition", and the full relative path becomes: +# "OpenPlaceRecognition_external/OpenPlaceRecognition" +BUILD_OPR_PATH="OpenPlaceRecognition_external/$(basename "$OPR_PATH")" + +# Allow external specification of the base image. +if [ -z "$BASE_IMAGE" ]; then + BASE_IMAGE=alexmelekhin/open-place_recognition:base +fi +echo "Using base image: ${orange}${BASE_IMAGE}${reset_color}" + +docker build "$TMP_BUILD_CONTEXT" \ + --build-arg MAX_JOBS=4 \ + --build-arg UID=$(id -u) \ + --build-arg GID=$(id -g) \ + --build-arg OPR_PATH="${BUILD_OPR_PATH}" \ + --build-arg BASE_IMAGE="${BASE_IMAGE}" \ + -f "$TMP_BUILD_CONTEXT/$(basename "$DOCKERFILE_PATH")" \ + -t open-place-recognition-ros2:devel \ + --network=host + +# Clean up the temporary build context. +rm -rf "$TMP_BUILD_CONTEXT" diff --git a/docker/start.sh b/docker/start_jetson.sh similarity index 100% rename from docker/start.sh rename to docker/start_jetson.sh diff --git a/docker/start_x86_64.sh b/docker/start_x86_64.sh new file mode 100644 index 0000000..5974e94 --- /dev/null +++ b/docker/start_x86_64.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +orange=`tput setaf 3` +reset_color=`tput sgr0` + +# get_real_path(){ +# if [ "${1:0:1}" == "/" ]; then +# echo "$1" +# else +# realpath -m "$PWD"/"$1" +# fi +# } + +ARCH=`uname -m` +if [ $ARCH == "x86_64" ]; then + if command -v nvidia-smi &> /dev/null; then + DEVICE=cuda + ARGS="--ipc host --gpus all" + else + echo "${orange}CPU-only${reset_color} build is not supported yet" + exit 1 + fi +else + echo "${orange}${ARCH}${reset_color} architecture is not supported" + exit 1 +fi + + +if [ -z "$DATASETS_DIR" ]; then + echo "Error: DATASETS_DIR environment variable is not set. Please set it to your Datasets directory." + exit 1 +fi + +if [ ! -d $DATASETS_DIR ]; then + echo "Error: DATASETS_DIR=$DATASETS_DIR is not an existing directory." + exit 1 +fi + +if [ -z "$OPR_PATH" ]; then + echo "Error: OPR_PATH environment variable is not set. Please set it to your OpenPlaceRecognition directory." + exit 1 +fi + +PROJECT_ROOT_DIR=$(cd ./"`dirname $0`"/.. || exit; pwd) + +echo "Running on ${orange}${ARCH}${reset_color} with ${orange}${DEVICE}${reset_color}" + +xhost + + docker run -it -d --rm \ + $ARGS \ + --env="DISPLAY=$DISPLAY" \ + --env="QT_X11_NO_MITSHM=1" \ + --privileged \ + --name ${USER}_opr_ros2 \ + --net host \ + -v /tmp/.X11-unix:/tmp/.X11-unix:rw \ + -v $PROJECT_ROOT_DIR:/home/docker_opr_ros2/ros2_ws/src:rw \ + -v $DATASETS_DIR:/home/docker_opr_ros2/Datasets:rw \ + -v $OPR_PATH:/home/docker_opr_ros2/OpenPlaceRecognition:rw \ + open-place-recognition-ros2:devel +xhost - + +docker exec --user root \ + ${USER}_opr_ros2 bash -c "/etc/init.d/ssh start" diff --git a/src/open_place_recognition/open_place_recognition/__init__.py b/docs/SETUP_OPR.md similarity index 100% rename from src/open_place_recognition/open_place_recognition/__init__.py rename to docs/SETUP_OPR.md diff --git a/open_place_recognition/CMakeLists.txt b/open_place_recognition/CMakeLists.txt new file mode 100644 index 0000000..4c3bd73 --- /dev/null +++ b/open_place_recognition/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.5) +project(open_place_recognition) + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + + +# Find ament and any required dependencies (e.g. rclpy if used) +find_package(ament_cmake REQUIRED) +find_package(rclpy REQUIRED) + +# Install launch files (matches glob pattern in setup.py) +install( + DIRECTORY + configs + launch + rviz + DESTINATION share/${PROJECT_NAME} +) + +install(PROGRAMS + src/dataset_from_rosbag_node.py + src/dataset_from_rtabmap_node.py + src/dataset_publisher_node.py + src/dataset_train_node.py + src/localization_node.py + src/place_recognition_node.py +# src/test_depth_estimation_node.py +# src/test_opr_odom_node.py +# src/test_visualizer_node.py + DESTINATION lib/${PROJECT_NAME} +) + +ament_package() diff --git a/src/open_place_recognition/configs/anno/ade20k.yaml b/open_place_recognition/configs/anno/ade20k.yaml similarity index 100% rename from src/open_place_recognition/configs/anno/ade20k.yaml rename to open_place_recognition/configs/anno/ade20k.yaml diff --git a/src/open_place_recognition/configs/anno/oneformer.yaml b/open_place_recognition/configs/anno/oneformer.yaml similarity index 100% rename from src/open_place_recognition/configs/anno/oneformer.yaml rename to open_place_recognition/configs/anno/oneformer.yaml diff --git a/src/open_place_recognition/configs/pipelines/aruco_localization_pipeline.yaml b/open_place_recognition/configs/pipelines/aruco_localization_pipeline.yaml similarity index 100% rename from src/open_place_recognition/configs/pipelines/aruco_localization_pipeline.yaml rename to open_place_recognition/configs/pipelines/aruco_localization_pipeline.yaml diff --git a/src/open_place_recognition/configs/pipelines/localization_pipeline.yaml b/open_place_recognition/configs/pipelines/localization_pipeline.yaml similarity index 100% rename from src/open_place_recognition/configs/pipelines/localization_pipeline.yaml rename to open_place_recognition/configs/pipelines/localization_pipeline.yaml diff --git a/src/open_place_recognition/configs/pipelines/place_recognition/multimodal_pr.yaml b/open_place_recognition/configs/pipelines/place_recognition/multimodal_pr.yaml similarity index 76% rename from src/open_place_recognition/configs/pipelines/place_recognition/multimodal_pr.yaml rename to open_place_recognition/configs/pipelines/place_recognition/multimodal_pr.yaml index 29efcfb..4128a21 100644 --- a/src/open_place_recognition/configs/pipelines/place_recognition/multimodal_pr.yaml +++ b/open_place_recognition/configs/pipelines/place_recognition/multimodal_pr.yaml @@ -28,7 +28,6 @@ model: fusion_module: _target_: opr.modules.Concat -database_dir: /home/docker_opr_ros2/Datasets/itlpcampus_nature_exps/databases/indoor_floor_5 -model_weights_path: /home/docker_opr_ros2/ros2_ws/src/open_place_recognition/weights/multi-image_lidar_late-fusion_nclt.pth +model_weights_path: OpenPlaceRecognition/weights/place_recognition/multi-image_lidar_late-fusion_nclt.pth device: cuda -pointcloud_quantization_size: 0.5 +pointcloud_quantization_size: 0.5 \ No newline at end of file diff --git a/src/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_pr.yaml b/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_pr.yaml similarity index 84% rename from src/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_pr.yaml rename to open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_pr.yaml index 2d54d3b..a2f3cda 100644 --- a/src/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_pr.yaml +++ b/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_pr.yaml @@ -41,7 +41,7 @@ model: fusion_module: _target_: opr.modules.Concat -database_dir: /home/docker_opr_ros2/Datasets/itlpcampus_nature_exps/databases/indoor_floor_5 -model_weights_path: /home/docker_opr_ros2/ros2_ws/src/open_place_recognition/weights/multi-image_multi-semantic_lidar_late-fusion_nclt.pth +# database_dir: /home/docker_opr_ros2/Datasets/itlpcampus_nature_exps/databases/indoor_floor_5 +model_weights_path: OpenPlaceRecognition/weights/place_recognition/multi-image_multi-semantic_lidar_late-fusion_nclt.pth device: cuda pointcloud_quantization_size: 0.5 diff --git a/src/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_with_soc_outdoor_pr.yaml b/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_with_soc_outdoor_pr.yaml similarity index 85% rename from src/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_with_soc_outdoor_pr.yaml rename to open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_with_soc_outdoor_pr.yaml index 39f7a10..a49a74f 100644 --- a/src/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_with_soc_outdoor_pr.yaml +++ b/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_with_soc_outdoor_pr.yaml @@ -49,7 +49,7 @@ model: fusion_module: _target_: opr.modules.Concat -database_dir: /home/docker_opr_ros2/Datasets/itlpcampus_nature_exps/databases/outdoor_2023-04-11-day -model_weights_path: /home/docker_opr_ros2/ros2_ws/src/open_place_recognition/weights/multimodal_semantic_with_soc_outdoor_nclt.pth +# database_dir: /home/docker_opr_ros2/Datasets/itlpcampus_nature_exps/databases/outdoor_2023-04-11-day +model_weights_path: OpenPlaceRecognition/weights/place_recognition/multimodal_semantic_with_soc_outdoor_nclt.pth device: cuda pointcloud_quantization_size: 0.5 diff --git a/src/open_place_recognition/configs/pipelines/place_recognition/multimodal_with_soc_outdoor_pr.yaml b/open_place_recognition/configs/pipelines/place_recognition/multimodal_with_soc_outdoor_pr.yaml similarity index 82% rename from src/open_place_recognition/configs/pipelines/place_recognition/multimodal_with_soc_outdoor_pr.yaml rename to open_place_recognition/configs/pipelines/place_recognition/multimodal_with_soc_outdoor_pr.yaml index 43a6335..e63420e 100644 --- a/src/open_place_recognition/configs/pipelines/place_recognition/multimodal_with_soc_outdoor_pr.yaml +++ b/open_place_recognition/configs/pipelines/place_recognition/multimodal_with_soc_outdoor_pr.yaml @@ -36,7 +36,7 @@ model: fusion_module: _target_: opr.modules.Concat -database_dir: /home/docker_opr_ros2/Datasets/itlpcampus_nature_exps/databases/outdoor_2023-04-11-day -model_weights_path: /home/docker_opr_ros2/ros2_ws/src/open_place_recognition/weights/multimodal_with_soc_outdoor_nclt.pth +# database_dir: /home/docker_opr_ros2/Datasets/itlpcampus_nature_exps/databases/outdoor_2023-04-11-day +model_weights_path: OpenPlaceRecognition/weights/place_recognition/multimodal_with_soc_outdoor_nclt.pth device: cuda pointcloud_quantization_size: 0.5 diff --git a/src/open_place_recognition/configs/pipelines/place_recognition/text_labels_pr.yaml b/open_place_recognition/configs/pipelines/place_recognition/text_labels_pr.yaml similarity index 80% rename from src/open_place_recognition/configs/pipelines/place_recognition/text_labels_pr.yaml rename to open_place_recognition/configs/pipelines/place_recognition/text_labels_pr.yaml index 82047c0..b300397 100644 --- a/src/open_place_recognition/configs/pipelines/place_recognition/text_labels_pr.yaml +++ b/open_place_recognition/configs/pipelines/place_recognition/text_labels_pr.yaml @@ -30,7 +30,7 @@ model: fusion_module: _target_: opr.modules.Concat -database_dir: /home/docker_opr_ros2/Datasets/itlpcampus_nature_exps/databases/indoor_floor_5 -model_weights_path: /home/docker_opr_ros2/ros2_ws/src/open_place_recognition/weights/multi-image_lidar_late-fusion_nclt.pth +# database_dir: /home/docker_opr_ros2/Datasets/itlpcampus_nature_exps/databases/indoor_floor_5 +model_weights_path: OpenPlaceRecognition/weights/place_recognition/multi-image_lidar_late-fusion_nclt.pth device: cuda pointcloud_quantization_size: 0.5 diff --git a/src/open_place_recognition/configs/pipelines/updated_pipelines/aruco_localization_pipeline.yaml b/open_place_recognition/configs/pipelines/updated_pipelines/aruco_localization_pipeline.yaml similarity index 100% rename from src/open_place_recognition/configs/pipelines/updated_pipelines/aruco_localization_pipeline.yaml rename to open_place_recognition/configs/pipelines/updated_pipelines/aruco_localization_pipeline.yaml diff --git a/src/open_place_recognition/configs/pipelines/updated_pipelines/localization_pipeline.yaml b/open_place_recognition/configs/pipelines/updated_pipelines/localization_pipeline.yaml similarity index 100% rename from src/open_place_recognition/configs/pipelines/updated_pipelines/localization_pipeline.yaml rename to open_place_recognition/configs/pipelines/updated_pipelines/localization_pipeline.yaml diff --git a/src/open_place_recognition/configs/pipelines/updated_pipelines/multimodal_pr.yaml b/open_place_recognition/configs/pipelines/updated_pipelines/multimodal_pr.yaml similarity index 100% rename from src/open_place_recognition/configs/pipelines/updated_pipelines/multimodal_pr.yaml rename to open_place_recognition/configs/pipelines/updated_pipelines/multimodal_pr.yaml diff --git a/src/open_place_recognition/configs/pipelines/updated_pipelines/multimodal_semantic_pr.yaml b/open_place_recognition/configs/pipelines/updated_pipelines/multimodal_semantic_pr.yaml similarity index 100% rename from src/open_place_recognition/configs/pipelines/updated_pipelines/multimodal_semantic_pr.yaml rename to open_place_recognition/configs/pipelines/updated_pipelines/multimodal_semantic_pr.yaml diff --git a/src/open_place_recognition/configs/pipelines/updated_pipelines/multimodal_semantic_with_soc_outdoor_pr.yaml b/open_place_recognition/configs/pipelines/updated_pipelines/multimodal_semantic_with_soc_outdoor_pr.yaml similarity index 100% rename from src/open_place_recognition/configs/pipelines/updated_pipelines/multimodal_semantic_with_soc_outdoor_pr.yaml rename to open_place_recognition/configs/pipelines/updated_pipelines/multimodal_semantic_with_soc_outdoor_pr.yaml diff --git a/src/open_place_recognition/configs/pipelines/updated_pipelines/multimodal_with_soc_outdoor_pr.yaml b/open_place_recognition/configs/pipelines/updated_pipelines/multimodal_with_soc_outdoor_pr.yaml similarity index 100% rename from src/open_place_recognition/configs/pipelines/updated_pipelines/multimodal_with_soc_outdoor_pr.yaml rename to open_place_recognition/configs/pipelines/updated_pipelines/multimodal_with_soc_outdoor_pr.yaml diff --git a/src/open_place_recognition/configs/pipelines/updated_pipelines/text_labels_pr.yaml b/open_place_recognition/configs/pipelines/updated_pipelines/text_labels_pr.yaml similarity index 100% rename from src/open_place_recognition/configs/pipelines/updated_pipelines/text_labels_pr.yaml rename to open_place_recognition/configs/pipelines/updated_pipelines/text_labels_pr.yaml diff --git a/src/open_place_recognition/configs/sensors/husky.yaml b/open_place_recognition/configs/sensors/husky.yaml similarity index 100% rename from src/open_place_recognition/configs/sensors/husky.yaml rename to open_place_recognition/configs/sensors/husky.yaml diff --git a/open_place_recognition/launch/dataset_from_bag.launch.py b/open_place_recognition/launch/dataset_from_bag.launch.py new file mode 100644 index 0000000..717e71f --- /dev/null +++ b/open_place_recognition/launch/dataset_from_bag.launch.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 + +import os +from launch import LaunchDescription +from launch_ros.actions import Node +from launch.actions import ExecuteProcess + +def generate_launch_description(): + rosbag_file = os.path.expanduser('~/.ros/opr_dataset') # Adjust this path as needed. + + return LaunchDescription([ + Node( + package='open_place_recognition', + executable='dataset_from_rosbag_node.py', + name='dataset_from_rosbag_node', + output='screen', + parameters=[ + {"front_camera_topic": "/front_cam/camera_depth/image_raw"}, + {"back_camera_topic": "/back_cam//camera_depth/image_raw"}, + {"lidar_topic": "/lidar/points2_raw"}, + {"pose_topic": "/my_pose_topic"}, + {"output_path": "~/.ros/opr_dataset"}, + {"track_name": "my_experiment_01"}, + # Optionally pass the rosbag file path as a parameter if your node needs it: + {"rosbag_file": rosbag_file} + ] + ), + # ExecuteProcess to run ros2 bag play using the specified rosbag directory + ExecuteProcess( + cmd=['ros2', 'bag', 'play', rosbag_file], + output='screen' + ) + ]) + +if __name__ == '__main__': + generate_launch_description() diff --git a/open_place_recognition/launch/dataset_from_rtabmap.launch.py b/open_place_recognition/launch/dataset_from_rtabmap.launch.py new file mode 100644 index 0000000..e960683 --- /dev/null +++ b/open_place_recognition/launch/dataset_from_rtabmap.launch.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +import os +import sys +from ament_index_python.packages import get_package_share_directory + +from launch import LaunchDescription +from launch.actions import OpaqueFunction, DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node + +def generate_launch_description(): + map_name = LaunchConfiguration('map_name') + input_path = LaunchConfiguration('input_path') + output_path = LaunchConfiguration('output_path') + + return LaunchDescription([ + DeclareLaunchArgument( + 'input_path', + default_value='~/Sync/map', + description='Path to the dataset directory' + ), + DeclareLaunchArgument( + 'map_name', + default_value='my_map', + description='Map name for dataset creation' + ), + DeclareLaunchArgument( + 'output_path', + default_value='~/.ros/opr_dataset', + description='Map name for dataset creation' + ), + Node( + package='orca_opr', + executable='dataset_from_rtabmap_node.py', + name='dataset_from_rtabmap', + output='screen', + parameters=[{ + 'input_path': input_path, + 'map_name': map_name, + 'output_path': output_path, + }], + ) + ]) diff --git a/open_place_recognition/launch/dataset_publisher.launch.py b/open_place_recognition/launch/dataset_publisher.launch.py new file mode 100644 index 0000000..8688f85 --- /dev/null +++ b/open_place_recognition/launch/dataset_publisher.launch.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python3 + +import os +from launch import LaunchDescription +from launch_ros.actions import Node +from launch.actions import DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration + +def generate_launch_description(): + # Declare launch arguments with default values + dataset_dir_arg = DeclareLaunchArgument( + 'dataset_dir', + default_value=os.path.join(os.path.expanduser("~"), "Datasets", "06_2023-08-18-night"), + description='Path to the dataset directory (database path)' + ) + enable_front_camera_arg = DeclareLaunchArgument( + 'enable_front_camera', + default_value='true', + description='Enable front camera' + ) + enable_back_camera_arg = DeclareLaunchArgument( + 'enable_back_camera', + default_value='true', + description='Enable back camera' + ) + enable_lidar_arg = DeclareLaunchArgument( + 'enable_lidar', + default_value='true', + description='Enable lidar' + ) + enable_global_ref_arg = DeclareLaunchArgument( + 'enable_global_ref', + default_value='false', + description='Enable global reference' + ) + global_ref_topic_arg = DeclareLaunchArgument( + 'global_ref_topic', + default_value='/global_ref', + description='Global reference topic' + ) + reserve_arg = DeclareLaunchArgument( + 'reserve', + default_value='false', + description='Reserve parameter' + ) + + # Topic names + front_cam_topic_arg = DeclareLaunchArgument( + 'front_cam_topic', + default_value='/zed_node/left/image_rect_color/compressed', + description='Front camera topic' + ) + front_cam_mask_topic_arg = DeclareLaunchArgument( + 'front_cam_mask_topic', + default_value='/zed_node/left/semantic_segmentation', + description='Front camera mask topic' + ) + front_cam_info_topic_arg = DeclareLaunchArgument( + 'front_cam_info_topic', + default_value='/zed_node/left/image_rect_color/camera_info', + description='Front camera info topic' + ) + back_cam_topic_arg = DeclareLaunchArgument( + 'back_cam_topic', + default_value='/realsense_back/color/image_raw/compressed', + description='Back camera topic' + ) + back_cam_mask_topic_arg = DeclareLaunchArgument( + 'back_cam_mask_topic', + default_value='/realsense_back/semantic_segmentation', + description='Back camera mask topic' + ) + back_cam_info_topic_arg = DeclareLaunchArgument( + 'back_cam_info_topic', + default_value='/realsense_back/color/image_raw/camera_info', + description='Back camera info topic' + ) + lidar_topic_arg = DeclareLaunchArgument( + 'lidar_topic', + default_value='/velodyne_points', + description='Lidar topic' + ) + # TF frames + tf_parent_frame_arg = DeclareLaunchArgument( + 'tf_parent_frame', + default_value='base_link', + description='TF parent frame' + ) + front_cam_frame_arg = DeclareLaunchArgument( + 'front_cam_frame', + default_value='zed_left', + description='Front camera TF frame' + ) + back_cam_frame_arg = DeclareLaunchArgument( + 'back_cam_frame', + default_value='realsense_back', + description='Back camera TF frame' + ) + lidar_frame_arg = DeclareLaunchArgument( + 'lidar_frame', + default_value='velodyne', + description='Lidar TF frame' + ) + + # Use LaunchConfiguration substitutions to pass these values as parameters + params = { + "dataset_dir": LaunchConfiguration('dataset_dir'), + "enable_front_camera": LaunchConfiguration('enable_front_camera'), + "enable_back_camera": LaunchConfiguration('enable_back_camera'), + "enable_lidar": LaunchConfiguration('enable_lidar'), + "enable_global_ref": LaunchConfiguration('enable_global_ref'), + "global_ref_topic": LaunchConfiguration('global_ref_topic'), + "reserve": LaunchConfiguration('reserve'), + # Topic names + "front_cam_topic": LaunchConfiguration('front_cam_topic'), + "front_cam_mask_topic": LaunchConfiguration('front_cam_mask_topic'), + "front_cam_info_topic": LaunchConfiguration('front_cam_info_topic'), + "back_cam_topic": LaunchConfiguration('back_cam_topic'), + "back_cam_mask_topic": LaunchConfiguration('back_cam_mask_topic'), + "back_cam_info_topic": LaunchConfiguration('back_cam_info_topic'), + "lidar_topic": LaunchConfiguration('lidar_topic'), + # TF frames + "tf_parent_frame": LaunchConfiguration('tf_parent_frame'), + "front_cam_frame": LaunchConfiguration('front_cam_frame'), + "back_cam_frame": LaunchConfiguration('back_cam_frame'), + "lidar_frame": LaunchConfiguration('lidar_frame') + } + + return LaunchDescription([ + # Declare all arguments + dataset_dir_arg, + enable_front_camera_arg, + enable_back_camera_arg, + enable_lidar_arg, + enable_global_ref_arg, + global_ref_topic_arg, + reserve_arg, + front_cam_topic_arg, + front_cam_mask_topic_arg, + front_cam_info_topic_arg, + back_cam_topic_arg, + back_cam_mask_topic_arg, + back_cam_info_topic_arg, + lidar_topic_arg, + tf_parent_frame_arg, + front_cam_frame_arg, + back_cam_frame_arg, + lidar_frame_arg, + # Launch the node with the parameters + Node( + package='open_place_recognition', + executable='dataset_publisher_node.py', + name='opr_dataset_publisher', + output='screen', + emulate_tty=True, + parameters=[params] + ) + ]) diff --git a/open_place_recognition/launch/dataset_train.launch.py b/open_place_recognition/launch/dataset_train.launch.py new file mode 100644 index 0000000..e07a8b0 --- /dev/null +++ b/open_place_recognition/launch/dataset_train.launch.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +import os +import sys +from ament_index_python.packages import get_package_share_directory + +from launch import LaunchDescription +from launch.actions import OpaqueFunction, DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node + +def generate_launch_description(): + dataset_path = LaunchConfiguration('dataset_path') + map_name = LaunchConfiguration('map_name') + output_path = LaunchConfiguration('output_path') + + return LaunchDescription([ + DeclareLaunchArgument( + 'dataset_path', + default_value='~/.ros/opr_dataset', + description='Path to the dataset directory' + ), + DeclareLaunchArgument( + 'map_name', + default_value='my_map', + description='Map name for dataset training' + ), + DeclareLaunchArgument( + 'output_path', + default_value='~/.ros/opr_dataset', + description='Map name for dataset creation' + ), + Node( + package='orca_opr', + executable='dataset_train_node.py', + name='dataset_train_node', + output='screen', + parameters=[{ + 'dataset_path': dataset_path, + 'map_name': map_name, + 'output_path': output_path, + }], + ) + ]) diff --git a/open_place_recognition/launch/localization.launch.py b/open_place_recognition/launch/localization.launch.py new file mode 100644 index 0000000..c0ef752 --- /dev/null +++ b/open_place_recognition/launch/localization.launch.py @@ -0,0 +1,136 @@ +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node +from ament_index_python.packages import get_package_share_directory +import os + +def generate_launch_description(): + # Get the path to the share directory of the package + config_dir = os.path.join( + get_package_share_directory('open_place_recognition'), + 'configs/pipelines' + ) + + # Declare launch arguments for configurable parameters + launch_args = [ + # Topics for images and masks + DeclareLaunchArgument( + 'image_front_topic', + default_value='/zed_node/left/image_rect_color/compressed', + description='Front camera image topic.' + ), + DeclareLaunchArgument( + 'image_back_topic', + default_value='/realsense_back/color/image_raw/compressed', + description='Back camera image topic.' + ), + DeclareLaunchArgument( + 'mask_front_topic', + default_value='/zed_node/left/semantic_segmentation', + description='Front semantic segmentation mask topic.' + ), + DeclareLaunchArgument( + 'mask_back_topic', + default_value='/realsense_back/semantic_segmentation', + description='Back semantic segmentation mask topic.' + ), + # Lidar topic + DeclareLaunchArgument( + 'lidar_topic', + default_value='/velodyne_points', + description='Lidar pointcloud topic.' + ), + # Global reference system (e.g. GPS, barometer) parameters + DeclareLaunchArgument( + 'enable_global_reference', + default_value='true', + description='Enable subscription to global reference system (e.g. GPS, barometer).' + ), + DeclareLaunchArgument( + 'global_ref_topic', + default_value='/global_ref', + description='Global reference system topic (WGS84).' + ), + DeclareLaunchArgument( + 'dataset_dir', + default_value=os.path.join(os.path.expanduser("~"), "Datasets", "06_2023-08-18-night"), + description='Path to the dataset directory (database path)' + ), + DeclareLaunchArgument( + 'pipeline_cfg', + default_value=os.path.join(config_dir, 'localization_pipeline.yaml'), + description='Path to the pipeline configuration file.' + ), + DeclareLaunchArgument( + 'image_resize', + default_value='[320, 192]', + description='Image resize dimensions.' + ), + DeclareLaunchArgument( + 'exclude_dynamic_classes', + default_value='false', + description='Exclude dynamic objects from the input data.' + ), + # New sensor enable/disable flags + DeclareLaunchArgument( + 'enable_front_camera', + default_value='true', + description='Enable the front camera.' + ), + DeclareLaunchArgument( + 'enable_back_camera', + default_value='true', + description='Enable the back camera.' + ), + DeclareLaunchArgument( + 'enable_lidar', + default_value='true', + description='Enable the lidar sensor.' + ), + # Reserve variable for future use + DeclareLaunchArgument( + 'reserve', + default_value='false', + description='Reserve variable for future use.' + ) + ] + + params = { + "image_front_topic": LaunchConfiguration("image_front_topic"), + "image_back_topic": LaunchConfiguration("image_back_topic"), + "mask_front_topic": LaunchConfiguration("mask_front_topic"), + "mask_back_topic": LaunchConfiguration("mask_back_topic"), + "lidar_topic": LaunchConfiguration("lidar_topic"), + "dataset_dir": LaunchConfiguration("dataset_dir"), + "pipeline_cfg": LaunchConfiguration("pipeline_cfg"), + "image_resize": LaunchConfiguration("image_resize"), + "exclude_dynamic_classes": LaunchConfiguration("exclude_dynamic_classes"), + "enable_front_camera": LaunchConfiguration("enable_front_camera"), + "enable_back_camera": LaunchConfiguration("enable_back_camera"), + "enable_lidar": LaunchConfiguration("enable_lidar"), + "enable_global_reference": LaunchConfiguration("enable_global_reference"), + "global_ref_topic": LaunchConfiguration("global_ref_topic"), + "reserve": LaunchConfiguration("reserve"), + } + + # If a sensor is disabled, the node code should (with proper checks) skip creating the Subscriber. + # For example, if enable_lidar is false, you may have your node check if lidar_topic is empty. + # Here we assume that the node code will interpret a disabled sensor if its topic string is empty. + # One way to do that is to pass an empty string when the sensor is disabled. + # This can be achieved by a remapping or by using a conditional in your node code. + # In this launch file we simply pass the value from LaunchConfiguration. + + localization_node = Node( + package='open_place_recognition', + executable='localization_node.py', + name='hierarchical_localization', + output='screen', + emulate_tty=True, + parameters=[params] + ) + + return LaunchDescription(launch_args + [localization_node]) + +if __name__ == '__main__': + generate_launch_description() diff --git a/open_place_recognition/launch/place_recognition.launch.py b/open_place_recognition/launch/place_recognition.launch.py new file mode 100644 index 0000000..18156dc --- /dev/null +++ b/open_place_recognition/launch/place_recognition.launch.py @@ -0,0 +1,115 @@ +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node +from ament_index_python.packages import get_package_share_directory +import os + +def generate_launch_description(): + # Get the path to the share directory of the package + config_dir = os.path.join( + get_package_share_directory('open_place_recognition'), + 'configs/pipelines/place_recognition' + ) + + # Declare launch arguments for configurable parameters + launch_arguments = [ + DeclareLaunchArgument( + 'image_front_topic', + default_value='/zed_node/left/image_rect_color/compressed', + description='Front camera image topic.' + ), + DeclareLaunchArgument( + 'image_back_topic', + default_value='/realsense_back/color/image_raw/compressed', + description='Back camera image topic.' + ), + DeclareLaunchArgument( + 'mask_front_topic', + default_value='/zed_node/left/semantic_segmentation', + description='Front semantic segmentation mask topic.' + ), + DeclareLaunchArgument( + 'mask_back_topic', + default_value='/realsense_back/semantic_segmentation', + description='Back semantic segmentation mask topic.' + ), + DeclareLaunchArgument( + 'lidar_topic', + default_value='/velodyne_points', + description='Lidar pointcloud topic.' + ), + DeclareLaunchArgument( + 'dataset_dir', + default_value=os.path.join(os.path.expanduser("~"), "Datasets", "06_2023-08-18-night"), + description='Path to the dataset directory (database path)' + ), + DeclareLaunchArgument( + 'pipeline_cfg', + default_value=os.path.join(config_dir, 'multimodal_pr.yaml'), + description='Path to the pipeline configuration file.' + ), + DeclareLaunchArgument( + 'image_resize', + default_value='[320, 192]', + description='Image resize dimensions.' + ), + # New arguments for sensor enable/disable and global reference system + DeclareLaunchArgument( + 'enable_front_camera', + default_value='true', + description='Enable front camera.' + ), + DeclareLaunchArgument( + 'enable_back_camera', + default_value='true', + description='Enable back camera.' + ), + DeclareLaunchArgument( + 'enable_lidar', + default_value='true', + description='Enable lidar sensor.' + ), + DeclareLaunchArgument( + 'global_ref_topic', + default_value='/global_ref', + description='Global reference system topic (e.g. GPS/Barometer, WGS84).' + ), + DeclareLaunchArgument( + 'reserve', + default_value='false', + description='Reserve variable for future use.' + ) + ] + + # Use LaunchConfiguration substitutions for all parameters + node_parameters = { + "image_front_topic": LaunchConfiguration("image_front_topic"), + "image_back_topic": LaunchConfiguration("image_back_topic"), + "mask_front_topic": LaunchConfiguration("mask_front_topic"), + "mask_back_topic": LaunchConfiguration("mask_back_topic"), + "lidar_topic": LaunchConfiguration("lidar_topic"), + "dataset_dir": LaunchConfiguration("dataset_dir"), + "pipeline_cfg": LaunchConfiguration("pipeline_cfg"), + "image_resize": LaunchConfiguration("image_resize"), + "enable_front_camera": LaunchConfiguration("enable_front_camera"), + "enable_back_camera": LaunchConfiguration("enable_back_camera"), + "enable_lidar": LaunchConfiguration("enable_lidar"), + "global_ref_topic": LaunchConfiguration("global_ref_topic"), + "reserve": LaunchConfiguration("reserve"), + } + + # Create the Node action with parameters from LaunchConfiguration + node = Node( + package='open_place_recognition', + executable='place_recognition_node.py', + name='multimodal_multicamera_lidar_place_recognition', + output='screen', + emulate_tty=True, + parameters=[node_parameters] + ) + + return LaunchDescription(launch_arguments + [node]) + +if __name__ == '__main__': + generate_launch_description() diff --git a/src/open_place_recognition/launch/depth_estimation_new.launch.py b/open_place_recognition/launch/test_depth_estimation.launch.py similarity index 62% rename from src/open_place_recognition/launch/depth_estimation_new.launch.py rename to open_place_recognition/launch/test_depth_estimation.launch.py index 07cfd51..6dc08a2 100644 --- a/src/open_place_recognition/launch/depth_estimation_new.launch.py +++ b/open_place_recognition/launch/test_depth_estimation.launch.py @@ -5,7 +5,7 @@ def generate_launch_description(): return LaunchDescription([ Node( package='open_place_recognition', - executable='depth_estimation', + executable='test_depth_estimation_node.py', name='depth_estimation_with_lidar', output='screen', emulate_tty=True, @@ -23,17 +23,17 @@ def generate_launch_description(): ] ), - Node( - package='tf2_ros', - executable='static_transform_publisher', - name='publish_tf_lidar_to_camera', - arguments="0.061 0.049 -0.131 -0.498, 0.498, -0.495, 0.510 velodyne zed_left_camera_optical_frame".split(" ") - ), + # Node( + # package='tf2_ros', + # executable='static_transform_publisher', + # name='publish_tf_lidar_to_camera', + # arguments="0.061 0.049 -0.131 -0.498, 0.498, -0.495, 0.510 velodyne zed_left_camera_optical_frame".split(" ") + # ), - Node( - package='tf2_ros', - executable='static_transform_publisher', - name='publish_tf_base_to_lidar', - arguments="-0.300 0.014 0.883 -0.016 0.009 -0.015 base_link velodyne".split(" ") - ) + # Node( + # package='tf2_ros', + # executable='static_transform_publisher', + # name='publish_tf_base_to_lidar', + # arguments="-0.300 0.014 0.883 -0.016 0.009 -0.015 base_link velodyne".split(" ") + # ) ]) diff --git a/open_place_recognition/launch/test_opr_odometry.launch.py b/open_place_recognition/launch/test_opr_odometry.launch.py new file mode 100644 index 0000000..2622bb6 --- /dev/null +++ b/open_place_recognition/launch/test_opr_odometry.launch.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +import os +import sys +from ament_index_python.packages import get_package_share_directory + +from launch import LaunchDescription +from launch.actions import OpaqueFunction, DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node + +def generate_launch_description(): + # Even though the model node only uses 'map_name', we declare it here. + map_name = LaunchConfiguration('map_name') + weight_path = LaunchConfiguration('weight_path') + + return LaunchDescription([ + DeclareLaunchArgument( + 'map_name', + default_value='my_map', + description='Map name for model operation' + ), + DeclareLaunchArgument( + 'weight_path', + default_value='~/Sync/3d_map', + description='Map name for model operation' + ), + Node( + package='orca_opr', + executable='test_opr_odom_node.py', + name='opr_odom_node', + output='screen', + parameters=[{ + 'map_name': map_name, + 'weight_path': weight_path, + }], + ) + ]) diff --git a/src/open_place_recognition/launch/visualizer_launch.py b/open_place_recognition/launch/test_visualizer.launch.py similarity index 58% rename from src/open_place_recognition/launch/visualizer_launch.py rename to open_place_recognition/launch/test_visualizer.launch.py index a87bb89..6f42f31 100644 --- a/src/open_place_recognition/launch/visualizer_launch.py +++ b/open_place_recognition/launch/test_visualizer.launch.py @@ -1,18 +1,20 @@ from launch import LaunchDescription from launch_ros.actions import Node +import os def generate_launch_description(): + database_path = os.path.join(os.path.expanduser("~"), "Datasets/00_2023-10-25-night") + return LaunchDescription([ Node( package='open_place_recognition', - executable='visualizer', + executable='test_visualizer_node.py', name='place_recognition_visualizer', output='screen', emulate_tty=True, parameters=[ { - # "database_dir": "/home/docker_opr_ros2/Datasets/itlpcampus_nature_exps/databases/indoor_floor_5", - "database_dir": "/home/docker_opr_ros2/Datasets/itlpcampus_nature_exps/databases/outdoor_2023-04-11-day", + "database_dir": database_path, } ] ) diff --git a/src/open_place_recognition/package.xml b/open_place_recognition/package.xml similarity index 53% rename from src/open_place_recognition/package.xml rename to open_place_recognition/package.xml index 59c8213..685a17b 100644 --- a/src/open_place_recognition/package.xml +++ b/open_place_recognition/package.xml @@ -7,15 +7,16 @@ docker_opr_ros2 TODO: License declaration - rclpy - sensor_msgs - - ament_copyright - ament_flake8 - ament_pep257 - python3-pytest + rclcpp + std_msgs + rclpy + ament_lint_auto + ament_lint_common + rosidl_default_generators + rosidl_default_runtime + rosidl_interface_packages - ament_python + ament_cmake diff --git a/rviz/depth_estimation_outdoor.rviz b/open_place_recognition/rviz/depth_estimation_outdoor.rviz similarity index 100% rename from rviz/depth_estimation_outdoor.rviz rename to open_place_recognition/rviz/depth_estimation_outdoor.rviz diff --git a/open_place_recognition/scripts/dataset_create.py b/open_place_recognition/scripts/dataset_create.py new file mode 100755 index 0000000..5f9897b --- /dev/null +++ b/open_place_recognition/scripts/dataset_create.py @@ -0,0 +1,388 @@ +#!/usr/bin/env python3 +""" +Script to extract data from an RTAB-Map database (rtabmap.db) for AI training. +It extracts: + - Node data from the Node table: + • Pose (as a 3x4 float matrix) converted to a quaternion (for CSV) + and saved as a raw text file in the "pose" folder. + • Velocity (6 floats) saved in the "velocity" folder. + • GPS (6 doubles) saved in the "gps" folder. + - Sensor data from the Data table: + • RGB images (from the "image" column) saved in "rgb". + • Depth images (from the "depth" column) saved in "depth". + • Calibration data (from the "calibration" column) saved in "calib". + • Laser scan data (from the "scan" column) saved in "scan". + • Scan info (from the "scan_info" column) saved in "scan_info". + - A CSV file with node pose (as quaternion) and sensor timestamps. + +Usage: + python extract_rtabmap_all.py /path/to/rtabmap.db [optional: output_dir] + +Requires: + - Python 3.x + - sqlite3 (built-in) + - (Optional) OpenCV (cv2) and numpy to decode and save images. +""" + +import os +import sys +import struct +import math +import sqlite3 + +# Optional: install with `pip install opencv-python numpy` +try: + import cv2 + import numpy as np + OPENCV_AVAILABLE = True +except ImportError: + OPENCV_AVAILABLE = False + +def rotation_matrix_to_quaternion(R): + """ + Convert a 3x3 rotation matrix R (list of 3 lists of 3 floats) + into a quaternion (qx, qy, qz, qw). + """ + m00, m01, m02 = R[0] + m10, m11, m12 = R[1] + m20, m21, m22 = R[2] + trace = m00 + m11 + m22 + + if trace > 0: + s = math.sqrt(trace + 1.0) * 2 # S = 4*qw + qw = 0.25 * s + qx = (m21 - m12) / s + qy = (m02 - m20) / s + qz = (m10 - m01) / s + elif (m00 > m11) and (m00 > m22): + s = math.sqrt(1.0 + m00 - m11 - m22) * 2 # S = 4*qx + qw = (m21 - m12) / s + qx = 0.25 * s + qy = (m01 + m10) / s + qz = (m02 + m20) / s + elif m11 > m22: + s = math.sqrt(1.0 + m11 - m00 - m22) * 2 # S = 4*qy + qw = (m02 - m20) / s + qx = (m01 + m10) / s + qy = 0.25 * s + qz = (m12 + m21) / s + else: + s = math.sqrt(1.0 + m22 - m00 - m11) * 2 # S = 4*qz + qw = (m10 - m01) / s + qx = (m02 + m20) / s + qy = (m12 + m21) / s + qz = 0.25 * s + + return (qx, qy, qz, qw) + +class RtabMapDatasetExtractor: + """ + Extracts dataset from an RTAB-Map database for AI training. + It extracts node poses, velocity, gps (from the Node table) and sensor data + (RGB, depth, calibration, scan, scan_info from the Data table). Each type is saved + in its own folder. + """ + def __init__(self, db_path="~/Sync/3d_map/rtabmap.db", output_dir="~/.ros/opr_dataset"): + self.db_path = os.path.expanduser(db_path) + self.output_dir = os.path.expanduser(output_dir) + # Use the base name of the DB as the map name. + self.map_name = os.path.splitext(os.path.basename(self.db_path))[0] + + def run(self): + if not os.path.isfile(self.db_path): + print(f"[ERROR] Database not found: {self.db_path}") + sys.exit(1) + + # Create output directories. + map_out = os.path.join(self.output_dir, self.map_name) + folders = { + "rgb": os.path.join(map_out, "rgb"), + "depth": os.path.join(map_out, "depth"), + "calib": os.path.join(map_out, "calib"), + "scan": os.path.join(map_out, "scan"), + "scan_info": os.path.join(map_out, "scan_info"), + "pose": os.path.join(map_out, "pose"), + "velocity": os.path.join(map_out, "velocity"), + "gps": os.path.join(map_out, "gps") + } + for folder in folders.values(): + os.makedirs(folder, exist_ok=True) + + csv_file = os.path.join(map_out, "tracker.csv") + + print(f"[INFO] Reading RTAB-Map DB: {self.db_path}") + node_data = self._extract_node_data() + if not node_data: + print("[WARN] No node data found in the DB!") + + # Extract sensor data from Data table. + self._attach_sensor_data(node_data, folders) + # Write additional node data to separate folders. + self._write_node_extras(node_data, folders) + # Write CSV file. + print(f"[INFO] Writing CSV data to: {csv_file}") + self._write_csv(csv_file, node_data) + print(f"[DONE] Dataset extraction complete. See '{map_out}'.") + + def _extract_node_data(self): + """ + Query the Node table to extract: + - id, map_id, stamp, pose, velocity, gps. + The pose is stored as a 3x4 float matrix (12 floats). The rotation (first 9) + is converted to a quaternion. Also store the raw 12-float pose. + The velocity is 6 floats and gps is 6 doubles. + """ + node_dict = {} + try: + conn = sqlite3.connect(self.db_path) + c = conn.cursor() + query = """ + SELECT id, map_id, stamp, pose, velocity, gps + FROM Node + ORDER BY stamp ASC + """ + c.execute(query) + rows = c.fetchall() + for row in rows: + node_id, map_id, stamp, pose_blob, velocity_blob, gps_blob = row + timestamp = int(stamp) + try: + # Unpack pose as 12 floats. + raw_pose = struct.unpack('12f', pose_blob) + # Build rotation matrix from values [0,1,2], [4,5,6], [8,9,10] + R = [ + [raw_pose[0], raw_pose[1], raw_pose[2]], + [raw_pose[4], raw_pose[5], raw_pose[6]], + [raw_pose[8], raw_pose[9], raw_pose[10]] + ] + # Translation: indices 3,7,11. + tx, ty, tz = raw_pose[3], raw_pose[7], raw_pose[11] + qx, qy, qz, qw = rotation_matrix_to_quaternion(R) + except Exception as e: + print(f"[ERROR] Failed to unpack pose for node {node_id}: {e}") + continue + + # Extract velocity if available. + velocity_val = None + if velocity_blob: + try: + velocity_val = struct.unpack('6f', velocity_blob) + except Exception as e: + print(f"[WARN] Failed to unpack velocity for node {node_id}: {e}") + + # Extract gps if available. + gps_val = None + if gps_blob: + try: + gps_val = struct.unpack('6d', gps_blob) + except Exception as e: + print(f"[WARN] Failed to unpack GPS for node {node_id}: {e}") + + node_dict[node_id] = { + "floor": map_id, + "timestamp": timestamp, + "tx": tx, "ty": ty, "tz": tz, + "qx": qx, "qy": qy, "qz": qz, "qw": qw, + "raw_pose": raw_pose, + "velocity": velocity_val, + "gps": gps_val, + # Placeholders for sensor timestamps. + "rgb_ts": 0, + "depth_ts": 0, + "calib_ts": 0, + "scan_ts": 0, + "scan_info_ts": 0 + } + conn.close() + except sqlite3.Error as e: + print(f"[ERROR] SQLite error while reading Node table: {e}") + return node_dict + + def _attach_sensor_data(self, node_dict, folders): + """ + Query the Data table to extract sensor data. + Uses columns: + - image: compressed RGB image + - depth: compressed depth image + - calibration: calibration data + - scan: laser scan data + - scan_info: scan information data + Data.id is assumed to match Node.id. + """ + if not node_dict: + return + try: + conn = sqlite3.connect(self.db_path) + c = conn.cursor() + c.execute("SELECT * FROM Data") + rows = c.fetchall() + cols = [desc[0] for desc in c.description] + # Get indices. + try: + data_id_idx = cols.index("id") + stamp_idx = cols.index("time_enter") if "time_enter" in cols else None + except ValueError: + print("[WARN] Required columns missing in Data table.") + conn.close() + return + + image_idx = cols.index("image") if "image" in cols else None + depth_idx = cols.index("depth") if "depth" in cols else None + calib_idx = cols.index("calibration") if "calibration" in cols else None + scan_idx = cols.index("scan") if "scan" in cols else None + scan_info_idx = cols.index("scan_info") if "scan_info" in cols else None + + for row in rows: + data_node_id = row[data_id_idx] # assume Data.id == Node.id + if data_node_id not in node_dict: + continue + # Use Data.time_enter if available. + if stamp_idx is not None and row[stamp_idx]: + try: + data_ts = float(row[stamp_idx]) + except Exception: + data_ts = node_dict[data_node_id]["timestamp"] + else: + data_ts = node_dict[data_node_id]["timestamp"] + + # Extract RGB image. + if image_idx is not None: + img_blob = row[image_idx] + if img_blob and OPENCV_AVAILABLE: + np_arr = np.frombuffer(img_blob, dtype=np.uint8) + rgb_img = cv2.imdecode(np_arr, cv2.IMREAD_COLOR) + if rgb_img is not None: + fname = f"node_{data_node_id}_{int(data_ts)}_rgb.jpg" + cv2.imwrite(os.path.join(folders["rgb"], fname), rgb_img) + if node_dict[data_node_id]["rgb_ts"] == 0: + node_dict[data_node_id]["rgb_ts"] = int(data_ts) + + # Extract depth image. + if depth_idx is not None: + depth_blob = row[depth_idx] + if depth_blob and OPENCV_AVAILABLE: + np_arr = np.frombuffer(depth_blob, dtype=np.uint8) + depth_img = cv2.imdecode(np_arr, cv2.IMREAD_UNCHANGED) + if depth_img is not None: + fname = f"node_{data_node_id}_{int(data_ts)}_depth.png" + cv2.imwrite(os.path.join(folders["depth"], fname), depth_img) + if node_dict[data_node_id]["depth_ts"] == 0: + node_dict[data_node_id]["depth_ts"] = int(data_ts) + + # Extract calibration data. + if calib_idx is not None: + calib_blob = row[calib_idx] + if calib_blob: + try: + calib_text = calib_blob.decode('utf-8') + except Exception: + calib_text = str(calib_blob) + fname = f"node_{data_node_id}_{int(data_ts)}_calib.txt" + with open(os.path.join(folders["calib"], fname), 'w') as f: + f.write(calib_text) + if node_dict[data_node_id]["calib_ts"] == 0: + node_dict[data_node_id]["calib_ts"] = int(data_ts) + + # Extract scan data. + if scan_idx is not None: + scan_blob = row[scan_idx] + if scan_blob: + fname = f"node_{data_node_id}_{int(data_ts)}_scan.bin" + with open(os.path.join(folders["scan"], fname), 'wb') as f: + f.write(scan_blob) + if node_dict[data_node_id]["scan_ts"] == 0: + node_dict[data_node_id]["scan_ts"] = int(data_ts) + + # Extract scan_info data. + if scan_info_idx is not None: + si_blob = row[scan_info_idx] + if si_blob: + # Attempt to decode as text; if not, write as binary. + try: + si_text = si_blob.decode('utf-8') + fname = f"node_{data_node_id}_{int(data_ts)}_scan_info.txt" + with open(os.path.join(folders["scan_info"], fname), 'w') as f: + f.write(si_text) + except Exception: + fname = f"node_{data_node_id}_{int(data_ts)}_scan_info.bin" + with open(os.path.join(folders["scan_info"], fname), 'wb') as f: + f.write(si_blob) + if node_dict[data_node_id]["scan_info_ts"] == 0: + node_dict[data_node_id]["scan_info_ts"] = int(data_ts) + conn.close() + except sqlite3.OperationalError as e: + print(f"[WARN] Data table query failed: {e}. Skipping sensor data extraction.") + except sqlite3.Error as e: + print(f"[ERROR] SQLite error while reading Data table: {e}") + + def _write_node_extras(self, node_dict, folders): + """ + Write additional node data (raw pose, velocity, gps) to separate folders. + - In folder "pose": write the 12 float values (raw pose) as a text file. + - In folder "velocity": write 6 float values if available. + - In folder "gps": write 6 double values if available. + """ + # Write raw pose. + for node_id, data in node_dict.items(): + if "raw_pose" in data: + fname = f"node_{node_id}_pose.txt" + with open(os.path.join(folders["pose"], fname), 'w') as f: + f.write(" ".join(f"{v:.6f}" for v in data["raw_pose"])) + # Write velocity. + if data.get("velocity"): + fname = f"node_{node_id}_velocity.txt" + with open(os.path.join(folders["velocity"], fname), 'w') as f: + f.write(" ".join(f"{v:.6f}" for v in data["velocity"])) + # Write GPS. + if data.get("gps"): + fname = f"node_{node_id}_gps.txt" + with open(os.path.join(folders["gps"], fname), 'w') as f: + f.write(" ".join(f"{v:.6f}" for v in data["gps"])) + + def _write_csv(self, csv_file_path, node_dict): + """ + Write a CSV file with columns: + track, floor, timestamp, rgb_ts, depth_ts, calib_ts, scan_ts, scan_info_ts, + tx, ty, tz, qx, qy, qz, qw + """ + if not node_dict: + print("[WARN] Node dictionary empty, no data to write to CSV.") + return + sorted_nodes = sorted(node_dict.values(), key=lambda x: x["timestamp"]) + os.makedirs(os.path.dirname(csv_file_path), exist_ok=True) + with open(csv_file_path, 'w') as f: + header = ("track,floor,timestamp,rgb_ts,depth_ts,calib_ts,scan_ts,scan_info_ts," + "tx,ty,tz,qx,qy,qz,qw\n") + f.write(header) + track = f"00_{self.map_name}" + for node in sorted_nodes: + row = ( + f"{track}," + f"{node['floor']}," + f"{node['timestamp']}," + f"{node['rgb_ts']}," + f"{node['depth_ts']}," + f"{node['calib_ts']}," + f"{node['scan_ts']}," + f"{node['scan_info_ts']}," + f"{node['tx']}," + f"{node['ty']}," + f"{node['tz']}," + f"{node['qx']}," + f"{node['qy']}," + f"{node['qz']}," + f"{node['qw']}\n" + ) + f.write(row) + +def main(): + if len(sys.argv) < 2: + print("Usage: python extract_rtabmap_all.py [db_path] [optional: output_dir]") + sys.exit(1) + db_path = sys.argv[1] + output_dir = sys.argv[2] if len(sys.argv) > 2 else "~/.ros/opr_dataset" + extractor = RtabMapDatasetExtractor(db_path=db_path, output_dir=output_dir) + extractor.run() + +if __name__ == '__main__': + main() diff --git a/open_place_recognition/scripts/dataset_train.py b/open_place_recognition/scripts/dataset_train.py new file mode 100755 index 0000000..82626fe --- /dev/null +++ b/open_place_recognition/scripts/dataset_train.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +import os +import sys +import time +import csv + +class DatasetTrain: + def __init__(self, dataset_path="datasets", map_name="default_map", output_path="~/.ros/opr_dataset"): + # Expand paths for consistency. + self.dataset_path = os.path.expanduser(dataset_path) + self.map_name = map_name + self.output_path = os.path.expanduser(output_path) + + # We assume that the dataset (extracted from RTAB-Map) is stored under: + # // + self.dataset_map_dir = os.path.join(self.dataset_path, self.map_name) + if not os.path.exists(self.dataset_map_dir): + print(f"[ERROR] Dataset directory {self.dataset_map_dir} does not exist.") + print("Please extract your RTAB-Map database to create this folder and try again.") + sys.exit(1) + if not os.path.exists(self.output_path): + print(f"[ERROR] Output directory {self.output_path} does not exist.") + print("Please create it and try again.") + sys.exit(1) + + # Start the training process. + if not self.run_torch_training(self.dataset_map_dir, self.output_path, self.map_name): + print(f"[ERROR] Error during training for map {self.map_name}") + sys.exit(1) + + def run_torch_training(self, dataset_map_dir: str, output_path: str, map_name: str): + """ + Loads the dataset from dataset_map_dir and performs training for map_name. + This dummy version reads tracker.csv to determine the number of nodes, + simulates training (using sleep), and writes out a dummy model file. + """ + print(f"[TRAINER] Starting training on dataset: {dataset_map_dir} for map: {map_name}") + + tracker_csv = os.path.join(dataset_map_dir, "tracker.csv") + if not os.path.exists(tracker_csv): + print(f"[ERROR] tracker.csv not found in {dataset_map_dir}.") + return False + + # Read the tracker CSV file and count the number of nodes. + try: + with open(tracker_csv, 'r') as csv_file: + reader = csv.DictReader(csv_file) + node_count = sum(1 for _ in reader) + except Exception as e: + print(f"[ERROR] Failed to read tracker.csv: {e}") + return False + + print(f"[TRAINER] Found {node_count} nodes in the dataset.") + + # Here you would load images, pose, velocity, gps, scan, etc. for training. + # For now we simulate training with a sleep. + training_time = min(max(node_count / 10.0, 1), 10) # simulate between 1 and 10 seconds + print(f"[TRAINER] Simulating training for {training_time:.1f} seconds...") + time.sleep(training_time) + + # Write out a dummy model file. + dummy_model_file = os.path.join(output_path, f"{map_name}.pt") + try: + with open(dummy_model_file, 'w') as f: + f.write("dummy model weights") + except Exception as e: + print(f"[ERROR] Failed to write dummy model file: {e}") + return False + + print(f"[TRAINER] Dummy model file created at: {dummy_model_file}") + print(f"[TRAINER] Finished training for map: {map_name} using dataset: {dataset_map_dir}") + return True + +def main(): + """ + Usage: + python train_dataset.py [dataset_path] [map_name] [optional: output_path] + + For example, if you extracted your RTAB-Map database into: + ~/.ros/opr_dataset/rtabmap + then you might run: + python train_dataset.py ~/.ros/opr_dataset rtabmap + """ + if len(sys.argv) < 3: + print("Usage: python train_dataset.py [dataset_path] [map_name] [optional: output_path]") + sys.exit(1) + + dataset_path = sys.argv[1] + map_name = sys.argv[2] + output_path = sys.argv[3] if len(sys.argv) > 3 else "~/.ros/opr_dataset" + + DatasetTrain(dataset_path, map_name, output_path) + +if __name__ == '__main__': + main() diff --git a/open_place_recognition/scripts/node_1_9_scan.pcd b/open_place_recognition/scripts/node_1_9_scan.pcd new file mode 100644 index 0000000..322a659 --- /dev/null +++ b/open_place_recognition/scripts/node_1_9_scan.pcd @@ -0,0 +1,3069 @@ +# .PCD v0.7 - Point Cloud Data file format +VERSION 0.7 +FIELDS x y z intensity +SIZE 4 4 4 4 +TYPE F F F F +COUNT 1 1 1 1 +WIDTH 3058 +HEIGHT 1 +VIEWPOINT 0 0 0 1 0 0 0 +POINTS 3058 +DATA ascii +0.24398112297058105 0.7587628364562988 -0.21202565729618073 0.0 +0.22803637385368347 0.7402730584144592 -0.2060602307319641 0.0 +0.21296194195747375 0.7227921485900879 -0.2004505842924118 0.0 +0.19868457317352295 0.706235945224762 -0.1951671540737152 0.0 +0.18513846397399902 0.690527617931366 -0.19018299877643585 0.0 +0.17226503789424896 0.6755990982055664 -0.18547432124614716 0.0 +0.1600119024515152 0.6613900065422058 -0.18101990222930908 0.0 +0.14833176136016846 0.6478452682495117 -0.1768004596233368 0.0 +0.13718228042125702 0.6349166631698608 -0.1727989912033081 0.0 +0.12652447819709778 0.6225570440292358 -0.16899922490119934 0.0 +0.11632397770881653 0.6107286214828491 -0.16538769006729126 0.0 +0.10654889047145844 0.5993934869766235 -0.1619512438774109 0.0 +0.09717018902301788 0.5885171890258789 -0.15867789089679718 0.0 +0.08854358643293381 0.5805737972259521 -0.15623097121715546 0.0 +0.08126898109912872 0.5806673765182495 -0.1559755951166153 0.0 +0.07401704788208008 0.5807607769966125 -0.15574456751346588 0.0 +0.06678546220064163 0.5808539390563965 -0.1555376797914505 0.0 +0.05957195907831192 0.5809465646743774 -0.15535469353199005 0.0 +0.05237434804439545 0.581039309501648 -0.15519563853740692 0.0 +0.04519035294651985 0.581131637096405 -0.15506024658679962 0.0 +0.03801780939102173 0.5812239050865173 -0.15494850277900696 0.0 +0.030854513868689537 0.5813159942626953 -0.154860258102417 0.0 +0.023698294535279274 0.5814081430435181 -0.15479551255702972 0.0 +0.01654697395861149 0.5815001130104065 -0.1547541618347168 0.0 +0.009398393332958221 0.5815920829772949 -0.1547362208366394 0.0 +0.0022503924556076527 0.5816841721534729 -0.15474167466163635 0.0 +-0.004899190738797188 0.5817760825157166 -0.15477046370506287 0.0 +-0.01205251645296812 0.5818681716918945 -0.15482266247272491 0.0 +-0.019211744889616966 0.5819600820541382 -0.1548982560634613 0.0 +-0.026379061862826347 0.5820523500442505 -0.15499739348888397 0.0 +-0.033556632697582245 0.5821446180343628 -0.15512007474899292 0.0 +-0.04074668139219284 0.5822373032569885 -0.15526647865772247 0.0 +-0.04795138165354729 0.5823298096656799 -0.15543659031391144 0.0 +-0.05517297983169556 0.58242267370224 -0.15563060343265533 0.0 +-0.062413737177848816 0.5825158357620239 -0.15584871172904968 0.0 +-0.06967592984437943 0.5826094746589661 -0.15609107911586761 0.0 +-0.07696182280778885 0.5827031135559082 -0.1563577800989151 0.0 +-0.08427376300096512 0.5827971696853638 -0.15664911270141602 0.0 +-0.09161409735679626 0.5828914642333984 -0.1569652557373047 0.0 +-0.09898526966571808 0.5829864144325256 -0.15730653703212738 0.0 +-0.10638967156410217 0.5830816626548767 -0.15767315030097961 0.0 +-0.11382976919412613 0.5831772685050964 -0.15806536376476288 0.0 +-0.12130811810493469 0.5832734107971191 -0.1584835648536682 0.0 +-0.12882733345031738 0.5833702683448792 -0.15892808139324188 0.0 +-0.13638992607593536 0.5834674835205078 -0.15939918160438538 0.0 +-0.14399869740009308 0.5835654735565186 -0.15989737212657928 0.0 +-0.15165628492832184 0.5836638808250427 -0.1604229360818863 0.0 +-0.15936559438705444 0.5837631821632385 -0.16097640991210938 0.0 +-0.16712944209575653 0.5838630795478821 -0.16155818104743958 0.0 +-0.17495079338550568 0.5839636921882629 -0.1621687412261963 0.0 +-0.18283265829086304 0.5840650200843811 -0.1628086119890213 0.0 +-0.19077813625335693 0.5841671228408813 -0.1634782999753952 0.0 +-0.1987905651330948 0.5842702984809875 -0.1641785055398941 0.0 +-0.2068730592727661 0.5843741297721863 -0.16490967571735382 0.0 +-0.21502913534641266 0.584479033946991 -0.16567254066467285 0.0 +-0.22326235473155975 0.5845850706100464 -0.1664678156375885 0.0 +-0.23157615959644318 0.5846920013427734 -0.16729608178138733 0.0 +-0.23997440934181213 0.5848000049591064 -0.1681581735610962 0.0 +-0.24846096336841583 0.5849091410636902 -0.16905488073825836 0.0 +-0.25703978538513184 0.5850194692611694 -0.16998697817325592 0.0 +-0.2657150328159332 0.5851309895515442 -0.1709553748369217 0.0 +-0.2744911313056946 0.5852439999580383 -0.17196105420589447 0.0 +-0.2833724021911621 0.5853582620620728 -0.1730048805475235 0.0 +-0.2923634648323059 0.5854739546775818 -0.17408789694309235 0.0 +-0.30146917700767517 0.5855909585952759 -0.17521117627620697 0.0 +-0.3106946647167206 0.5857097506523132 -0.17637591063976288 0.0 +-0.3200449049472809 0.5858299136161804 -0.17758315801620483 0.0 +-0.32952558994293213 0.5859518647193909 -0.17883430421352386 0.0 +-0.33914217352867126 0.586075484752655 -0.18013054132461548 0.0 +-0.34890079498291016 0.5862011313438416 -0.18147340416908264 0.0 +-0.3588074743747711 0.5863285660743713 -0.1828642189502716 0.0 +-0.3688686192035675 0.5864579677581787 -0.18430455029010773 0.0 +-0.3790910542011261 0.5865892767906189 -0.18579600751399994 0.0 +-0.3894820511341095 0.5867230892181396 -0.1873404085636139 0.0 +-0.40004873275756836 0.5868589878082275 -0.1889394372701645 0.0 +-0.4107990860939026 0.586997389793396 -0.19059506058692932 0.0 +-0.42174094915390015 0.5871379375457764 -0.19230917096138 0.0 +-0.4328833520412445 0.587281346321106 -0.1940840780735016 0.0 +-0.4442349970340729 0.5874274373054504 -0.1959218829870224 0.0 +-0.4558054208755493 0.5875762701034546 -0.19782496988773346 0.0 +-0.46760451793670654 0.5877278447151184 -0.19979581236839294 0.0 +-0.4796431064605713 0.5878828167915344 -0.2018372118473053 0.0 +-0.49193185567855835 0.5880406498908997 -0.20395174622535706 0.0 +-0.5044829845428467 0.588202178478241 -0.20614264905452728 0.0 +-0.5173085927963257 0.5883671045303345 -0.20841290056705475 0.0 +-0.530421793460846 0.5885357856750488 -0.21076591312885284 0.0 +-0.5438365340232849 0.5887082815170288 -0.2132052183151245 0.0 +-0.5575677752494812 0.5888851284980774 -0.21573469042778015 0.0 +-0.571630597114563 0.5890659689903259 -0.21835818886756897 0.0 +-0.5860419273376465 0.5892512798309326 -0.22108009457588196 0.0 +-0.6008191704750061 0.589441180229187 -0.22390490770339966 0.0 +-0.6159815192222595 0.5896363258361816 -0.2268376499414444 0.0 +-0.6315486431121826 0.5898365378379822 -0.2298833727836609 0.0 +-0.6475417613983154 0.5900421142578125 -0.23304763436317444 0.0 +0.2439812868833542 0.7587633728981018 -0.18269899487495422 0.0 +0.22803650796413422 0.7402734756469727 -0.17755864560604095 0.0 +0.2129622846841812 0.7227933406829834 -0.172725111246109 0.0 +0.19868463277816772 0.7062361836433411 -0.168172225356102 0.0 +0.18513862788677216 0.690528154373169 -0.16387756168842316 0.0 +0.17226524651050568 0.6755998730659485 -0.15982022881507874 0.0 +0.16001208126544952 0.6613907217979431 -0.1559819132089615 0.0 +0.14833205938339233 0.6478465795516968 -0.15234622359275818 0.0 +0.13718241453170776 0.6349172592163086 -0.14889806509017944 0.0 +0.12652461230754852 0.6225578188896179 -0.14562389254570007 0.0 +0.11632410436868668 0.6107292771339417 -0.14251188933849335 0.0 +0.10654892027378082 0.5993936657905579 -0.13955064117908478 0.0 +0.09717029333114624 0.5885178446769714 -0.1367301642894745 0.0 +0.08854365348815918 0.5805742144584656 -0.13462163507938385 0.0 +0.0812690407037735 0.5806677937507629 -0.1344015747308731 0.0 +0.07401707768440247 0.5807610750198364 -0.1342024803161621 0.0 +0.06678549200296402 0.5808541774749756 -0.13402420282363892 0.0 +0.059571992605924606 0.5809468626976013 -0.133866548538208 0.0 +0.05237436667084694 0.581039547920227 -0.1337294727563858 0.0 +0.045190371572971344 0.5811318755149841 -0.13361279666423798 0.0 +0.03801783546805382 0.5812243223190308 -0.13351655006408691 0.0 +0.03085453435778618 0.5813164114952087 -0.1334405243396759 0.0 +0.02369830384850502 0.5814083814620972 -0.13338468968868256 0.0 +0.016546985134482384 0.5815004706382751 -0.13334910571575165 0.0 +0.009398400783538818 0.5815925002098083 -0.13333363831043243 0.0 +0.00225039292126894 0.5816842317581177 -0.13333827257156372 0.0 +-0.004899193532764912 0.5817764401435852 -0.13336312770843506 0.0 +-0.012052521109580994 0.5818683505058289 -0.1334080696105957 0.0 +-0.01921175979077816 0.5819605588912964 -0.13347327709197998 0.0 +-0.026379074901342392 0.5820526480674744 -0.13355866074562073 0.0 +-0.03355666249990463 0.582145094871521 -0.13366441428661346 0.0 +-0.04074670001864433 0.5822375416755676 -0.133790522813797 0.0 +-0.04795141518115997 0.5823302268981934 -0.13393713533878326 0.0 +-0.05517302080988884 0.5824230909347534 -0.13410431146621704 0.0 +-0.062413789331912994 0.5825163722038269 -0.13429227471351624 0.0 +-0.06967595964670181 0.5826097130775452 -0.13450105488300323 0.0 +-0.07696185261011124 0.5827034115791321 -0.13473087549209595 0.0 +-0.0842737928032875 0.5827974081039429 -0.1349819004535675 0.0 +-0.09161417186260223 0.5828919410705566 -0.135254368185997 0.0 +-0.09898534417152405 0.5829868316650391 -0.1355484426021576 0.0 +-0.10638973861932755 0.5830820798873901 -0.13586433231830597 0.0 +-0.11382986605167389 0.5831778049468994 -0.13620233535766602 0.0 +-0.12130822241306305 0.5832739472389221 -0.13656267523765564 0.0 +-0.12882739305496216 0.5833706259727478 -0.1369456797838211 0.0 +-0.13638998568058014 0.5834677815437317 -0.1373516172170639 0.0 +-0.14399877190589905 0.5835658311843872 -0.13778090476989746 0.0 +-0.1516563594341278 0.5836641788482666 -0.13823376595973969 0.0 +-0.15936563909053802 0.5837633609771729 -0.1387106478214264 0.0 +-0.1671295315027237 0.583863377571106 -0.1392119824886322 0.0 +-0.17495082318782806 0.5839638113975525 -0.1397380530834198 0.0 +-0.1828327625989914 0.5840653777122498 -0.14028945565223694 0.0 +-0.19077825546264648 0.5841674208641052 -0.14086653292179108 0.0 +-0.19879066944122314 0.5842705965042114 -0.14146986603736877 0.0 +-0.20687316358089447 0.5843744277954102 -0.14209990203380585 0.0 +-0.21502932906150818 0.584479570388794 -0.14275731146335602 0.0 +-0.2232624590396881 0.5845853686332703 -0.1434425264596939 0.0 +-0.23157626390457153 0.5846922397613525 -0.14415621757507324 0.0 +-0.23997454345226288 0.5848003029823303 -0.14489908516407013 0.0 +-0.24846108257770538 0.5849094390869141 -0.1456717550754547 0.0 +-0.25703996419906616 0.5850198268890381 -0.1464749574661255 0.0 +-0.26571521162986755 0.5851313471794128 -0.14730940759181976 0.0 +-0.27449122071266174 0.5852442383766174 -0.1481759399175644 0.0 +-0.28337252140045166 0.5853585600852966 -0.14907540380954742 0.0 +-0.29236358404159546 0.5854741334915161 -0.15000861883163452 0.0 +-0.3014693260192871 0.5855912566184998 -0.1509765386581421 0.0 +-0.3106948137283325 0.5857100486755371 -0.15198016166687012 0.0 +-0.3200451135635376 0.5858302712440491 -0.1530204564332962 0.0 +-0.32952582836151123 0.5859523415565491 -0.15409855544567108 0.0 +-0.3391423523426056 0.5860757827758789 -0.15521547198295593 0.0 +-0.3489009141921997 0.5862013101577759 -0.1563725620508194 0.0 +-0.35880759358406067 0.5863288044929504 -0.15757101774215698 0.0 +-0.3688688576221466 0.5864582657814026 -0.15881216526031494 0.0 +-0.37909135222435 0.5865897536277771 -0.16009736061096191 0.0 +-0.38948220014572144 0.5867233276367188 -0.1614280790090561 0.0 +-0.40004900097846985 0.5868593454360962 -0.16280597448349 0.0 +-0.4107992649078369 0.5869976282119751 -0.16423256695270538 0.0 +-0.42174115777015686 0.5871382355690002 -0.16570959985256195 0.0 +-0.4328835904598236 0.5872817039489746 -0.1672389954328537 0.0 +-0.4442351162433624 0.58742755651474 -0.16882255673408508 0.0 +-0.45580562949180603 0.5875765085220337 -0.1704624593257904 0.0 +-0.46760478615760803 0.5877282023429871 -0.17216072976589203 0.0 +-0.479643315076828 0.5878830552101135 -0.17391972243785858 0.0 +-0.4919322729110718 0.5880411863327026 -0.17574186623096466 0.0 +-0.5044832229614258 0.5882024765014648 -0.17762966454029083 0.0 +-0.5173088908195496 0.5883675217628479 -0.17958593368530273 0.0 +-0.5304222106933594 0.588536262512207 -0.1816135048866272 0.0 +-0.5438369512557983 0.588708758354187 -0.18371541798114777 0.0 +-0.5575679540634155 0.5888853073120117 -0.1858949363231659 0.0 +-0.5716309547424316 0.5890663266181946 -0.1881556212902069 0.0 +-0.5860421061515808 0.5892515182495117 -0.19050098955631256 0.0 +-0.6008197069168091 0.5894417762756348 -0.19293519854545593 0.0 +-0.615981936454773 0.5896367430686951 -0.19546224176883698 0.0 +-0.6315489411354065 0.589836835861206 -0.19808664917945862 0.0 +-0.6475423574447632 0.5900426506996155 -0.20081332325935364 0.0 +-0.6639845967292786 0.5902541279792786 -0.20364724099636078 0.0 +-0.6809002757072449 0.5904718041419983 -0.20659399032592773 0.0 +-0.6983150243759155 0.5906956791877747 -0.20965930819511414 0.0 +-0.7162573933601379 0.5909265279769897 -0.2128496766090393 0.0 +-0.7347567081451416 0.5911642909049988 -0.21617166697978973 0.0 +-0.758976399898529 0.595434844493866 -0.22112758457660675 0.0 +-0.7862435579299927 0.6013650894165039 -0.22690139710903168 0.0 +-0.8149780631065369 0.6076148748397827 -0.23302114009857178 0.0 +1.2174038887023926 0.007480814587324858 -0.23497708141803741 0.0 +1.2163046598434448 0.05235005170106888 -0.2349778264760971 0.0 +0.24398192763328552 0.7587653398513794 -0.15383517742156982 0.0 +0.2280370444059372 0.7402752041816711 -0.14950691163539886 0.0 +0.2129625678062439 0.7227942943572998 -0.1454368382692337 0.0 +0.1986851841211319 0.7062380909919739 -0.14160345494747162 0.0 +0.1851390302181244 0.6905297040939331 -0.13798721134662628 0.0 +0.17226563394069672 0.6756013631820679 -0.1345708817243576 0.0 +0.160012349486351 0.6613918542861938 -0.13133889436721802 0.0 +0.14833232760429382 0.6478477120399475 -0.12827759981155396 0.0 +0.13718250393867493 0.6349176168441772 -0.12537404894828796 0.0 +0.12652488052845 0.6225590705871582 -0.12261735647916794 0.0 +0.11632433533668518 0.6107304692268372 -0.11999698728322983 0.0 +0.10654906183481216 0.5993945002555847 -0.11750350892543793 0.0 +0.09717050194740295 0.5885190367698669 -0.11512871086597443 0.0 +0.08854372054338455 0.5805746912956238 -0.11335314810276031 0.0 +0.08126908540725708 0.5806680917739868 -0.11316782981157303 0.0 +0.07401713728904724 0.5807614922523499 -0.11300020664930344 0.0 +0.066785529255867 0.5808544754981995 -0.11285007745027542 0.0 +0.059572044759988785 0.5809473991394043 -0.11271736770868301 0.0 +0.052374400198459625 0.5810399055480957 -0.11260191351175308 0.0 +0.04519041255116463 0.5811324119567871 -0.11250371485948563 0.0 +0.03801786154508591 0.5812247395515442 -0.1124226376414299 0.0 +0.03085455670952797 0.5813168287277222 -0.11235862225294113 0.0 +0.023698318749666214 0.5814087390899658 -0.11231160908937454 0.0 +0.01654699072241783 0.5815007090568542 -0.11228161305189133 0.0 +0.009398404508829117 0.5815927982330322 -0.1122686043381691 0.0 +0.002250394318252802 0.5816846489906311 -0.11227253079414368 0.0 +-0.004899195861071348 0.5817766785621643 -0.11229342967271805 0.0 +-0.012052525766193867 0.581868588924408 -0.11233127862215042 0.0 +-0.019211765378713608 0.5819606781005859 -0.11238615214824677 0.0 +-0.026379093527793884 0.5820530652999878 -0.11245810985565186 0.0 +-0.03355667367577553 0.5821452736854553 -0.11254710704088211 0.0 +-0.040746718645095825 0.5822378396987915 -0.11265330761671066 0.0 +-0.04795144125819206 0.582330584526062 -0.11277676373720169 0.0 +-0.05517305061221123 0.5824233889579773 -0.11291753500699997 0.0 +-0.06241380423307419 0.5825164914131165 -0.11307576298713684 0.0 +-0.0696759894490242 0.5826098918914795 -0.11325156688690186 0.0 +-0.07696191221475601 0.5827037692070007 -0.11344511806964874 0.0 +-0.08427385985851288 0.5827978849411011 -0.11365649849176407 0.0 +-0.09161421656608582 0.5828922390937805 -0.11388588696718216 0.0 +-0.09898537397384644 0.5829870104789734 -0.11413347721099854 0.0 +-0.10638979822397232 0.583082377910614 -0.1143994852900505 0.0 +-0.11382993310689926 0.5831781029701233 -0.1146840900182724 0.0 +-0.12130827456712723 0.5832741856575012 -0.11498748511075974 0.0 +-0.12882748246192932 0.5833709836006165 -0.11531000584363937 0.0 +-0.1363900899887085 0.5834681987762451 -0.11565181612968445 0.0 +-0.1439988613128662 0.5835661888122559 -0.11601327359676361 0.0 +-0.15165647864341736 0.5836646556854248 -0.11639460176229477 0.0 +-0.15936575829982758 0.5837637782096863 -0.11679614335298538 0.0 +-0.16712959110736847 0.5838636159896851 -0.11721822619438171 0.0 +-0.1749510020017624 0.5839644074440002 -0.1176612600684166 0.0 +-0.18283288180828094 0.5840657353401184 -0.11812551319599152 0.0 +-0.19077837467193604 0.5841678380966187 -0.1186114102602005 0.0 +-0.1987907439470291 0.5842708349227905 -0.11911939829587936 0.0 +-0.20687329769134521 0.5843747854232788 -0.11964992433786392 0.0 +-0.21502947807312012 0.5844799280166626 -0.12020347267389297 0.0 +-0.22326259315013885 0.5845857262611389 -0.12078043073415756 0.0 +-0.23157645761966705 0.5846927165985107 -0.12138140201568604 0.0 +-0.23997467756271362 0.5848006010055542 -0.1220068708062172 0.0 +-0.24846121668815613 0.5849097371101379 -0.12265745550394058 0.0 +-0.2570400834083557 0.585020124912262 -0.12333376705646515 0.0 +-0.2657153904438019 0.5851317644119263 -0.12403640151023865 0.0 +-0.27449148893356323 0.5852447748184204 -0.12476605921983719 0.0 +-0.28337275981903076 0.5853590369224548 -0.1255234181880951 0.0 +-0.29236382246017456 0.5854746103286743 -0.12630918622016907 0.0 +-0.3014695346355438 0.5855916738510132 -0.12712417542934418 0.0 +-0.3106950521469116 0.5857104659080505 -0.12796925008296967 0.0 +-0.3200452923774719 0.585830569267273 -0.12884515523910522 0.0 +-0.32952603697776794 0.5859526991844177 -0.12975294888019562 0.0 +-0.33914270997047424 0.5860763788223267 -0.1306934654712677 0.0 +-0.34890124201774597 0.5862019062042236 -0.13166773319244385 0.0 +-0.35880786180496216 0.5863292813301086 -0.13267682492733002 0.0 +-0.36886903643608093 0.5864585638046265 -0.13372184336185455 0.0 +-0.3790915906429291 0.5865901112556458 -0.13480401039123535 0.0 +-0.3894824683666229 0.5867236852645874 -0.13592450320720673 0.0 +-0.4000492990016937 0.5868598222732544 -0.1370847225189209 0.0 +-0.4107995331287384 0.5869980454444885 -0.13828592002391815 0.0 +-0.4217416048049927 0.587138831615448 -0.13952964544296265 0.0 +-0.43288397789001465 0.5872822403907776 -0.14081740379333496 0.0 +-0.44423550367355347 0.587428092956543 -0.14215077459812164 0.0 +-0.4558059275150299 0.5875768661499023 -0.14353156089782715 0.0 +-0.4676051735877991 0.58772873878479 -0.14496155083179474 0.0 +-0.4796438217163086 0.587883710861206 -0.1464426964521408 0.0 +-0.49193263053894043 0.5880416035652161 -0.14797692000865936 0.0 +-0.504483699798584 0.5882030129432678 -0.14956648647785187 0.0 +-0.5173093676567078 0.5883679986000061 -0.15121367573738098 0.0 +-0.5304226875305176 0.5885367393493652 -0.1529209166765213 0.0 +-0.543837308883667 0.5887091159820557 -0.1546907126903534 0.0 +-0.5575685501098633 0.5888859629631042 -0.15652596950531006 0.0 +-0.5716314911842346 0.5890668630599976 -0.15842947363853455 0.0 +-0.5860428214073181 0.5892521739006042 -0.16040435433387756 0.0 +-0.6008203029632568 0.5894423127174377 -0.16245394945144653 0.0 +-0.6159823536872864 0.5896371006965637 -0.16458170115947723 0.0 +-0.6315494775772095 0.589837372303009 -0.16679152846336365 0.0 +-0.6475429534912109 0.5900431871414185 -0.16908742487430573 0.0 +-0.6639850735664368 0.590254545211792 -0.17147359251976013 0.0 +-0.6809006929397583 0.5904721617698669 -0.1739547699689865 0.0 +-0.6983156800270081 0.5906962156295776 -0.17653585970401764 0.0 +-0.7162579894065857 0.590927004814148 -0.17922216653823853 0.0 +-0.7347576022148132 0.5911650061607361 -0.1820194125175476 0.0 +-0.7589768767356873 0.5954352021217346 -0.18619222939014435 0.0 +-0.7862444519996643 0.6013657450675964 -0.19105395674705505 0.0 +-0.814978837966919 0.6076154708862305 -0.19620683789253235 0.0 +-0.8453105688095093 0.6142123937606812 -0.201676607131958 0.0 +-0.8773871064186096 0.6211888790130615 -0.20749236643314362 0.0 +-0.9113733768463135 0.6285805702209473 -0.21368663012981415 0.0 +-0.9474576711654663 0.6364288926124573 -0.22029659152030945 0.0 +-0.9858512878417969 0.6447793245315552 -0.22736389935016632 0.0 +-1.026795744895935 0.6536843180656433 -0.2349362075328827 0.0 +1.2275879383087158 -0.05283568799495697 -0.19325122237205505 0.0 +1.2043110132217407 -0.0370129831135273 -0.18950095772743225 0.0 +1.1941213607788086 -0.02201545611023903 -0.18784083425998688 0.0 +1.1891433000564575 -0.00730715598911047 -0.18702949583530426 0.0 +1.1878939867019653 0.007299480028450489 -0.18683302402496338 0.0 +1.190101146697998 0.02194133587181568 -0.18720842897891998 0.0 +1.1963084936141968 0.03676703944802284 -0.18824175000190735 0.0 +1.2087690830230713 0.05202571675181389 -0.19028867781162262 0.0 +0.24398256838321686 0.7587673664093018 -0.1253550797700882 0.0 +0.228037491440773 0.7402766942977905 -0.12182803452014923 0.0 +0.2129630446434021 0.7227959036827087 -0.11851150542497635 0.0 +0.19868558645248413 0.7062395215034485 -0.11538778990507126 0.0 +0.1851392537355423 0.69053053855896 -0.11244094371795654 0.0 +0.1722659468650818 0.6756026148796082 -0.1096571609377861 0.0 +0.16001272201538086 0.661393404006958 -0.10702358186244965 0.0 +0.14833250641822815 0.6478485465049744 -0.10452892631292343 0.0 +0.13718284666538239 0.634919285774231 -0.10216306149959564 0.0 +0.12652510404586792 0.6225602030754089 -0.09991664439439774 0.0 +0.11632443219423294 0.6107310056686401 -0.09778130799531937 0.0 +0.10654919594526291 0.599395215511322 -0.09574948996305466 0.0 +0.09717061370611191 0.5885196924209595 -0.09381434321403503 0.0 +0.08854376524686813 0.5805749893188477 -0.09236744791269302 0.0 +0.08126913756132126 0.5806685090065002 -0.09221645444631577 0.0 +0.07401715964078903 0.5807616710662842 -0.09207982569932938 0.0 +0.06678557395935059 0.5808548927307129 -0.09195751696825027 0.0 +0.05957207828760147 0.580947756767273 -0.09184937179088593 0.0 +0.052374422550201416 0.5810401439666748 -0.09175528585910797 0.0 +0.04519042372703552 0.5811325311660767 -0.09167524427175522 0.0 +0.0380178801715374 0.5812249779701233 -0.09160920232534409 0.0 +0.03085457719862461 0.5813171863555908 -0.09155705571174622 0.0 +0.023698333650827408 0.5814090967178345 -0.09151873737573624 0.0 +0.016547003760933876 0.5815011262893677 -0.09149430692195892 0.0 +0.009398410096764565 0.5815931558609009 -0.0914836972951889 0.0 +0.00225039548240602 0.581684947013855 -0.09148687869310379 0.0 +-0.004899199120700359 0.5817770957946777 -0.09150393307209015 0.0 +-0.012052536942064762 0.5818691253662109 -0.09153479337692261 0.0 +-0.019211778417229652 0.5819610953330994 -0.09157948940992355 0.0 +-0.02637910097837448 0.5820532441139221 -0.09163808822631836 0.0 +-0.03355669602751732 0.5821456909179688 -0.0917106419801712 0.0 +-0.04074674844741821 0.5822382569313049 -0.09179718792438507 0.0 +-0.04795147106051445 0.5823309421539307 -0.09189777821302414 0.0 +-0.05517307668924332 0.5824236869812012 -0.09201247245073318 0.0 +-0.06241385266184807 0.5825169086456299 -0.09214143455028534 0.0 +-0.06967604905366898 0.5826104283332825 -0.09228470176458359 0.0 +-0.076961949467659 0.5827040672302246 -0.09244238585233688 0.0 +-0.08427391201257706 0.5827982425689697 -0.09261464327573776 0.0 +-0.09161427617073059 0.5828925967216492 -0.09280156344175339 0.0 +-0.09898544102907181 0.5829874277114868 -0.09300332516431808 0.0 +-0.1063898578286171 0.5830826759338379 -0.0932200700044632 0.0 +-0.11382997781038284 0.5831783413887024 -0.09345196932554245 0.0 +-0.1213083565235138 0.5832745432853699 -0.09369922429323196 0.0 +-0.1288275420665741 0.5833712220191956 -0.09396200627088547 0.0 +-0.13639016449451447 0.5834685564041138 -0.09424055367708206 0.0 +-0.1439989060163498 0.5835663080215454 -0.09453506022691727 0.0 +-0.1516565978527069 0.5836650729179382 -0.09484583884477615 0.0 +-0.15936589241027832 0.5837642550468445 -0.09517304599285126 0.0 +-0.16712971031665802 0.5838640332221985 -0.09551697969436646 0.0 +-0.17495104670524597 0.5839645862579346 -0.09587795287370682 0.0 +-0.1828329712152481 0.5840660333633423 -0.09625627845525742 0.0 +-0.19077855348587036 0.5841683745384216 -0.09665225446224213 0.0 +-0.19879089295864105 0.584271252155304 -0.09706617891788483 0.0 +-0.20687349140644073 0.5843753814697266 -0.09749850630760193 0.0 +-0.2150295376777649 0.5844801068305969 -0.09794950485229492 0.0 +-0.2232627123594284 0.5845860242843628 -0.0984196737408638 0.0 +-0.231576606631279 0.5846931338310242 -0.0989094004034996 0.0 +-0.23997490108013153 0.584801197052002 -0.09941909462213516 0.0 +-0.24846145510673523 0.5849103331565857 -0.09994924068450928 0.0 +-0.25704026222229004 0.5850205421447754 -0.10050030797719955 0.0 +-0.2657155990600586 0.5851321816444397 -0.10107287019491196 0.0 +-0.2744916081428528 0.5852450132369995 -0.10166741162538528 0.0 +-0.2833728790283203 0.5853593349456787 -0.10228455811738968 0.0 +-0.2923639714717865 0.5854749083518982 -0.10292485356330872 0.0 +-0.30146971344947815 0.5855920314788818 -0.10358896851539612 0.0 +-0.3106951415538788 0.5857106447219849 -0.10427756607532501 0.0 +-0.32004550099372864 0.5858309864997864 -0.1049913540482521 0.0 +-0.3295261561870575 0.585952877998352 -0.1057310402393341 0.0 +-0.3391428589820862 0.5860766768455505 -0.10649744421243668 0.0 +-0.3489014208316803 0.5862022042274475 -0.10729134827852249 0.0 +-0.35880807042121887 0.5863295793533325 -0.10811362415552139 0.0 +-0.3688693046569824 0.5864590406417847 -0.1089651957154274 0.0 +-0.37909191846847534 0.5865906476974487 -0.10984702408313751 0.0 +-0.38948288559913635 0.5867243409156799 -0.11076010018587112 0.0 +-0.40004962682724 0.5868602991104126 -0.1117054894566536 0.0 +-0.4107997715473175 0.5869983434677124 -0.11268427968025208 0.0 +-0.421741783618927 0.5871390700340271 -0.11369772255420685 0.0 +-0.43288424611091614 0.5872825980186462 -0.11474710702896118 0.0 +-0.4442359209060669 0.587428629398346 -0.11583366245031357 0.0 +-0.45580634474754333 0.5875774025917053 -0.11695880442857742 0.0 +-0.4676055908203125 0.5877292156219482 -0.11812405288219452 0.0 +-0.4796440899372101 0.5878840088844299 -0.11933093518018723 0.0 +-0.4919329583644867 0.5880420207977295 -0.12058113515377045 0.0 +-0.5044841170310974 0.588203489780426 -0.12187643349170685 0.0 +-0.517309844493866 0.5883685350418091 -0.12321869283914566 0.0 +-0.530423104763031 0.5885372757911682 -0.12460985034704208 0.0 +-0.5438379049301147 0.588709831237793 -0.12605203688144684 0.0 +-0.5575689673423767 0.5888863801956177 -0.1275474727153778 0.0 +-0.5716317296028137 0.5890671610832214 -0.1290985345840454 0.0 +-0.586043119430542 0.5892525315284729 -0.130707785487175 0.0 +-0.6008205413818359 0.5894425511360168 -0.13237792253494263 0.0 +-0.6159828305244446 0.5896375775337219 -0.13411180675029755 0.0 +-0.6315500140190125 0.5898378491401672 -0.13591252267360687 0.0 +-0.6475434899330139 0.5900437235832214 -0.13778336346149445 0.0 +-0.6639858484268188 0.5902552604675293 -0.13972781598567963 0.0 +-0.6809014081954956 0.5904728174209595 -0.14174962043762207 0.0 +-0.6983163356781006 0.5906968116760254 -0.1438528448343277 0.0 +-0.7162584662437439 0.5909274220466614 -0.14604179561138153 0.0 +-0.7347581386566162 0.5911654233932495 -0.14832116663455963 0.0 +-0.7589776515960693 0.5954358577728271 -0.1517215073108673 0.0 +-0.7862452268600464 0.6013663411140442 -0.15568313002586365 0.0 +-0.814979612827301 0.6076160073280334 -0.15988202393054962 0.0 +-0.8453113436698914 0.6142129898071289 -0.16433915495872498 0.0 +-0.8773879408836365 0.621189534664154 -0.16907821595668793 0.0 +-0.9113747477531433 0.6285815238952637 -0.1741258054971695 0.0 +-0.9474589228630066 0.6364297270774841 -0.17951199412345886 0.0 +-0.9858523011207581 0.6447799801826477 -0.18527084589004517 0.0 +-1.0267971754074097 0.6536852121353149 -0.19144132733345032 0.0 +-1.070570468902588 0.6632056832313538 -0.19806796312332153 0.0 +-1.1174901723861694 0.6734105944633484 -0.20520195364952087 0.0 +-1.1893832683563232 0.6969544291496277 -0.21681420505046844 0.0 +1.2183351516723633 -0.052437443286180496 -0.14869190752506256 0.0 +0.24397896230220795 0.7587561011314392 -0.09718213230371475 0.0 +0.2280343472957611 0.7402664422988892 -0.09444786608219147 0.0 +0.21295996010303497 0.7227854132652283 -0.09187664836645126 0.0 +0.19868271052837372 0.7062293291091919 -0.08945497870445251 0.0 +0.18513676524162292 0.690521240234375 -0.08717050403356552 0.0 +0.1722635179758072 0.6755930781364441 -0.08501230925321579 0.0 +0.16001048684120178 0.6613841652870178 -0.08297061920166016 0.0 +0.14833056926727295 0.6478400826454163 -0.08103670179843903 0.0 +0.13718102872371674 0.6349108219146729 -0.07920253276824951 0.0 +0.12652352452278137 0.6225523948669434 -0.07746104151010513 0.0 +0.11632287502288818 0.6107228398323059 -0.07580553740262985 0.0 +0.10654786974191666 0.5993877649307251 -0.07423043251037598 0.0 +0.09716934710741043 0.5885120630264282 -0.072730153799057 0.0 +0.0885433703660965 0.5805723667144775 -0.07160905748605728 0.0 +0.0812688022851944 0.5806660652160645 -0.0714920163154602 0.0 +0.07401687651872635 0.5807594656944275 -0.07138612121343613 0.0 +0.0667852982878685 0.5808525085449219 -0.07129127532243729 0.0 +0.05957183614373207 0.5809453725814819 -0.0712074339389801 0.0 +0.052374206483364105 0.5810377597808838 -0.07113449275493622 0.0 +0.045190248638391495 0.58113032579422 -0.07107245922088623 0.0 +0.038017719984054565 0.5812225341796875 -0.07102123647928238 0.0 +0.030854452401399612 0.5813148617744446 -0.07098081707954407 0.0 +0.023698246106505394 0.5814069509506226 -0.07095114141702652 0.0 +0.016546938568353653 0.581498920917511 -0.07093217968940735 0.0 +0.009398377500474453 0.5815910696983337 -0.07092398405075073 0.0 +0.0022503884974867105 0.5816830992698669 -0.0709264799952507 0.0 +-0.004899181425571442 0.5817750096321106 -0.07093966752290726 0.0 +-0.01205249410122633 0.5818670988082886 -0.07096359133720398 0.0 +-0.019211718812584877 0.5819593071937561 -0.07099827378988266 0.0 +-0.026379022747278214 0.5820515155792236 -0.0710437148809433 0.0 +-0.03355658799409866 0.5821437835693359 -0.07109995186328888 0.0 +-0.040746625512838364 0.5822364687919617 -0.07116705179214478 0.0 +-0.047951314598321915 0.5823290348052979 -0.07124502211809158 0.0 +-0.05517292767763138 0.582422137260437 -0.07133398205041885 0.0 +-0.06241368502378464 0.5825153589248657 -0.07143396139144897 0.0 +-0.06967584788799286 0.5826087594032288 -0.07154502719640732 0.0 +-0.07696173340082169 0.5827024579048157 -0.07166727632284164 0.0 +-0.08427367359399796 0.582796573638916 -0.07180081307888031 0.0 +-0.0916140154004097 0.5828909873962402 -0.07194572687149048 0.0 +-0.0989852100610733 0.582986056804657 -0.07210217416286469 0.0 +-0.10638957470655441 0.5830811858177185 -0.07227019220590591 0.0 +-0.11382970213890076 0.5831769108772278 -0.07244998961687088 0.0 +-0.1213080957531929 0.5832732915878296 -0.07264170050621033 0.0 +-0.1288272887468338 0.5833701491355896 -0.0728454440832138 0.0 +-0.13638988137245178 0.5834673047065735 -0.07306137681007385 0.0 +-0.1439986675977707 0.583565354347229 -0.07328972965478897 0.0 +-0.15165627002716064 0.5836638808250427 -0.07353062927722931 0.0 +-0.15936557948589325 0.5837631225585938 -0.07378431409597397 0.0 +-0.16712939739227295 0.5838629007339478 -0.07405096292495728 0.0 +-0.1749507486820221 0.5839635729789734 -0.07433082163333893 0.0 +-0.1828327178955078 0.5840651988983154 -0.07462414354085922 0.0 +-0.1907782256603241 0.5841674208641052 -0.07493111491203308 0.0 +-0.19879063963890076 0.5842705368995667 -0.07525204867124557 0.0 +-0.20687320828437805 0.5843745470046997 -0.0755872130393982 0.0 +-0.2150292843580246 0.5844793915748596 -0.07593686878681183 0.0 +-0.2232624739408493 0.584585428237915 -0.07630138099193573 0.0 +-0.23157638311386108 0.5846925377845764 -0.07668105512857437 0.0 +-0.23997458815574646 0.5848004221916199 -0.07707618176937103 0.0 +-0.24846124649047852 0.5849098563194275 -0.07748721539974213 0.0 +-0.2570401132106781 0.5850202441215515 -0.07791446894407272 0.0 +-0.26571547985076904 0.5851319432258606 -0.07835835963487625 0.0 +-0.27449148893356323 0.5852447748184204 -0.07881929725408554 0.0 +-0.28337275981903076 0.5853590369224548 -0.079297736287117 0.0 +-0.2923639118671417 0.5854747891426086 -0.07979416102170944 0.0 +-0.30146974325180054 0.5855920314788818 -0.08030904829502106 0.0 +-0.31069517135620117 0.5857107043266296 -0.08084289729595184 0.0 +-0.3200455904006958 0.5858311057090759 -0.08139628171920776 0.0 +-0.32952627539634705 0.5859531164169312 -0.08196975290775299 0.0 +-0.33914297819137573 0.5860768556594849 -0.08256391435861588 0.0 +-0.3489016592502594 0.5862025618553162 -0.08317942172288895 0.0 +-0.35880836844444275 0.5863300561904907 -0.08381692320108414 0.0 +-0.3688696622848511 0.5864595770835876 -0.08447712659835815 0.0 +-0.3790922164916992 0.5865910649299622 -0.0851607695221901 0.0 +-0.38948315382003784 0.5867247581481934 -0.08586864173412323 0.0 +-0.4000500738620758 0.5868609547615051 -0.08660160005092621 0.0 +-0.4108003079891205 0.5869991183280945 -0.0873604416847229 0.0 +-0.42174243927001953 0.5871400237083435 -0.0881461650133133 0.0 +-0.43288493156433105 0.5872835516929626 -0.0889597162604332 0.0 +-0.4442366659641266 0.5874296426773071 -0.0898020938038826 0.0 +-0.45580723881721497 0.5875785946846008 -0.09067440032958984 0.0 +-0.46760645508766174 0.5877302885055542 -0.09157776832580566 0.0 +-0.4796451926231384 0.5878853797912598 -0.09251347184181213 0.0 +-0.4919341802597046 0.5880434513092041 -0.09348272532224655 0.0 +-0.5044854879379272 0.588205099105835 -0.09448695927858353 0.0 +-0.5173112750053406 0.5883702039718628 -0.09552757441997528 0.0 +-0.5304246544837952 0.5885390043258667 -0.09660610556602478 0.0 +-0.5438395142555237 0.5887115001678467 -0.09772418439388275 0.0 +-0.5575708746910095 0.58888840675354 -0.09888360649347305 0.0 +-0.57163405418396 0.5890694856643677 -0.10008614510297775 0.0 +-0.586045503616333 0.5892548561096191 -0.10133375972509384 0.0 +-0.6008232831954956 0.5894452333450317 -0.10262861102819443 0.0 +-0.6159855127334595 0.5896401405334473 -0.10397281497716904 0.0 +-0.631553053855896 0.5898406505584717 -0.10536890476942062 0.0 +-0.6475464701652527 0.5900464057922363 -0.10681929439306259 0.0 +-0.6639890074729919 0.5902580618858337 -0.10832679271697998 0.0 +-0.680904746055603 0.5904756784439087 -0.10989425331354141 0.0 +-0.6983202695846558 0.590700089931488 -0.11152490228414536 0.0 +-0.716262936592102 0.5909311175346375 -0.11322199553251266 0.0 +-0.7347627878189087 0.5911691784858704 -0.11498913913965225 0.0 +-0.7589854001998901 0.5954418778419495 -0.11762577295303345 0.0 +-0.7862538695335388 0.601373016834259 -0.12069722265005112 0.0 +-0.814988911151886 0.6076229810714722 -0.12395257502794266 0.0 +-0.8453214168548584 0.6142202615737915 -0.12740813195705414 0.0 +-0.8773992657661438 0.621197521686554 -0.13108234107494354 0.0 +-0.9113868474960327 0.6285898685455322 -0.13499566912651062 0.0 +-0.9474725127220154 0.6364388465881348 -0.13917161524295807 0.0 +-0.9858676195144653 0.64478999376297 -0.14363647997379303 0.0 +-1.0268142223358154 0.6536960601806641 -0.14842048287391663 0.0 +-1.0705891847610474 0.6632173657417297 -0.15355812013149261 0.0 +-1.1175105571746826 0.6734228134155273 -0.15908905863761902 0.0 +-1.189439058303833 0.6969871520996094 -0.1680966466665268 0.0 +-1.318461298942566 0.7509788870811462 -0.18501226603984833 0.0 +1.219041347503662 -0.007490876596421003 -0.1059175580739975 0.0 +1.2171144485473633 0.0074790362268686295 -0.10575014352798462 0.0 +1.2206679582595825 0.022504881024360657 -0.10607490688562393 0.0 +0.24397911131381989 0.7587565779685974 -0.06924834102392197 0.0 +0.22803427278995514 0.7402662038803101 -0.06729993969202042 0.0 +0.21296021342277527 0.7227863073348999 -0.06546789407730103 0.0 +0.19868290424346924 0.7062300443649292 -0.06374228000640869 0.0 +0.18513672053813934 0.6905210614204407 -0.062114376574754715 0.0 +0.17226360738277435 0.6755934953689575 -0.06057657673954964 0.0 +0.16001057624816895 0.6613845229148865 -0.0591217465698719 0.0 +0.14833059906959534 0.6478402018547058 -0.05774368718266487 0.0 +0.13718105852603912 0.6349109411239624 -0.056436728686094284 0.0 +0.12652340531349182 0.6225518584251404 -0.05519574508070946 0.0 +0.11632301658391953 0.6107235550880432 -0.05401621386408806 0.0 +0.10654788464307785 0.5993878841400146 -0.05289379879832268 0.0 +0.09716944396495819 0.588512659072876 -0.05182480067014694 0.0 +0.08854334056377411 0.5805721879005432 -0.0510258749127388 0.0 +0.08126875013113022 0.5806657075881958 -0.05094246193766594 0.0 +0.07401682436466217 0.5807590484619141 -0.050867002457380295 0.0 +0.06678525358438492 0.5808520913124084 -0.0507994182407856 0.0 +0.05957179516553879 0.5809449553489685 -0.050739679485559464 0.0 +0.05237418785691261 0.5810375213623047 -0.05068771913647652 0.0 +0.0451902337372303 0.5811300873756409 -0.05064351484179497 0.0 +0.03801770880818367 0.5812223553657532 -0.050607018172740936 0.0 +0.03085443750023842 0.5813146233558655 -0.05057821050286293 0.0 +0.0236982349306345 0.5814067125320435 -0.05055706202983856 0.0 +0.016546931117773056 0.5814986228942871 -0.05054355785250664 0.0 +0.00939837098121643 0.5815907120704651 -0.050537701696157455 0.0 +0.002250386867672205 0.5816826820373535 -0.05053947865962982 0.0 +-0.004899178631603718 0.5817746520042419 -0.05054888129234314 0.0 +-0.012052489444613457 0.5818668007850647 -0.0505659393966198 0.0 +-0.019211700186133385 0.5819587111473083 -0.050590626895427704 0.0 +-0.02637900970876217 0.5820512175559998 -0.05062302574515343 0.0 +-0.03355657681822777 0.5821436047554016 -0.05066310614347458 0.0 +-0.04074658825993538 0.5822359323501587 -0.05071089416742325 0.0 +-0.04795129597187042 0.5823287963867188 -0.0507664754986763 0.0 +-0.05517289415001869 0.5824217796325684 -0.05082985758781433 0.0 +-0.06241362914443016 0.5825148820877075 -0.05090108513832092 0.0 +-0.06967578828334808 0.5826082825660706 -0.05098022520542145 0.0 +-0.07696168124675751 0.5827020406723022 -0.05106734111905098 0.0 +-0.08427361398935318 0.5827961564064026 -0.05116249620914459 0.0 +-0.09161398559808731 0.5828908085823059 -0.05126577615737915 0.0 +-0.09898513555526733 0.5829856395721436 -0.05137723684310913 0.0 +-0.10638953000307083 0.5830808877944946 -0.051496975123882294 0.0 +-0.11382965743541718 0.5831766724586487 -0.0516250915825367 0.0 +-0.12130800634622574 0.5832728743553162 -0.0517616793513298 0.0 +-0.12882716953754425 0.5833696126937866 -0.051906850188970566 0.0 +-0.136389821767807 0.5834670066833496 -0.05206073820590973 0.0 +-0.14399856328964233 0.5835649371147156 -0.05222344025969505 0.0 +-0.1516561508178711 0.5836634039878845 -0.05239509418606758 0.0 +-0.1593654304742813 0.5837625861167908 -0.05257585272192955 0.0 +-0.16712933778762817 0.5838627219200134 -0.05276588350534439 0.0 +-0.17495065927505493 0.5839632749557495 -0.05296529084444046 0.0 +-0.1828325390815735 0.5840646624565125 -0.05317428335547447 0.0 +-0.19077809154987335 0.584166944026947 -0.05339302867650986 0.0 +-0.19879046082496643 0.5842700004577637 -0.05362170562148094 0.0 +-0.20687304437160492 0.5843740701675415 -0.05386053025722504 0.0 +-0.21502913534641266 0.584479033946991 -0.05410969257354736 0.0 +-0.22326229512691498 0.5845849514007568 -0.054369423538446426 0.0 +-0.23157623410224915 0.5846921801567078 -0.05463997274637222 0.0 +-0.2399744838476181 0.5848001837730408 -0.05492153763771057 0.0 +-0.2484610229730606 0.5849093198776245 -0.055214401334524155 0.0 +-0.2570399045944214 0.5850197672843933 -0.055518846958875656 0.0 +-0.26571524143218994 0.5851314067840576 -0.055835142731666565 0.0 +-0.2744913399219513 0.5852444767951965 -0.05616360530257225 0.0 +-0.2833726406097412 0.5853587985038757 -0.05650453642010689 0.0 +-0.2923637628555298 0.5854745507240295 -0.05685826390981674 0.0 +-0.30146947503089905 0.5855915546417236 -0.05722513049840927 0.0 +-0.31069502234458923 0.5857104063034058 -0.057605545967817307 0.0 +-0.3200454115867615 0.585830807685852 -0.0579998679459095 0.0 +-0.32952600717544556 0.585952639579773 -0.05840848386287689 0.0 +-0.3391427993774414 0.586076557636261 -0.05883187800645828 0.0 +-0.3489013612270355 0.586202085018158 -0.059270452708005905 0.0 +-0.35880815982818604 0.5863296985626221 -0.05972471833229065 0.0 +-0.3688693046569824 0.5864589810371399 -0.060195133090019226 0.0 +-0.37909191846847534 0.5865906476974487 -0.060682281851768494 0.0 +-0.3894830048084259 0.5867245197296143 -0.06118670850992203 0.0 +-0.4000498056411743 0.5868605375289917 -0.0617089718580246 0.0 +-0.4108000099658966 0.586998701095581 -0.06224969029426575 0.0 +-0.42174217104911804 0.5871396064758301 -0.06280956417322159 0.0 +-0.4328845739364624 0.5872830748558044 -0.06338925659656525 0.0 +-0.4442363679409027 0.5874292254447937 -0.06398951262235641 0.0 +-0.45580679178237915 0.5875779986381531 -0.06461107730865479 0.0 +-0.46760621666908264 0.5877299904823303 -0.065254807472229 0.0 +-0.4796448051929474 0.5878849029541016 -0.06592153757810593 0.0 +-0.49193382263183594 0.5880430340766907 -0.06661219149827957 0.0 +-0.504485011100769 0.588204562664032 -0.06732775270938873 0.0 +-0.5173107385635376 0.588369607925415 -0.06806925684213638 0.0 +-0.5304242968559265 0.5885385870933533 -0.06883779913187027 0.0 +-0.5438390970230103 0.5887110233306885 -0.06963448971509933 0.0 +-0.5575703382492065 0.5888878107070923 -0.07046063244342804 0.0 +-0.5716334581375122 0.5890688896179199 -0.07131751626729965 0.0 +-0.5860449075698853 0.5892543196678162 -0.0722065195441246 0.0 +-0.6008227467536926 0.5894446969032288 -0.07312918454408646 0.0 +-0.615985095500946 0.5896397829055786 -0.07408703863620758 0.0 +-0.6315523386001587 0.5898400545120239 -0.07508180290460587 0.0 +-0.6475458741188049 0.5900458693504333 -0.07611530274152756 0.0 +-0.6639885306358337 0.5902576446533203 -0.07718950510025024 0.0 +-0.6809041500091553 0.5904752016067505 -0.0783063992857933 0.0 +-0.6983194351196289 0.5906994342803955 -0.07946831732988358 0.0 +-0.7162619829177856 0.5909303426742554 -0.0806775838136673 0.0 +-0.7347620129585266 0.5911685228347778 -0.0819368064403534 0.0 +-0.7589844465255737 0.5954411625862122 -0.0838155597448349 0.0 +-0.786252498626709 0.6013719439506531 -0.0860041081905365 0.0 +-0.8149877786636353 0.6076221466064453 -0.08832377940416336 0.0 +-0.8453201651573181 0.6142193675041199 -0.09078606218099594 0.0 +-0.877397358417511 0.6211961507797241 -0.09340409934520721 0.0 +-0.9113855361938477 0.6285889744758606 -0.09619265049695969 0.0 +-0.9474706053733826 0.6364375948905945 -0.09916820377111435 0.0 +-0.9858652949333191 0.6447884440422058 -0.1023496612906456 0.0 +-1.0268117189407349 0.6536944508552551 -0.10575854033231735 0.0 +-1.0705865621566772 0.663215696811676 -0.10941941291093826 0.0 +-1.117507815361023 0.6734212040901184 -0.11336053907871246 0.0 +-1.1894320249557495 0.6969830393791199 -0.1197785809636116 0.0 +-1.3184524774551392 0.7509738802909851 -0.1318318396806717 0.0 +-3.8961386680603027 -0.39056235551834106 -0.2037983238697052 0.0 +-3.8967628479003906 -0.43905800580978394 -0.20409780740737915 0.0 +-3.897388458251953 -0.48770374059677124 -0.20442909002304077 0.0 +-3.898016929626465 -0.5365151166915894 -0.20479245483875275 0.0 +-3.8986477851867676 -0.5855077505111694 -0.20518817007541656 0.0 +-3.899280071258545 -0.6346973180770874 -0.20561645925045013 0.0 +-3.899916887283325 -0.6841004490852356 -0.20607782900333405 0.0 +-3.900554895401001 -0.7337329983711243 -0.20657247304916382 0.0 +-3.9011974334716797 -0.7836121916770935 -0.20710089802742004 0.0 +-3.9018425941467285 -0.8337546586990356 -0.20766344666481018 0.0 +-3.902491331100464 -0.8841779232025146 -0.20826059579849243 0.0 +-3.903144121170044 -0.9348997473716736 -0.2088928371667862 0.0 +-3.9038007259368896 -0.9859381318092346 -0.20956066250801086 0.0 +-3.9044618606567383 -1.0373116731643677 -0.2102646380662918 0.0 +-3.905128002166748 -1.0890395641326904 -0.21100537478923798 0.0 +-3.9057986736297607 -1.1411410570144653 -0.21178342401981354 0.0 +-3.9064741134643555 -1.1936359405517578 -0.21259944140911102 0.0 +-3.9071550369262695 -1.2465451955795288 -0.21345415711402893 0.0 +-3.907841205596924 -1.2998894453048706 -0.21434825658798218 0.0 +-3.9085335731506348 -1.3536906242370605 -0.21528252959251404 0.0 +-3.9092323780059814 -1.4079713821411133 -0.21625781059265137 0.0 +-3.9099373817443848 -1.462754249572754 -0.21727491915225983 0.0 +-3.910649299621582 -1.5180634260177612 -0.21833477914333344 0.0 +-3.911367893218994 -1.573923110961914 -0.2194383144378662 0.0 +-3.9120943546295166 -1.6303589344024658 -0.22058656811714172 0.0 +-3.912828207015991 -1.6873972415924072 -0.22178055346012115 0.0 +-3.9135706424713135 -1.7450653314590454 -0.22302143275737762 0.0 +-3.9143214225769043 -1.8033909797668457 -0.22431033849716187 0.0 +-3.9150803089141846 -1.8624035120010376 -0.22564846277236938 0.0 +-3.9158496856689453 -1.9221338033676147 -0.2270372062921524 0.0 +-3.916627883911133 -1.98261296749115 -0.2284778505563736 0.0 +-3.9174160957336426 -2.0438735485076904 -0.22997182607650757 0.0 +-3.918215036392212 -2.105950355529785 -0.23152068257331848 0.0 +-3.919025182723999 -2.1688785552978516 -0.23312601447105408 0.0 +-3.9198460578918457 -2.2326948642730713 -0.2347894161939621 0.0 +-0.4775119125843048 -3.9928128719329834 -0.20929446816444397 0.0 +-0.3783605694770813 -3.9940884113311768 -0.20881065726280212 0.0 +-0.3289417028427124 -3.994724988937378 -0.20861682295799255 0.0 +-0.27960705757141113 -3.995359420776367 -0.20845475792884827 0.0 +-0.23034155368804932 -3.9959936141967773 -0.2083244025707245 0.0 +-0.18113020062446594 -3.996626615524292 -0.20822562277317047 0.0 +-0.13195806741714478 -3.9972596168518066 -0.20815838873386383 0.0 +-0.08281027525663376 -3.997892141342163 -0.2081226110458374 0.0 +-0.03367194905877113 -3.9985246658325195 -0.20811827480793 0.0 +0.015471750870347023 -3.999156951904297 -0.2081453651189804 0.0 +0.06463567912578583 -3.9997899532318115 -0.20820392668247223 0.0 +0.11383470892906189 -4.000422954559326 -0.20829397439956665 0.0 +0.1630837470293045 -4.001056671142578 -0.20841559767723083 0.0 +0.21239779889583588 -4.0016913414001465 -0.20856888592243195 0.0 +0.2617918848991394 -4.002326965332031 -0.20875394344329834 0.0 +0.3112812042236328 -4.002964019775391 -0.20897091925144196 0.0 +0.3608810603618622 -4.003602504730225 -0.2092200070619583 0.0 +0.4106067419052124 -4.004242420196533 -0.20950134098529816 0.0 +0.460473895072937 -4.004884243011475 -0.20981517434120178 0.0 +0.5104982256889343 -4.005527973175049 -0.2101617157459259 0.0 +0.5606957077980042 -4.006174087524414 -0.21054129302501678 0.0 +0.6110824346542358 -4.00682258605957 -0.21095412969589233 0.0 +0.6616747975349426 -4.007473468780518 -0.2114005833864212 0.0 +0.7124894857406616 -4.008127689361572 -0.21188101172447205 0.0 +0.7635433077812195 -4.008784294128418 -0.21239575743675232 0.0 +0.8148537278175354 -4.0094451904296875 -0.21294529736042023 0.0 +0.866438090801239 -4.0101094245910645 -0.21353000402450562 0.0 +0.9183142781257629 -4.010776519775391 -0.2141503393650055 0.0 +0.9705007672309875 -4.011448383331299 -0.21480685472488403 0.0 +1.023016095161438 -4.012124061584473 -0.21550002694129944 0.0 +1.0758793354034424 -4.01280403137207 -0.21623045206069946 0.0 +1.1291104555130005 -4.013489246368408 -0.21699874103069305 0.0 +1.1827292442321777 -4.014179229736328 -0.21780553460121155 0.0 +1.236756443977356 -4.0148749351501465 -0.21865150332450867 0.0 +1.2912131547927856 -4.015575408935547 -0.21953731775283813 0.0 +1.3461214303970337 -4.016282558441162 -0.2204638123512268 0.0 +1.4015034437179565 -4.016995429992676 -0.22143174707889557 0.0 +1.4573819637298584 -4.017714023590088 -0.2224419116973877 0.0 +1.5137816667556763 -4.018439769744873 -0.2234952747821808 0.0 +1.5707266330718994 -4.019172668457031 -0.22459276020526886 0.0 +1.6282423734664917 -4.019913196563721 -0.22573533654212952 0.0 +1.6863549947738647 -4.020660877227783 -0.22692401707172394 0.0 +1.7450917959213257 -4.021416664123535 -0.22815994918346405 0.0 +1.804481029510498 -4.022181034088135 -0.2294442504644394 0.0 +1.8645519018173218 -4.02295446395874 -0.23077815771102905 0.0 +1.9253344535827637 -4.023736953735352 -0.2321629375219345 0.0 +1.9868600368499756 -4.024528503417969 -0.23359991610050201 0.0 +3.487550973892212 -0.36564698815345764 -0.18251119554042816 0.0 +3.488107442855835 -0.3224201500415802 -0.18231916427612305 0.0 +3.1899988651275635 -0.25536876916885376 -0.16656075417995453 0.0 +3.1490776538848877 -0.21318022906780243 -0.1642749309539795 0.0 +3.1092581748962402 -0.1721278429031372 -0.16207510232925415 0.0 +3.070485830307007 -0.1321544647216797 -0.15995727479457855 0.0 +3.0327084064483643 -0.0932064801454544 -0.15791766345500946 0.0 +2.9958763122558594 -0.05523356422781944 -0.15595263242721558 0.0 +2.983647584915161 -0.018334191292524338 -0.1552926003932953 0.0 +2.9844863414764404 0.01833934523165226 -0.15533626079559326 0.0 +2.985325574874878 0.055039048194885254 -0.15540340542793274 0.0 +2.98616623878479 0.0917760580778122 -0.15549413859844208 0.0 +2.9870071411132812 0.12856152653694153 -0.15560846030712128 0.0 +2.9878499507904053 0.1654067039489746 -0.15574650466442108 0.0 +2.988694190979004 0.20232288539409637 -0.15590834617614746 0.0 +2.9895405769348145 0.2393215000629425 -0.15609414875507355 0.0 +2.990388870239258 0.2764139771461487 -0.1563040167093277 0.0 +2.991239309310913 0.3136119246482849 -0.15653811395168304 0.0 +2.992093563079834 0.3509272336959839 -0.1567966789007187 0.0 +2.9929494857788086 0.3883715271949768 -0.1570798009634018 0.0 +2.993809223175049 0.4259570837020874 -0.15738779306411743 0.0 +2.9946720600128174 0.4636959731578827 -0.15772084891796112 0.0 +2.9955391883850098 0.5016006827354431 -0.15807925164699554 0.0 +2.9964098930358887 0.5396837592124939 -0.1584632694721222 0.0 +2.9972856044769287 0.5779582262039185 -0.15887321531772614 0.0 +2.9981658458709717 0.6164370775222778 -0.15930944681167603 0.0 +2.9990508556365967 0.6551335453987122 -0.15977223217487335 0.0 +2.999941110610962 0.6940614581108093 -0.16026198863983154 0.0 +3.0008368492126465 0.7332346439361572 -0.16077911853790283 0.0 +3.0017385482788086 0.772667407989502 -0.16132403910160065 0.0 +3.0026466846466064 0.812374472618103 -0.161897212266922 0.0 +3.003561496734619 0.8523707389831543 -0.1624990999698639 0.0 +3.004483461380005 0.8926717042922974 -0.16313022375106812 0.0 +3.0054128170013428 0.9332931637763977 -0.16379110515117645 0.0 +3.0063493251800537 0.9742510318756104 -0.16448228061199188 0.0 +3.007293939590454 1.0155622959136963 -0.16520436108112335 0.0 +3.0082473754882812 1.0572444200515747 -0.16595801711082458 0.0 +3.009209394454956 1.09931480884552 -0.16674385964870453 0.0 +3.010181188583374 1.1417921781539917 -0.16756263375282288 0.0 +3.011162519454956 1.1846951246261597 -0.16841503977775574 0.0 +3.0121536254882812 1.2280433177947998 -0.169301837682724 0.0 +3.013155698776245 1.2718571424484253 -0.1702238917350769 0.0 +3.039585828781128 1.3272560834884644 -0.17262552678585052 0.0 +3.090146541595459 1.3947978019714355 -0.1764572262763977 0.0 +3.1430113315582275 1.4654169082641602 -0.18049079179763794 0.0 +3.198357105255127 1.539351224899292 -0.1847415715456009 0.0 +0.24398377537727356 0.7587711215019226 -0.041483115404844284 0.0 +0.22803883254528046 0.7402810454368591 -0.04031596705317497 0.0 +0.21296408772468567 0.7227994203567505 -0.03921840712428093 0.0 +0.1986866295337677 0.7062432169914246 -0.03818470239639282 0.0 +0.18514016270637512 0.6905339360237122 -0.03720950707793236 0.0 +0.17226676642894745 0.6756058931350708 -0.03628828004002571 0.0 +0.16001352667808533 0.6613966822624207 -0.03541676700115204 0.0 +0.14833307266235352 0.6478509902954102 -0.0345911830663681 0.0 +0.13718338310718536 0.6349217295646667 -0.03380826488137245 0.0 +0.12652558088302612 0.6225625276565552 -0.033064864575862885 0.0 +0.11632494628429413 0.610733687877655 -0.03235825151205063 0.0 +0.10654973983764648 0.5993982553482056 -0.03168589621782303 0.0 +0.09717098623514175 0.5885219573974609 -0.031045466661453247 0.0 +0.08854391425848007 0.5805759429931641 -0.030566588044166565 0.0 +0.0812692791223526 0.5806695222854614 -0.030516620725393295 0.0 +0.07401731610298157 0.5807629227638245 -0.030471421778202057 0.0 +0.06678569316864014 0.5808558464050293 -0.030430933460593224 0.0 +0.05957217887043953 0.5809487104415894 -0.0303951445966959 0.0 +0.05237452685832977 0.5810412764549255 -0.0303640179336071 0.0 +0.045190513134002686 0.5811336636543274 -0.030337529256939888 0.0 +0.03801793232560158 0.5812258124351501 -0.030315658077597618 0.0 +0.030854616314172745 0.5813179612159729 -0.030298396944999695 0.0 +0.023698370903730392 0.5814100503921509 -0.030285729095339775 0.0 +0.016547031700611115 0.5815021395683289 -0.030277647078037262 0.0 +0.009398425929248333 0.5815941095352173 -0.030274132266640663 0.0 +0.002250399673357606 0.5816860198974609 -0.030275192111730576 0.0 +-0.004899207502603531 0.5817780494689941 -0.03028082847595215 0.0 +-0.012052553705871105 0.5818699598312378 -0.030291033908724785 0.0 +-0.01921180821955204 0.581961989402771 -0.030305828899145126 0.0 +-0.026379145681858063 0.5820542573928833 -0.030325226485729218 0.0 +-0.033556755632162094 0.5821467041969299 -0.030349239706993103 0.0 +-0.04074681177735329 0.5822390913963318 -0.030377868562936783 0.0 +-0.04795154184103012 0.5823318362236023 -0.03041115775704384 0.0 +-0.05517318844795227 0.5824248194694519 -0.03044912964105606 0.0 +-0.062413956969976425 0.5825179219245911 -0.030491793528199196 0.0 +-0.06967616081237793 0.5826113820075989 -0.03053920716047287 0.0 +-0.07696208357810974 0.5827051401138306 -0.030591389164328575 0.0 +-0.08427403122186661 0.5827990174293518 -0.030648380517959595 0.0 +-0.09161439538002014 0.5828933715820312 -0.030710237100720406 0.0 +-0.09898560494184494 0.5829883813858032 -0.030777012929320335 0.0 +-0.10639002919197083 0.5830836296081543 -0.03084873966872692 0.0 +-0.11383016407489777 0.5831792950630188 -0.030925480648875237 0.0 +-0.12130855768918991 0.5832754969596863 -0.031007302924990654 0.0 +-0.12882773578166962 0.583372175693512 -0.03109426237642765 0.0 +-0.13639043271541595 0.5834696292877197 -0.031186452135443687 0.0 +-0.14399918913841248 0.5835674405097961 -0.0312839113175869 0.0 +-0.15165682137012482 0.5836659669876099 -0.03138674423098564 0.0 +-0.15936611592769623 0.5837650895118713 -0.03149501979351044 0.0 +-0.16712996363639832 0.5838648676872253 -0.031608838587999344 0.0 +-0.17495138943195343 0.5839656591415405 -0.03172830492258072 0.0 +-0.18283326923847198 0.5840669870376587 -0.03185348957777023 0.0 +-0.19077885150909424 0.5841692686080933 -0.03198453038930893 0.0 +-0.1987912505865097 0.5842723250389099 -0.03212151303887367 0.0 +-0.2068737894296646 0.5843762159347534 -0.03226456791162491 0.0 +-0.2150299847126007 0.5844812989234924 -0.03241383656859398 0.0 +-0.22326311469078064 0.5845870971679688 -0.032569415867328644 0.0 +-0.23157697916030884 0.5846940279006958 -0.032731473445892334 0.0 +-0.23997530341148376 0.5848021507263184 -0.03290014714002609 0.0 +-0.24846188724040985 0.5849113464355469 -0.03307558596134186 0.0 +-0.25704076886177063 0.5850217342376709 -0.03325795754790306 0.0 +-0.2657160460948944 0.5851331949234009 -0.03344741836190224 0.0 +-0.2744920551776886 0.5852459669113159 -0.033644165843725204 0.0 +-0.2833734452724457 0.5853604078292847 -0.03384840488433838 0.0 +-0.29236456751823425 0.5854761004447937 -0.03406029939651489 0.0 +-0.3014702796936035 0.5855931043624878 -0.03428006172180176 0.0 +-0.31069570779800415 0.5857117176055908 -0.034507934004068375 0.0 +-0.3200460970401764 0.5858320593833923 -0.03474414721131325 0.0 +-0.32952678203582764 0.5859540104866028 -0.034988924860954285 0.0 +-0.33914342522621155 0.5860776901245117 -0.03524254262447357 0.0 +-0.3489021062850952 0.5862033367156982 -0.0355052724480629 0.0 +-0.35880881547927856 0.586330771446228 -0.03577738627791405 0.0 +-0.3688700795173645 0.5864602327346802 -0.036059193313121796 0.0 +-0.37909263372421265 0.5865917205810547 -0.036351002752780914 0.0 +-0.38948357105255127 0.5867254137992859 -0.03665315732359886 0.0 +-0.4000503122806549 0.5868613123893738 -0.03696600720286369 0.0 +-0.410800576210022 0.5869995355606079 -0.03728992119431496 0.0 +-0.42174258828163147 0.5871402025222778 -0.03762529790401459 0.0 +-0.4328851103782654 0.5872837901115417 -0.03797256201505661 0.0 +-0.44423672556877136 0.5874297022819519 -0.03833211958408356 0.0 +-0.4558071494102478 0.5875784754753113 -0.03870445862412453 0.0 +-0.46760648488998413 0.587730348110199 -0.03909007087349892 0.0 +-0.47964513301849365 0.587885320186615 -0.039489470422267914 0.0 +-0.49193403124809265 0.5880432724952698 -0.0399031899869442 0.0 +-0.5044850707054138 0.5882046222686768 -0.040331825613975525 0.0 +-0.5173108577728271 0.5883697271347046 -0.04077601060271263 0.0 +-0.5304240584373474 0.5885382890701294 -0.04123637080192566 0.0 +-0.5438389182090759 0.5887108445167542 -0.04171362519264221 0.0 +-0.5575700402259827 0.5888875722885132 -0.042208511382341385 0.0 +-0.5716331601142883 0.589068591594696 -0.042721811681985855 0.0 +-0.5860444903373718 0.5892539024353027 -0.04325434938073158 0.0 +-0.6008219718933105 0.5894439220428467 -0.04380703717470169 0.0 +-0.6159842610359192 0.5896389484405518 -0.04438081756234169 0.0 +-0.6315515637397766 0.5898392796516418 -0.04497672617435455 0.0 +-0.6475450396537781 0.5900450944900513 -0.04559582844376564 0.0 +-0.6639873385429382 0.5902565717697144 -0.04623928666114807 0.0 +-0.6809030175209045 0.5904741883277893 -0.046908359974622726 0.0 +-0.6983180046081543 0.5906981825828552 -0.04760436341166496 0.0 +-0.7162603735923767 0.5909289717674255 -0.04832875356078148 0.0 +-0.7347601056098938 0.5911670327186584 -0.049083054065704346 0.0 +-0.7589795589447021 0.5954373478889465 -0.050208304077386856 0.0 +-0.786247730255127 0.6013683080673218 -0.05151933804154396 0.0 +-0.8149817585945129 0.6076176166534424 -0.052908822894096375 0.0 +-0.845314085483551 0.6142149567604065 -0.05438382178544998 0.0 +-0.877390444278717 0.6211912631988525 -0.055952075868844986 0.0 +-0.9113772511482239 0.6285832524299622 -0.05762244015932083 0.0 +-0.9474614858627319 0.6364314556121826 -0.059404853731393814 0.0 +-0.9858554601669312 0.6447820067405701 -0.061310626566410065 0.0 +-1.0268009901046753 0.6536877155303955 -0.06335262954235077 0.0 +-1.0705742835998535 0.6632080674171448 -0.06554552912712097 0.0 +-1.1174941062927246 0.6734129190444946 -0.06790633499622345 0.0 +-1.1893916130065918 0.696959376335144 -0.07174937427043915 0.0 +-1.3183989524841309 0.7509434223175049 -0.07896894961595535 0.0 +-3.8636045455932617 2.13820743560791 -0.22982926666736603 0.0 +-3.864391565322876 2.077021360397339 -0.22834034264087677 0.0 +-3.865168333053589 2.016613721847534 -0.22690461575984955 0.0 +-3.865935802459717 1.9569523334503174 -0.22552070021629333 0.0 +-3.8666937351226807 1.8980052471160889 -0.2241872102022171 0.0 +-3.867443799972534 1.8397427797317505 -0.22290289402008057 0.0 +-3.868185043334961 1.782135248184204 -0.22166648507118225 0.0 +-3.8689181804656982 1.7251546382904053 -0.22047683596611023 0.0 +-3.8696436882019043 1.6687740087509155 -0.21933284401893616 0.0 +-3.870361089706421 1.612966775894165 -0.2182334065437317 0.0 +-3.871072292327881 1.5577082633972168 -0.217177614569664 0.0 +-3.8717761039733887 1.5029733180999756 -0.2161644548177719 0.0 +-3.872473955154419 1.448738694190979 -0.21519307792186737 0.0 +-3.8731653690338135 1.3949812650680542 -0.21426258981227875 0.0 +-3.8738515377044678 1.3416787385940552 -0.21337223052978516 0.0 +-3.8745312690734863 1.2888092994689941 -0.21252118051052094 0.0 +-3.875206470489502 1.2363522052764893 -0.21170875430107117 0.0 +-3.8758761882781982 1.1842867136001587 -0.21093423664569855 0.0 +-3.8765411376953125 1.1325929164886475 -0.21019700169563293 0.0 +-3.8778579235076904 1.0302437543869019 -0.20883196592330933 0.0 +-3.878509759902954 0.9795506596565247 -0.2082030177116394 0.0 +-3.879803419113159 0.8790375590324402 -0.20704983174800873 0.0 +-3.8911936283111572 -0.006197328679263592 -0.06745419651269913 0.0 +-3.8918089866638184 -0.054030660539865494 -0.06747128069400787 0.0 +-3.892425060272217 -0.10189545899629593 -0.0674985721707344 0.0 +-3.8930413722991943 -0.14980623126029968 -0.06753609329462051 0.0 +-3.893658399581909 -0.19777753949165344 -0.06758385896682739 0.0 +-3.8942763805389404 -0.24582400918006897 -0.06764191389083862 0.0 +-3.894895315170288 -0.2939603626728058 -0.06771031022071838 0.0 +-3.8955163955688477 -0.3422015309333801 -0.06778910011053085 0.0 +-3.9269351959228516 -3.9484405517578125 -0.09653470665216446 0.0 +-3.832749128341675 -3.9496519565582275 -0.0954054519534111 0.0 +-3.740726947784424 -3.9508352279663086 -0.09431637823581696 0.0 +-3.6507692337036133 -3.9519927501678467 -0.0932658389210701 0.0 +-3.5627801418304443 -3.953124761581421 -0.0922522097826004 0.0 +-3.476670026779175 -3.9542324542999268 -0.09127402305603027 0.0 +-3.3923544883728027 -3.955317497253418 -0.0903298631310463 0.0 +-3.309752941131592 -3.9563798904418945 -0.08941838890314102 0.0 +-3.2287893295288086 -3.957421064376831 -0.08853836357593536 0.0 +-3.1493923664093018 -3.9584426879882812 -0.0876886248588562 0.0 +-3.07149338722229 -3.9594452381134033 -0.0868680328130722 0.0 +-2.9950265884399414 -3.960428237915039 -0.08607551455497742 0.0 +-2.9199323654174805 -3.961394786834717 -0.08531012386083603 0.0 +-2.8461499214172363 -3.962343692779541 -0.08457086980342865 0.0 +-2.7736244201660156 -3.9632761478424072 -0.08385686576366425 0.0 +-2.702303171157837 -3.9641942977905273 -0.08316729217767715 0.0 +-2.632134437561035 -3.965096950531006 -0.08250132203102112 0.0 +-2.563070297241211 -3.9659852981567383 -0.08185818791389465 0.0 +-2.4950644969940186 -3.96686053276062 -0.08123718947172165 0.0 +-2.428072690963745 -3.9677224159240723 -0.080637626349926 0.0 +-2.3620519638061523 -3.968571186065674 -0.08005883544683456 0.0 +-2.2969627380371094 -3.9694080352783203 -0.0795002207159996 0.0 +-2.2327663898468018 -3.970233917236328 -0.07896120101213455 0.0 +-2.1694254875183105 -3.9710497856140137 -0.07844122499227524 0.0 +-2.106903076171875 -3.971853494644165 -0.0779397189617157 0.0 +-2.045166254043579 -3.9726479053497314 -0.07745622098445892 0.0 +-1.984181523323059 -3.9734325408935547 -0.07699023932218552 0.0 +-1.9239170551300049 -3.974207878112793 -0.07654131948947906 0.0 +-1.864342212677002 -3.9749739170074463 -0.07610902935266495 0.0 +-1.8054279088974 -3.9757320880889893 -0.07569297403097153 0.0 +-1.747145175933838 -3.9764814376831055 -0.07529273629188538 0.0 +-1.689467191696167 -3.9772236347198486 -0.07490798085927963 0.0 +-1.6323670148849487 -3.9779584407806396 -0.07453832775354385 0.0 +-1.5758191347122192 -3.9786856174468994 -0.07418345659971237 0.0 +-1.519798755645752 -3.9794065952301025 -0.07384305447340012 0.0 +-1.4642815589904785 -3.9801201820373535 -0.07351679354906082 0.0 +-1.4092447757720947 -3.9808287620544434 -0.07320443540811539 0.0 +-1.3546652793884277 -3.9815304279327393 -0.07290566712617874 0.0 +-1.3005216121673584 -3.982227325439453 -0.07262026518583298 0.0 +-1.2467918395996094 -3.9829182624816895 -0.0723479613661766 0.0 +-1.193455696105957 -3.983604669570923 -0.07208855450153351 0.0 +-1.140492558479309 -3.984286069869995 -0.07184180617332458 0.0 +-1.0878827571868896 -3.984962224960327 -0.07160750031471252 0.0 +-1.0356072187423706 -3.9856348037719727 -0.07138548791408539 0.0 +-0.9836471676826477 -3.9863035678863525 -0.07117556035518646 0.0 +-0.9319838881492615 -3.9869682788848877 -0.07097755372524261 0.0 +-0.8805995583534241 -3.9876291751861572 -0.07079129666090012 0.0 +-0.829476535320282 -3.9882872104644775 -0.07061666995286942 0.0 +-0.7785974144935608 -3.9889416694641113 -0.07045350968837738 0.0 +-0.7279451489448547 -3.9895927906036377 -0.07030168175697327 0.0 +-0.677503228187561 -3.9902420043945312 -0.07016108930110931 0.0 +-0.6272550225257874 -3.9908881187438965 -0.07003161311149597 0.0 +-0.5771844983100891 -3.991532802581787 -0.06991317123174667 0.0 +-0.5272753834724426 -3.9921746253967285 -0.06980562955141068 0.0 +-0.4775121212005615 -3.992814540863037 -0.0697089359164238 0.0 +-0.4278790354728699 -3.993452787399292 -0.06962301582098007 0.0 +-0.37836071848869324 -3.9940900802612305 -0.06954780220985413 0.0 +-0.32894179224967957 -3.9947259426116943 -0.06948322802782059 0.0 +-0.2796071171760559 -3.9953606128692627 -0.06942924857139587 0.0 +-0.23034162819385529 -3.995994806289673 -0.0693858340382576 0.0 +-0.18113026022911072 -3.9966280460357666 -0.06935293972492218 0.0 +-0.13195808231830597 -3.997260093688965 -0.06933052837848663 0.0 +-0.08281027525663376 -3.997892141342163 -0.06931859999895096 0.0 +-0.033671945333480835 -3.9985244274139404 -0.06931715458631516 0.0 +0.015471750870347023 -3.999156951904297 -0.06932617723941803 0.0 +0.06463566422462463 -3.999788999557495 -0.06934567540884018 0.0 +0.1138346791267395 -4.00042200088501 -0.0693756639957428 0.0 +0.16308368742465973 -4.0010552406311035 -0.06941616535186768 0.0 +0.2123977243900299 -4.001689910888672 -0.0694672167301178 0.0 +0.26179179549217224 -4.002325534820557 -0.06952885538339615 0.0 +0.3112810254096985 -4.0029616355896 -0.06960111111402512 0.0 +0.3608808219432831 -4.003600120544434 -0.06968406587839127 0.0 +0.4106064438819885 -4.004239559173584 -0.06977776437997818 0.0 +0.46047353744506836 -4.004881381988525 -0.06988228857517242 0.0 +0.5104978084564209 -4.0055251121521 -0.06999770551919937 0.0 +0.560695230960846 -4.006170749664307 -0.07012412697076797 0.0 +0.6110818386077881 -4.006818771362305 -0.07026161998510361 0.0 +0.6616740822792053 -4.007469654083252 -0.07041031867265701 0.0 +0.7124887108802795 -4.008123397827148 -0.07057032734155655 0.0 +0.7635424733161926 -4.008780002593994 -0.07074177265167236 0.0 +0.8148527145385742 -4.0094404220581055 -0.0709247887134552 0.0 +0.8664368987083435 -4.010103702545166 -0.071119524538517 0.0 +0.9183130860328674 -4.01077127456665 -0.07132614403963089 0.0 +0.9704993367195129 -4.0114426612854 -0.07154479622840881 0.0 +1.0230145454406738 -4.012118339538574 -0.07177566736936569 0.0 +1.0758779048919678 -4.012798309326172 -0.07201895117759705 0.0 +1.1291086673736572 -4.013483047485352 -0.0722748339176178 0.0 +1.182727336883545 -4.0141730308532715 -0.07254354655742645 0.0 +1.236754298210144 -4.014867782592773 -0.07282529026269913 0.0 +1.2912108898162842 -4.015568256378174 -0.07312033325433731 0.0 +1.3461188077926636 -4.016274929046631 -0.07342890650033951 0.0 +1.4015007019042969 -4.016987323760986 -0.0737512856721878 0.0 +1.4573792219161987 -4.017706394195557 -0.07408773899078369 0.0 +1.513778567314148 -4.018431663513184 -0.07443857192993164 0.0 +1.5707231760025024 -4.019164085388184 -0.07480408996343613 0.0 +1.628238558769226 -4.019904136657715 -0.07518463581800461 0.0 +1.68635094165802 -4.020651340484619 -0.07558053731918335 0.0 +1.7450875043869019 -4.021407127380371 -0.0759921744465828 0.0 +1.8044763803482056 -4.0221710205078125 -0.07641992717981339 0.0 +1.8645471334457397 -4.022944450378418 -0.07686420530080795 0.0 +1.9253289699554443 -4.023725509643555 -0.07732540369033813 0.0 +1.9868545532226562 -4.02451753616333 -0.07780402153730392 0.0 +2.0491554737091064 -4.025318622589111 -0.07830047607421875 0.0 +2.112266778945923 -4.0261311531066895 -0.07881530374288559 0.0 +2.176222562789917 -4.026953220367432 -0.07934898883104324 0.0 +2.241060733795166 -4.027788162231445 -0.07990212738513947 0.0 +2.306819200515747 -4.028634071350098 -0.08047526329755783 0.0 +2.373537540435791 -4.029491901397705 -0.0810689926147461 0.0 +2.441258430480957 -4.0303635597229 -0.08168400079011917 0.0 +2.5100247859954834 -4.031247615814209 -0.0823209285736084 0.0 +2.5798826217651367 -4.032146453857422 -0.08298049867153168 0.0 +2.6508800983428955 -4.033059597015381 -0.0836634635925293 0.0 +2.723067045211792 -4.033988952636719 -0.08437062054872513 0.0 +2.7964954376220703 -4.034933567047119 -0.08510278910398483 0.0 +2.8712210655212402 -4.035894870758057 -0.08586085587739944 0.0 +2.9473013877868652 -4.0368733406066895 -0.08664575219154358 0.0 +3.024796724319458 -4.037869453430176 -0.08745845407247543 0.0 +3.1037726402282715 -4.038886070251465 -0.08830002695322037 0.0 +3.184295177459717 -4.03992223739624 -0.08917154371738434 0.0 +3.266435146331787 -4.04097843170166 -0.09007416665554047 0.0 +3.350268602371216 -4.042057514190674 -0.09100916236639023 0.0 +3.435873031616211 -4.043158054351807 -0.09197778254747391 0.0 +3.5233330726623535 -4.044283390045166 -0.09298144280910492 0.0 +3.612736225128174 -4.045433044433594 -0.09402161091566086 0.0 +3.704176425933838 -4.046609401702881 -0.09509983658790588 0.0 +3.797752857208252 -4.047813892364502 -0.0962177962064743 0.0 +3.8935701847076416 -4.049046993255615 -0.0973772257566452 0.0 +3.991739273071289 -4.050309181213379 -0.09857999533414841 0.0 +4.092379570007324 -4.051604270935059 -0.09982813149690628 0.0 +4.195616722106934 -4.052932262420654 -0.10112373530864716 0.0 +4.3015851974487305 -4.054295539855957 -0.10246909409761429 0.0 +4.410427570343018 -4.055695533752441 -0.10386663675308228 0.0 +4.522296905517578 -4.057134628295898 -0.10531894117593765 0.0 +4.637357711791992 -4.058615207672119 -0.10682882368564606 0.0 +4.755782604217529 -4.06013822555542 -0.10839921236038208 0.0 +4.877760410308838 -4.061707496643066 -0.11003334075212479 0.0 +5.003490924835205 -4.063324928283691 -0.11173461377620697 0.0 +5.1331915855407715 -4.0649943351745605 -0.11350676417350769 0.0 +5.267091751098633 -4.06671667098999 -0.11535370349884033 0.0 +5.40544319152832 -4.068495750427246 -0.11727975308895111 0.0 +5.548515796661377 -4.070336818695068 -0.11928955465555191 0.0 +5.696599960327148 -4.072242259979248 -0.12138808518648148 0.0 +5.850010871887207 -4.074215412139893 -0.12358076125383377 0.0 +6.009091377258301 -4.076262474060059 -0.12587349116802216 0.0 +6.1742095947265625 -4.078385829925537 -0.12827259302139282 0.0 +6.345772743225098 -4.080593109130859 -0.13078510761260986 0.0 +6.52421760559082 -4.082888603210449 -0.13341856002807617 0.0 +6.710025310516357 -4.08527946472168 -0.13618122041225433 0.0 +6.903720378875732 -4.087770938873291 -0.1390821784734726 0.0 +7.105878829956055 -4.090372085571289 -0.14213134348392487 0.0 +7.317131042480469 -4.0930891036987305 -0.14533963799476624 0.0 +7.538176536560059 -4.095932960510254 -0.14871911704540253 0.0 +7.769781589508057 -4.098912239074707 -0.15228302776813507 0.0 +8.012797355651855 -4.102038383483887 -0.1560460925102234 0.0 +8.268166542053223 -4.105323791503906 -0.16002462804317474 0.0 +8.5225191116333 -4.101840496063232 -0.16395936906337738 0.0 +8.505647659301758 -3.9657256603240967 -0.162684828042984 0.0 +8.489034652709961 -3.831690788269043 -0.16145415604114532 0.0 +8.472668647766113 -3.6996490955352783 -0.1602659970521927 0.0 +8.456537246704102 -3.5695159435272217 -0.15911900997161865 0.0 +8.443655967712402 -3.4424455165863037 -0.15806861221790314 0.0 +8.445197105407715 -3.322631597518921 -0.15732111036777496 0.0 +8.446723937988281 -3.203927755355835 -0.15660418570041656 0.0 +8.448238372802734 -3.0862834453582764 -0.1559172421693802 0.0 +8.449738502502441 -2.969648838043213 -0.1552596092224121 0.0 +8.451226234436035 -2.8539767265319824 -0.15463076531887054 0.0 +8.452702522277832 -2.7392208576202393 -0.15403017401695251 0.0 +8.454168319702148 -2.625335454940796 -0.15345731377601624 0.0 +8.455622673034668 -2.512277126312256 -0.1529117077589035 0.0 +8.457066535949707 -2.400002956390381 -0.1523928940296173 0.0 +8.458500862121582 -2.288470983505249 -0.15190045535564423 0.0 +8.45992660522461 -2.1776411533355713 -0.15143398940563202 0.0 +8.461344718933105 -2.0674736499786377 -0.15099312365055084 0.0 +8.462753295898438 -1.9579288959503174 -0.15057748556137085 0.0 +8.5535888671875 -1.7586582899093628 -0.15137869119644165 0.0 +8.554991722106934 -1.6496353149414062 -0.15103331208229065 0.0 +3.487548828125 -0.36564674973487854 -0.060788270086050034 0.0 +3.488105058670044 -0.3224199414253235 -0.06072431057691574 0.0 +3.1899986267089844 -0.25536873936653137 -0.05547575652599335 0.0 +3.1490769386291504 -0.21318016946315765 -0.05471440777182579 0.0 +3.1092581748962402 -0.1721278429031372 -0.05398173630237579 0.0 +3.070486068725586 -0.1321544647216797 -0.053276363760232925 0.0 +3.032707929611206 -0.09320646524429321 -0.05259702727198601 0.0 +2.9958760738372803 -0.055233560502529144 -0.05194254219532013 0.0 +2.9836459159851074 -0.018334180116653442 -0.051722683012485504 0.0 +2.9844844341278076 0.018339332193136215 -0.0517372228205204 0.0 +2.985323905944824 0.05503901466727257 -0.051759589463472366 0.0 +2.9861643314361572 0.09177599847316742 -0.05178980529308319 0.0 +2.9870049953460693 0.12856143712997437 -0.05182787775993347 0.0 +2.9878480434417725 0.16540659964084625 -0.05187385901808739 0.0 +2.98869252204895 0.20232278108596802 -0.05192777141928673 0.0 +2.9895384311676025 0.23932133615016937 -0.05198964849114418 0.0 +2.990386724472046 0.27641379833221436 -0.05205954983830452 0.0 +2.9912376403808594 0.3136117458343506 -0.05213752016425133 0.0 +2.992091417312622 0.3509269952774048 -0.05222363770008087 0.0 +2.992947578430176 0.3883712887763977 -0.05231793597340584 0.0 +2.993806838989258 0.42595675587654114 -0.05242051184177399 0.0 +2.9946703910827637 0.4636957049369812 -0.05253145471215248 0.0 +2.995537042617798 0.5016003251075745 -0.0526508167386055 0.0 +2.996407985687256 0.53968346118927 -0.05277872458100319 0.0 +2.997283697128296 0.5779578685760498 -0.052915267646312714 0.0 +2.9981637001037598 0.6164366006851196 -0.05306054651737213 0.0 +2.9990487098693848 0.6551331281661987 -0.05321468785405159 0.0 +2.99993896484375 0.6940609812736511 -0.05337781459093094 0.0 +3.0008349418640137 0.733234167098999 -0.053550053387880325 0.0 +3.001736879348755 0.7726669907569885 -0.05373154953122139 0.0 +3.0026450157165527 0.8123739957809448 -0.05392245575785637 0.0 +3.0035598278045654 0.8523702621459961 -0.0541229248046875 0.0 +3.004481077194214 0.8926709890365601 -0.05433311685919762 0.0 +3.0054101943969727 0.9332923293113708 -0.054553233087062836 0.0 +3.006347179412842 0.974250316619873 -0.05478344485163689 0.0 +3.007291793823242 1.015561580657959 -0.05502394959330559 0.0 +3.0082454681396484 1.057243824005127 -0.05527497082948685 0.0 +3.009207010269165 1.0993139743804932 -0.055536698549985886 0.0 +3.010179281234741 1.1417914628982544 -0.05580941215157509 0.0 +3.011159896850586 1.1846941709518433 -0.056093305349349976 0.0 +3.0121517181396484 1.228042483329773 -0.05638867989182472 0.0 +3.013153553009033 1.2718561887741089 -0.05669578164815903 0.0 +3.0395803451538086 1.3272535800933838 -0.05749562010169029 0.0 +3.0901412963867188 1.3947954177856445 -0.05877183750271797 0.0 +3.143005132675171 1.4654141664505005 -0.0601152628660202 0.0 +3.1983518600463867 1.5393487215042114 -0.06153107061982155 0.0 +6.466650009155273 3.210831880569458 -0.12515752017498016 0.0 +6.388558864593506 3.2705328464508057 -0.12441468983888626 0.0 +6.311376571655273 3.3295376300811768 -0.12369916588068008 0.0 +6.2350664138793945 3.3878769874572754 -0.12301032245159149 0.0 +6.139826774597168 3.434523344039917 -0.12195492535829544 0.0 +6.044660568237305 3.4795007705688477 -0.12090492993593216 0.0 +5.951106071472168 3.5237174034118652 -0.11989083141088486 0.0 +5.806712627410889 3.6338706016540527 -0.11874576658010483 0.0 +5.654122829437256 3.635833978652954 -0.11653034389019012 0.0 +5.507099628448486 3.6377251148223877 -0.11441302299499512 0.0 +5.365303039550781 3.6395492553710938 -0.11238794773817062 0.0 +5.228418350219727 3.641309976577759 -0.11044969409704208 0.0 +5.096156597137451 3.643012046813965 -0.10859331488609314 0.0 +4.968246936798096 3.6446571350097656 -0.10681413859128952 0.0 +4.844443321228027 3.6462502479553223 -0.10510796308517456 0.0 +4.724514484405518 3.6477928161621094 -0.1034708023071289 0.0 +4.608246803283691 3.6492884159088135 -0.10189902037382126 0.0 +4.4954423904418945 3.650739908218384 -0.10038921982049942 0.0 +4.385915279388428 3.652148723602295 -0.0989382192492485 0.0 +4.279494285583496 3.6535184383392334 -0.09754310548305511 0.0 +4.130281448364258 3.70544171333313 -0.09618936479091644 0.0 +4.030928134918213 3.7067196369171143 -0.09492933750152588 0.0 +3.9341301918029785 3.7079648971557617 -0.09371586889028549 0.0 +3.839761734008789 3.709179162979126 -0.09254683554172516 0.0 +3.74770450592041 3.7103633880615234 -0.0914202407002449 0.0 +3.657848358154297 3.711519241333008 -0.09033422917127609 0.0 +3.5700886249542236 3.7126479148864746 -0.08928702771663666 0.0 +3.484328269958496 3.713751792907715 -0.08827703446149826 0.0 +3.4266011714935303 3.7433741092681885 -0.0879734605550766 0.0 +3.387428045272827 3.793140172958374 -0.08815795928239822 0.0 +3.348083972930908 3.8431224822998047 -0.08835659176111221 0.0 +3.308556079864502 3.893338203430176 -0.0885695219039917 0.0 +3.268831968307495 3.943804979324341 -0.0887969583272934 0.0 +3.2288966178894043 3.9945387840270996 -0.08903902024030685 0.0 +3.216688394546509 5.166191101074219 -0.10549727082252502 0.0 +4.60235071182251 7.813288688659668 -0.15719486773014069 0.0 +4.474873065948486 7.81492805480957 -0.15610957145690918 0.0 +4.349124908447266 7.816545486450195 -0.15506243705749512 0.0 +4.225035190582275 7.818142890930176 -0.15405237674713135 0.0 +4.102531909942627 7.819718360900879 -0.1530783474445343 0.0 +3.9815502166748047 7.821274280548096 -0.15213938057422638 0.0 +3.862025499343872 7.822812080383301 -0.15123456716537476 0.0 +3.743896484375 7.824331283569336 -0.1503630429506302 0.0 +3.6271040439605713 7.82583475112915 -0.14952397346496582 0.0 +3.511590003967285 7.827320098876953 -0.1487165093421936 0.0 +3.397299289703369 7.828789710998535 -0.14793996512889862 0.0 +3.2946290969848633 7.855158805847168 -0.14766192436218262 0.0 +3.1958980560302734 7.8902459144592285 -0.14757199585437775 0.0 +0.24398423731327057 0.7587725520133972 -0.01381665002554655 0.0 +0.22803913056850433 0.7402819991111755 -0.013427902944386005 0.0 +0.21296457946300507 0.7228010892868042 -0.013062355108559132 0.0 +0.19868683815002441 0.7062439918518066 -0.012718047015368938 0.0 +0.18514062464237213 0.6905356049537659 -0.012393259443342686 0.0 +0.17226694524288177 0.6756065487861633 -0.012086411006748676 0.0 +0.16001370549201965 0.6613974571228027 -0.011796141974627972 0.0 +0.14833343029022217 0.6478525400161743 -0.011521181091666222 0.0 +0.13718362152576447 0.6349228620529175 -0.011260409839451313 0.0 +0.1265258491039276 0.6225638389587402 -0.01101281214505434 0.0 +0.11632511019706726 0.6107345819473267 -0.010777454823255539 0.0 +0.10654985159635544 0.5993989109992981 -0.010553511790931225 0.0 +0.09717115014791489 0.5885229706764221 -0.010340213775634766 0.0 +0.08854395896196365 0.5805762410163879 -0.0101807015016675 0.0 +0.08126932382583618 0.5806698203086853 -0.01016406062990427 0.0 +0.07401733100414276 0.580763041973114 -0.010149002075195312 0.0 +0.06678570806980133 0.5808560252189636 -0.010135517455637455 0.0 +0.059572212398052216 0.5809490084648132 -0.010123600251972675 0.0 +0.052374549210071564 0.5810415744781494 -0.010113232769072056 0.0 +0.045190535485744476 0.5811339616775513 -0.010104411281645298 0.0 +0.03801795467734337 0.581226110458374 -0.010097125545144081 0.0 +0.030854644253849983 0.5813184976577759 -0.010091381147503853 0.0 +0.023698389530181885 0.5814104676246643 -0.010087160393595695 0.0 +0.01654704101383686 0.5815024375915527 -0.010084466077387333 0.0 +0.00939843151718378 0.5815944075584412 -0.010083296336233616 0.0 +0.002250400837510824 0.5816863179206848 -0.01008364837616682 0.0 +-0.00489920936524868 0.5817782878875732 -0.01008552499115467 0.0 +-0.012052561156451702 0.5818703174591064 -0.010088926181197166 0.0 +-0.019211821258068085 0.5819624066352844 -0.010093854740262032 0.0 +-0.026379168033599854 0.5820547342300415 -0.010100315324962139 0.0 +-0.03355676680803299 0.582146942615509 -0.010108308866620064 0.0 +-0.04074683040380478 0.5822393894195557 -0.010117846541106701 0.0 +-0.047951579093933105 0.5823322534561157 -0.010128935799002647 0.0 +-0.055173203349113464 0.5824249982833862 -0.010141578502953053 0.0 +-0.06241400167346001 0.5825183391571045 -0.010155793279409409 0.0 +-0.06967619806528091 0.5826116800308228 -0.010171581991016865 0.0 +-0.07696210592985153 0.5827053189277649 -0.010188961401581764 0.0 +-0.08427409827709198 0.58279949426651 -0.01020794827491045 0.0 +-0.09161447733640671 0.5828939080238342 -0.010228550992906094 0.0 +-0.09898563474416733 0.5829885601997375 -0.010250785388052464 0.0 +-0.1063900887966156 0.5830839276313782 -0.010274677537381649 0.0 +-0.11383023858070374 0.5831796526908875 -0.010300238616764545 0.0 +-0.12130863964557648 0.5832759141921997 -0.010327491909265518 0.0 +-0.12882782518863678 0.5833725929260254 -0.010356455110013485 0.0 +-0.13639050722122192 0.5834699869155884 -0.010387158021330833 0.0 +-0.14399929344654083 0.5835678577423096 -0.010419621132314205 0.0 +-0.1516568809747696 0.583666205406189 -0.010453866794705391 0.0 +-0.1593661904335022 0.5837653279304504 -0.0104899313300848 0.0 +-0.16713008284568787 0.5838652849197388 -0.010527842678129673 0.0 +-0.1749514788389206 0.5839659571647644 -0.010567630641162395 0.0 +-0.18283338844776154 0.5840674042701721 -0.01060932781547308 0.0 +-0.190778911113739 0.5841694474220276 -0.010652968659996986 0.0 +-0.19879136979579926 0.5842726230621338 -0.010698596946895123 0.0 +-0.20687389373779297 0.5843765139579773 -0.01074624340981245 0.0 +-0.2150300294160843 0.5844814777374268 -0.01079595647752285 0.0 +-0.22326327860355377 0.5845875144004822 -0.010847779922187328 0.0 +-0.231577068567276 0.5846942663192749 -0.01090175099670887 0.0 +-0.23997539281845093 0.5848023891448975 -0.010957930237054825 0.0 +-0.2484620362520218 0.5849117040634155 -0.011016366071999073 0.0 +-0.2570408582687378 0.5850219130516052 -0.011077105067670345 0.0 +-0.26571616530418396 0.5851334929466248 -0.011140210554003716 0.0 +-0.2744922935962677 0.5852465033531189 -0.011205743998289108 0.0 +-0.28337353467941284 0.5853606462478638 -0.01127376314252615 0.0 +-0.2923647463321686 0.5854764580726624 -0.01134434062987566 0.0 +-0.3014705181121826 0.585593581199646 -0.011417538858950138 0.0 +-0.310696005821228 0.5857122540473938 -0.011493436992168427 0.0 +-0.32004639506340027 0.5858325958251953 -0.011572110466659069 0.0 +-0.3295270502567291 0.585954487323761 -0.011653638444840908 0.0 +-0.33914363384246826 0.5860780477523804 -0.011738106608390808 0.0 +-0.34890225529670715 0.5862035751342773 -0.01182560995221138 0.0 +-0.3588089942932129 0.5863310694694519 -0.011916243471205235 0.0 +-0.36887025833129883 0.586460530757904 -0.012010104022920132 0.0 +-0.3790927827358246 0.5865919589996338 -0.012107294984161854 0.0 +-0.38948383927345276 0.5867257714271545 -0.012207936495542526 0.0 +-0.40005049109458923 0.5868616104125977 -0.01231213379651308 0.0 +-0.4108008146286011 0.5869998335838318 -0.012420019134879112 0.0 +-0.4217430055141449 0.5871407985687256 -0.012531726621091366 0.0 +-0.4328853487968445 0.5872840881347656 -0.012647382915019989 0.0 +-0.44423708319664 0.5874301791191101 -0.012767144478857517 0.0 +-0.4558074176311493 0.5875788331031799 -0.012891153804957867 0.0 +-0.4676068127155304 0.5877307653427124 -0.013019589707255363 0.0 +-0.4796452820301056 0.5878854990005493 -0.013152611441910267 0.0 +-0.4919344186782837 0.5880436897277832 -0.013290412724018097 0.0 +-0.5044854879379272 0.5882051587104797 -0.013433178886771202 0.0 +-0.5173112154006958 0.588370144367218 -0.013581120409071445 0.0 +-0.5304244756698608 0.5885387659072876 -0.013734452426433563 0.0 +-0.5438394546508789 0.5887114405632019 -0.013893412426114082 0.0 +-0.5575703978538513 0.5888879299163818 -0.014058236964046955 0.0 +-0.5716334581375122 0.5890689492225647 -0.014229198917746544 0.0 +-0.5860450863838196 0.5892544984817505 -0.014406576752662659 0.0 +-0.6008224487304688 0.5894443988800049 -0.014590654522180557 0.0 +-0.6159849166870117 0.5896395444869995 -0.014781764708459377 0.0 +-0.6315520405769348 0.5898396968841553 -0.014980236999690533 0.0 +-0.647545337677002 0.5900453329086304 -0.015186435543000698 0.0 +-0.6639878749847412 0.5902570486068726 -0.015400756150484085 0.0 +-0.6809035539627075 0.5904746651649475 -0.015623601153492928 0.0 +-0.6983185410499573 0.5906986594200134 -0.015855418518185616 0.0 +-0.716261088848114 0.5909295678138733 -0.0160966906696558 0.0 +-0.7347607016563416 0.5911675095558167 -0.016347920522093773 0.0 +-0.7589804530143738 0.5954380035400391 -0.016722707077860832 0.0 +-0.7862481474876404 0.6013686060905457 -0.0171593576669693 0.0 +-0.8149828910827637 0.607618510723114 -0.017622165381908417 0.0 +-0.8453149199485779 0.6142155528068542 -0.018113432452082634 0.0 +-0.8773913383483887 0.6211919188499451 -0.018635762855410576 0.0 +-0.9113785624504089 0.6285841464996338 -0.019192112609744072 0.0 +-0.9474625587463379 0.6364321708679199 -0.019785771146416664 0.0 +-0.9858567118644714 0.6447829008102417 -0.02042052336037159 0.0 +-1.0268021821975708 0.653688371181488 -0.021100640296936035 0.0 +-1.070575475692749 0.6632087826728821 -0.021831024438142776 0.0 +-1.1174955368041992 0.6734137535095215 -0.022617332637310028 0.0 +-1.1893928050994873 0.6969600319862366 -0.023897312581539154 0.0 +-1.3184010982513428 0.7509446144104004 -0.026301929727196693 0.0 +-3.863607168197632 2.1382088661193848 -0.07654841244220734 0.0 +-3.864394187927246 2.0770227909088135 -0.07605250179767609 0.0 +-3.865171432495117 2.016615390777588 -0.07557431608438492 0.0 +-3.865938901901245 1.956954002380371 -0.07511338591575623 0.0 +-3.866697072982788 1.8980069160461426 -0.0746692419052124 0.0 +-3.8674466609954834 1.839744210243225 -0.07424147427082062 0.0 +-3.86818790435791 1.7821365594863892 -0.07382967323064804 0.0 +-3.8689208030700684 1.7251558303833008 -0.07343342900276184 0.0 +-3.8696463108062744 1.668775200843811 -0.07305240631103516 0.0 +-3.870363712310791 1.612967848777771 -0.07268621772527695 0.0 +-3.871074914932251 1.5577092170715332 -0.07233457267284393 0.0 +-3.871779203414917 1.502974510192871 -0.07199712842702866 0.0 +-3.872476577758789 1.448739767074585 -0.07167358696460724 0.0 +-3.873168468475342 1.3949823379516602 -0.07136368751525879 0.0 +-3.873853921890259 1.341679573059082 -0.07106711715459824 0.0 +-3.8745341300964355 1.2888102531433105 -0.07078366726636887 0.0 +-3.875208854675293 1.2363529205322266 -0.07051306962966919 0.0 +-3.8758790493011475 1.1842875480651855 -0.07025511562824249 0.0 +-3.8765437602996826 1.1325937509536743 -0.07000955939292908 0.0 +-3.877203941345215 1.0812523365020752 -0.06977622210979462 0.0 +-3.8778605461120605 1.0302443504333496 -0.06955491006374359 0.0 +-3.878512382507324 0.9795513153076172 -0.06934542953968048 0.0 +-3.8791604042053223 0.9291550517082214 -0.06914762407541275 0.0 +-3.87980580329895 0.8790380954742432 -0.06896133720874786 0.0 +-3.8804469108581543 0.8291828036308289 -0.06878640502691269 0.0 +-3.8810853958129883 0.7795724272727966 -0.06862270087003708 0.0 +-3.881720781326294 0.730190098285675 -0.06847009062767029 0.0 +-3.8823530673980713 0.6810195446014404 -0.06832844018936157 0.0 +-3.8829829692840576 0.6320446133613586 -0.06819766759872437 0.0 +-3.883610963821411 0.5832495093345642 -0.06807765364646912 0.0 +-3.8842363357543945 0.5346183776855469 -0.06796830147504807 0.0 +-3.8848602771759033 0.4861360192298889 -0.06786955147981644 0.0 +-3.8854825496673584 0.4377870559692383 -0.06778129935264587 0.0 +-3.8861021995544434 0.38955625891685486 -0.067703478038311 0.0 +-3.886721611022949 0.3414289355278015 -0.06763605028390884 0.0 +-3.8873391151428223 0.29339006543159485 -0.06757894903421402 0.0 +-3.8879568576812744 0.24542509019374847 -0.06753215193748474 0.0 +-3.888573169708252 0.1975192278623581 -0.06749559193849564 0.0 +-3.889188766479492 0.1496579796075821 -0.06746925413608551 0.0 +-3.889803647994995 0.10182683914899826 -0.06745311617851257 0.0 +-3.8904192447662354 0.05401136726140976 -0.06744718551635742 0.0 +-3.8910343647003174 0.006197074893862009 -0.06745143234729767 0.0 +-3.8911962509155273 -0.0061973328702151775 0.06745424121618271 0.0 +-3.8918113708496094 -0.05403069406747818 0.06747132539749146 0.0 +-3.8924272060394287 -0.1018955186009407 0.06749860942363739 0.0 +-3.8930435180664062 -0.14980632066726685 0.0675361305475235 0.0 +-3.893660545349121 -0.1977776437997818 0.06758389621973038 0.0 +-3.8942785263061523 -0.24582414329051971 0.06764195114374161 0.0 +-3.894897937774658 -0.2939605712890625 0.06771035492420197 0.0 +-3.8955185413360596 -0.34220170974731445 0.06778913736343384 0.0 +-3.8961410522460938 -0.39056259393692017 0.0678783729672432 0.0 +-3.8967645168304443 -0.43905821442604065 0.06797811388969421 0.0 +-3.897390365600586 -0.48770397901535034 0.06808845698833466 0.0 +-3.8980183601379395 -0.5365152955055237 0.06820946931838989 0.0 +-3.898648500442505 -0.5855078101158142 0.06834125518798828 0.0 +-3.8992815017700195 -0.6346975564956665 0.06848391890525818 0.0 +-3.8999176025390625 -0.6841005682945251 0.06863757222890854 0.0 +-3.9005556106567383 -0.7337331771850586 0.06880231946706772 0.0 +-3.9011969566345215 -0.7836121320724487 0.06897830218076706 0.0 +-3.9018423557281494 -0.8337545990943909 0.0691656693816185 0.0 +-3.9024908542633057 -0.8841778039932251 0.06936455518007278 0.0 +-3.9031434059143066 -0.9348995089530945 0.06957513093948364 0.0 +-3.9038000106811523 -0.9859378933906555 0.0697975605726242 0.0 +-3.904460906982422 -1.0373114347457886 0.0700320303440094 0.0 +-3.905125856399536 -1.0890389680862427 0.07027871906757355 0.0 +-3.905796527862549 -1.141140341758728 0.07053785771131516 0.0 +-3.9064719676971436 -1.19363534450531 0.07080965489149094 0.0 +-3.9071524143218994 -1.2465442419052124 0.07109431177377701 0.0 +-3.907839059829712 -1.2998887300491333 0.07139211148023605 0.0 +-3.908531427383423 -1.3536899089813232 0.07170329242944717 0.0 +-3.909229278564453 -1.4079701900482178 0.07202810794115067 0.0 +-3.909933567047119 -1.4627528190612793 0.0723668560385704 0.0 +-3.9106452465057373 -1.5180617570877075 0.07271985709667206 0.0 +-3.9113640785217285 -1.57392156124115 0.0730874091386795 0.0 +-3.912090301513672 -1.6303573846817017 0.0734698548913002 0.0 +-3.9128239154815674 -1.6873953342437744 0.07386752218008041 0.0 +-3.9135656356811523 -1.745063066482544 0.07428080588579178 0.0 +-3.914315938949585 -1.8033884763717651 0.07471008598804474 0.0 +-3.9150755405426025 -1.8624011278152466 0.07515577971935272 0.0 +-3.915843963623047 -1.922131061553955 0.07561831176280975 0.0 +-3.9166219234466553 -1.9826098680496216 0.07609812915325165 0.0 +-3.917409896850586 -2.043870449066162 0.0765957161784172 0.0 +-3.918208360671997 -2.1059467792510986 0.07711157947778702 0.0 +-3.919018030166626 -2.168874740600586 0.07764625549316406 0.0 +-3.9198389053344727 -2.2326908111572266 0.07820027321577072 0.0 +-3.9206721782684326 -2.2974343299865723 0.07877425104379654 0.0 +-3.9215173721313477 -2.363144874572754 0.07936878502368927 0.0 +-3.9223756790161133 -2.4298651218414307 0.07998453825712204 0.0 +-3.9232475757598877 -2.4976391792297363 0.08062218874692917 0.0 +-3.92413330078125 -2.5665128231048584 0.08128245919942856 0.0 +-3.925034284591675 -2.6365346908569336 0.08196611702442169 0.0 +-3.925950527191162 -2.7077553272247314 0.08267397433519363 0.0 +-3.9268829822540283 -2.7802278995513916 0.08340686559677124 0.0 +-3.9278318881988525 -2.8540079593658447 0.08416568487882614 0.0 +-3.9287991523742676 -2.929154634475708 0.08495140820741653 0.0 +-3.9297842979431152 -3.0057289600372314 0.08576500415802002 0.0 +-3.930788278579712 -3.0837957859039307 0.08660753071308136 0.0 +-3.9318125247955322 -3.163424015045166 0.08748012036085129 0.0 +-3.9328579902648926 -3.244685649871826 0.08838396519422531 0.0 +-3.933925151824951 -3.3276565074920654 0.08932030200958252 0.0 +-3.9350154399871826 -3.412416934967041 0.09029047936201096 0.0 +-3.9361298084259033 -3.4990525245666504 0.09129590541124344 0.0 +-3.937270164489746 -3.587653160095215 0.09233809262514114 0.0 +-3.938436269760132 -3.6783130168914795 0.09341860562562943 0.0 +-3.9396300315856934 -3.7711341381073 0.09453915059566498 0.0 +-3.9408531188964844 -3.8662235736846924 0.09570153057575226 0.0 +-3.926931858062744 -3.948436975479126 0.0965346246957779 0.0 +-3.8327465057373047 -3.9496493339538574 0.09540538489818573 0.0 +-3.7407238483428955 -3.9508321285247803 0.09431630373001099 0.0 +-3.650766372680664 -3.9519896507263184 0.09326576441526413 0.0 +-3.562777519226074 -3.9531219005584717 0.09225215017795563 0.0 +-3.476667881011963 -3.9542300701141357 0.0912739634513855 0.0 +-3.3923518657684326 -3.9553141593933105 0.09032978862524033 0.0 +-3.3097503185272217 -3.9563770294189453 0.08941832184791565 0.0 +-3.228787422180176 -3.957418918609619 0.08853831887245178 0.0 +-3.149390459060669 -3.958440065383911 0.08768856525421143 0.0 +-3.07149076461792 -3.959441661834717 0.08686795830726624 0.0 +-2.9950249195098877 -3.960425853729248 0.08607546985149384 0.0 +-2.9199302196502686 -3.9613921642303467 0.08531006425619125 0.0 +-2.8461482524871826 -3.96234130859375 0.08457081764936447 0.0 +-2.773622989654541 -3.9632742404937744 0.08385682851076126 0.0 +-2.702301502227783 -3.9641919136047363 0.08316724747419357 0.0 +-2.6321327686309814 -3.9650943279266357 0.08250126242637634 0.0 +-2.5630686283111572 -3.9659829139709473 0.08185814321041107 0.0 +-2.4950625896453857 -3.966857433319092 0.08123712986707687 0.0 +-2.4280707836151123 -3.967719554901123 0.08063756674528122 0.0 +-2.3620505332946777 -3.9685685634613037 0.08005878329277039 0.0 +-2.296961545944214 -3.9694058895111084 0.07950017601251602 0.0 +-2.2327651977539062 -3.9702320098876953 0.07896115630865097 0.0 +-2.1694235801696777 -3.9710464477539062 0.07844115793704987 0.0 +-2.1069021224975586 -3.9718515872955322 0.07793967425823212 0.0 +-2.0451648235321045 -3.9726450443267822 0.07745616137981415 0.0 +-1.984180212020874 -3.9734299182891846 0.07699018716812134 0.0 +-1.923915982246399 -3.974205732345581 0.07654127478599548 0.0 +-1.8643412590026855 -3.9749717712402344 0.07610899209976196 0.0 +-1.8054267168045044 -3.9757297039031982 0.07569292187690735 0.0 +-1.7471442222595215 -3.9764792919158936 0.0752926915884018 0.0 +-1.6894662380218506 -3.9772214889526367 0.07490793615579605 0.0 +-1.6323659420013428 -3.9779558181762695 0.07453827559947968 0.0 +-1.5758181810379028 -3.9786834716796875 0.07418341189622879 0.0 +-1.5197975635528564 -3.9794037342071533 0.07384299486875534 0.0 +-1.4642807245254517 -3.9801180362701416 0.07351675629615784 0.0 +-1.4092438220977783 -3.9808261394500732 0.0732043907046318 0.0 +-1.3546645641326904 -3.9815282821655273 0.07290562987327576 0.0 +-1.3005207777023315 -3.982224941253662 0.07262022793292999 0.0 +-1.246791124343872 -3.9829158782958984 0.07234792411327362 0.0 +-1.1934549808502197 -3.983602285385132 0.07208850979804993 0.0 +-1.1404918432235718 -3.984283447265625 0.0718417540192604 0.0 +-1.0878822803497314 -3.9849603176116943 0.07160747051239014 0.0 +-1.0356067419052124 -3.98563289642334 0.0713854506611824 0.0 +-0.9836465716362 -3.9863011837005615 0.07117552310228348 0.0 +-0.9319834113121033 -3.986966133117676 0.07097751647233963 0.0 +-0.8805990815162659 -3.9876270294189453 0.07079125940799713 0.0 +-0.8294760584831238 -3.9882848262786865 0.07061662524938583 0.0 +-0.778596818447113 -3.988938808441162 0.0704534500837326 0.0 +-0.7279447317123413 -3.989590644836426 0.07030164450407028 0.0 +-0.6775029301643372 -3.9902400970458984 0.07016105949878693 0.0 +-0.6272547245025635 -3.9908862113952637 0.07003158330917358 0.0 +-0.5771841406822205 -3.991530418395996 0.06991312652826309 0.0 +-0.5272750854492188 -3.9921722412109375 0.06980559229850769 0.0 +-0.42787882685661316 -3.993450880050659 0.06962297856807709 0.0 +2.04915452003479 -4.0253167152404785 0.07830043137073517 0.0 +8.54526138305664 -1.8666865825653076 0.15162590146064758 0.0 +8.493124961853027 -1.5296978950500488 0.1495978832244873 0.0 +8.567780494689941 -1.4346681833267212 0.1505909115076065 0.0 +8.654045104980469 -1.3399951457977295 0.15180622041225433 0.0 +9.119654655456543 -1.297538161277771 0.15968197584152222 0.0 +9.874942779541016 -1.2813937664031982 0.17261801660060883 0.0 +11.105927467346191 -1.302557110786438 0.19384165108203888 0.0 +3.4875454902648926 -0.3656463921070099 0.06078821048140526 0.0 +3.4881017208099365 -0.3224196434020996 0.060724250972270966 0.0 +3.189971923828125 -0.25536662340164185 0.05547529086470604 0.0 +3.1490511894226074 -0.21317842602729797 0.05471396446228027 0.0 +3.1092333793640137 -0.17212645709514618 0.05398130416870117 0.0 +3.0704619884490967 -0.1321534365415573 0.0532759465277195 0.0 +3.032684326171875 -0.09320573508739471 0.05259661749005318 0.0 +2.9958531856536865 -0.05523313954472542 0.05194214731454849 0.0 +2.983644485473633 -0.018334170803427696 0.05172266066074371 0.0 +2.984483242034912 0.018339326605200768 0.05173720046877861 0.0 +2.985323190689087 0.05503900349140167 0.05175957828760147 0.0 +2.986163377761841 0.09177596867084503 0.051789790391922 0.0 +2.9870047569274902 0.12856142222881317 0.05182787403464317 0.0 +2.9878478050231934 0.16540658473968506 0.05187385529279709 0.0 +2.988692045211792 0.20232273638248444 0.05192776396870613 0.0 +2.9895389080047607 0.23932136595249176 0.05198965594172478 0.0 +2.990386962890625 0.27641379833221436 0.05205955356359482 0.0 +2.9912383556365967 0.31361183524131775 0.05213753506541252 0.0 +2.9920918941497803 0.35092705488204956 0.05222364515066147 0.0 +2.992948293685913 0.38837137818336487 0.05231795087456703 0.0 +2.9938082695007324 0.42595693469047546 0.052420537918806076 0.0 +2.99467134475708 0.46369585394859314 0.052531469613313675 0.0 +2.9955387115478516 0.5016006231307983 0.05265084654092789 0.0 +2.9964098930358887 0.5396837592124939 0.05277875438332558 0.0 +2.9972853660583496 0.5779582262039185 0.0529152974486351 0.0 +2.9981653690338135 0.6164369583129883 0.05306057631969452 0.0 +2.9990508556365967 0.6551335453987122 0.053214725106954575 0.0 +2.99994158744812 0.6940615773200989 0.05337785929441452 0.0 +3.000837802886963 0.7332348823547363 0.053550105541944504 0.0 +3.001739740371704 0.7726677656173706 0.05373160541057587 0.0 +3.002647876739502 0.8123748302459717 0.05392250791192055 0.0 +3.0035626888275146 0.852371096611023 0.05412297695875168 0.0 +3.0044848918914795 0.8926721811294556 0.05433318763971329 0.0 +3.0054144859313965 0.9332935810089111 0.054553307592868805 0.0 +3.0063509941101074 0.9742515683174133 0.05478351563215256 0.0 +3.007296323776245 1.0155631303787231 0.055024031549692154 0.0 +3.0082499980926514 1.0572453737258911 0.05527505278587341 0.0 +3.0092127323150635 1.0993160009384155 0.05553680285811424 0.0 +3.010183811187744 1.141793131828308 0.05580949783325195 0.0 +3.011164903640747 1.184696078300476 0.056093402206897736 0.0 +3.0121567249298096 1.2280445098876953 0.05638877674937248 0.0 +3.0131592750549316 1.2718586921691895 0.05669588968157768 0.0 +3.03961181640625 1.3272674083709717 0.057496216148138046 0.0 +3.0901741981506348 1.3948101997375488 0.05877246335148811 0.0 +3.1430394649505615 1.4654301404953003 0.06011591851711273 0.0 +3.1983871459960938 1.5393656492233276 0.06153174862265587 0.0 +6.466626167297363 3.210819959640503 0.12515705823898315 0.0 +6.388535976409912 3.2705211639404297 0.12441424280405045 0.0 +6.311354160308838 3.3295257091522217 0.12369872629642487 0.0 +6.235044956207275 3.3878650665283203 0.12300989776849747 0.0 +6.139796733856201 3.43450665473938 0.12195432931184769 0.0 +6.044631481170654 3.4794840812683105 0.1209043487906456 0.0 +5.951077938079834 3.523700714111328 0.11989026516675949 0.0 +5.867961406707764 3.572603702545166 0.11909137666225433 0.0 +5.806656837463379 3.633835554122925 0.1187446266412735 0.0 +5.654068946838379 3.6357994079589844 0.11652923375368118 0.0 +5.5070481300354 3.637691020965576 0.11441195011138916 0.0 +5.365254878997803 3.639516592025757 0.11238693445920944 0.0 +5.228372573852539 3.641278028488159 0.11044872552156448 0.0 +5.09611177444458 3.6429800987243652 0.10859236121177673 0.0 +4.968204975128174 3.6446263790130615 0.10681323707103729 0.0 +4.84440279006958 3.6462197303771973 0.10510708391666412 0.0 +4.724475860595703 3.6477630138397217 0.10346996039152145 0.0 +4.60821008682251 3.649259328842163 0.1018982082605362 0.0 +4.4954071044921875 3.6507110595703125 0.10038843005895615 0.0 +4.3858819007873535 3.65212082862854 0.09893746674060822 0.0 +4.27946138381958 3.6534905433654785 0.09754236787557602 0.0 +4.229487419128418 3.7016470432281494 0.09743288904428482 0.0 +4.130251884460449 3.7054152488708496 0.09618867933750153 0.0 +4.030900478363037 3.7066941261291504 0.09492868185043335 0.0 +3.934103488922119 3.707939863204956 0.09371523559093475 0.0 +3.839735507965088 3.709153890609741 0.09254620969295502 0.0 +3.7476794719696045 3.710338592529297 0.09141962975263596 0.0 +3.6578245162963867 3.7114951610565186 0.09033364057540894 0.0 +3.570066452026367 3.712625026702881 0.08928647637367249 0.0 +3.4843063354492188 3.713728427886963 0.08827648311853409 0.0 +3.426600933074951 3.7433736324310303 0.087973453104496 0.0 +3.3874285221099854 3.793140411376953 0.08815796673297882 0.0 +3.348083734512329 3.8431222438812256 0.08835658431053162 0.0 +3.3085567951202393 3.893338918685913 0.08856954425573349 0.0 +3.268832206726074 3.943805456161499 0.08879696577787399 0.0 +3.2288970947265625 3.9945390224456787 0.08903902769088745 0.0 +3.1962332725524902 4.055068016052246 0.08950585871934891 0.0 +3.197596788406372 4.160977840423584 0.0909692570567131 0.0 +3.199005603790283 4.270424842834473 0.09249549359083176 0.0 +3.2004618644714355 4.3836236000061035 0.09408825635910034 0.0 +3.2019705772399902 4.500808238983154 0.0957515686750412 0.0 +3.2035329341888428 4.622228622436523 0.09748972952365875 0.0 +3.205153465270996 4.748157978057861 0.09930742532014847 0.0 +3.2680394649505615 4.972008228302002 0.1031414046883583 0.0 +3.2698209285736084 5.1104631423950195 0.10517197102308273 0.0 +3.216674566268921 5.166168689727783 0.10549681633710861 0.0 +3.2122979164123535 5.303300857543945 0.10748282819986343 0.0 +3.1335768699645996 8.018192291259766 0.14923341572284698 0.0 +3.137575387954712 8.328914642333984 0.1542871743440628 0.0 +3.1418559551239014 8.66147518157959 0.1597202718257904 0.0 +3.1464483737945557 9.018363952636719 0.1655758023262024 0.0 +3.2516655921936035 9.701656341552734 0.17737382650375366 0.0 +0.24397896230220795 0.758756160736084 0.0138163510710001 0.0 +0.22803440690040588 0.7402666807174683 0.013427624478936195 0.0 +0.21295998990535736 0.7227855324745178 0.013062073849141598 0.0 +0.19868285953998566 0.7062298655509949 0.012717792764306068 0.0 +0.18513664603233337 0.6905207633972168 0.012392993085086346 0.0 +0.17226359248161316 0.6755934357643127 0.012086176313459873 0.0 +0.16001056134700775 0.6613844633102417 0.011795910075306892 0.0 +0.1483304500579834 0.6478395462036133 0.011520950123667717 0.0 +0.137180894613266 0.6349102258682251 0.011260186322033405 0.0 +0.12652337551116943 0.622551679611206 0.01101259607821703 0.0 +0.11632285267114639 0.6107227206230164 0.01077724527567625 0.0 +0.10654786229133606 0.5993877053260803 0.010553314350545406 0.0 +0.09716934710741043 0.5885120630264282 0.01034002099186182 0.0 +0.08854316174983978 0.5805709958076477 0.010180610232055187 0.0 +0.08126859366893768 0.5806646347045898 0.010163969360291958 0.0 +0.07401670515537262 0.5807580947875977 0.010148916393518448 0.0 +0.06678514182567596 0.580851137638092 0.010135432705283165 0.0 +0.059571683406829834 0.5809438824653625 0.010123510845005512 0.0 +0.05237410590052605 0.5810366272926331 0.010113147087395191 0.0 +0.04519015550613403 0.5811291337013245 0.010104326531291008 0.0 +0.038017638027668 0.5812212824821472 0.010097041726112366 0.0 +0.030854374170303345 0.5813133716583252 0.010091292671859264 0.0 +0.023698193952441216 0.5814056992530823 0.01008707657456398 0.0 +0.016546903178095818 0.5814976692199707 0.010084383189678192 0.0 +0.009398353286087513 0.5815896391868591 0.0100832125172019 0.0 +0.002250382676720619 0.5816816091537476 0.010083566419780254 0.0 +-0.004899169318377972 0.581773579120636 0.010085443034768105 0.0 +-0.012052464298903942 0.5818656086921692 0.0100888442248106 0.0 +-0.019211675971746445 0.581957995891571 0.010093777440488338 0.0 +-0.026378953829407692 0.5820500254631042 0.010100234299898148 0.0 +-0.033556513488292694 0.5821424722671509 0.010108232498168945 0.0 +-0.040746524930000305 0.5822350382804871 0.010117770172655582 0.0 +-0.047951195389032364 0.5823276042938232 0.010128854773938656 0.0 +-0.055172789841890335 0.5824206471443176 0.010141502134501934 0.0 +-0.06241350620985031 0.582513689994812 0.010155712254345417 0.0 +-0.06967567652463913 0.5826073288917542 0.010171506553888321 0.0 +-0.07696153968572617 0.5827009677886963 0.01018888596445322 0.0 +-0.08427347242832184 0.5827952027320862 0.010207871906459332 0.0 +-0.09161379933357239 0.5828895568847656 0.010228474624454975 0.0 +-0.09898494929075241 0.5829845666885376 0.010250714607536793 0.0 +-0.10638931393623352 0.5830796957015991 0.01027460303157568 0.0 +-0.11382941901683807 0.5831754803657532 0.010300164110958576 0.0 +-0.12130776047706604 0.5832716822624207 0.010327416472136974 0.0 +-0.12882694602012634 0.5833685994148254 0.010356384329497814 0.0 +-0.13638953864574432 0.5834658145904541 0.010387084446847439 0.0 +-0.14399826526641846 0.5835637450218201 0.010419546626508236 0.0 +-0.1516558825969696 0.5836623311042786 0.01045379787683487 0.0 +-0.15936513245105743 0.5837615132331848 0.010489861480891705 0.0 +-0.16712898015975952 0.5838614702224731 0.010527773760259151 0.0 +-0.17495033144950867 0.5839622020721436 0.010567561723291874 0.0 +-0.18283219635486603 0.5840635895729065 0.010609258897602558 0.0 +-0.1907777488231659 0.5841659307479858 0.010652904398739338 0.0 +-0.19879010319709778 0.5842689275741577 0.010698528960347176 0.0 +-0.20687267184257507 0.5843729972839355 0.010746179148554802 0.0 +-0.215028777718544 0.5844780206680298 0.010795893147587776 0.0 +-0.22326189279556274 0.5845838785171509 0.010847712866961956 0.0 +-0.23157574236392975 0.5846909284591675 0.01090168859809637 0.0 +-0.2399740219116211 0.58479905128479 0.010957867838442326 0.0 +-0.24846051633358002 0.584908127784729 0.011016298085451126 0.0 +-0.2570394277572632 0.5850186347961426 0.011077042669057846 0.0 +-0.2657146453857422 0.5851301550865173 0.011140147224068642 0.0 +-0.2744907736778259 0.5852432250976562 0.011205681599676609 0.0 +-0.2833719849586487 0.5853574275970459 0.01127370074391365 0.0 +-0.29236313700675964 0.5854732394218445 0.01134427823126316 0.0 +-0.3014688789844513 0.5855903625488281 0.011417476460337639 0.0 +-0.3106943368911743 0.5857090950012207 0.011493375524878502 0.0 +-0.32004469633102417 0.585829496383667 0.011572049930691719 0.0 +-0.32952532172203064 0.5859513878822327 0.011653576977550983 0.0 +-0.3391420245170593 0.5860752463340759 0.011738050729036331 0.0 +-0.34890061616897583 0.5862008333206177 0.011825555004179478 0.0 +-0.3588073253631592 0.5863283276557922 0.011916187591850758 0.0 +-0.3688685894012451 0.5864579081535339 0.01201004907488823 0.0 +-0.3790910542011261 0.5865892767906189 0.012107240036129951 0.0 +-0.3894820809364319 0.5867231488227844 0.012207881547510624 0.0 +-0.40004876255989075 0.5868590474128723 0.012312079779803753 0.0 +-0.4107992351055145 0.5869976282119751 0.012419971637427807 0.0 +-0.42174121737480164 0.587138295173645 0.012531672604382038 0.0 +-0.4328835606575012 0.5872816443443298 0.012647331692278385 0.0 +-0.44423526525497437 0.5874277949333191 0.012767092324793339 0.0 +-0.45580577850341797 0.5875767469406128 0.01289110817015171 0.0 +-0.46760499477386475 0.5877284407615662 0.013019539415836334 0.0 +-0.47964367270469666 0.587883472442627 0.013152566738426685 0.0 +-0.49193260073661804 0.5880415439605713 0.013290364295244217 0.0 +-0.5044838786125183 0.5882031917572021 0.013433135114610195 0.0 +-0.5173096060752869 0.58836829662323 0.013581077568233013 0.0 +-0.5304228663444519 0.5885369777679443 0.013734410516917706 0.0 +-0.54383784532547 0.5887097120285034 0.0138933714479208 0.0 +-0.5575688481330872 0.5888862609863281 0.014058196917176247 0.0 +-0.5716319680213928 0.5890673398971558 0.014229160733520985 0.0 +-0.5860435366630554 0.5892528891563416 0.014406537637114525 0.0 +-0.6008208990097046 0.5894429087638855 0.014590617269277573 0.0 +-0.6159834265708923 0.5896381139755249 0.014781730249524117 0.0 +-0.6315506100654602 0.5898383855819702 0.014980202540755272 0.0 +-0.647544264793396 0.590044379234314 0.015186410397291183 0.0 +-0.6639865040779114 0.590255856513977 0.015400724485516548 0.0 +-0.6809022426605225 0.5904735326766968 0.015623570419847965 0.0 +-0.6983175873756409 0.5906978249549866 0.015855396166443825 0.0 +-0.7162599563598633 0.5909286141395569 0.01609666459262371 0.0 +-0.7347596287727356 0.591166615486145 0.016347896307706833 0.0 +-0.7589805722236633 0.5954381227493286 0.01672271080315113 0.0 +-0.7862485647201538 0.6013689041137695 0.017159366980195045 0.0 +-0.814983069896698 0.6076185703277588 0.017622167244553566 0.0 +-0.8453153967857361 0.6142159104347229 0.01811344176530838 0.0 +-0.877392590045929 0.6211928129196167 0.018635790795087814 0.0 +-0.9113803505897522 0.6285853385925293 0.019192149862647057 0.0 +-0.9474648833274841 0.6364337205886841 0.019785819575190544 0.0 +-0.9858598709106445 0.6447849273681641 0.020420588552951813 0.0 +-1.0268054008483887 0.6536904573440552 0.021100707352161407 0.0 +-1.0705796480178833 0.663211464881897 0.02183111198246479 0.0 +-1.1175005435943604 0.6734168529510498 0.022617435082793236 0.0 +-1.189410924911499 0.6969707012176514 0.023897677659988403 0.0 +-1.318427324295044 0.7509595155715942 0.026302451267838478 0.0 +-3.8772013187408447 1.0812515020370483 0.06977616995573044 0.0 +-3.8791584968566895 0.9291545748710632 0.06914758682250977 0.0 +-3.8804447650909424 0.8291823267936707 0.0687863677740097 0.0 +-3.8810834884643555 0.7795720100402832 0.0686226636171341 0.0 +-3.881718873977661 0.7301898002624512 0.0684700533747673 0.0 +-3.8823516368865967 0.6810192465782166 0.06832841783761978 0.0 +-3.8829822540283203 0.6320444941520691 0.06819765269756317 0.0 +-3.8836100101470947 0.5832493305206299 0.06807763874530792 0.0 +-3.8842358589172363 0.5346183180809021 0.06796829402446747 0.0 +-3.884859800338745 0.48613595962524414 0.06786954402923584 0.0 +-3.8854820728302 0.4377869963645935 0.06778129190206528 0.0 +-3.8861026763916016 0.38955631852149963 0.0677034854888916 0.0 +-3.8867223262786865 0.3414289951324463 0.06763606518507004 0.0 +-3.887340545654297 0.2933901846408844 0.06757897138595581 0.0 +-3.88795804977417 0.24542516469955444 0.06753216683864594 0.0 +-3.8885743618011475 0.19751928746700287 0.06749560683965683 0.0 +-3.8891899585723877 0.14965802431106567 0.0674692764878273 0.0 +-3.889805793762207 0.10182689875364304 0.06745315343141556 0.0 +-3.8904213905334473 0.05401139706373215 0.0674472227692604 0.0 +-3.89103627204895 0.00619707815349102 0.06745146960020065 0.0 +-3.89119815826416 -0.006197335664182901 0.20252513885498047 0.0 +-3.8918142318725586 -0.054030731320381165 0.20257645845413208 0.0 +-3.892430067062378 -0.10189559310674667 0.20265839993953705 0.0 +-3.8930463790893555 -0.1498064249753952 0.20277103781700134 0.0 +-3.8936638832092285 -0.19777782261371613 0.20291447639465332 0.0 +-3.894282579421997 -0.24582439661026 0.20308883488178253 0.0 +-3.894902229309082 -0.2939608693122864 0.20329420268535614 0.0 +-3.8955228328704834 -0.3422020971775055 0.20353074371814728 0.0 +-3.8961448669433594 -0.3905629813671112 0.20379865169525146 0.0 +-3.8967692852020264 -0.43905875086784363 0.2040981650352478 0.0 +-3.897395372390747 -0.4877046048641205 0.20442944765090942 0.0 +-3.898023843765259 -0.5365160703659058 0.2047928124666214 0.0 +-3.8986544609069824 -0.5855087637901306 0.20518852770328522 0.0 +-3.899287223815918 -0.6346985101699829 0.20561684668064117 0.0 +-3.89992356300354 -0.6841016411781311 0.2060782015323639 0.0 +-3.900562047958374 -0.7337343692779541 0.20657284557819366 0.0 +-3.9012041091918945 -0.7836135625839233 0.2071012556552887 0.0 +-3.9018492698669434 -0.8337560892105103 0.20766380429267883 0.0 +-3.9024980068206787 -0.8841794729232788 0.20826095342636108 0.0 +-3.903151035308838 -0.9349013566970825 0.20889319479465485 0.0 +-3.9038078784942627 -0.9859399199485779 0.2095610499382019 0.0 +-3.904468536376953 -1.037313461303711 0.21026501059532166 0.0 +-3.905135154724121 -1.0890415906906128 0.21100576221942902 0.0 +-3.9058051109313965 -1.1411428451538086 0.2117837816476822 0.0 +-3.9064810276031494 -1.1936380863189697 0.21259982883930206 0.0 +-3.9071617126464844 -1.2465472221374512 0.21345451474189758 0.0 +-3.907848358154297 -1.299891710281372 0.21434862911701202 0.0 +-3.908540725708008 -1.3536931276321411 0.21528291702270508 0.0 +-3.9092392921447754 -1.4079738855361938 0.2162581980228424 0.0 +-3.909944534301758 -1.4627569913864136 0.21727532148361206 0.0 +-3.910655975341797 -1.5180659294128418 0.21833515167236328 0.0 +-3.9113752841949463 -1.5739259719848633 0.21943871676921844 0.0 +-3.9121012687683105 -1.6303619146347046 0.22058695554733276 0.0 +-3.9128353595733643 -1.6874003410339355 0.2217809557914734 0.0 +-3.9135777950286865 -1.7450684309005737 0.22302183508872986 0.0 +-3.9143283367156982 -1.8033941984176636 0.2243107408285141 0.0 +-3.915088176727295 -1.8624072074890137 0.2256489098072052 0.0 +-3.9158568382263184 -1.9221373796463013 0.22703763842582703 0.0 +-3.9166347980499268 -1.9826164245605469 0.22847825288772583 0.0 +-3.9174232482910156 -2.043877363204956 0.229972243309021 0.0 +-3.918222427368164 -2.10595440864563 0.2315211296081543 0.0 +-3.9190328121185303 -2.1688826084136963 0.2331264615058899 0.0 +-3.919853448867798 -2.232699155807495 0.2347898632287979 0.0 +-3.920687198638916 -2.297443151473999 0.23651321232318878 0.0 +-3.92153263092041 -2.363154172897339 0.23829825222492218 0.0 +-3.922391653060913 -2.429875135421753 0.24014705419540405 0.0 +-3.9232635498046875 -2.4976494312286377 0.2420615404844284 0.0 +-3.9241504669189453 -2.566524028778076 0.24404402077198029 0.0 +-3.925051212310791 -2.6365461349487305 0.2460966557264328 0.0 +-3.9259684085845947 -2.7077677249908447 0.2482219934463501 0.0 +-3.926900863647461 -2.780240774154663 0.2504224479198456 0.0 +-3.9278507232666016 -2.8540215492248535 0.2527008056640625 0.0 +-3.9288177490234375 -2.929168462753296 0.2550598382949829 0.0 +-3.9298031330108643 -3.0057435035705566 0.25750261545181274 0.0 +-3.930807590484619 -3.083811044692993 0.2600322663784027 0.0 +-3.931832790374756 -3.163440465927124 0.2626522183418274 0.0 +-3.9328789710998535 -3.2447030544281006 0.26536598801612854 0.0 +-3.933946371078491 -3.327674627304077 0.2681773006916046 0.0 +-3.93503737449646 -3.4124362468719482 0.27109020948410034 0.0 +-3.936152219772339 -3.499072313308716 0.2741089463233948 0.0 +-3.93729305267334 -3.587674140930176 0.27723807096481323 0.0 +-3.938459634780884 -3.678334951400757 0.2804822623729706 0.0 +-3.939654588699341 -3.7711575031280518 0.2838466763496399 0.0 +-3.94087815284729 -3.86624813079834 0.28733667731285095 0.0 +-3.92692232131958 -3.948427438735962 0.28983545303344727 0.0 +-3.8327369689941406 -3.9496395587921143 0.2864450216293335 0.0 +-3.740715980529785 -3.9508235454559326 0.2831752598285675 0.0 +-3.650758743286133 -3.95198130607605 0.2800211012363434 0.0 +-3.562769889831543 -3.953113317489624 0.2769778072834015 0.0 +-3.47666072845459 -3.9542219638824463 0.27404093742370605 0.0 +-3.392345905303955 -3.9553072452545166 0.27120622992515564 0.0 +-3.3097445964813232 -3.9563701152801514 0.2684696614742279 0.0 +-3.2287819385528564 -3.957412004470825 0.2658275365829468 0.0 +-2.1694228649139404 -3.9710452556610107 0.2355121523141861 0.0 +-2.1069014072418213 -3.9718503952026367 0.23400649428367615 0.0 +-2.0451645851135254 -3.972644567489624 0.2325548231601715 0.0 +-1.9841798543930054 -3.9734292030334473 0.23115578293800354 0.0 +-1.9239155054092407 -3.9742047786712646 0.22980795800685883 0.0 +-1.864341378211975 -3.9749722480773926 0.22851012647151947 0.0 +-1.805426836013794 -3.9757297039031982 0.22726091742515564 0.0 +-1.7471445798873901 -3.976480007171631 0.22605930268764496 0.0 +-1.6894663572311401 -3.977221727371216 0.22490407526493073 0.0 +-1.6323665380477905 -3.977957248687744 0.22379428148269653 0.0 +-1.575818657875061 -3.978684663772583 0.22272880375385284 0.0 +-1.5197982788085938 -3.979405641555786 0.22170677781105042 0.0 +-1.464281439781189 -3.9801201820373535 0.22072727978229523 0.0 +-1.4092445373535156 -3.980827808380127 0.21978941559791565 0.0 +-1.3546653985977173 -3.9815306663513184 0.21889245510101318 0.0 +-1.3005216121673584 -3.9822275638580322 0.21803556382656097 0.0 +-1.2467920780181885 -3.9829189777374268 0.21721802651882172 0.0 +-1.193455696105957 -3.983604907989502 0.2164391279220581 0.0 +-1.1404929161071777 -3.9842870235443115 0.21569833159446716 0.0 +-1.0878833532333374 -3.984964370727539 0.21499492228031158 0.0 +-1.0356078147888184 -3.9856371879577637 0.2143283486366272 0.0 +-0.9836476445198059 -3.9863057136535645 0.21369805932044983 0.0 +-0.9319844245910645 -3.9869704246520996 0.21310356259346008 0.0 +-0.880600094795227 -3.9876315593719482 0.21254436671733856 0.0 +-0.829477071762085 -3.9882895946502686 0.21202005445957184 0.0 +-0.7785979509353638 -3.9889442920684814 0.2115301787853241 0.0 +-0.7279458045959473 -3.989596366882324 0.21107438206672668 0.0 +-0.6775038242340088 -3.9902455806732178 0.21065229177474976 0.0 +-0.6272556781768799 -3.990892171859741 0.21026356518268585 0.0 +-0.5771850347518921 -3.991536855697632 0.20990793406963348 0.0 +-0.5272759795188904 -3.9921791553497314 0.20958510041236877 0.0 +-0.4775126874446869 -3.992819309234619 0.20929479598999023 0.0 +-0.42787957191467285 -3.9934580326080322 0.20903684198856354 0.0 +-0.3783612847328186 -3.994096040725708 0.20881105959415436 0.0 +-0.32894229888916016 -3.994732141494751 0.2086171954870224 0.0 +-0.27960753440856934 -3.9953665733337402 0.2084551304578781 0.0 +-0.23034195601940155 -3.9960005283355713 0.20832476019859314 0.0 +-0.181130513548851 -3.996633768081665 0.20822599530220032 0.0 +-0.13195830583572388 -3.9972667694091797 0.20815876126289368 0.0 +-0.0828104168176651 -3.997898817062378 0.20812295377254486 0.0 +-0.03367200866341591 -3.9985315799713135 0.20811863243579865 0.0 +0.015471778810024261 -3.99916410446167 0.20814573764801025 0.0 +0.06463579088449478 -3.9997971057891846 0.20820429921150208 0.0 +0.11383489519357681 -4.000429630279541 0.2082943320274353 0.0 +0.16308404505252838 -4.001064300537109 0.20841598510742188 0.0 +0.21239817142486572 -4.0016984939575195 0.2085692435503006 0.0 +0.2617923319339752 -4.002334117889404 0.208754301071167 0.0 +0.31128180027008057 -4.002971172332764 0.208971306681633 0.0 +0.36088165640830994 -4.003609657287598 0.20922036468982697 0.0 +0.4106074571609497 -4.004249572753906 0.209501713514328 0.0 +0.4604746699333191 -4.004891395568848 0.20981553196907043 0.0 +0.5104991793632507 -4.00553560256958 0.21016211807727814 0.0 +0.5606966614723206 -4.006181240081787 0.21054165065288544 0.0 +0.611083447933197 -4.006829261779785 0.210954487323761 0.0 +0.6616759300231934 -4.007480621337891 0.21140094101428986 0.0 +0.7124907970428467 -4.008134841918945 0.21188139915466309 0.0 +0.7635446190834045 -4.008791446685791 0.21239612996578217 0.0 +0.8148550987243652 -4.009451866149902 0.21294565498828888 0.0 +0.8664395809173584 -4.010116100311279 0.21353037655353546 0.0 +0.9183157682418823 -4.0107831954956055 0.21415069699287415 0.0 +0.9705024361610413 -4.011455535888672 0.21480722725391388 0.0 +1.0230180025100708 -4.012131690979004 0.21550044417381287 0.0 +1.0758813619613647 -4.012811660766602 0.2162308543920517 0.0 +1.1291124820709229 -4.013496398925781 0.2169991433620453 0.0 +1.1827315092086792 -4.014186859130859 0.21780593693256378 0.0 +1.2367585897445679 -4.014881610870361 0.2186518758535385 0.0 +1.2912155389785767 -4.01558256149292 0.21953772008419037 0.0 +1.3461236953735352 -4.016289234161377 0.22046419978141785 0.0 +1.4015058279037476 -4.017002105712891 0.2214321345090866 0.0 +1.457384705543518 -4.017721176147461 0.22244231402873993 0.0 +1.5137845277786255 -4.018447399139404 0.2234957069158554 0.0 +1.5707297325134277 -4.019180774688721 0.22459320724010468 0.0 +1.628245234489441 -4.019920349121094 0.22573573887348175 0.0 +1.686358094215393 -4.0206685066223145 0.22692444920539856 0.0 +1.745094895362854 -4.021423816680908 0.2281603366136551 0.0 +1.8044841289520264 -4.022188186645508 0.22944463789463043 0.0 +1.8645551204681396 -4.022961616516113 0.2307785600423813 0.0 +1.9253379106521606 -4.023744106292725 0.23216335475444794 0.0 +1.986863613128662 -4.0245361328125 0.23360033333301544 0.0 +2.0491654872894287 -4.025338172912598 0.235090970993042 0.0 +2.112276554107666 -4.026149749755859 0.2366366684436798 0.0 +2.1762332916259766 -4.026973247528076 0.2382390797138214 0.0 +2.241072177886963 -4.02780818939209 0.23989984393119812 0.0 +2.306830644607544 -4.028654098510742 0.24162063002586365 0.0 +2.373549699783325 -4.029512405395508 0.24340328574180603 0.0 +2.4412713050842285 -4.030384540557861 0.24524985253810883 0.0 +2.510038375854492 -4.031269550323486 0.24716219305992126 0.0 +2.5798966884613037 -4.032167911529541 0.24914251267910004 0.0 +2.6508946418762207 -4.033082008361816 0.2511930763721466 0.0 +2.7230823040008545 -4.034011363983154 0.2533162832260132 0.0 +2.7965118885040283 -4.034956932067871 0.25551465153694153 0.0 +2.871237277984619 -4.03591775894165 0.25779062509536743 0.0 +2.9473187923431396 -4.0368971824646 0.2601472735404968 0.0 +3.024815559387207 -4.0378947257995605 0.26258742809295654 0.0 +3.103792428970337 -4.038911819458008 0.2651142477989197 0.0 +3.1843152046203613 -4.039947509765625 0.2677308917045593 0.0 +3.266456365585327 -4.041004657745361 0.2704409956932068 0.0 +3.350290536880493 -4.042083740234375 0.27324825525283813 0.0 +3.435896396636963 -4.043185710906982 0.27615654468536377 0.0 +3.5233569145202637 -4.044311046600342 0.2791699767112732 0.0 +3.6127614974975586 -4.045461654663086 0.28229305148124695 0.0 +3.704202890396118 -4.046638488769531 0.2855303883552551 0.0 +3.7977805137634277 -4.0478434562683105 0.28888699412345886 0.0 +3.8935978412628174 -4.049075603485107 0.2923680543899536 0.0 +3.9917688369750977 -4.050339221954346 0.295979380607605 0.0 +4.092411041259766 -4.0516357421875 0.2997269034385681 0.0 +4.195649147033691 -4.052963733673096 0.30361688137054443 0.0 +4.301619529724121 -4.054327964782715 0.30765631794929504 0.0 +4.410463333129883 -4.055728435516357 0.311852365732193 0.0 +4.522334575653076 -4.057168483734131 0.31621289253234863 0.0 +4.637397289276123 -4.058650016784668 0.3207462430000305 0.0 +4.755823612213135 -4.060173511505127 0.3254612684249878 0.0 +4.877803802490234 -4.061744213104248 0.3303677439689636 0.0 +5.003536224365234 -4.063361644744873 0.33547574281692505 0.0 +5.133238315582275 -4.065031051635742 0.34079650044441223 0.0 +5.267141819000244 -4.0667548179626465 0.34634196758270264 0.0 +5.405494689941406 -4.068534851074219 0.35212481021881104 0.0 +5.548570156097412 -4.070376873016357 0.35815921425819397 0.0 +5.696656703948975 -4.072282314300537 0.36445993185043335 0.0 +5.850070953369141 -4.0742573738098145 0.37104347348213196 0.0 +6.009153842926025 -4.076304912567139 0.3779272735118866 0.0 +6.174275875091553 -4.078429698944092 0.38513055443763733 0.0 +6.345842361450195 -4.0806379318237305 0.3926743268966675 0.0 +2.9836435317993164 -0.01833416521549225 0.15529239177703857 0.0 +2.984482526779175 0.01833932101726532 0.15533606708049774 0.0 +2.9853222370147705 0.05503898486495018 0.1554032266139984 0.0 +2.9861626625061035 0.09177594631910324 0.15549394488334656 0.0 +2.987004041671753 0.12856139242649078 0.15560829639434814 0.0 +2.987847328186035 0.16540656983852386 0.15574637055397034 0.0 +2.988691806793213 0.20232272148132324 0.1559082269668579 0.0 +2.989537477493286 0.2393212467432022 0.15609398484230042 0.0 +2.990386724472046 0.27641376852989197 0.15630389750003815 0.0 +2.9912374019622803 0.3136117458343506 0.1565380096435547 0.0 +2.992090940475464 0.35092693567276 0.15679654479026794 0.0 +2.992947578430176 0.3883712887763977 0.15707969665527344 0.0 +2.993807554244995 0.4259568452835083 0.15738770365715027 0.0 +2.9946706295013428 0.4636957347393036 0.15772077441215515 0.0 +2.9955379962921143 0.5016005039215088 0.15807919204235077 0.0 +2.9964089393615723 0.5396835803985596 0.15846320986747742 0.0 +2.997284173965454 0.5779579281806946 0.15887314081192017 0.0 +2.998164653778076 0.616436779499054 0.15930937230587006 0.0 +2.9990499019622803 0.6551333665847778 0.15977217257022858 0.0 +2.9999406337738037 0.6940613389015198 0.16026195883750916 0.0 +3.0008366107940674 0.7332345843315125 0.16077910363674164 0.0 +3.0017385482788086 0.772667407989502 0.16132403910160065 0.0 +3.0026471614837646 0.8123745918273926 0.16189724206924438 0.0 +3.0035619735717773 0.8523709177970886 0.16249912977218628 0.0 +3.004483699798584 0.8926717638969421 0.1631302386522293 0.0 +3.005413055419922 0.9332932233810425 0.16379112005233765 0.0 +3.006349802017212 0.9742512106895447 0.16448231041431427 0.0 +3.0072948932647705 1.015562653541565 0.16520442068576813 0.0 +3.008248805999756 1.057244896888733 0.16595809161663055 0.0 +3.0092105865478516 1.0993152856826782 0.1667439341545105 0.0 +3.0101823806762695 1.14179265499115 0.16756270825862885 0.0 +3.0111641883850098 1.1846957206726074 0.1684151291847229 0.0 +3.012155771255493 1.2280441522598267 0.16930195689201355 0.0 +3.013158082962036 1.2718580961227417 0.17022402584552765 0.0 +3.0396106243133545 1.327266812324524 0.17262692749500275 0.0 +3.090172529220581 1.3948094844818115 0.1764587014913559 0.0 +3.143038511276245 1.465429663658142 0.1804923415184021 0.0 +3.1983864307403564 1.539365291595459 0.1847432553768158 0.0 +6.466622352600098 3.21081805229187 0.3757721185684204 0.0 +6.38853120803833 3.2705187797546387 0.37354183197021484 0.0 +6.311350345611572 3.329523801803589 0.371393620967865 0.0 +6.235040187835693 3.3878626823425293 0.3693253993988037 0.0 +6.139792442321777 3.4345040321350098 0.3661561608314514 0.0 +6.044627666473389 3.4794816970825195 0.3630037307739258 0.0 +5.95107364654541 3.523698329925537 0.35995903611183167 0.0 +5.867958068847656 3.572601556777954 0.35756048560142517 0.0 +5.8066534996032715 3.633833646774292 0.3565194010734558 0.0 +5.654065132141113 3.6357970237731934 0.34986788034439087 0.0 +5.507045745849609 3.6376895904541016 0.34351101517677307 0.0 +5.365251541137695 3.639514207839966 0.33743101358413696 0.0 +5.22836971282959 3.6412761211395264 0.3316117525100708 0.0 +5.096109390258789 3.6429781913757324 0.3260382115840912 0.0 +4.968202114105225 3.6446242332458496 0.32069653272628784 0.0 +4.844400405883789 3.6462178230285645 0.3155740201473236 0.0 +4.724473476409912 3.647761344909668 0.31065869331359863 0.0 +4.608207702636719 3.6492574214935303 0.305939644575119 0.0 +4.4954047203063965 3.6507091522216797 0.3014066815376282 0.0 +4.385879993438721 3.6521191596984863 0.2970503270626068 0.0 +4.279459476470947 3.6534886360168457 0.2928616404533386 0.0 +4.2294840812683105 3.7016441822052 0.29253289103507996 0.0 +4.130249500274658 3.7054128646850586 0.2887973189353943 0.0 +4.030898094177246 3.7066919803619385 0.2850143015384674 0.0 +3.934101104736328 3.707937479019165 0.28137102723121643 0.0 +3.839733600616455 3.7091519832611084 0.2778611481189728 0.0 +3.747677803039551 3.710336923599243 0.2744787335395813 0.0 +3.657823324203491 3.711493968963623 0.2712181806564331 0.0 +3.5700643062591553 3.712622880935669 0.2680741250514984 0.0 +3.484304428100586 3.713726758956909 0.265041708946228 0.0 +3.348081588745117 3.8431196212768555 0.26528218388557434 0.0 +3.308554172515869 3.893336057662964 0.26592153310775757 0.0 +3.2688300609588623 3.943802833557129 0.26660436391830444 0.0 +3.2288947105407715 3.9945363998413086 0.26733115315437317 0.0 +3.196229934692383 4.055063724517822 0.2687326669692993 0.0 +3.1975929737091064 4.160973072052002 0.2731263339519501 0.0 +3.1990013122558594 4.270419120788574 0.27770867943763733 0.0 +3.200458526611328 4.3836188316345215 0.2824908494949341 0.0 +3.2019665241241455 4.500802516937256 0.2874847650527954 0.0 +3.203529119491577 4.622223377227783 0.29270341992378235 0.0 +3.2051491737365723 4.748151779174805 0.2981608510017395 0.0 +3.2680346965789795 4.972001075744629 0.30967193841934204 0.0 +3.2698166370391846 5.110456466674805 0.3157685697078705 0.0 +3.2166733741760254 5.16616678237915 0.3167441785335541 0.0 +3.2122936248779297 5.303293228149414 0.3227066397666931 0.0 +0.24397842586040497 0.7587544918060303 0.04148220643401146 0.0 +0.2280339002609253 0.7402650117874146 0.040315091609954834 0.0 +0.21295960247516632 0.7227842211723328 0.03921758010983467 0.0 +0.1986825317144394 0.7062286734580994 0.03818391636013985 0.0 +0.18513637781143188 0.6905198097229004 0.03720874711871147 0.0 +0.17226330935955048 0.675592303276062 0.03628754988312721 0.0 +0.16001024842262268 0.6613831520080566 0.03541604429483414 0.0 +0.14833013713359833 0.6478381752967834 0.034590497612953186 0.0 +0.13718059659004211 0.6349088549613953 0.033807579427957535 0.0 +0.12652304768562317 0.6225500702857971 0.03306420147418976 0.0 +0.11632268875837326 0.6107218861579895 0.03235762566328049 0.0 +0.10654769837856293 0.5993867516517639 0.03168528899550438 0.0 +0.09716912358999252 0.5885106921195984 0.031044872477650642 0.0 +0.0885431244969368 0.5805707573890686 0.030566316097974777 0.0 +0.0812685489654541 0.5806642770767212 0.03051634691655636 0.0 +0.07401665300130844 0.580757737159729 0.03047114796936512 0.0 +0.06678509712219238 0.5808507204055786 0.030430663377046585 0.0 +0.05957164987921715 0.5809435248374939 0.03039487451314926 0.0 +0.052374064922332764 0.5810361504554749 0.030363749712705612 0.0 +0.04519011452794075 0.5811285376548767 0.0303372610360384 0.0 +0.03801761567592621 0.5812209844589233 0.030315404757857323 0.0 +0.030854357406497 0.5813130736351013 0.0302981436252594 0.0 +0.023698173463344574 0.5814052224159241 0.03028547577559948 0.0 +0.01654689572751522 0.5814973711967468 0.030277397483587265 0.0 +0.00939834862947464 0.5815892815589905 0.030273882672190666 0.0 +0.0022503812797367573 0.5816812515258789 0.030274944379925728 0.0 +-0.004899166990071535 0.5817732810974121 0.0302805807441473 0.0 +-0.012052460573613644 0.5818654298782349 0.03029080107808113 0.0 +-0.01921166107058525 0.5819575190544128 0.030305596068501472 0.0 +-0.026378944516181946 0.5820497870445251 0.030324993655085564 0.0 +-0.033556487411260605 0.5821420550346375 0.030348995700478554 0.0 +-0.040746498852968216 0.5822346806526184 0.030377639457583427 0.0 +-0.047951165586709976 0.5823272466659546 0.030410919338464737 0.0 +-0.05517274886369705 0.5824202299118042 0.03044888749718666 0.0 +-0.06241348385810852 0.5825135111808777 0.03049156256020069 0.0 +-0.06967563927173615 0.5826070308685303 0.030538976192474365 0.0 +-0.07696148008108139 0.5827005505561829 0.030591148883104324 0.0 +-0.08427339792251587 0.5827946662902832 0.03064815141260624 0.0 +-0.0916137546300888 0.5828893184661865 0.030710021033883095 0.0 +-0.09898487478494644 0.5829840898513794 0.03077678568661213 0.0 +-0.10638925433158875 0.5830793976783752 0.030848514288663864 0.0 +-0.11382933706045151 0.5831750631332397 0.03092525526881218 0.0 +-0.12130773067474365 0.5832715034484863 0.03100709244608879 0.0 +-0.12882685661315918 0.583368182182312 0.031094050034880638 0.0 +-0.13638944923877716 0.5834654569625854 0.03118622675538063 0.0 +-0.14399820566177368 0.583563506603241 0.031283698976039886 0.0 +-0.15165580809116364 0.5836620926856995 0.03138653188943863 0.0 +-0.15936505794525146 0.5837612152099609 0.03149481117725372 0.0 +-0.16712884604930878 0.5838609933853149 0.03160862997174263 0.0 +-0.1749502420425415 0.5839618444442749 0.031728096306324005 0.0 +-0.18283207714557648 0.5840631723403931 0.03185328468680382 0.0 +-0.19077759981155396 0.5841654539108276 0.031984321773052216 0.0 +-0.19878995418548584 0.5842685103416443 0.03212130442261696 0.0 +-0.20687244832515717 0.5843724608421326 0.03226436302065849 0.0 +-0.21502859890460968 0.5844775438308716 0.032413631677627563 0.0 +-0.22326168417930603 0.5845833420753479 0.03256920725107193 0.0 +-0.2315755933523178 0.5846905708312988 0.032731276005506516 0.0 +-0.23997379839420319 0.5847985148429871 0.03289994224905968 0.0 +-0.2484603375196457 0.5849077105522156 0.033075377345085144 0.0 +-0.2570391893386841 0.5850180983543396 0.03325774893164635 0.0 +-0.26571449637413025 0.5851297974586487 0.03344722464680672 0.0 +-0.27449050545692444 0.5852426290512085 0.03364397585391998 0.0 +-0.28337183594703674 0.585357129573822 0.03384821116924286 0.0 +-0.2923629581928253 0.5854728817939758 0.03406010940670967 0.0 +-0.3014686107635498 0.5855898261070251 0.034279871731996536 0.0 +-0.31069400906562805 0.585708498954773 0.03450774401426315 0.0 +-0.3200443387031555 0.5858289003372192 0.03474395349621773 0.0 +-0.3295249938964844 0.5859508514404297 0.03498873859643936 0.0 +-0.33914175629615784 0.5860747694969177 0.035242367535829544 0.0 +-0.34890028834342957 0.5862002968788147 0.035505086183547974 0.0 +-0.35880693793296814 0.5863277316093445 0.035777200013399124 0.0 +-0.3688682019710541 0.5864572525024414 0.03605900704860687 0.0 +-0.37909072637557983 0.5865887999534607 0.03635082021355629 0.0 +-0.38948163390159607 0.5867224335670471 0.03665297478437424 0.0 +-0.4000483453273773 0.5868584513664246 0.03696582838892937 0.0 +-0.4107987880706787 0.5869969129562378 0.037289757281541824 0.0 +-0.4217407703399658 0.5871376395225525 0.03762513026595116 0.0 +-0.43288302421569824 0.5872809290885925 0.037972379475831985 0.0 +-0.44423481822013855 0.5874271988868713 0.038331955671310425 0.0 +-0.455805242061615 0.5875760316848755 0.038704294711351395 0.0 +-0.4676045775413513 0.587727963924408 0.03908991068601608 0.0 +-0.4796431362628937 0.5878828763961792 0.03948930278420448 0.0 +-0.49193206429481506 0.5880409479141235 0.039903029799461365 0.0 +-0.504483163356781 0.5882024168968201 0.04033167287707329 0.0 +-0.5173089504241943 0.5883675217628479 0.04077586159110069 0.0 +-0.5304223299026489 0.5885363817214966 0.041236236691474915 0.0 +-0.5438371896743774 0.5887089967727661 0.041713494807481766 0.0 +-0.5575681328773499 0.5888855457305908 0.042208362370729446 0.0 +-0.5716311931610107 0.5890665650367737 0.042721666395664215 0.0 +-0.5860428214073181 0.5892521739006042 0.04325422644615173 0.0 +-0.6008203625679016 0.5894423723220825 0.04380691796541214 0.0 +-0.6159825921058655 0.5896373391151428 0.04438069835305214 0.0 +-0.6315498948097229 0.5898377299308777 0.044976606965065 0.0 +-0.6475432515144348 0.5900434255599976 0.04559570178389549 0.0 +-0.6639857292175293 0.5902552008628845 0.046239178627729416 0.0 +-0.6809014081954956 0.5904728174209595 0.04690824821591377 0.0 +-0.6983165144920349 0.5906969308853149 0.0476042665541172 0.0 +-0.7162589430809021 0.5909278392791748 0.04832865670323372 0.0 +-0.7347587943077087 0.5911659598350525 0.04908296838402748 0.0 +-0.7589793801307678 0.595437228679657 0.05020828917622566 0.0 +-0.7862473130226135 0.6013679504394531 0.051519304513931274 0.0 +-0.8149817585945129 0.6076176166534424 0.052908822894096375 0.0 +-0.8453140258789062 0.6142148971557617 0.05438382178544998 0.0 +-0.8773910999298096 0.6211917400360107 0.05595211684703827 0.0 +-0.9113783240318298 0.6285840272903442 0.057622507214546204 0.0 +-0.9474632740020752 0.6364326477050781 0.05940496549010277 0.0 +-0.985857367515564 0.6447833180427551 0.061310749500989914 0.0 +-1.026802897453308 0.653688907623291 0.06335274130105972 0.0 +-1.0705769062042236 0.6632096767425537 0.0655456930398941 0.0 +-1.1174979209899902 0.6734153032302856 0.06790656596422195 0.0 +-1.1894049644470215 0.6969671249389648 0.07175017148256302 0.0 +-1.3184176683425903 0.7509540915489197 0.07897007465362549 0.0 +-3.863600254058838 2.138205051422119 0.22982902824878693 0.0 +-3.8643877506256104 2.077019453048706 0.22834011912345886 0.0 +-3.8651652336120605 2.0166122913360596 0.22690443694591522 0.0 +-3.8659329414367676 1.9569509029388428 0.2255205363035202 0.0 +-3.8666913509368896 1.8980040550231934 0.22418706119060516 0.0 +-3.867441177368164 1.8397414684295654 0.22290274500846863 0.0 +-3.868182897567749 1.7821341753005981 0.2216663658618927 0.0 +-3.8689160346984863 1.7251536846160889 0.22047671675682068 0.0 +-3.8696417808532715 1.6687731742858887 0.2193327397108078 0.0 +-3.8703598976135254 1.6129662990570068 0.21823333203792572 0.0 +-3.8710711002349854 1.557707667350769 0.21717755496501923 0.0 +-3.8717753887176514 1.502972960472107 0.21616441011428833 0.0 +-3.8724727630615234 1.4487383365631104 0.2151930183172226 0.0 +-3.8731653690338135 1.3949812650680542 0.21426258981227875 0.0 +-3.8738512992858887 1.3416787385940552 0.21337221562862396 0.0 +-3.8745315074920654 1.2888094186782837 0.21252118051052094 0.0 +-3.875206708908081 1.2363523244857788 0.21170876920223236 0.0 +-3.8758764266967773 1.1842868328094482 0.21093425154685974 0.0 +-3.876542091369629 1.1325932741165161 0.2101970613002777 0.0 +-3.877202272415161 1.0812517404556274 0.20949646830558777 0.0 +-3.877859115600586 1.030243992805481 0.2088320255279541 0.0 +-3.878511428833008 0.9795510768890381 0.20820310711860657 0.0 +-3.879160165786743 0.9291549324989319 0.20760923624038696 0.0 +-3.879804849624634 0.8790378570556641 0.2070499062538147 0.0 +-3.880446672439575 0.8291827440261841 0.20652471482753754 0.0 +-3.881085157394409 0.7795723676681519 0.20603321492671967 0.0 +-3.8817203044891357 0.7301900386810303 0.20557498931884766 0.0 +-3.8823533058166504 0.6810195446014404 0.20514975488185883 0.0 +-3.882983446121216 0.6320446729660034 0.20475710928440094 0.0 +-3.8836116790771484 0.583249568939209 0.2043968141078949 0.0 +-3.884237051010132 0.5346184968948364 0.20406849682331085 0.0 +-3.8848612308502197 0.48613613843917847 0.20377199351787567 0.0 +-3.8854830265045166 0.43778711557388306 0.20350702106952667 0.0 +-3.886104106903076 0.3895564377307892 0.20327343046665192 0.0 +-3.886723518371582 0.34142911434173584 0.2030710130929947 0.0 +-3.8873417377471924 0.29339027404785156 0.20289959013462067 0.0 +-3.8879587650299072 0.24542522430419922 0.2027590423822403 0.0 +-3.888575792312622 0.19751936197280884 0.2026493102312088 0.0 +-3.8891918659210205 0.14965809881687164 0.20257025957107544 0.0 +-3.8898072242736816 0.10182693600654602 0.20252183079719543 0.0 +-3.8904225826263428 0.05401141196489334 0.2025040239095688 0.0 +-3.891037702560425 0.006197080481797457 0.20251677930355072 0.0 +-3.8911995887756348 -0.006197338458150625 0.3380846083164215 0.0 +-3.891815662384033 -0.054030753672122955 0.33817028999328613 0.0 +-3.8924312591552734 -0.10189563035964966 0.33830705285072327 0.0 +-3.89304780960083 -0.14980648458003998 0.3384951055049896 0.0 +-3.8936655521392822 -0.1977778971195221 0.33873456716537476 0.0 +-3.8942837715148926 -0.24582448601722717 0.339025616645813 0.0 +-3.8949031829833984 -0.29396095871925354 0.33936840295791626 0.0 +-3.8955237865448 -0.34220215678215027 0.3397632837295532 0.0 +-3.896146535873413 -0.39056313037872314 0.34021055698394775 0.0 +-3.896770715713501 -0.43905889987945557 0.34071052074432373 0.0 +-3.8973965644836426 -0.4877047538757324 0.3412635624408722 0.0 +-3.8980252742767334 -0.5365162491798401 0.34187015891075134 0.0 +-3.898655414581299 -0.5855088829994202 0.3425306975841522 0.0 +-3.8992884159088135 -0.6346986889839172 0.3432457149028778 0.0 +-3.899923801422119 -0.6841017007827759 0.34401580691337585 0.0 +-3.9005630016326904 -0.7337344884872437 0.3448415994644165 0.0 +-3.901204824447632 -0.7836136817932129 0.3457236886024475 0.0 +-3.9018499851226807 -0.8337562084197998 0.3466627597808838 0.0 +-3.9024994373321533 -0.8841797113418579 0.3476596772670746 0.0 +-3.9031519889831543 -0.9349015951156616 0.3487150967121124 0.0 +-3.903809070587158 -0.985940158367157 0.3498299717903137 0.0 +-3.904470205307007 -1.0373139381408691 0.3510051667690277 0.0 +-3.9051358699798584 -1.089041829109192 0.3522416651248932 0.0 +-3.905806064605713 -1.1411432027816772 0.35354045033454895 0.0 +-3.906481981277466 -1.1936384439468384 0.3549027144908905 0.0 +-3.907162666320801 -1.2465475797653198 0.3563295006752014 0.0 +-3.9078495502471924 -1.2998921871185303 0.35782212018966675 0.0 +-3.9085419178009033 -1.3536936044692993 0.359381765127182 0.0 +-3.9092400074005127 -1.407974123954773 0.36100977659225464 0.0 +-3.9099457263946533 -1.4627573490142822 0.3627077639102936 0.0 +-3.9106574058532715 -1.5180665254592896 0.3644770085811615 0.0 +-3.9113759994506836 -1.573926329612732 0.3663191795349121 0.0 +-3.912102460861206 -1.6303625106811523 0.3682360351085663 0.0 +-3.9128365516662598 -1.6874008178710938 0.37022921442985535 0.0 +-3.913578510284424 -1.7450687885284424 0.3723006546497345 0.0 +-3.914329767227173 -1.8033947944641113 0.3744523227214813 0.0 +-3.9150891304016113 -1.8624076843261719 0.376686155796051 0.0 +-3.915858030319214 -1.9221380949020386 0.37900444865226746 0.0 +-3.9166364669799805 -1.9826172590255737 0.3814093768596649 0.0 +-3.9174249172210693 -2.0438780784606934 0.3839033544063568 0.0 +-3.9182238578796387 -2.105954885482788 0.3864889442920685 0.0 +-3.9190335273742676 -2.1688830852508545 0.38916873931884766 0.0 +-3.9198546409606934 -2.2326998710632324 0.39194560050964355 0.0 +-3.9206881523132324 -2.2974436283111572 0.39482244849205017 0.0 +-3.9215335845947266 -2.363154888153076 0.39780232310295105 0.0 +-2.2969624996185303 -3.969407558441162 0.3984593451023102 0.0 +-2.2327661514282227 -3.970233917236328 0.395757794380188 0.0 +-2.1694247722625732 -3.971048593521118 0.39315155148506165 0.0 +-2.106902837753296 -3.971853017807007 0.3906380236148834 0.0 +-2.045166254043579 -3.9726481437683105 0.38821476697921753 0.0 +-1.9841816425323486 -3.973432779312134 0.3858792781829834 0.0 +-1.923917293548584 -3.974208354949951 0.38362929224967957 0.0 +-1.8643425703048706 -3.9749746322631836 0.3814626634120941 0.0 +-1.8054282665252686 -3.9757330417633057 0.3793773651123047 0.0 +-1.7471458911895752 -3.976483106613159 0.3773714303970337 0.0 +-1.6894677877426147 -3.9772250652313232 0.3754429817199707 0.0 +-1.632367491722107 -3.977959632873535 0.37359026074409485 0.0 +-1.575819969177246 -3.9786880016326904 0.37181171774864197 0.0 +-1.5197994709014893 -3.9794085025787354 0.3701055645942688 0.0 +-1.464282512664795 -3.9801230430603027 0.3684704303741455 0.0 +-1.4092457294464111 -3.9808313846588135 0.3669048547744751 0.0 +-1.3546663522720337 -3.9815335273742676 0.36540746688842773 0.0 +-1.3005224466323853 -3.9822301864624023 0.36397698521614075 0.0 +-1.2467930316925049 -3.982922077178955 0.3626122772693634 0.0 +-1.193456768989563 -3.9836084842681885 0.3613120913505554 0.0 +-1.1404937505722046 -3.98429012298584 0.3600753843784332 0.0 +-1.0878840684890747 -3.984966993331909 0.35890111327171326 0.0 +-1.0356084108352661 -3.9856395721435547 0.3577883541584015 0.0 +-0.9836483597755432 -3.9863083362579346 0.3567362129688263 0.0 +-0.9319850206375122 -3.9869730472564697 0.35574376583099365 0.0 +-0.8806007504463196 -3.9876344203948975 0.35481032729148865 0.0 +-0.8294776678085327 -3.988292694091797 0.3539350628852844 0.0 +-0.7785984873771667 -3.9889471530914307 0.3531172573566437 0.0 +-0.7279463410377502 -3.9895992279052734 0.3523564040660858 0.0 +-0.6775043606758118 -3.990248680114746 0.35165178775787354 0.0 +-0.6272559762001038 -3.990894317626953 0.3510027825832367 0.0 +-0.5771853923797607 -3.991539239883423 0.3504091501235962 0.0 +-0.5272762775421143 -3.9921813011169434 0.3498701751232147 0.0 +-0.47751307487487793 -3.9928224086761475 0.34938567876815796 0.0 +-0.42787986993789673 -3.9934608936309814 0.3489550054073334 0.0 +-0.37836146354675293 -3.99409818649292 0.3485780358314514 0.0 +-0.3289424479007721 -3.9947338104248047 0.34825438261032104 0.0 +-0.27960771322250366 -3.9953689575195312 0.3479838967323303 0.0 +-0.2303420901298523 -3.9960029125213623 0.34776628017425537 0.0 +-0.18113064765930176 -3.996636390686035 0.34760141372680664 0.0 +-0.13195838034152985 -3.9972689151763916 0.3474891483783722 0.0 +-0.08281047642230988 -3.9979019165039062 0.34742945432662964 0.0 +-0.0336720272898674 -3.9985337257385254 0.34742215275764465 0.0 +0.015471789985895157 -3.999166965484619 0.34746745228767395 0.0 +0.06463582813739777 -3.9997990131378174 0.3475651443004608 0.0 +0.11383496224880219 -4.000432014465332 0.34771546721458435 0.0 +0.16308413445949554 -4.001066207885742 0.3479185402393341 0.0 +0.21239830553531647 -4.001701354980469 0.34817442297935486 0.0 +0.26179248094558716 -4.002336025238037 0.3484833240509033 0.0 +0.3112819492816925 -4.002973556518555 0.34884557127952576 0.0 +0.36088189482688904 -4.003612041473389 0.3492613732814789 0.0 +0.4106076955795288 -4.004251956939697 0.3497309982776642 0.0 +0.46047496795654297 -4.004893779754639 0.3502548933029175 0.0 +0.5104994177818298 -4.005537509918213 0.3508334159851074 0.0 +0.5606970191001892 -4.006183624267578 0.3514670431613922 0.0 +0.6110838055610657 -4.006831645965576 0.3521561920642853 0.0 +0.661676287651062 -4.007482528686523 0.35290148854255676 0.0 +0.7124910354614258 -4.00813627243042 0.35370346903800964 0.0 +0.763545036315918 -4.008793354034424 0.35456278920173645 0.0 +0.8148555755615234 -4.009454250335693 0.3554801642894745 0.0 +0.8664401173591614 -4.0101189613342285 0.3564562499523163 0.0 +0.9183163046836853 -4.0107855796813965 0.35749176144599915 0.0 +0.9705029726028442 -4.011457443237305 0.35858774185180664 0.0 +1.0230183601379395 -4.0121331214904785 0.3597448766231537 0.0 +1.0758819580078125 -4.012813568115234 0.36096426844596863 0.0 +1.1291130781173706 -4.013498783111572 0.3622468113899231 0.0 +1.182732105255127 -4.01418924331665 0.3635936379432678 0.0 +1.2367594242095947 -4.0148844718933105 0.36500585079193115 0.0 +1.291216254234314 -4.015584945678711 0.3664845824241638 0.0 +1.3461246490478516 -4.016292095184326 0.36803123354911804 0.0 +1.4015065431594849 -4.017004489898682 0.36964699625968933 0.0 +1.457385540008545 -4.017723560333252 0.37133336067199707 0.0 +1.5137852430343628 -4.018449306488037 0.37309178709983826 0.0 +1.5707303285598755 -4.0191826820373535 0.3749238848686218 0.0 +1.6282460689544678 -4.019922256469727 0.37683120369911194 0.0 +1.6863588094711304 -4.020670413970947 0.37881553173065186 0.0 +1.74509596824646 -4.021426200866699 0.380878746509552 0.0 +1.8044854402542114 -4.022191047668457 0.3830227255821228 0.0 +1.8645563125610352 -4.022964000701904 0.38524946570396423 0.0 +1.925338864326477 -4.023746013641357 0.3875611126422882 0.0 +1.9868645668029785 -4.024538040161133 0.3899599313735962 0.0 +2.049166440963745 -4.0253400802612305 0.3924483060836792 0.0 +2.1122777462005615 -4.02615213394165 0.39502865076065063 0.0 +2.176234483718872 -4.026975154876709 0.397703617811203 0.0 +3.487544059753418 -0.36564624309539795 0.3046737015247345 0.0 +3.488100290298462 -0.32241949439048767 0.30435311794281006 0.0 +3.190000534057617 -0.2553688883781433 0.278047651052475 0.0 +3.1490800380706787 -0.21318037807941437 0.27423185110092163 0.0 +3.1092605590820312 -0.17212797701358795 0.2705595791339874 0.0 +3.070488214492798 -0.13215456902980804 0.2670242190361023 0.0 +3.032709836959839 -0.09320652484893799 0.2636193335056305 0.0 +2.995878219604492 -0.05523360148072243 0.26033902168273926 0.0 +2.9836416244506836 -0.018334154039621353 0.25923654437065125 0.0 +2.984480619430542 0.018339309841394424 0.25930944085121155 0.0 +2.9853196144104004 0.0550389364361763 0.2594214975833893 0.0 +2.9861600399017334 0.09177586436271667 0.25957295298576355 0.0 +2.9870011806488037 0.12856125831604004 0.25976380705833435 0.0 +2.9878435134887695 0.16540634632110596 0.2599942088127136 0.0 +2.9886882305145264 0.20232248306274414 0.26026442646980286 0.0 +2.9895341396331787 0.23932099342346191 0.2605745792388916 0.0 +2.990382432937622 0.2764133810997009 0.26092490553855896 0.0 +2.9912333488464355 0.31361132860183716 0.2613157331943512 0.0 +2.992086887359619 0.3509264886379242 0.2617473006248474 0.0 +2.9929428100585938 0.38837066292762756 0.2622199058532715 0.0 +2.993802547454834 0.425956130027771 0.2627340853214264 0.0 +2.99466609954834 0.4636950194835663 0.2632901072502136 0.0 +2.995532512664795 0.5015996098518372 0.2638883590698242 0.0 +2.996403455734253 0.5396826267242432 0.26452940702438354 0.0 +2.997278928756714 0.5779569745063782 0.2652137577533722 0.0 +2.998159170150757 0.616435706615448 0.26594194769859314 0.0 +2.999044179916382 0.6551321148872375 0.26671451330184937 0.0 +2.999933958053589 0.6940598487854004 0.2675320506095886 0.0 +3.0008301734924316 0.7332330346107483 0.2683953642845154 0.0 +3.0017318725585938 0.7726656794548035 0.2693049907684326 0.0 +3.0026400089263916 0.8123726844787598 0.27026182413101196 0.0 +3.0035548210144043 0.8523688912391663 0.2712666094303131 0.0 +3.004476308822632 0.8926695585250854 0.27232009172439575 0.0 +3.0054054260253906 0.9332907795906067 0.27342331409454346 0.0 +3.0063421726226807 0.9742487668991089 0.27457717061042786 0.0 +3.00728702545166 1.0155600309371948 0.27578258514404297 0.0 +3.008239984512329 1.0572417974472046 0.27704066038131714 0.0 +3.009202480316162 1.0993123054504395 0.2783525288105011 0.0 +3.010173797607422 1.141789436340332 0.2797192931175232 0.0 +3.011154890060425 1.184692144393921 0.2811422348022461 0.0 +3.012146234512329 1.228040337562561 0.28262263536453247 0.0 +3.013148307800293 1.271854043006897 0.28416183590888977 0.0 +3.039564371109009 1.3272466659545898 0.28816965222358704 0.0 +3.09012508392334 1.3947880268096924 0.2945660650730133 0.0 +3.1429882049560547 1.4654061794281006 0.3012993037700653 0.0 +3.198333501815796 1.5393399000167847 0.30839529633522034 0.0 +0.24398499727249146 0.7587749361991882 0.06925000995397568 0.0 +0.22804002463817596 0.7402849197387695 0.06730163842439651 0.0 +0.2129652351140976 0.7228032946586609 0.06546943634748459 0.0 +0.1986875832080841 0.7062466740608215 0.06374378502368927 0.0 +0.18514108657836914 0.6905373334884644 0.06211584061384201 0.0 +0.1722673773765564 0.675608217716217 0.06057789921760559 0.0 +0.16001422703266144 0.6613995432853699 0.05912309139966965 0.0 +0.1483338326215744 0.6478543281555176 0.05774494633078575 0.0 +0.13718397915363312 0.6349244713783264 0.05643793195486069 0.0 +0.12652604281902313 0.6225647926330566 0.05519689619541168 0.0 +0.11632535606622696 0.6107358336448669 0.05401730164885521 0.0 +0.10655005276203156 0.5994000434875488 0.05289487540721893 0.0 +0.09717122465372086 0.5885234475135803 0.05182574689388275 0.0 +0.0885440930724144 0.5805771350860596 0.05102631077170372 0.0 +0.08126945048570633 0.5806707143783569 0.05094289779663086 0.0 +0.07401745021343231 0.5807639360427856 0.05086743086576462 0.0 +0.06678584218025208 0.5808572173118591 0.05079986900091171 0.0 +0.05957229807972908 0.5809498429298401 0.05074010789394379 0.0 +0.05237462744116783 0.5810424089431763 0.05068814381957054 0.0 +0.04519060626626015 0.5811349153518677 0.050643935799598694 0.0 +0.03801802545785904 0.5812272429466248 0.05060743913054466 0.0 +0.03085467964410782 0.5813191533088684 0.050578609108924866 0.0 +0.023698419332504272 0.5814112424850464 0.0505574569106102 0.0 +0.01654706709086895 0.5815033912658691 0.05054397135972977 0.0 +0.00939844362437725 0.5815951824188232 0.05053809657692909 0.0 +0.0022504040971398354 0.5816872119903564 0.05053986608982086 0.0 +-0.004899218212813139 0.5817793607711792 0.05054929107427597 0.0 +-0.012052581645548344 0.5818712711334229 0.05056632682681084 0.0 +-0.01921185478568077 0.5819634199142456 0.050591032952070236 0.0 +-0.026379209011793137 0.5820556282997131 0.05062340945005417 0.0 +-0.03355681523680687 0.5821477770805359 0.05066346749663353 0.0 +-0.04074689745903015 0.5822403430938721 0.05071127787232399 0.0 +-0.047951653599739075 0.5823331475257874 0.05076685547828674 0.0 +-0.05517328158020973 0.5824258327484131 0.050830211490392685 0.0 +-0.06241409480571747 0.5825191736221313 0.05090146139264107 0.0 +-0.06967630982398987 0.5826125741004944 0.05098060145974159 0.0 +-0.07696224004030228 0.5827063322067261 0.051067713648080826 0.0 +-0.08427422493696213 0.5828003883361816 0.05116286501288414 0.0 +-0.09161461144685745 0.5828947424888611 0.051266126334667206 0.0 +-0.09898582100868225 0.5829896330833435 0.051377587020397186 0.0 +-0.10639025270938873 0.5830848813056946 0.05149732157588005 0.0 +-0.11383041739463806 0.5831806063652039 0.051625438034534454 0.0 +-0.1213088110089302 0.5832767486572266 0.05176202207803726 0.0 +-0.1288280189037323 0.5833734273910522 0.051907192915678024 0.0 +-0.13639067113399506 0.5834707021713257 0.052061066031455994 0.0 +-0.14399944245815277 0.5835685133934021 0.05222376063466072 0.0 +-0.1516571342945099 0.5836671590805054 0.05239543691277504 0.0 +-0.1593664586544037 0.5837663412094116 0.05257619172334671 0.0 +-0.16713033616542816 0.5838662385940552 0.05276620015501976 0.0 +-0.1749517023563385 0.5839667320251465 0.05296560749411583 0.0 +-0.18283362686634064 0.5840681195259094 0.05317459627985954 0.0 +-0.1907792091369629 0.584170401096344 0.05339334160089493 0.0 +-0.19879163801670074 0.5842734575271606 0.05362201854586601 0.0 +-0.20687425136566162 0.5843774676322937 0.05386084318161011 0.0 +-0.21503035724163055 0.5844823122024536 0.05410999804735184 0.0 +-0.22326356172561646 0.5845882296562195 0.0543697290122509 0.0 +-0.23157744109630585 0.5846952199935913 0.054640255868434906 0.0 +-0.2399757355451584 0.5848032236099243 0.054921820759773254 0.0 +-0.24846237897872925 0.5849125385284424 0.05521470308303833 0.0 +-0.25704121589660645 0.5850227475166321 0.05551912635564804 0.0 +-0.26571667194366455 0.5851345658302307 0.05583544075489044 0.0 +-0.27449271082878113 0.5852473974227905 0.056163884699344635 0.0 +-0.28337404131889343 0.585361659526825 0.056504812091588974 0.0 +-0.2923651933670044 0.585477352142334 0.05685853585600853 0.0 +-0.30147096514701843 0.5855944156646729 0.057225409895181656 0.0 +-0.31069648265838623 0.5857132077217102 0.05760582163929939 0.0 +-0.3200467526912689 0.5858333110809326 0.0580001138150692 0.0 +-0.32952752709388733 0.5859553217887878 0.05840874835848808 0.0 +-0.33914414048194885 0.586078941822052 0.058832112699747086 0.0 +-0.34890294075012207 0.5862047076225281 0.059270717203617096 0.0 +-0.35880956053733826 0.5863320231437683 0.05972495302557945 0.0 +-0.36887088418006897 0.5864615440368652 0.06019539386034012 0.0 +-0.3790934979915619 0.5865930914878845 0.06068253517150879 0.0 +-0.3894844353199005 0.5867266654968262 0.061186932027339935 0.0 +-0.4000512659549713 0.5868626832962036 0.0617091991007328 0.0 +-0.41080164909362793 0.5870010256767273 0.062249936163425446 0.0 +-0.42174363136291504 0.5871416926383972 0.0628097876906395 0.0 +-0.4328860640525818 0.587285041809082 0.06338948011398315 0.0 +-0.44423776865005493 0.5874310731887817 0.06398971378803253 0.0 +-0.45580828189849854 0.5875799655914307 0.0646112859249115 0.0 +-0.4676074981689453 0.5877315998077393 0.06525498628616333 0.0 +-0.4796462655067444 0.5878866910934448 0.06592173874378204 0.0 +-0.49193528294563293 0.5880447626113892 0.06661239266395569 0.0 +-0.5044865012168884 0.5882062315940857 0.06732795387506485 0.0 +-0.5173121690750122 0.5883712768554688 0.0680694431066513 0.0 +-0.530425488948822 0.5885398387908936 0.06883794814348221 0.0 +-0.5438404083251953 0.5887125134468079 0.06963466107845306 0.0 +-0.5575715899467468 0.5888891816139221 0.07046079635620117 0.0 +-0.5716344714164734 0.5890699625015259 0.0713176429271698 0.0 +-0.586046040058136 0.5892553925514221 0.07220665365457535 0.0 +-0.600823700428009 0.5894456505775452 0.07312930375337601 0.0 +-0.6159860491752625 0.5896406173706055 0.07408714294433594 0.0 +-0.6315531730651855 0.5898407697677612 0.07508189976215363 0.0 +-0.647546648979187 0.5900465846061707 0.07611539959907532 0.0 +-0.6639891862869263 0.5902582406997681 0.07718957960605621 0.0 +-0.680904746055603 0.5904757380485535 0.07830647379159927 0.0 +-0.6983199715614319 0.5906998515129089 0.07946837693452835 0.0 +-0.7162623405456543 0.5909306406974792 0.08067762106657028 0.0 +-0.7347622513771057 0.5911687612533569 0.08193683624267578 0.0 +-0.7589824199676514 0.5954395532608032 0.0838153287768364 0.0 +-0.7862505912780762 0.6013704538345337 0.08600389957427979 0.0 +-0.814984917640686 0.6076200008392334 0.08832345902919769 0.0 +-0.8453172445297241 0.6142172813415527 0.09078574925661087 0.0 +-0.8773940801620483 0.6211938858032227 0.09340374916791916 0.0 +-0.9113810062408447 0.6285858154296875 0.09619217365980148 0.0 +-0.9474655389785767 0.6364341378211975 0.09916767477989197 0.0 +-0.9858598709106445 0.6447849273681641 0.10234909504652023 0.0 +-1.0268054008483887 0.6536904573440552 0.10575789213180542 0.0 +-1.0705785751342773 0.6632107496261597 0.1094186007976532 0.0 +-1.117498755455017 0.6734157204627991 0.11335962265729904 0.0 +-1.189400315284729 0.69696444272995 0.11977538466453552 0.0 +-1.3184096813201904 0.750949501991272 0.13182754814624786 0.0 +-3.863614797592163 2.1382131576538086 0.383665531873703 0.0 +-3.864401340484619 2.077026605606079 0.38117995858192444 0.0 +-3.8651788234710693 2.0166192054748535 0.37878331542015076 0.0 +-3.865945816040039 1.956957459449768 0.37647300958633423 0.0 +-3.8667049407958984 1.8980107307434082 0.37424707412719727 0.0 +-3.8674538135528564 1.8397475481033325 0.3721030056476593 0.0 +-3.868194818496704 1.782139778137207 0.3700389862060547 0.0 +-3.8689281940460205 1.7251591682434082 0.36805304884910583 0.0 +-3.8696532249450684 1.6687781810760498 0.36614328622817993 0.0 +-3.870371103286743 1.6129709482192993 0.3643079698085785 0.0 +-3.871081829071045 1.5577120780944824 0.3625454306602478 0.0 +-3.871785879135132 1.5029770135879517 0.3608541190624237 0.0 +-3.872483253479004 1.4487422704696655 0.3592325448989868 0.0 +-3.8731749057769775 1.3949846029281616 0.35767924785614014 0.0 +-3.8738608360290527 1.3416820764541626 0.3561929166316986 0.0 +-3.8745408058166504 1.2888123989105225 0.3547722101211548 0.0 +-3.875215768814087 1.236355185508728 0.35341596603393555 0.0 +-3.875885486602783 1.184289574623108 0.3521230220794678 0.0 +-3.8765501976013184 1.1325955390930176 0.3508923053741455 0.0 +-3.8772106170654297 1.0812541246414185 0.34972280263900757 0.0 +-3.877866744995117 1.0302460193634033 0.34861356019973755 0.0 +-3.878519058227539 0.9795529842376709 0.34756365418434143 0.0 +-3.879167318344116 0.9291567206382751 0.34657225012779236 0.0 +-3.8798115253448486 0.8790394067764282 0.3456384837627411 0.0 +-3.880453109741211 0.8291841149330139 0.3447617292404175 0.0 +-3.881091594696045 0.7795736193656921 0.34394124150276184 0.0 +-3.8817265033721924 0.7301912307739258 0.34317630529403687 0.0 +-3.882359027862549 0.6810205578804016 0.3424663841724396 0.0 +-3.8829894065856934 0.6320456266403198 0.341810941696167 0.0 +-3.8836169242858887 0.5832503437995911 0.34120941162109375 0.0 +-3.884242534637451 0.5346192121505737 0.34066134691238403 0.0 +-3.8848659992218018 0.4861367344856262 0.3401663601398468 0.0 +-3.8854880332946777 0.4377876818180084 0.33972403407096863 0.0 +-3.8861083984375 0.389556884765625 0.33933404088020325 0.0 +-3.886727809906006 0.3414295017719269 0.33899611234664917 0.0 +-3.887345314025879 0.29339054226875305 0.33870989084243774 0.0 +-3.887962579727173 0.24542546272277832 0.3384752869606018 0.0 +-3.8885786533355713 0.19751951098442078 0.33829203248023987 0.0 +-3.8891942501068115 0.149658203125 0.33816003799438477 0.0 +-3.8898098468780518 0.10182700306177139 0.33807921409606934 0.0 +-3.890424966812134 0.05401144549250603 0.33804944157600403 0.0 +-3.891040086746216 0.006197084207087755 0.33807075023651123 0.0 +3.1900007724761963 -0.2553689181804657 0.3902083933353424 0.0 +3.1490793228149414 -0.2131803333759308 0.38485321402549744 0.0 +3.109259843826294 -0.17212793231010437 0.37969961762428284 0.0 +3.0704877376556396 -0.13215455412864685 0.3747381865978241 0.0 +3.0327095985412598 -0.0932065099477768 0.3699597716331482 0.0 +2.995877742767334 -0.05523359403014183 0.3653562664985657 0.0 +2.9836394786834717 -0.01833414100110531 0.36380884051322937 0.0 +2.98447847366333 0.01833929680287838 0.36391112208366394 0.0 +2.9853174686431885 0.05503889545798302 0.3640683889389038 0.0 +2.9869987964630127 0.12856116890907288 0.3645487427711487 0.0 +2.987842082977295 0.1654062718153 0.3648722171783447 0.0 +2.9886860847473145 0.2023223340511322 0.3652513325214386 0.0 +2.989532470703125 0.23932084441184998 0.3656866252422333 0.0 +2.9903807640075684 0.276413232088089 0.3661783039569855 0.0 +2.9912314414978027 0.31361111998558044 0.36672675609588623 0.0 +2.9920849800109863 0.3509262204170227 0.367332398891449 0.0 +2.99294114112854 0.38837045431137085 0.3679957091808319 0.0 +2.993800640106201 0.4259558618068695 0.368717223405838 0.0 +2.994663953781128 0.46369469165802 0.36949753761291504 0.0 +2.995530366897583 0.5015992522239685 0.3703371286392212 0.0 +2.996401786804199 0.5396823287010193 0.3712368309497833 0.0 +2.997277021408081 0.5779566168785095 0.3721972107887268 0.0 +2.998157024383545 0.6164352893829346 0.3732191026210785 0.0 +2.999041795730591 0.6551315784454346 0.37430328130722046 0.0 +2.999932289123535 0.694059431552887 0.3754507005214691 0.0 +3.0008280277252197 0.7332324981689453 0.37666216492652893 0.0 +3.001729965209961 0.77266526222229 0.37793880701065063 0.0 +3.0026378631591797 0.812372088432312 0.37928158044815063 0.0 +3.0035526752471924 0.8523682355880737 0.38069161772727966 0.0 +3.00447416305542 0.8926689624786377 0.3821701109409332 0.0 +3.0054032802581787 0.9332901835441589 0.3837183713912964 0.0 +3.0063395500183105 0.9742478728294373 0.38533756136894226 0.0 +3.007284641265869 1.015559196472168 0.3870292901992798 0.0 +3.008237838745117 1.0572410821914673 0.388794869184494 0.0 +3.00920033454895 1.0993114709854126 0.3906359076499939 0.0 +3.01017165184021 1.1417884826660156 0.39255401492118835 0.0 +3.011152982711792 1.184691309928894 0.39455097913742065 0.0 +3.0121443271636963 1.2280395030975342 0.39662855863571167 0.0 +3.0131466388702393 1.2718532085418701 0.3987886905670166 0.0 +0.24398548901081085 0.7587764859199524 0.09718474000692368 0.0 +0.22804057598114014 0.7402867078781128 0.0944504514336586 0.0 +0.21296575665473938 0.7228050827980042 0.09187915176153183 0.0 +0.19868791103363037 0.7062478065490723 0.08945732563734055 0.0 +0.1851413995027542 0.6905385255813599 0.08717268705368042 0.0 +0.1722678393125534 0.6756100654602051 0.08501444011926651 0.0 +0.16001442074775696 0.6614003777503967 0.08297266066074371 0.0 +0.14833399653434753 0.6478549838066101 0.08103856444358826 0.0 +0.1371840387582779 0.6349247694015503 0.07920427620410919 0.0 +0.12652623653411865 0.622565746307373 0.07746270298957825 0.0 +0.11632553488016129 0.6107367873191833 0.07580727338790894 0.0 +0.10655026137828827 0.5994011759757996 0.07423210144042969 0.0 +0.09717147797346115 0.5885249972343445 0.07273175567388535 0.0 +0.08854416012763977 0.580577552318573 0.07160969078540802 0.0 +0.08126949518918991 0.5806710124015808 0.07149261981248856 0.0 +0.07401750236749649 0.5807644128799438 0.07138672471046448 0.0 +0.06678586453199387 0.5808573961257935 0.07129187881946564 0.0 +0.059572335332632065 0.5809502005577087 0.07120802998542786 0.0 +0.05237464979290962 0.5810426473617554 0.07113509625196457 0.0 +0.04519062489271164 0.5811351537704468 0.07107304781675339 0.0 +0.038018036633729935 0.5812274217605591 0.07102182507514954 0.0 +0.030854707583785057 0.5813196897506714 0.07098140567541122 0.0 +0.023698441684246063 0.5814117789268494 0.07095172256231308 0.0 +0.016547072678804398 0.5815036296844482 0.07093276083469391 0.0 +0.009398449212312698 0.5815955400466919 0.07092452794313431 0.0 +0.002250405726954341 0.5816876292228699 0.07092702388763428 0.0 +-0.004899219144135714 0.5817794799804688 0.07094021141529083 0.0 +-0.012052585370838642 0.581871509552002 0.07096413522958755 0.0 +-0.019211864098906517 0.5819637179374695 0.07099881768226624 0.0 +-0.02637922205030918 0.582055926322937 0.07104425132274628 0.0 +-0.03355684131383896 0.5821481943130493 0.07110048830509186 0.0 +-0.04074692726135254 0.5822408199310303 0.07116758078336716 0.0 +-0.04795167222619057 0.5823333859443665 0.07124555110931396 0.0 +-0.05517331138253212 0.5824261903762817 0.07133448123931885 0.0 +-0.06241411715745926 0.5825194120407104 0.07143445312976837 0.0 +-0.06967633217573166 0.5826128125190735 0.07154551893472672 0.0 +-0.07696226239204407 0.5827065110206604 0.07166776806116104 0.0 +-0.08427425473928452 0.5828006267547607 0.07180130481719971 0.0 +-0.09161464869976044 0.5828949809074402 0.07194621860980988 0.0 +-0.09898588061332703 0.5829899907112122 0.07210266590118408 0.0 +-0.10639029741287231 0.5830850601196289 0.07227068394422531 0.0 +-0.11383046209812164 0.583180844783783 0.07245047390460968 0.0 +-0.12130890041589737 0.58327716588974 0.07264218479394913 0.0 +-0.12882809340953827 0.5833737254142761 0.07284589856863022 0.0 +-0.1363907754421234 0.5834711790084839 0.07306186109781265 0.0 +-0.14399954676628113 0.5835689306259155 0.07329017668962479 0.0 +-0.15165719389915466 0.5836674571037292 0.07353108376264572 0.0 +-0.15936653316020966 0.5837666392326355 0.07378476113080978 0.0 +-0.1671304553747177 0.5838666558265686 0.07405143231153488 0.0 +-0.17495185136795044 0.5839672684669495 0.07433129101991653 0.0 +-0.18283377587795258 0.5840686559677124 0.07462458312511444 0.0 +-0.19077934324741364 0.5841708183288574 0.0749315544962883 0.0 +-0.19879180192947388 0.5842739343643188 0.0752524882555008 0.0 +-0.20687440037727356 0.5843779444694519 0.07558764517307281 0.0 +-0.2150304913520813 0.584482729434967 0.07593730092048645 0.0 +-0.2232637107372284 0.5845886468887329 0.07630180567502975 0.0 +-0.23157759010791779 0.58469557762146 0.07668145000934601 0.0 +-0.2399759292602539 0.5848037004470825 0.07707661390304565 0.0 +-0.2484624981880188 0.5849127769470215 0.07748761028051376 0.0 +-0.25704142451286316 0.5850231647491455 0.07791485637426376 0.0 +-0.2657168209552765 0.5851348638534546 0.07835875451564789 0.0 +-0.27449285984039307 0.5852476954460144 0.07881968468427658 0.0 +-0.283374160528183 0.585361897945404 0.07929812371730804 0.0 +-0.29236531257629395 0.5854775905609131 0.07979454100131989 0.0 +-0.30147117376327515 0.5855948328971863 0.0803094357252121 0.0 +-0.31069663166999817 0.5857135057449341 0.08084327727556229 0.0 +-0.3200470507144928 0.5858338475227356 0.08139665424823761 0.0 +-0.32952776551246643 0.5859557390213013 0.08197011798620224 0.0 +-0.3391444683074951 0.586079478263855 0.08256427943706512 0.0 +-0.34890303015708923 0.5862048864364624 0.08317975699901581 0.0 +-0.3588097393512726 0.5863323211669922 0.0838172435760498 0.0 +-0.3688710629940033 0.5864618420600891 0.08447745442390442 0.0 +-0.37909364700317383 0.5865932703018188 0.08516108989715576 0.0 +-0.3894847333431244 0.5867271423339844 0.08586899191141129 0.0 +-0.4000515043735504 0.5868630409240723 0.08660191297531128 0.0 +-0.41080179810523987 0.5870012640953064 0.08736075460910797 0.0 +-0.4217439293861389 0.5871420502662659 0.08814647048711777 0.0 +-0.43288639187812805 0.5872854590415955 0.08896000683307648 0.0 +-0.4442381262779236 0.5874315500259399 0.08980238437652588 0.0 +-0.4558086395263672 0.5875803828239441 0.09067468345165253 0.0 +-0.46760785579681396 0.5877320766448975 0.09157805144786835 0.0 +-0.47964659333229065 0.5878871083259583 0.09251374751329422 0.0 +-0.4919355809688568 0.5880451202392578 0.09348299354314804 0.0 +-0.5044867396354675 0.5882065296173096 0.09448719024658203 0.0 +-0.5173124670982361 0.5883715748786926 0.09552779048681259 0.0 +-0.5304258465766907 0.588540256023407 0.09660632163286209 0.0 +-0.5438408851623535 0.5887129902839661 0.09772443026304245 0.0 +-0.5575719475746155 0.5888895392417908 0.09888380020856857 0.0 +-0.5716350674629211 0.5890705585479736 0.10008633136749268 0.0 +-0.5860464572906494 0.5892558097839355 0.10133392363786697 0.0 +-0.6008241772651672 0.5894460678100586 0.10262876003980637 0.0 +-0.6159864068031311 0.5896409749984741 0.10397296398878098 0.0 +-0.6315538287162781 0.589841365814209 0.10536903142929077 0.0 +-0.64754718542099 0.5900470614433289 0.10681942105293274 0.0 +-0.6639896631240845 0.5902586579322815 0.10832689702510834 0.0 +-0.6809054017066956 0.5904762744903564 0.10989435762166977 0.0 +-0.6983204483985901 0.5907002687454224 0.11152493208646774 0.0 +-0.716262936592102 0.5909311175346375 0.11322199553251266 0.0 +-0.7347627878189087 0.5911691784858704 0.11498913913965225 0.0 +-0.7589833736419678 0.5954403281211853 0.11762546747922897 0.0 +-0.7862511873245239 0.6013709306716919 0.12069681286811829 0.0 +-0.8149856328964233 0.6076205372810364 0.12395208328962326 0.0 +-0.8453179597854614 0.6142177581787109 0.12740761041641235 0.0 +-0.8773947954177856 0.6211943626403809 0.13108167052268982 0.0 +-0.9113821983337402 0.6285866498947144 0.1349949836730957 0.0 +-0.9474665522575378 0.6364348530769348 0.13917073607444763 0.0 +-0.9858607649803162 0.6447855234146118 0.14363548159599304 0.0 +-1.0268064737319946 0.6536911129951477 0.1484193652868271 0.0 +-1.0705803632736206 0.6632118225097656 0.15355685353279114 0.0 +-1.1175003051757812 0.6734166741371155 0.15908759832382202 0.0 +-1.1894035339355469 0.696966290473938 0.16809162497520447 0.0 +-1.3184125423431396 0.7509511113166809 0.18500542640686035 0.0 +0.24398618936538696 0.7587786316871643 0.12535694241523743 0.0 +0.22804100811481476 0.7402880787849426 0.12182990461587906 0.0 +0.21296624839305878 0.7228067517280579 0.11851329356431961 0.0 +0.19868825376033783 0.7062489986419678 0.11538933962583542 0.0 +0.18514184653759003 0.6905401945114136 0.1124425157904625 0.0 +0.17226815223693848 0.6756112575531006 0.10965856909751892 0.0 +0.16001464426517487 0.6614012718200684 0.10702485591173172 0.0 +0.14833438396453857 0.6478567719459534 0.10453025251626968 0.0 +0.13718438148498535 0.6349263191223145 0.10216420143842697 0.0 +0.12652646005153656 0.622566819190979 0.0999177098274231 0.0 +0.11632578074932098 0.6107380986213684 0.0977824330329895 0.0 +0.10655044764280319 0.5994022488594055 0.09575061500072479 0.0 +0.09717155247926712 0.5885254144668579 0.09381525218486786 0.0 +0.08854421973228455 0.5805779099464417 0.09236791729927063 0.0 +0.08126954734325409 0.5806713700294495 0.09221690893173218 0.0 +0.07401755452156067 0.5807647705078125 0.09208031743764877 0.0 +0.06678590923547745 0.5808578133583069 0.09195798635482788 0.0 +0.05957237631082535 0.5809506177902222 0.09184983372688293 0.0 +0.05237468332052231 0.581043004989624 0.09175574034452438 0.0 +0.04519065096974373 0.5811354517936707 0.09167569875717163 0.0 +0.03801807016134262 0.5812278389930725 0.0916096493601799 0.0 +0.03085472621023655 0.58132004737854 0.09155749529600143 0.0 +0.02369845099747181 0.5814120173454285 0.09151919186115265 0.0 +0.016547083854675293 0.5815039873123169 0.09149475395679474 0.0 +0.009398456662893295 0.5815959572792053 0.09148414433002472 0.0 +0.002250406425446272 0.5816878080368042 0.0914873257279396 0.0 +-0.004899223335087299 0.581779956817627 0.09150438010692596 0.0 +-0.012052596546709538 0.5818719863891602 0.09153524041175842 0.0 +-0.019211871549487114 0.5819639563560486 0.09157993644475937 0.0 +-0.026379233226180077 0.5820561647415161 0.09163854271173477 0.0 +-0.03355685994029045 0.582148551940918 0.09171109646558762 0.0 +-0.04074694961309433 0.5822411179542542 0.09179764240980148 0.0 +-0.04795170575380325 0.5823338031768799 0.09189822524785995 0.0 +-0.055173344910144806 0.5824265480041504 0.092012919485569 0.0 +-0.06241416186094284 0.5825198292732239 0.09214188903570175 0.0 +-0.06967638432979584 0.5826132297515869 0.09228515625 0.0 +-0.07696232944726944 0.5827069878578186 0.09244284778833389 0.0 +-0.0842742919921875 0.5828008651733398 0.09261506050825119 0.0 +-0.091614730656147 0.5828955173492432 0.0928020253777504 0.0 +-0.09898592531681061 0.582990288734436 0.0930037721991539 0.0 +-0.10639037936925888 0.5830855965614319 0.0932205319404602 0.0 +-0.11383054405450821 0.5831812024116516 0.09345243126153946 0.0 +-0.12130895256996155 0.5832774639129639 0.09369968622922897 0.0 +-0.12882818281650543 0.5833741426467896 0.09396247565746307 0.0 +-0.1363908350467682 0.583471417427063 0.09424101561307907 0.0 +-0.1439996212720871 0.5835692286491394 0.09453553706407547 0.0 +-0.15165728330612183 0.5836677551269531 0.09484627097845078 0.0 +-0.15936662256717682 0.5837669372558594 0.09517348557710648 0.0 +-0.16713055968284607 0.5838669538497925 0.09551745653152466 0.0 +-0.1749519258737564 0.5839675068855286 0.09587842971086502 0.0 +-0.18283383548259735 0.5840688347816467 0.09625672549009323 0.0 +-0.1907794177532196 0.5841710567474365 0.09665269404649734 0.0 +-0.19879190623760223 0.5842742323875427 0.09706667810678482 0.0 +-0.20687447488307953 0.5843781232833862 0.09749896824359894 0.0 +-0.21503065526485443 0.5844831466674805 0.09795001894235611 0.0 +-0.22326387465000153 0.5845890641212463 0.09842018783092499 0.0 +-0.23157772421836853 0.5846959352493286 0.0989098772406578 0.0 +-0.23997603356838226 0.5848039388656616 0.09941956400871277 0.0 +-0.24846266210079193 0.5849131941795349 0.09994972497224808 0.0 +-0.2570416033267975 0.5850235819816589 0.10050082951784134 0.0 +-0.2657169699668884 0.585135281085968 0.10107339918613434 0.0 +-0.2744930386543274 0.5852480530738831 0.10166794061660767 0.0 +-0.2833743989467621 0.585362434387207 0.10228510200977325 0.0 +-0.29236552119255066 0.5854780077934265 0.10292540490627289 0.0 +-0.3014713525772095 0.5855951905250549 0.10358952730894089 0.0 +-0.3106968402862549 0.5857138633728027 0.10427813231945038 0.0 +-0.3200472593307495 0.5858342051506042 0.10499192774295807 0.0 +-0.32952794432640076 0.5859560966491699 0.10573161393404007 0.0 +-0.3391447067260742 0.5860798954963684 0.10649802535772324 0.0 +-0.3489033579826355 0.5862054824829102 0.10729194432497025 0.0 +-0.35881009697914124 0.5863329172134399 0.10811422765254974 0.0 +-0.36887142062187195 0.5864623785018921 0.10896581411361694 0.0 +-0.3790939152240753 0.5865936875343323 0.10984760522842407 0.0 +-0.3894849419593811 0.5867274403572083 0.11076068878173828 0.0 +-0.4000517427921295 0.5868633985519409 0.11170608550310135 0.0 +-0.41080212593078613 0.5870017409324646 0.11268492788076401 0.0 +-0.4217442572116852 0.5871425271034241 0.11369839310646057 0.0 +-0.43288663029670715 0.5872858166694641 0.11474773287773132 0.0 +-0.4442383944988251 0.5874319076538086 0.1158342957496643 0.0 +-0.4558088481426239 0.587580680847168 0.11695945262908936 0.0 +-0.467608243227005 0.5877325534820557 0.11812472343444824 0.0 +-0.47964680194854736 0.5878873467445374 0.11933161318302155 0.0 +-0.49193599820137024 0.588045597076416 0.12058187276124954 0.0 +-0.5044872760772705 0.5882071852684021 0.12187720835208893 0.0 +-0.5173128843307495 0.588371992111206 0.12321941554546356 0.0 +-0.5304262638092041 0.5885407328605652 0.12461058795452118 0.0 +-0.5438411831855774 0.5887133479118347 0.12605279684066772 0.0 +-0.5575724244117737 0.588890016078949 0.12754826247692108 0.0 +-0.5716354250907898 0.5890709161758423 0.12909936904907227 0.0 +-0.5860470533370972 0.5892564058303833 0.13070866465568542 0.0 +-0.6008245944976807 0.5894465446472168 0.13237881660461426 0.0 +-0.6159870624542236 0.5896416306495667 0.13411271572113037 0.0 +-0.631554365158081 0.589841902256012 0.13591346144676208 0.0 +-0.647547721862793 0.5900475382804871 0.13778427243232727 0.0 +-0.6639901995658875 0.5902591347694397 0.13972873985767365 0.0 +-0.6809059977531433 0.5904768109321594 0.14175057411193848 0.0 +-0.6983211636543274 0.5907008647918701 0.14385384321212769 0.0 +-0.7162637710571289 0.5909318327903748 0.1460428684949875 0.0 +-0.7347635626792908 0.5911697745323181 0.14832226932048798 0.0 +-0.7589842081069946 0.5954409837722778 0.15172281861305237 0.0 +-0.7862517833709717 0.6013714075088501 0.1556844264268875 0.0 +-0.8149864077568054 0.6076210737228394 0.15988336503505707 0.0 +-0.8453192114830017 0.6142187118530273 0.16434067487716675 0.0 +-0.8773958086967468 0.6211950778961182 0.1690797358751297 0.0 +-0.9113827347755432 0.6285870671272278 0.17412734031677246 0.0 +-0.9474676847457886 0.6364355683326721 0.17951366305351257 0.0 +-0.9858614206314087 0.6447859406471252 0.18527255952358246 0.0 +-1.0268073081970215 0.6536917090415955 0.19144321978092194 0.0 +-1.0705814361572266 0.6632124781608582 0.1980699896812439 0.0 +-1.117501974105835 0.6734176278114319 0.2052040994167328 0.0 +-1.189406156539917 0.6969678997993469 0.21681839227676392 0.0 +-1.3184162378311157 0.750953197479248 0.2386353313922882 0.0 +0.24398669600486755 0.7587801814079285 0.15383818745613098 0.0 +0.22804145514965057 0.7402895092964172 0.14950978755950928 0.0 +0.21296653151512146 0.7228077054023743 0.14543955028057098 0.0 +0.19868877530097961 0.7062508463859558 0.14160601794719696 0.0 +0.18514226377010345 0.6905417442321777 0.1379896104335785 0.0 +0.17226846516132355 0.6756125092506409 0.1345731019973755 0.0 +0.16001494228839874 0.6614025831222534 0.13134102523326874 0.0 +0.14833465218544006 0.6478579044342041 0.12827961146831512 0.0 +0.1371847540140152 0.6349280476570129 0.12537610530853271 0.0 +0.12652677297592163 0.6225683689117432 0.12261918932199478 0.0 +0.11632595211267471 0.61073899269104 0.11999865621328354 0.0 +0.10655049234628677 0.5994024872779846 0.11750508099794388 0.0 +0.09717181324958801 0.5885270237922668 0.11513026803731918 0.0 +0.08854424953460693 0.5805781483650208 0.11335382610559464 0.0 +0.08126960694789886 0.5806717872619629 0.11316855996847153 0.0 +0.07401757687330246 0.5807649493217468 0.11300088465213776 0.0 +0.06678593158721924 0.5808579921722412 0.11285075545310974 0.0 +0.05957239866256714 0.5809508562088013 0.11271803826093674 0.0 +0.05237472802400589 0.581043541431427 0.11260262876749039 0.0 +0.045190680772066116 0.5811358690261841 0.11250437796115875 0.0 +0.03801808878779411 0.5812281370162964 0.11242330819368362 0.0 +0.030854739248752594 0.5813202857971191 0.11235928535461426 0.0 +0.0236984696239233 0.5814124345779419 0.11231233179569244 0.0 +0.016547096893191338 0.5815044045448303 0.11228232830762863 0.0 +0.009398460388183594 0.5815962553024292 0.11226927489042282 0.0 +0.0022504085209220648 0.5816883444786072 0.11227323114871979 0.0 +-0.0048992265947163105 0.5817803740501404 0.11229413747787476 0.0 +-0.012052602134644985 0.581872284412384 0.11233198642730713 0.0 +-0.019211886450648308 0.581964373588562 0.11238686740398407 0.0 +-0.02637924998998642 0.5820565223693848 0.11245877295732498 0.0 +-0.03355688229203224 0.5821489691734314 0.11254781484603882 0.0 +-0.040746960788965225 0.5822412371635437 0.11265397071838379 0.0 +-0.047951724380254745 0.582334041595459 0.11277743428945541 0.0 +-0.055173393338918686 0.5824270248413086 0.11291824281215668 0.0 +-0.062414202839136124 0.5825202465057373 0.11307648569345474 0.0 +-0.06967642158269882 0.5826135873794556 0.11325228214263916 0.0 +-0.07696236670017242 0.5827072262763977 0.11344578862190247 0.0 +-0.08427436649799347 0.582801342010498 0.11365717649459839 0.0 +-0.09161476045846939 0.5828956961631775 0.11388656497001648 0.0 +-0.09898596256971359 0.5829905271530151 0.11413415521383286 0.0 +-0.10639043152332306 0.583085834980011 0.11440016329288483 0.0 +-0.11383061110973358 0.5831815600395203 0.11468476802110672 0.0 +-0.12130900472402573 0.583277702331543 0.11498818546533585 0.0 +-0.1288282573223114 0.5833745002746582 0.11531069874763489 0.0 +-0.13639089465141296 0.5834716558456421 0.11565250158309937 0.0 +-0.14399974048137665 0.5835697054862976 0.11601397395133972 0.0 +-0.15165738761425018 0.5836681723594666 0.11639530211687088 0.0 +-0.15936672687530518 0.583767294883728 0.11679685115814209 0.0 +-0.16713066399097443 0.5838673114776611 0.117218978703022 0.0 +-0.17495207488536835 0.5839679837226868 0.1176619827747345 0.0 +-0.1828339844942093 0.5840693116188049 0.11812622845172882 0.0 +-0.19077952206134796 0.5841713547706604 0.1186121255159378 0.0 +-0.19879205524921417 0.5842747092247009 0.11912018805742264 0.0 +-0.2068745642900467 0.5843784213066101 0.11965066194534302 0.0 +-0.21503080427646637 0.5844835638999939 0.12020422518253326 0.0 +-0.22326397895812988 0.5845893621444702 0.12078117579221725 0.0 +-0.23157790303230286 0.584696352481842 0.12138216197490692 0.0 +-0.2399761974811554 0.584804356098175 0.12200764566659927 0.0 +-0.24846288561820984 0.5849136710166931 0.12265828251838684 0.0 +-0.25704169273376465 0.585023820400238 0.12333453446626663 0.0 +-0.265717089176178 0.5851355195045471 0.12403719872236252 0.0 +-0.2744932472705841 0.5852485299110413 0.12476686388254166 0.0 +-0.28337445855140686 0.5853625535964966 0.12552417814731598 0.0 +-0.292365700006485 0.5854784250259399 0.12631000578403473 0.0 +-0.3014715015888214 0.5855954885482788 0.12712499499320984 0.0 +-0.3106969892978668 0.5857141017913818 0.12797005474567413 0.0 +-0.32004740834236145 0.5858344435691833 0.12884600460529327 0.0 +-0.32952821254730225 0.5859565734863281 0.12975379824638367 0.0 +-0.3391449451446533 0.5860803127288818 0.13069432973861694 0.0 +-0.3489035665988922 0.5862058401107788 0.13166861236095428 0.0 +-0.35881027579307556 0.5863332152366638 0.13267771899700165 0.0 +-0.3688715696334839 0.5864626169204712 0.13372276723384857 0.0 +-0.3790942132472992 0.5865941643714905 0.13480493426322937 0.0 +-0.3894851803779602 0.5867277979850769 0.13592545688152313 0.0 +-0.40005210041999817 0.5868639349937439 0.1370856761932373 0.0 +-0.41080242395401 0.587002158164978 0.13828688859939575 0.0 +-0.42174458503723145 0.5871430039405823 0.13953062891960144 0.0 +-0.43288689851760864 0.5872861742973328 0.14081835746765137 0.0 +-0.44423869252204895 0.587432324886322 0.14215180277824402 0.0 +-0.45580926537513733 0.5875811576843262 0.14353260397911072 0.0 +-0.4676031470298767 0.5877261757850647 0.1449609249830246 0.0 +-0.47964155673980713 0.5878809094429016 0.1464419960975647 0.0 +-0.4919305741786957 0.5880391597747803 0.14797629415988922 0.0 +-0.5044816732406616 0.5882006287574768 0.14956587553024292 0.0 +-0.5173072218894958 0.5883655548095703 0.15121304988861084 0.0 +-0.5304205417633057 0.588534414768219 0.15292030572891235 0.0 +-0.5438351631164551 0.5887068510055542 0.15469011664390564 0.0 +-0.5575664639472961 0.5888836979866028 0.1565253883600235 0.0 +-0.5716291666030884 0.5890644788742065 0.1584288328886032 0.0 +-0.586040735244751 0.5892500877380371 0.160403773188591 0.0 +-0.6008181571960449 0.5894402265548706 0.16245336830615997 0.0 +-0.6159802675247192 0.5896350741386414 0.16458113491535187 0.0 +-0.6315473914146423 0.5898353457450867 0.16679096221923828 0.0 +-0.6475408673286438 0.5900412797927856 0.16908687353134155 0.0 +-0.6639829277992249 0.590252697467804 0.17147304117679596 0.0 +-0.6808985471725464 0.5904703140258789 0.17395423352718353 0.0 +-0.6983135342597961 0.5906943678855896 0.17653530836105347 0.0 +-0.7162559032440186 0.5909253358840942 0.17922165989875793 0.0 +-0.7347556948661804 0.5911634564399719 0.1820189356803894 0.0 +-0.7589738368988037 0.5954328775405884 0.18619149923324585 0.0 +-0.7862419486045837 0.6013638377189636 0.1910533457994461 0.0 +-0.8149760365486145 0.6076133847236633 0.19620616734027863 0.0 +-0.8453078269958496 0.6142103672027588 0.20167595148086548 0.0 +-0.8773844242095947 0.6211870312690735 0.20749174058437347 0.0 +-0.9113712906837463 0.6285791397094727 0.21368615329265594 0.0 +-0.947455108165741 0.6364271640777588 0.2202960103750229 0.0 +-0.9858490824699402 0.6447778940200806 0.22736340761184692 0.0 +-1.026794195175171 0.6536833047866821 0.23493586480617523 0.0 +-1.0705674886703491 0.6632038950920105 0.24306809902191162 0.0 +-1.1174874305725098 0.6734089255332947 0.25182291865348816 0.0 +-1.1893770694732666 0.6969508528709412 0.26607272028923035 0.0 +-1.318382740020752 0.7509341239929199 0.2928455173969269 0.0 +0.24397826194763184 0.7587539553642273 0.18269672989845276 0.0 +0.228033646941185 0.7402641773223877 0.17755642533302307 0.0 +0.2129596322774887 0.7227842807769775 0.1727229505777359 0.0 +0.19868209958076477 0.70622718334198 0.16817009449005127 0.0 +0.18513624370098114 0.6905192732810974 0.16387546062469482 0.0 +0.172263041138649 0.675591230392456 0.15981818735599518 0.0 +0.16001002490520477 0.6613821983337402 0.15597990155220032 0.0 +0.1483299732208252 0.6478374600410461 0.15234406292438507 0.0 +0.13718046247959137 0.6349081993103027 0.14889593422412872 0.0 +0.1265230029821396 0.622549831867218 0.14562204480171204 0.0 +0.11632248759269714 0.6107208132743835 0.14250990748405457 0.0 +0.10654757171869278 0.5993860363960266 0.1395488679409027 0.0 +0.09716904908418655 0.588510274887085 0.1367284059524536 0.0 +0.08854284137487411 0.5805689096450806 0.13462041318416595 0.0 +0.0812683030962944 0.5806624889373779 0.1344003528356552 0.0 +0.07401642203330994 0.580755889415741 0.1342012882232666 0.0 +0.06678488850593567 0.5808489322662354 0.13402298092842102 0.0 +0.059571485966444016 0.580941915512085 0.13386540114879608 0.0 +0.05237390100955963 0.5810343623161316 0.1337282806634903 0.0 +0.0451899878680706 0.5811269283294678 0.13361166417598724 0.0 +0.038017500191926956 0.5812191367149353 0.1335153579711914 0.0 +0.030854273587465286 0.5813115239143372 0.13343939185142517 0.0 +0.0236981064081192 0.5814034938812256 0.13338357210159302 0.0 +0.01654684729874134 0.5814956426620483 0.1333479881286621 0.0 +0.009398317895829678 0.5815874338150024 0.13333247601985931 0.0 +0.002250374061986804 0.5816794633865356 0.13333715498447418 0.0 +-0.004899151157587767 0.5817713737487793 0.13336196541786194 0.0 +-0.012052422389388084 0.5818635821342468 0.13340698182582855 0.0 +-0.019211603328585625 0.5819557905197144 0.13347217440605164 0.0 +-0.02637885883450508 0.5820478796958923 0.13355757296085358 0.0 +-0.033556386828422546 0.582140326499939 0.1336633265018463 0.0 +-0.04074636846780777 0.5822327733039856 0.13378943502902985 0.0 +-0.047951024025678635 0.5823255181312561 0.1339360475540161 0.0 +-0.055172573775053024 0.5824183821678162 0.13410323858261108 0.0 +-0.0624132864177227 0.5825116634368896 0.13429118692874908 0.0 +-0.06967540085315704 0.5826050043106079 0.13449996709823608 0.0 +-0.07696127146482468 0.5826990008354187 0.13472986221313477 0.0 +-0.08427315950393677 0.5827929973602295 0.13498087227344513 0.0 +-0.09161344915628433 0.5828873515129089 0.13525329530239105 0.0 +-0.09898455440998077 0.5829821825027466 0.13554735481739044 0.0 +-0.10638889670372009 0.5830774307250977 0.13586324453353882 0.0 +-0.11382898688316345 0.5831732153892517 0.13620127737522125 0.0 +-0.12130732834339142 0.5832695960998535 0.13656166195869446 0.0 +-0.12882645428180695 0.583366334438324 0.13694466650485992 0.0 +-0.13638898730278015 0.5834634900093079 0.13735060393810272 0.0 +-0.14399772882461548 0.5835615992546082 0.13777990639209747 0.0 +-0.15165527164936066 0.5836600065231323 0.1382327675819397 0.0 +-0.15936455130577087 0.5837593674659729 0.13870969414710999 0.0 +-0.16712833940982819 0.5838592052459717 0.13921098411083221 0.0 +-0.17494963109493256 0.5839598178863525 0.1397370994091034 0.0 +-0.18283145129680634 0.5840612053871155 0.14028845727443695 0.0 +-0.1907769739627838 0.5841635465621948 0.14086559414863586 0.0 +-0.1987893283367157 0.5842666625976562 0.14146891236305237 0.0 +-0.20687179267406464 0.5843705534934998 0.14209896326065063 0.0 +-0.2150278389453888 0.5844755172729492 0.14275631308555603 0.0 +-0.2232610136270523 0.5845815539360046 0.1434415876865387 0.0 +-0.23157477378845215 0.5846884846687317 0.14415529370307922 0.0 +-0.2399730086326599 0.5847965478897095 0.1448981612920761 0.0 +-0.24845950305461884 0.584905743598938 0.1456708163022995 0.0 +-0.25703832507133484 0.585016131401062 0.14647403359413147 0.0 +-0.26571354269981384 0.5851276516914368 0.14730846881866455 0.0 +-0.27448952198028564 0.5852405428886414 0.14817501604557037 0.0 +-0.2833707630634308 0.5853549242019653 0.1490744799375534 0.0 +-0.29236188530921936 0.5854707360267639 0.15000773966312408 0.0 +-0.3014675974845886 0.5855878591537476 0.15097565948963165 0.0 +-0.3106929063796997 0.5857064127922058 0.1519792228937149 0.0 +-0.32004329562187195 0.5858269333839417 0.15301957726478577 0.0 +-0.32952380180358887 0.5859487652778625 0.15409761667251587 0.0 +-0.33914047479629517 0.586072564125061 0.15521462261676788 0.0 +-0.3488990068435669 0.5861981511116028 0.15637171268463135 0.0 +-0.3588056266307831 0.5863255858421326 0.15757015347480774 0.0 +-0.36886686086654663 0.5864551663398743 0.1588113009929657 0.0 +-0.3790893256664276 0.586586594581604 0.16009649634361267 0.0 +-0.3894801437854767 0.5867202281951904 0.16142722964286804 0.0 +-0.4000469148159027 0.5868563055992126 0.16280512511730194 0.0 +-0.410797119140625 0.5869945883750916 0.16423171758651733 0.0 +-0.4217391908168793 0.5871354937553406 0.16570882499217987 0.0 +-0.43288135528564453 0.5872786641120911 0.16723814606666565 0.0 +-0.44423291087150574 0.587424635887146 0.16882172226905823 0.0 +-0.45580339431762695 0.5875736474990845 0.17046162486076355 0.0 +-0.4676026701927185 0.5877255797386169 0.17215994000434875 0.0 +-0.4796411991119385 0.5878804922103882 0.1739189624786377 0.0 +-0.49192991852760315 0.5880383849143982 0.1757410317659378 0.0 +-0.5044810771942139 0.5881999731063843 0.17762890458106995 0.0 +-0.5173065662384033 0.588364839553833 0.17958512902259827 0.0 +-0.5304200649261475 0.5885338187217712 0.1816127598285675 0.0 +-0.5438348650932312 0.5887064337730408 0.18371468782424927 0.0 +-0.5575657486915588 0.5888829827308655 0.1858942061662674 0.0 +-0.5716285705566406 0.589063823223114 0.18815483152866364 0.0 +-0.5860400199890137 0.5892493724822998 0.19050030410289764 0.0 +-0.6008173227310181 0.5894393920898438 0.19293442368507385 0.0 +-0.615979790687561 0.5896346569061279 0.19546155631542206 0.0 +-0.6315467953681946 0.5898348093032837 0.1980859786272049 0.0 +-0.647540271282196 0.5900407433509827 0.2008126676082611 0.0 +-0.6639823913574219 0.5902522206306458 0.20364658534526825 0.0 +-0.680898129940033 0.5904699563980103 0.2065933346748352 0.0 +-0.6983129978179932 0.5906939506530762 0.2096586972475052 0.0 +-0.7162553668022156 0.590924859046936 0.21284906566143036 0.0 +-0.7347549200057983 0.5911628603935242 0.21617116034030914 0.0 +-0.7589729428291321 0.5954321026802063 0.22112657129764557 0.0 +-0.7862405180931091 0.6013627648353577 0.22690051794052124 0.0 +-0.8149745464324951 0.6076122522354126 0.2330201417207718 0.0 +-0.8453063368797302 0.6142093539237976 0.2395162433385849 0.0 +-0.8773828744888306 0.6211858987808228 0.24642322957515717 0.0 +-0.9113694429397583 0.6285778284072876 0.2537798285484314 0.0 +-0.9474536776542664 0.6364262104034424 0.26163002848625183 0.0 +-0.9858468770980835 0.644776463508606 0.27002328634262085 0.0 +-1.0267918109893799 0.6536818146705627 0.27901652455329895 0.0 +-1.0705652236938477 0.6632025241851807 0.28867465257644653 0.0 +-1.1174849271774292 0.6734073758125305 0.29907211661338806 0.0 +-1.1893702745437622 0.6969467997550964 0.3159944713115692 0.0 +-1.3183752298355103 0.7509298920631409 0.34779053926467896 0.0 +0.24397853016853333 0.7587547898292542 0.21202339231967926 0.0 +0.2280336618423462 0.7402642369270325 0.20605777204036713 0.0 +0.2129596322774887 0.7227842807769775 0.2004484087228775 0.0 +0.19868215918540955 0.7062273621559143 0.1951647847890854 0.0 +0.18513618409633636 0.6905190944671631 0.19018065929412842 0.0 +0.17226308584213257 0.6755914092063904 0.18547222018241882 0.0 +0.16001014411449432 0.6613827347755432 0.1810179054737091 0.0 +0.14833012223243713 0.6478381156921387 0.1767984926700592 0.0 +0.13718056678771973 0.6349086761474609 0.172796830534935 0.0 +0.12652303278446198 0.6225499510765076 0.16899728775024414 0.0 +0.11632263660430908 0.6107215881347656 0.16538578271865845 0.0 +0.10654748231172562 0.5993855595588684 0.16194909811019897 0.0 +0.09716905653476715 0.588510274887085 0.15867604315280914 0.0 +0.08854278922080994 0.5805685520172119 0.15622955560684204 0.0 +0.08126824349164963 0.5806621313095093 0.15597417950630188 0.0 +0.07401637732982635 0.5807555913925171 0.15574316680431366 0.0 +0.06678486615419388 0.5808486938476562 0.15553627908229828 0.0 +0.05957143008708954 0.580941379070282 0.15535330772399902 0.0 +0.05237388238310814 0.5810341238975525 0.1551942676305771 0.0 +0.04518995061516762 0.5811264514923096 0.1550588607788086 0.0 +0.03801747411489487 0.5812187790870667 0.15494713187217712 0.0 +0.030854254961013794 0.5813111662864685 0.15485896170139313 0.0 +0.02369808591902256 0.5814030766487122 0.15479415655136108 0.0 +0.016546834260225296 0.5814952254295349 0.15475288033485413 0.0 +0.009398315101861954 0.5815872550010681 0.15473493933677673 0.0 +0.002250372665002942 0.5816790461540222 0.1547403186559677 0.0 +-0.004899149760603905 0.581771194934845 0.154769167304039 0.0 +-0.012052415870130062 0.581863284111023 0.15482138097286224 0.0 +-0.01921158842742443 0.5819553136825562 0.15489698946475983 0.0 +-0.026378843933343887 0.5820475816726685 0.1549961268901825 0.0 +-0.03355636075139046 0.5821398496627808 0.15511880815029144 0.0 +-0.04074634984135628 0.5822325348854065 0.1552652269601822 0.0 +-0.04795099422335625 0.5823251008987427 0.15543532371520996 0.0 +-0.05517255514860153 0.5824182033538818 0.15562941133975983 0.0 +-0.062413256615400314 0.5825113654136658 0.15584751963615417 0.0 +-0.06967537105083466 0.5826047658920288 0.15608982741832733 0.0 +-0.0769612044095993 0.5826984643936157 0.15635652840137482 0.0 +-0.0842730924487114 0.5827925205230713 0.15664786100387573 0.0 +-0.09161340445280075 0.5828871130943298 0.15696407854557037 0.0 +-0.098984494805336 0.5829818248748779 0.1573053002357483 0.0 +-0.1063888743519783 0.5830773115158081 0.1576719582080841 0.0 +-0.11382891982793808 0.5831729173660278 0.15806418657302856 0.0 +-0.12130721658468246 0.5832690596580505 0.1584823727607727 0.0 +-0.12882636487483978 0.5833659768104553 0.15892690420150757 0.0 +-0.13638891279697418 0.583463191986084 0.15939801931381226 0.0 +-0.14399763941764832 0.5835612416267395 0.15989620983600616 0.0 +-0.1516551673412323 0.5836596488952637 0.16042175889015198 0.0 +-0.15936443209648132 0.5837589502334595 0.16097523272037506 0.0 +-0.16712823510169983 0.583858847618103 0.16155700385570526 0.0 +-0.1749495416879654 0.5839595198631287 0.16216757893562317 0.0 +-0.18283134698867798 0.5840608477592468 0.162807434797287 0.0 +-0.19077685475349426 0.5841631889343262 0.16347719728946686 0.0 +-0.19878916442394257 0.584266185760498 0.16417734324932098 0.0 +-0.20687167346477509 0.5843702554702759 0.16490857303142548 0.0 +-0.21502773463726044 0.5844752192497253 0.1656714528799057 0.0 +-0.2232607901096344 0.5845810174942017 0.16646665334701538 0.0 +-0.2315746545791626 0.584688127040863 0.16729499399662018 0.0 +-0.23997284471988678 0.5847961902618408 0.16815708577632904 0.0 +-0.2484593540430069 0.5849053859710693 0.16905377805233002 0.0 +-0.2570381760597229 0.5850157737731934 0.16998590528964996 0.0 +-0.26571333408355713 0.5851272344589233 0.17095428705215454 0.0 +-0.2744893729686737 0.5852402448654175 0.17195995151996613 0.0 +-0.28337058424949646 0.5853545665740967 0.17300379276275635 0.0 +-0.29236164689064026 0.5854702591896057 0.1740868091583252 0.0 +-0.30146726965904236 0.5855872631072998 0.17521007359027863 0.0 +-0.3106927275657654 0.5857061147689819 0.17637480795383453 0.0 +-0.3200429677963257 0.5858263373374939 0.17758207023143768 0.0 +-0.32952359318733215 0.5859483480453491 0.1788332164287567 0.0 +-0.33914026618003845 0.5860722064971924 0.1801295429468155 0.0 +-0.3488987386226654 0.5861976742744446 0.18147233128547668 0.0 +-0.3588053584098816 0.5863251686096191 0.18286314606666565 0.0 +-0.36886659264564514 0.5864547491073608 0.18430353701114655 0.0 +-0.37908902764320374 0.5865861773490906 0.18579500913619995 0.0 +-0.38947993516921997 0.5867199301719666 0.1873393952846527 0.0 +-0.40004658699035645 0.5868558287620544 0.1889384239912033 0.0 +-0.41079673171043396 0.5869939923286438 0.19059397280216217 0.0 +-0.42173874378204346 0.587134838104248 0.19230815768241882 0.0 +-0.43288111686706543 0.5872783064842224 0.1940830647945404 0.0 +-0.4442327320575714 0.5874244570732117 0.1959208846092224 0.0 +-0.45580294728279114 0.5875730514526367 0.1978238970041275 0.0 +-0.4676022231578827 0.5877249836921692 0.19979484379291534 0.0 +-0.4796407222747803 0.5878798961639404 0.2018362134695053 0.0 +-0.49192970991134644 0.5880380868911743 0.20395086705684662 0.0 +-0.5044807195663452 0.5881995558738708 0.20614172518253326 0.0 +-0.5173061490058899 0.5883643627166748 0.20841191709041595 0.0 +-0.530419647693634 0.5885334014892578 0.2107650488615036 0.0 +-0.543834388256073 0.5887059569358826 0.21320435404777527 0.0 +-0.5575652718544006 0.5888825058937073 0.21573373675346375 0.0 +-0.5716280937194824 0.5890634059906006 0.21835723519325256 0.0 +-0.5860394239425659 0.589248776435852 0.22107915580272675 0.0 +-0.6008168458938599 0.5894389152526855 0.2239040583372116 0.0 +-0.6159792542457581 0.589634120464325 0.22683680057525635 0.0 +-0.631546139717102 0.5898342132568359 0.22988247871398926 0.0 +-0.647539496421814 0.5900400876998901 0.23304682970046997 0.0 +-0.6639819145202637 0.5902517437934875 0.23633570969104767 0.0 +-0.8149730563163757 0.6076111793518066 0.2704240083694458 0.0 +-0.8453049659729004 0.6142083406448364 0.27796289324760437 0.0 +-0.8773812055587769 0.621184766292572 0.2859785258769989 0.0 +-0.9113677740097046 0.6285766959190369 0.294515997171402 0.0 +-0.9474517703056335 0.6364248991012573 0.3036262094974518 0.0 +-0.9858450293540955 0.6447752118110657 0.31336677074432373 0.0 +-1.0267897844314575 0.6536805033683777 0.323803573846817 0.0 +-1.0705628395080566 0.6632009744644165 0.33501186966896057 0.0 +-1.1174821853637695 0.6734057664871216 0.3470782935619354 0.0 +-1.189361333847046 0.696941614151001 0.36671510338783264 0.0 diff --git a/open_place_recognition/scripts/read_scan copy.py b/open_place_recognition/scripts/read_scan copy.py new file mode 100644 index 0000000..98c934f --- /dev/null +++ b/open_place_recognition/scripts/read_scan copy.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +import os +import struct + +def main(): + # Path to your scan binary file (adjust as needed) + bin_path = "/home/rover2/Downloads/08_2023-10-11-night/lidar/1697045307522036406.bin" + + # Read the entire binary file. + with open(bin_path, "rb") as f: + data = f.read() + + # Print file size and header (first 16 bytes) + print("File size:", len(data)) + header = data[:16] + print("Header (hex):", header.hex()) + + # Assume the first 16 bytes are header metadata. + # The rest of the file is raw float32 data. + float_data = data[16:] + n_floats = len(float_data) // 4 + print("Number of floats:", n_floats) + + # Unpack the data as little-endian float32 values. + floats = struct.unpack("<" + "f" * n_floats, float_data) + + # Assume each point is represented by 4 floats: x, y, z, intensity (or a placeholder) + points_per_entry = 4 + if n_floats % points_per_entry != 0: + print("Warning: Total float count is not a multiple of", points_per_entry) + n_points = n_floats // points_per_entry + print("Number of points:", n_points) + print("First 10 floats:", floats[:10]) + + # Create an ASCII PCD file from these points. + pcd_filename = "1697045307522036406.pcd" + with open(pcd_filename, "w") as f: + # Write PCD header (version 0.7, ASCII format) + f.write("# .PCD v0.7 - Point Cloud Data file format\n") + f.write("VERSION 0.7\n") + f.write("FIELDS x y z intensity\n") + f.write("SIZE 4 4 4 4\n") + f.write("TYPE F F F F\n") + f.write("COUNT 1 1 1 1\n") + f.write("WIDTH {}\n".format(n_points)) + f.write("HEIGHT 1\n") + f.write("VIEWPOINT 0 0 0 1 0 0 0\n") + f.write("POINTS {}\n".format(n_points)) + f.write("DATA ascii\n") + # Write each point (one per line) + for i in range(n_points): + idx = i * points_per_entry + x, y, z, intensity = floats[idx], floats[idx+1], floats[idx+2], floats[idx+3] + f.write(f"{x} {y} {z} {intensity}\n") + + print("PCD file written:", pcd_filename) + +if __name__ == '__main__': + main() diff --git a/open_place_recognition/scripts/read_scan.py b/open_place_recognition/scripts/read_scan.py new file mode 100644 index 0000000..ab07322 --- /dev/null +++ b/open_place_recognition/scripts/read_scan.py @@ -0,0 +1,83 @@ +import struct + +with open("/home/rover2/Downloads/08_2023-10-11-night/lidar/1697045307522036406.bin", "rb") as f: + data = f.read() + +# Print the first 16 bytes in hex for inspection. +print("Header (hex):", data[:16].hex()) + +# Try interpreting the first 4 bytes as little-endian integer. +try: + count_le = struct.unpack('i', data[:4])[0] + print("Big-endian count:", count_be) +except Exception as e: + print("Error unpacking as big-endian integer:", e) + + +import zlib +import struct + +# Open the binary scan file. +with open("/home/rover2/.ros/opr_dataset/my_map/scan/node_1_9_scan.bin", "rb") as f: + data = f.read() + +print("Compressed file size:", len(data)) +print("Header (hex):", data[:16].hex()) + +# Decompress using zlib. +try: + decompressed = zlib.decompress(data) +except Exception as e: + print("Decompression failed:", e) + exit(1) + +print("Decompressed data size:", len(decompressed)) + +# (Optional) Interpret the decompressed data as a sequence of float32 values. +# Note: The internal format of scan data is defined by RTAB-Map. +n_floats = len(decompressed) // 4 # Number of 4-byte floats. +try: + floats = struct.unpack("f" * n_floats, decompressed) + print("First 10 floats:", floats[:10]) +except Exception as e: + print("Error unpacking floats:", e) + + +# Interpret the decompressed data as 32-bit floats. +n_floats = len(decompressed) // 4 +floats = struct.unpack("f" * n_floats, decompressed) + +# Assume each point consists of 4 floats: x, y, z, intensity (or a placeholder) +n_points = n_floats // 4 +print("Number of points:", n_points) +print("First 10 floats:", floats[:10]) + +# Create a PCD file (ASCII format) +pcd_filename = "node_1_9_scan.pcd" +with open(pcd_filename, "w") as f: + # Write the header for an ASCII PCD file. + f.write("# .PCD v0.7 - Point Cloud Data file format\n") + f.write("VERSION 0.7\n") + f.write("FIELDS x y z intensity\n") + f.write("SIZE 4 4 4 4\n") + f.write("TYPE F F F F\n") + f.write("COUNT 1 1 1 1\n") + f.write("WIDTH {}\n".format(n_points)) + f.write("HEIGHT 1\n") + f.write("VIEWPOINT 0 0 0 1 0 0 0\n") + f.write("POINTS {}\n".format(n_points)) + f.write("DATA ascii\n") + # Write each point. + for i in range(n_points): + idx = i * 4 + x, y, z, intensity = floats[idx], floats[idx+1], floats[idx+2], floats[idx+3] + f.write(f"{x} {y} {z} {intensity}\n") + +print("PCD file written:", pcd_filename) diff --git a/open_place_recognition/src/dataset_from_rosbag_node.py b/open_place_recognition/src/dataset_from_rosbag_node.py new file mode 100755 index 0000000..5f49f4c --- /dev/null +++ b/open_place_recognition/src/dataset_from_rosbag_node.py @@ -0,0 +1,314 @@ +#!/usr/bin/env python3 + +import rclpy +from rclpy.node import Node +from rclpy.time import Time + +# Messages we’ll be subscribing to: +from sensor_msgs.msg import Image, LaserScan # or PointCloud2 +from geometry_msgs.msg import PoseStamped + +# For writing images: +import os +import cv2 +import numpy as np + +import math +import struct + +def euler_to_quaternion(roll, pitch, yaw): + """ + Convert Euler angles (roll, pitch, yaw) to quaternion (qx, qy, qz, qw). + Assuming roll = x-rotation, pitch = y-rotation, yaw = z-rotation. + """ + cy = math.cos(yaw * 0.5) + sy = math.sin(yaw * 0.5) + cp = math.cos(pitch * 0.5) + sp = math.sin(pitch * 0.5) + cr = math.cos(roll * 0.5) + sr = math.sin(roll * 0.5) + + qw = cr * cp * cy + sr * sp * sy + qx = sr * cp * cy - cr * sp * sy + qy = cr * sp * cy + sr * cp * sy + qz = cr * cp * sy - sr * sp * cy + return (qx, qy, qz, qw) + +class DatasetCreateNode(Node): + """ + This node subscribes to front camera, back camera, lidar, and pose topics + and builds a dataset in a specified output directory. + + The user can configure the following ROS parameters: + - front_camera_topic (default: /camera_front/image_raw) + - back_camera_topic (default: /camera_back/image_raw) + - lidar_topic (default: /scan) + - pose_topic (default: /robot_pose) + - output_path (default: ~/.ros/opr_dataset) + - track_name (default: 00_my_map) + + For each message received, the node: + - Decodes images and writes them to disk. + - Buffers topic timestamps and relevant data in memory. + - On shutdown, writes out a CSV describing all data. + + NOTE: This example is not time-synchronizing the topics. + Each message will appear in the CSV under its own stamp entry. + """ + def __init__(self): + super().__init__('dataset_create_node') + + # Declare parameters + self.declare_parameter('front_camera_topic', '/camera_front/image_raw') + self.declare_parameter('back_camera_topic', '/camera_back/image_raw') + self.declare_parameter('lidar_topic', '/scan') + self.declare_parameter('pose_topic', '/robot_pose') + self.declare_parameter('output_path', '~/.ros/opr_dataset') + self.declare_parameter('track_name', '00_my_map') + + # Retrieve parameter values + self.front_cam_topic = self.get_parameter('front_camera_topic').value + self.back_cam_topic = self.get_parameter('back_camera_topic').value + self.lidar_topic = self.get_parameter('lidar_topic').value + self.pose_topic = self.get_parameter('pose_topic').value + self.output_path = os.path.expanduser(self.get_parameter('output_path').value) + self.track_name = self.get_parameter('track_name').value + + # Prepare output directories + self.images_dir = os.path.join(self.output_path, "images") + os.makedirs(self.images_dir, exist_ok=True) + self.csv_path = os.path.join(self.output_path, "tracker.csv") + + # Data storage: dictionary keyed by stamp (float) + # We store a subdict with e.g.: + # { 'front_cam_ts': stamp_if_front_camera, + # 'back_cam_ts': stamp_if_back_camera, + # 'lidar_ts': stamp_if_lidar, + # 'pose_stamp': stamp_if_pose, + # 'x': ..., + # 'y': ..., + # 'z': ..., + # 'qx': ..., + # 'qy': ..., + # 'qz': ..., + # 'qw': ... } + # + # In practice, you may want more sophisticated time alignment or + # separate dictionaries for each topic, etc. + self.data = {} + + # Subscriptions + self.sub_front_cam = self.create_subscription( + Image, + self.front_cam_topic, + self.front_camera_callback, + 10 + ) + self.sub_back_cam = self.create_subscription( + Image, + self.back_cam_topic, + self.back_camera_callback, + 10 + ) + self.sub_lidar = self.create_subscription( + LaserScan, + self.lidar_topic, + self.lidar_callback, + 10 + ) + self.sub_pose = self.create_subscription( + PoseStamped, + self.pose_callback, + 10 + ) + + self.get_logger().info("DatasetCreateNode started. Listening to topics:") + self.get_logger().info(f" front_camera_topic: {self.front_cam_topic}") + self.get_logger().info(f" back_camera_topic: {self.back_cam_topic}") + self.get_logger().info(f" lidar_topic: {self.lidar_topic}") + self.get_logger().info(f" pose_topic: {self.pose_topic}") + self.get_logger().info(f"Writing results to: {self.output_path}") + + def _to_float_stamp(self, stamp_msg): + """ + Convert a builtin_interfaces.msg.Time or ROS2 stamp to a float of seconds. + """ + return float(stamp_msg.sec) + 1e-9 * float(stamp_msg.nanosec) + + def _ensure_entry(self, t: float): + """ + Ensure our data dictionary has an entry for this time. + Returns the subdict for that time. + """ + if t not in self.data: + self.data[t] = { + "front_cam_ts": 0, + "back_cam_ts": 0, + "lidar_ts": 0, + # We'll store the pose separately: + "pose_ts": 0, + "tx": 0.0, + "ty": 0.0, + "tz": 0.0, + "qx": 0.0, + "qy": 0.0, + "qz": 0.0, + "qw": 1.0 + } + return self.data[t] + + def front_camera_callback(self, msg: Image): + """ + Front camera image callback. + Write out the image to file, store timestamp in our dictionary. + """ + stamp_float = self._to_float_stamp(msg.header.stamp) + entry = self._ensure_entry(stamp_float) + + # Mark that we have a front camera image at this time + entry["front_cam_ts"] = stamp_float + + # Decode the image if it's something like raw or compressed: + # We'll assume it's an 8UC3 (BGR) or 8UC1 for demonstration. + # The encoding can vary (e.g. 'bgr8', 'rgb8', 'mono8', etc.). + # We demonstrate a simple approach with OpenCV. + try: + # Convert ROS Image (raw bytes) to a NumPy array + dtype = np.uint8 + channels = 3 + if msg.encoding == 'mono8': + channels = 1 + # Construct a 2D array from the raw data + img_np = np.frombuffer(msg.data, dtype=dtype).reshape(msg.height, msg.width, channels) + + # If needed to convert from RGB->BGR or vice versa + # depending on the encoding. Here we assume it's already BGR. + # If it was 'rgb8', you might do: img_np = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR) + + # Write to disk + out_name = f"front_{stamp_float:.6f}.png" + out_path = os.path.join(self.images_dir, out_name) + cv2.imwrite(out_path, img_np) + except Exception as e: + self.get_logger().warn(f"Front camera image decode failed at stamp {stamp_float}: {e}") + + def back_camera_callback(self, msg: Image): + """ + Back camera image callback. + """ + stamp_float = self._to_float_stamp(msg.header.stamp) + entry = self._ensure_entry(stamp_float) + entry["back_cam_ts"] = stamp_float + + try: + dtype = np.uint8 + channels = 3 + if msg.encoding == 'mono8': + channels = 1 + img_np = np.frombuffer(msg.data, dtype=dtype).reshape(msg.height, msg.width, channels) + + out_name = f"back_{stamp_float:.6f}.png" + out_path = os.path.join(self.images_dir, out_name) + cv2.imwrite(out_path, img_np) + except Exception as e: + self.get_logger().warn(f"Back camera image decode failed at stamp {stamp_float}: {e}") + + def lidar_callback(self, msg: LaserScan): + """ + Example LIDAR callback. We only store the timestamp here. + If needed, you could also dump the data (ranges, intensities) to disk. + """ + stamp_float = self._to_float_stamp(msg.header.stamp) + entry = self._ensure_entry(stamp_float) + entry["lidar_ts"] = stamp_float + # If you want to save the entire scan, you might do so here. + # E.g., out_name = f"lidar_{stamp_float:.6f}.txt" or .csv + # For demonstration, we only store the timestamp in memory. + + def pose_callback(self, msg: PoseStamped): + """ + Pose callback. We'll store the pose in our dictionary. + """ + stamp_float = self._to_float_stamp(msg.header.stamp) + entry = self._ensure_entry(stamp_float) + entry["pose_ts"] = stamp_float + + # Extract position + px = msg.pose.position.x + py = msg.pose.position.y + pz = msg.pose.position.z + + # Extract orientation + qx = msg.pose.orientation.x + qy = msg.pose.orientation.y + qz = msg.pose.orientation.z + qw = msg.pose.orientation.w + + entry["tx"] = px + entry["ty"] = py + entry["tz"] = pz + entry["qx"] = qx + entry["qy"] = qy + entry["qz"] = qz + entry["qw"] = qw + + def write_csv(self): + """ + Write out a CSV of all the data we've collected. + """ + self.get_logger().info(f"Writing CSV to: {self.csv_path}") + + with open(self.csv_path, 'w') as f: + f.write("track,floor,timestamp,front_cam_ts,back_cam_ts,lidar_ts,tx,ty,tz,qx,qy,qz,qw\n") + + # We do not have a 'floor' concept in this example, so let's store '0' or something static. + floor_id = 0 + + # Sort all entries by the earliest stamp + sorted_stamps = sorted(self.data.keys()) + for t in sorted_stamps: + row = self.data[t] + # We'll store 't' as the primary timestamp + # front_cam_ts, back_cam_ts, etc. are in row + front_cam_ts = row["front_cam_ts"] + back_cam_ts = row["back_cam_ts"] + lidar_ts = row["lidar_ts"] + tx = row["tx"] + ty = row["ty"] + tz = row["tz"] + qx = row["qx"] + qy = row["qy"] + qz = row["qz"] + qw = row["qw"] + + csv_line = ( + f"{self.track_name},{floor_id},{t:.6f}," + f"{front_cam_ts:.6f},{back_cam_ts:.6f},{lidar_ts:.6f}," + f"{tx:.6f},{ty:.6f},{tz:.6f}," + f"{qx:.6f},{qy:.6f},{qz:.6f},{qw:.6f}\n" + ) + f.write(csv_line) + + def destroy_node(self): + """ + Override destroy_node to write out the CSV before shutting down. + """ + self.write_csv() + super().destroy_node() + + +def main(args=None): + rclpy.init(args=args) + node = DatasetCreateNode() + + try: + rclpy.spin(node) + except KeyboardInterrupt: + pass + finally: + node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/open_place_recognition/src/dataset_from_rtabmap_node.py b/open_place_recognition/src/dataset_from_rtabmap_node.py new file mode 100755 index 0000000..b2e913f --- /dev/null +++ b/open_place_recognition/src/dataset_from_rtabmap_node.py @@ -0,0 +1,274 @@ +#!/usr/bin/env python3 +import rclpy +from rclpy.node import Node +import os +import sys +from ament_index_python.packages import get_package_share_directory +import time +import sqlite3 +import struct +import math + +# If needed for image decoding: +try: + import cv2 + import numpy as np + OPENCV_AVAILABLE = True +except ImportError: + OPENCV_AVAILABLE = False + + +def euler_to_quaternion(roll, pitch, yaw): + """ + Convert Euler angles (roll, pitch, yaw) to quaternion (qx, qy, qz, qw). + Assuming roll = x-rotation, pitch = y-rotation, yaw = z-rotation. + """ + cy = math.cos(yaw * 0.5) + sy = math.sin(yaw * 0.5) + cp = math.cos(pitch * 0.5) + sp = math.sin(pitch * 0.5) + cr = math.cos(roll * 0.5) + sr = math.sin(roll * 0.5) + + qw = cr * cp * cy + sr * sp * sy + qx = sr * cp * cy - cr * sp * sy + qy = cr * sp * cy + sr * cp * sy + qz = cr * cp * sy - sr * sp * cy + return (qx, qy, qz, qw) + + +class DatasetCreateNode(Node): + def __init__(self): + super().__init__('dataset_create_node') + self.declare_parameter('map_name', 'my_map') + self.declare_parameter('input_path', '~/Sync/map') + self.declare_parameter('output_path', '~/.ros/opr_dataset') + + map_name = self.get_parameter('map_name').value + output_path = self.get_parameter('output_path').value + dataset_dir = os.path.join(os.path.expanduser(self.get_parameter('input_path').value), map_name) + share_directory = self.get_parameter('use_share_directory').value + if not os.path.exists(dataset_dir): + self.get_logger().error(f"Databse directory {dataset_dir} not found.") + sys.exit(1) + + # Actually create the dataset + if not self.create_dataset(dataset_dir, map_name, output_path): + self.get_logger().error(f"Error creating dataset for map {map_name}") + sys.exit(1) + + def create_dataset(self, dataset_dir: str, map_name: str, output_path: str): + """ + Main routine to: + 1. Connect to the RTAB-Map database + 2. Extract node poses, camera timestamps, LIDAR timestamps, etc. + 3. Write them to a CSV + 4. Extract images from the DB + """ + self.get_logger().info(f"[CREATE] Creating dataset for map '{map_name}' at '{dataset_dir}' ...") + + # The RTAB-Map database file + rtabmap_db = os.path.join(dataset_dir, f"{map_name}.db") + + if not os.path.exists(rtabmap_db): + self.get_logger().error(f"RTAB-Map DB '{rtabmap_db}' does not exist!") + return False + + # Prepare output directories + dataset_path = os.path.join(os.path.expanduser(output_path), map_name) + if not os.path.exists(dataset_path): + os.makedirs(dataset_path) + + csv_path = os.path.join(dataset_path, "tracker.csv") + images_dir = os.path.join(dataset_path, "images") + if not os.path.exists(images_dir): + os.makedirs(images_dir) + + # -------------------- + # Extract data from DB + # -------------------- + try: + # Connect to the .db + conn = sqlite3.connect(rtabmap_db) + c = conn.cursor() + + # 1) Gather Node info (id, mapId, stamp, pose, etc.) + # + # Typically the Nodes table might be called "Node" or "Nodes". + # The columns often are something like: + # - id (PRIMARY KEY) + # - mapId + # - stamp + # - pose (BLOB) + # - ground_truth_pose (BLOB) + # - ... + # + # Adjust to match your DB schema. + c.execute("SELECT id, mapId, stamp, pose FROM Node ORDER BY stamp ASC") + node_rows = c.fetchall() + + # We will store aggregated info in a dict keyed by node_id + # so we can combine cameras, lidar, pose, etc. + node_dict = {} + for (node_id, map_id, stamp, pose_blob) in node_rows: + # Convert stamp from float to int (or keep as float, depending on your usage) + # Some DBs store stamps in seconds, others in nanoseconds, etc. + # For demonstration, let's keep them as is, or cast to int if you prefer: + timestamp = int(stamp) + + # Decode the pose (you may need '6f', '7f', '6d', '7d', etc.): + # Example: x, y, z, roll, pitch, yaw = struct.unpack('6f', pose_blob) + # or x, y, z, qx, qy, qz, qw = struct.unpack('7f', pose_blob) + # Adapt to your exact RTAB-Map version! + + x = y = z = 0.0 + qx = qy = qz = qw = 0.0 + + # Example assume 6 floats [x, y, z, roll, pitch, yaw] + try: + x, y, z, roll, pitch, yaw = struct.unpack('6f', pose_blob) + qx, qy, qz, qw = euler_to_quaternion(roll, pitch, yaw) + except: + # Fallback if your DB actually stores x,y,z,qx,qy,qz,qw + x, y, z, qx, qy, qz, qw = struct.unpack('7f', pose_blob) + + node_dict[node_id] = { + "floor": map_id, + "timestamp": timestamp, # This will be the 'primary' or 'node' timestamp + "front_cam_ts": None, + "back_cam_ts": None, + "lidar_ts": None, + "tx": x, + "ty": y, + "tz": z, + "qx": qx, + "qy": qy, + "qz": qz, + "qw": qw + } + + # 2) Gather camera images (front, back) by node + # + # Typically in the "Images" table: + # - image_id + # - node_id + # - data (BLOB) + # - stamp + # - camera_id + # - ... + # + # Adjust to match your DB schema (and camera numbering). + # We'll guess camera_id=0 => front, camera_id=1 => back. + try: + c.execute("SELECT image_id, node_id, stamp, camera_id, data FROM Images") + image_rows = c.fetchall() + for (img_id, node_id, img_stamp, cam_id, img_blob) in image_rows: + # Convert image_stamp to int if needed + img_ts = int(img_stamp) + + if node_id not in node_dict: + # This might be a node not in the Node table, skip + continue + + # Save the camera stamp in our dictionary + if cam_id == 0: + node_dict[node_id]["front_cam_ts"] = img_ts + elif cam_id == 1: + node_dict[node_id]["back_cam_ts"] = img_ts + + # Optionally decode and save the image + if OPENCV_AVAILABLE: + np_arr = np.frombuffer(img_blob, np.uint8) + img_decoded = cv2.imdecode(np_arr, cv2.IMREAD_COLOR) + if img_decoded is not None: + out_name = f"node_{node_id}_cam_{cam_id}_{img_ts}.jpg" + out_path = os.path.join(images_dir, out_name) + cv2.imwrite(out_path, img_decoded) + else: + # If you can't decode, but the data is e.g. raw JPEG, + # you could just write the BLOB directly to file: + # with open(os.path.join(images_dir, f"node_{node_id}_cam_{cam_id}.jpg"), 'wb') as img_file: + # img_file.write(img_blob) + pass + except sqlite3.OperationalError: + # Possibly no Images table + self.get_logger().warn("No Images table found or query failed. Skipping camera extraction.") + + # 3) Gather LIDAR scans by node (if stored), stamp, etc. + # Typical table might be "LaserScans" with columns: + # - id + # - node_id + # - stamp + # - scan (BLOB) + # ... + try: + c.execute("SELECT node_id, stamp FROM LaserScans") + lidar_rows = c.fetchall() + for (node_id, scan_stamp) in lidar_rows: + if node_id not in node_dict: + continue + node_dict[node_id]["lidar_ts"] = int(scan_stamp) + except sqlite3.OperationalError: + # Possibly no LaserScans table + self.get_logger().warn("No LaserScans table found or query failed. Skipping lidar extraction.") + + conn.close() + + except Exception as e: + self.get_logger().error(f"Error reading RTAB-Map DB: {e}") + return False + + # -------------------- + # Write out the CSV + # -------------------- + self.get_logger().info(f"Writing CSV file: {csv_path}") + with open(csv_path, 'w') as f: + # Header + f.write("track,floor,timestamp,front_cam_ts,back_cam_ts,lidar_ts,tx,ty,tz,qx,qy,qz,qw\n") + + # For your sample, track could be "00_", or directly map_name, etc. + # Just adapt to your usage: + track_name = f"00_{map_name}" + + # We'll iterate in ascending node timestamp order: + sorted_nodes = sorted(node_dict.values(), key=lambda x: x["timestamp"]) + for row in sorted_nodes: + floor = row["floor"] + timestamp = row["timestamp"] + front_cam_ts = row["front_cam_ts"] if row["front_cam_ts"] else 0 + back_cam_ts = row["back_cam_ts"] if row["back_cam_ts"] else 0 + lidar_ts = row["lidar_ts"] if row["lidar_ts"] else 0 + tx, ty, tz = row["tx"], row["ty"], row["tz"] + qx, qy, qz, qw = row["qx"], row["qy"], row["qz"], row["qw"] + + csv_line = ( + f"{track_name}," + f"{floor}," + f"{timestamp}," + f"{front_cam_ts}," + f"{back_cam_ts}," + f"{lidar_ts}," + f"{tx}," + f"{ty}," + f"{tz}," + f"{qx}," + f"{qy}," + f"{qz}," + f"{qw}\n" + ) + f.write(csv_line) + + self.get_logger().info("[CREATE] Dataset creation completed.") + return True + + +def main(args=None): + rclpy.init(args=args) + node = DatasetCreateNode() + # Spin briefly to process log messages + rclpy.spin_once(node, timeout_sec=1) + node.destroy_node() + rclpy.shutdown() + +if __name__ == '__main__': + main() diff --git a/open_place_recognition/src/dataset_publisher_node.py b/open_place_recognition/src/dataset_publisher_node.py new file mode 100755 index 0000000..476e7de --- /dev/null +++ b/open_place_recognition/src/dataset_publisher_node.py @@ -0,0 +1,372 @@ +#!/usr/bin/env python3 + +import os +import sys +import time +import yaml +import numpy as np +import pandas as pd +import cv2 + +import rclpy +from rclpy.node import Node +from rcl_interfaces.msg import ParameterDescriptor +from std_msgs.msg import Header +from sensor_msgs.msg import CompressedImage, Image, PointCloud2, CameraInfo, NavSatFix +from cv_bridge import CvBridge +from sensor_msgs_py import point_cloud2 +import tf2_ros +from geometry_msgs.msg import TransformStamped +from ament_index_python.packages import get_package_share_directory + +class DatabasePublisherNode(Node): + def __init__(self): + super().__init__('database_publisher') + + # Declare parameters + self.declare_parameter('dataset_dir', '', ParameterDescriptor(description="Path to the dataset directory.")) + self.declare_parameter('enable_front_camera', True, ParameterDescriptor(description="Enable front camera publishing.")) + self.declare_parameter('enable_back_camera', True, ParameterDescriptor(description="Enable back camera publishing.")) + self.declare_parameter('enable_lidar', True, ParameterDescriptor(description="Enable lidar publishing.")) + self.declare_parameter('enable_global_ref', True, ParameterDescriptor(description="Enable global reference subscription.")) + self.declare_parameter('global_ref_topic', '/global_ref', ParameterDescriptor(description="Global reference topic.")) + self.declare_parameter('reserve', False, ParameterDescriptor(description="Reserved for future use.")) + + # Declare topic parameters + self.declare_parameter('front_cam_topic', '/zed_node/left/image_rect_color/compressed') + self.declare_parameter('front_cam_mask_topic', '/zed_node/left/semantic_segmentation') + self.declare_parameter('front_cam_info_topic', '/zed_node/left/image_rect_color/camera_info') + self.declare_parameter('back_cam_topic', '/realsense_back/color/image_raw/compressed') + self.declare_parameter('back_cam_mask_topic', '/realsense_back/semantic_segmentation') + self.declare_parameter('back_cam_info_topic', '/realsense_back/color/image_raw/camera_info') + self.declare_parameter('lidar_topic', '/velodyne_points') + + # Declare TF frame parameters + self.declare_parameter('tf_parent_frame', 'base_link') + self.declare_parameter('front_cam_frame', 'zed_left') + self.declare_parameter('back_cam_frame', 'realsense_back') + self.declare_parameter('lidar_frame', 'velodyne') + + # Retrieve parameters + self.dataset_dir = self.get_parameter('dataset_dir').get_parameter_value().string_value + if not self.dataset_dir: + self.get_logger().error("Dataset directory not provided!") + sys.exit(1) + + self.enable_front_camera = self.get_parameter('enable_front_camera').get_parameter_value().bool_value + self.enable_back_camera = self.get_parameter('enable_back_camera').get_parameter_value().bool_value + self.enable_lidar = self.get_parameter('enable_lidar').get_parameter_value().bool_value + self.enable_global_ref = self.get_parameter('enable_global_ref').get_parameter_value().bool_value + self.global_ref_topic = self.get_parameter('global_ref_topic').get_parameter_value().string_value + self.reserve = self.get_parameter('reserve').get_parameter_value().bool_value + + # Topics and frames + self.front_cam_topic = self.get_parameter('front_cam_topic').get_parameter_value().string_value + self.front_cam_mask_topic = self.get_parameter('front_cam_mask_topic').get_parameter_value().string_value + self.front_cam_info_topic = self.get_parameter('front_cam_info_topic').get_parameter_value().string_value + self.back_cam_topic = self.get_parameter('back_cam_topic').get_parameter_value().string_value + self.back_cam_mask_topic = self.get_parameter('back_cam_mask_topic').get_parameter_value().string_value + self.back_cam_info_topic = self.get_parameter('back_cam_info_topic').get_parameter_value().string_value + self.lidar_topic = self.get_parameter('lidar_topic').get_parameter_value().string_value + + self.tf_parent_frame = self.get_parameter('tf_parent_frame').get_parameter_value().string_value + self.front_cam_frame = self.get_parameter('front_cam_frame').get_parameter_value().string_value + self.back_cam_frame = self.get_parameter('back_cam_frame').get_parameter_value().string_value + self.lidar_frame = self.get_parameter('lidar_frame').get_parameter_value().string_value + + # Create publishers using the parameterized topics + if self.enable_front_camera: + self.pub_front_cam = self.create_publisher(CompressedImage, self.front_cam_topic, 1) + self.pub_front_cam_mask = self.create_publisher(Image, self.front_cam_mask_topic, 1) + self.pub_front_cam_info = self.create_publisher(CameraInfo, self.front_cam_info_topic, 1) + else: + self.pub_front_cam = self.pub_front_cam_mask = self.pub_front_cam_info = None + + if self.enable_back_camera: + self.pub_back_cam = self.create_publisher(CompressedImage, self.back_cam_topic, 1) + self.pub_back_cam_mask = self.create_publisher(Image, self.back_cam_mask_topic, 1) + self.pub_back_cam_info = self.create_publisher(CameraInfo, self.back_cam_info_topic, 1) + else: + self.pub_back_cam = self.pub_back_cam_mask = self.pub_back_cam_info = None + + if self.enable_lidar: + self.pub_lidar = self.create_publisher(PointCloud2, self.lidar_topic, 1) + else: + self.pub_lidar = None + + # TF Broadcaster for publishing transforms + self.tf_broadcaster = tf2_ros.TransformBroadcaster(self) + + # Global reference subscription (if enabled) + if self.enable_global_ref: + self.global_ref_sub = self.create_subscription(NavSatFix, self.global_ref_topic, self.global_ref_callback, 10) + else: + self.global_ref_sub = None + self.global_ref = None + + # Load CSV (track.csv) + csv_path = os.path.join(self.dataset_dir, 'track.csv') + dtypes = {'floor': int, 'timestamp': np.int64, 'front_cam_ts': np.int64, + 'back_cam_ts': np.int64, 'lidar_ts': np.int64} + self.track_df = pd.read_csv(csv_path, dtype=dtypes) + self.get_logger().info(f"Loaded track.csv with {len(self.track_df)} rows.") + + self.cv_bridge = CvBridge() + + # Load sensor configuration from husky.yaml + config_path = os.path.join(get_package_share_directory('open_place_recognition'), + 'configs', 'sensors', 'husky.yaml') + try: + with open(config_path, 'r') as f: + self.sensor_config = yaml.safe_load(f) + self.get_logger().info("Loaded sensor configuration from husky.yaml") + except Exception as e: + self.get_logger().error(f"Failed to load sensor configuration: {e}") + self.sensor_config = None + + self.get_logger().info("DatabasePublisherNode initialized.") + + def global_ref_callback(self, msg): + self.global_ref = msg + + def publish_sensor_config(self): + if not self.sensor_config: + return + + now = self.get_clock().now().to_msg() + + # Front camera configuration publishing + if self.enable_front_camera and self.pub_front_cam_info is not None: + try: + front = self.sensor_config['front_cam']['left'] + tfs = TransformStamped() + tfs.header.stamp = now + tfs.header.frame_id = self.tf_parent_frame + tfs.child_frame_id = self.front_cam_frame + t = front['baselink2cam']['t'] + q = front['baselink2cam']['q'] + tfs.transform.translation.x = t[0] + tfs.transform.translation.y = t[1] + tfs.transform.translation.z = t[2] + tfs.transform.rotation.x = q[1] + tfs.transform.rotation.y = q[2] + tfs.transform.rotation.z = q[3] + tfs.transform.rotation.w = q[0] + self.tf_broadcaster.sendTransform(tfs) + + cam_info = CameraInfo() + cam_info.header.stamp = now + cam_info.header.frame_id = self.front_cam_frame + resolution = front['resolution'] + cam_info.width = resolution[0] + cam_info.height = resolution[1] + cam_info.distortion_model = "plumb_bob" + cam_info.d = [0.0]*5 + P = front['rect']['P'] + cam_info.p = [elem for row in P for elem in row] + cam_info.k = [P[0][0], P[0][1], P[0][2], + P[1][0], P[1][1], P[1][2], + P[2][0], P[2][1], P[2][2]] + cam_info.r = [1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0] + self.pub_front_cam_info.publish(cam_info) + except Exception as e: + self.get_logger().error(f"Error publishing front_cam config: {e}") + + # Back camera configuration publishing + if self.enable_back_camera and self.pub_back_cam_info is not None: + try: + back = self.sensor_config['back_cam']['left'] + tbs = TransformStamped() + tbs.header.stamp = now + tbs.header.frame_id = self.tf_parent_frame + tbs.child_frame_id = self.back_cam_frame + t = back['baselink2cam']['t'] + q = back['baselink2cam']['q'] + tbs.transform.translation.x = t[0] + tbs.transform.translation.y = t[1] + tbs.transform.translation.z = t[2] + tbs.transform.rotation.x = q[1] + tbs.transform.rotation.y = q[2] + tbs.transform.rotation.z = q[3] + tbs.transform.rotation.w = q[0] + self.tf_broadcaster.sendTransform(tbs) + + cam_info = CameraInfo() + cam_info.header.stamp = now + cam_info.header.frame_id = self.back_cam_frame + resolution = back['resolution'] + cam_info.width = resolution[0] + cam_info.height = resolution[1] + cam_info.distortion_model = "plumb_bob" + cam_info.d = [0.0]*5 + P = back['rect']['P'] + cam_info.p = [elem for row in P for elem in row] + cam_info.k = [P[0][0], P[0][1], P[0][2], + P[1][0], P[1][1], P[1][2], + P[2][0], P[2][1], P[2][2]] + cam_info.r = [1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0] + self.pub_back_cam_info.publish(cam_info) + except Exception as e: + self.get_logger().error(f"Error publishing back_cam config: {e}") + + # Lidar configuration publishing + if self.enable_lidar: + try: + lidar = self.sensor_config['lidar'] + tls = TransformStamped() + tls.header.stamp = now + tls.header.frame_id = self.tf_parent_frame + tls.child_frame_id = self.lidar_frame + t = lidar['baselink2lidar']['t'] + q = lidar['baselink2lidar']['q'] + tls.transform.translation.x = t[0] + tls.transform.translation.y = t[1] + tls.transform.translation.z = t[2] + tls.transform.rotation.x = q[1] + tls.transform.rotation.y = q[2] + tls.transform.rotation.z = q[3] + tls.transform.rotation.w = q[0] + self.tf_broadcaster.sendTransform(tls) + except Exception as e: + self.get_logger().error(f"Error publishing lidar config: {e}") + + def publish_one_row(self, i): + self.publish_sensor_config() + floor_num = int(self.track_df['floor'][i]) + floor_folder = f"floor_{floor_num}" + back_cam_ts = int(self.track_df['back_cam_ts'][i]) + front_cam_ts = int(self.track_df['front_cam_ts'][i]) + lidar_ts = int(self.track_df['lidar_ts'][i]) + self.get_logger().info(f"Publishing data for {floor_folder}") + + if self.enable_back_camera: + back_cam_path = os.path.join(self.dataset_dir, floor_folder, 'back_cam', f"{back_cam_ts}.png") + msg = self.read_image_as_compressed(back_cam_path, frame_id=self.back_cam_frame) + if msg and self.pub_back_cam: + self.pub_back_cam.publish(msg) + mask_path = os.path.join(self.dataset_dir, floor_folder, 'masks', 'back_cam', f"{back_cam_ts}.png") + mask_msg = self.read_image_as_uncompressed(mask_path, frame_id=self.back_cam_frame) + if mask_msg and self.pub_back_cam_mask: + self.pub_back_cam_mask.publish(mask_msg) + + if self.enable_front_camera: + front_cam_path = os.path.join(self.dataset_dir, floor_folder, 'front_cam', f"{front_cam_ts}.png") + msg = self.read_image_as_compressed(front_cam_path, frame_id=self.front_cam_frame) + if msg and self.pub_front_cam: + self.pub_front_cam.publish(msg) + mask_path = os.path.join(self.dataset_dir, floor_folder, 'masks', 'front_cam', f"{front_cam_ts}.png") + mask_msg = self.read_image_as_uncompressed(mask_path, frame_id=self.front_cam_frame) + if mask_msg and self.pub_front_cam_mask: + self.pub_front_cam_mask.publish(mask_msg) + + if self.enable_lidar: + lidar_path = os.path.join(self.dataset_dir, floor_folder, 'lidar', f"{lidar_ts}.bin") + lidar_msg = self.read_lidar_as_pointcloud2(lidar_path, frame_id=self.lidar_frame) + if lidar_msg and self.pub_lidar: + self.pub_lidar.publish(lidar_msg) + + def publish_loop(self): + if len(self.track_df) < 1: + self.get_logger().warn("track.csv is empty. Nothing to publish.") + return + + timestamps = self.track_df['timestamp'] + for i in range(len(self.track_df)): + self.publish_one_row(i) + if i < len(self.track_df) - 1: + dt_ns = timestamps[i + 1] - timestamps[i] + dt_s = dt_ns / 1e9 + if dt_s < 0 or dt_s > 10: + self.get_logger().warn(f"Skipping sleep due to invalid dt at index {i}.") + continue + time.sleep(dt_s) + self.get_logger().info("Finished publishing all rows from track.csv.") + + def read_image_as_compressed(self, image_path, frame_id='camera'): + if not os.path.exists(image_path): + self.get_logger().error(f"Image not found: {image_path}") + return None + try: + with open(image_path, 'rb') as f: + image_data = f.read() + msg = CompressedImage() + msg.header.stamp = self.get_clock().now().to_msg() + msg.header.frame_id = frame_id + msg.format = "png" + msg.data = list(image_data) + return msg + except Exception as e: + self.get_logger().error(f"Failed to read compressed image: {e}") + return None + + def read_image_as_uncompressed(self, image_path, frame_id='camera'): + + if not os.path.exists(image_path): + self.get_logger().error(f"Mask image not found: {image_path}") + return None + + img = cv2.imread(image_path, cv2.IMREAD_UNCHANGED) + if img is None: + self.get_logger().error(f"Failed to read image {image_path}") + return None + + if len(img.shape) == 2: + encoding = "mono8" + elif len(img.shape) == 3: + if img.shape[2] == 1: + encoding = "mono8" + elif img.shape[2] == 3: + encoding = "bgr8" + elif img.shape[2] == 4: + encoding = "bgra8" + else: + encoding = "bgr8" + else: + encoding = "bgr8" + try: + msg = self.cv_bridge.cv2_to_imgmsg(img, encoding=encoding) + except Exception as e: + self.get_logger().error(f"cv_bridge conversion error: {e}") + return None + msg.header.stamp = self.get_clock().now().to_msg() + msg.header.frame_id = frame_id + return msg + + def read_lidar_as_pointcloud2(self, lidar_path, frame_id='velodyne'): + if not os.path.exists(lidar_path): + self.get_logger().error(f"Lidar file not found: {lidar_path}") + return None + try: + points = np.fromfile(lidar_path, dtype=np.float32).reshape(-1, 4) + except Exception as e: + self.get_logger().error(f"Error reading lidar file: {e}") + return None + header = Header() + header.stamp = self.get_clock().now().to_msg() + header.frame_id = frame_id + from sensor_msgs.msg import PointField + fields = [ + PointField(name='x', offset=0, datatype=PointField.FLOAT32, count=1), + PointField(name='y', offset=4, datatype=PointField.FLOAT32, count=1), + PointField(name='z', offset=8, datatype=PointField.FLOAT32, count=1), + PointField(name='intensity', offset=12, datatype=PointField.FLOAT32, count=1), + ] + pc2_msg = point_cloud2.create_cloud(header, fields, points) + return pc2_msg + +def main(args=None): + rclpy.init(args=args) + node = DatabasePublisherNode() + try: + node.publish_loop() + except KeyboardInterrupt: + pass + node.destroy_node() + rclpy.shutdown() + +if __name__ == '__main__': + main() diff --git a/open_place_recognition/src/dataset_train_node.py b/open_place_recognition/src/dataset_train_node.py new file mode 100755 index 0000000..ac4577f --- /dev/null +++ b/open_place_recognition/src/dataset_train_node.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +import rclpy +from rclpy.node import Node +import os +import sys +from ament_index_python.packages import get_package_share_directory +import time + +class DatasetTrainNode(Node): + def __init__(self): + super().__init__('dataset_train_node') + # Get parameters + self.declare_parameter('dataset_path', 'datasets') + self.declare_parameter('map_name', 'default_map') + self.declare_parameter('output_path', '~/.ros/opr_dataset') + + dataset_path = self.get_parameter('dataset_path').value + map_name = self.get_parameter('map_name').value + output_path = os.path.expanduser(self.get_parameter('output_path').value) + + # Get package share directory and build paths for datasets + package_dir = get_package_share_directory('orca_opr') + dataset_dir = os.path.join(package_dir, dataset_path) + + # Check that required folders exist + if not os.path.exists(dataset_dir): + self.get_logger().error(f"Datasets directory {dataset_dir} does not exist. Please create it and try again.") + sys.exit(1) + if not os.path.exists(output_path): + self.get_logger().error(f"Output directory {output_path} does not exist. Please create it and try again.") + sys.exit(1) + + if not self.run_torch_training(dataset_dir, output_path, map_name): + self.get_logger().error(f"Error during training {map_name}") + sys.exit(1) + + def run_torch_training(self, dataset_path: str, output_path: str, map_name: str): + """ + Loads dataset from dataset_path and performs training for map_name. + """ + print(f"[TRAINER] Starting training on dataset: {dataset_path} for map: {map_name}") + time.sleep(3) # Simulate training time + + # Simulate training by creating a dummy .pt file in the output_path folder + dummy_model_file = os.path.join(output_path, f"{map_name}.pt") + with open(dummy_model_file, 'w') as f: + f.write("dummy model weights") + + self.get_logger().info(f"Dummy model file created at: {dummy_model_file}") + print(f"[TRAINER] Finished training for map: {map_name} using dataset: {dataset_path}") + return True + +def main(args=None): + rclpy.init(args=args) + node = DatasetTrainNode() + rclpy.spin_once(node, timeout_sec=1) + node.destroy_node() + rclpy.shutdown() + +if __name__ == '__main__': + main() diff --git a/open_place_recognition/src/localization_node.py b/open_place_recognition/src/localization_node.py new file mode 100755 index 0000000..10824ae --- /dev/null +++ b/open_place_recognition/src/localization_node.py @@ -0,0 +1,510 @@ +#!/usr/bin/env python3 +""" +Localization Node for image and lidar-based localization. +This node subscribes to front/back camera images, semantic masks, and lidar pointclouds. +It then synchronizes the messages, preprocesses the data, and runs a localization pipeline. +""" + +import os +import cv2 +import numpy as np +import torch +import rclpy +from cv_bridge import CvBridge +from hydra.utils import instantiate +from message_filters import ApproximateTimeSynchronizer, Subscriber +from omegaconf import OmegaConf +from rclpy.node import Node +from rcl_interfaces.msg import ParameterDescriptor +from builtin_interfaces.msg import Time +from geometry_msgs.msg import PoseStamped +from sensor_msgs.msg import Image, CompressedImage, PointCloud2 +from sensor_msgs_py.point_cloud2 import read_points +from std_msgs.msg import Int32 +from torch import Tensor +import albumentations as A +from albumentations.pytorch import ToTensorV2 +from ament_index_python.packages import get_package_share_directory + +# Importing required modules from our package +from opr.pipelines.localization import ArucoLocalizationPipeline +from opr_interfaces.msg import DatabaseMatchIndex +from opr.datasets.augmentations import DefaultImageTransform, DefaultSemanticTransform +from opr.datasets.projection import Projector +from opr.datasets.soc_utils import ( + get_points_labels_by_mask, + instance_masks_to_objects, + pack_objects, + semantic_mask_to_instances, +) + + +class ImageTransformWithoutNormalize: + """Custom image transformation without normalization. + + Converts an image in cv2 format to a PyTorch tensor (channel-first) using albumentations. + """ + def __call__(self, img: np.ndarray) -> Tensor: + augmented = A.Compose([ToTensorV2()])(image=img) + return augmented["image"] + + +class LocalizationNode(Node): + """ROS2 node for localization based on synchronized image and lidar data.""" + + def __init__(self): + super().__init__("localization") + + # Declare required parameters directly in __init__ + self.declare_parameter("image_front_topic", "", ParameterDescriptor(description="Front camera image topic.")) + self.declare_parameter("image_back_topic", "", ParameterDescriptor(description="Back camera image topic.")) + self.declare_parameter("mask_front_topic", "", ParameterDescriptor(description="Front semantic segmentation mask topic.")) + self.declare_parameter("mask_back_topic", "", ParameterDescriptor(description="Back semantic segmentation mask topic.")) + self.declare_parameter("lidar_topic", "", ParameterDescriptor(description="Lidar pointcloud topic.")) + self.declare_parameter("pipeline_cfg", "", ParameterDescriptor(description="Path to the pipeline configuration file.")) + self.declare_parameter("exclude_dynamic_classes", False, ParameterDescriptor(description="Exclude dynamic objects from the input data.")) + self.declare_parameter("image_resize", [], ParameterDescriptor(description="Image resize dimensions.")) + # New parameters for enabling/disabling sensors and global reference. + self.declare_parameter("enable_front_camera", True, ParameterDescriptor(description="Enable front camera.")) + self.declare_parameter("enable_back_camera", True, ParameterDescriptor(description="Enable back camera.")) + self.declare_parameter("enable_lidar", True, ParameterDescriptor(description="Enable lidar sensor.")) + self.declare_parameter("enable_global_reference", True, ParameterDescriptor(description="Enable global reference system subscription.")) + self.declare_parameter("global_ref_topic", "", ParameterDescriptor(description="Global reference topic (e.g. GPS/Barometer, WGS84).")) + + # Retrieve parameters from the parameter server. + self.image_front_topic = self.get_parameter("image_front_topic").get_parameter_value().string_value + self.image_back_topic = self.get_parameter("image_back_topic").get_parameter_value().string_value + self.mask_front_topic = self.get_parameter("mask_front_topic").get_parameter_value().string_value + self.mask_back_topic = self.get_parameter("mask_back_topic").get_parameter_value().string_value + self.lidar_topic = self.get_parameter("lidar_topic").get_parameter_value().string_value + self.pipeline_cfg = self.get_parameter("pipeline_cfg").get_parameter_value().string_value + self.exclude_dynamic_classes = self.get_parameter("exclude_dynamic_classes").get_parameter_value().bool_value + self.image_resize = self.get_parameter("image_resize").get_parameter_value().integer_array_value + + self.enable_front_camera = self.get_parameter("enable_front_camera").get_parameter_value().bool_value + self.enable_back_camera = self.get_parameter("enable_back_camera").get_parameter_value().bool_value + self.enable_lidar = self.get_parameter("enable_lidar").get_parameter_value().bool_value + self.enable_global_reference = self.get_parameter("enable_global_reference").get_parameter_value().bool_value + self.global_ref_topic = self.get_parameter("global_ref_topic").get_parameter_value().string_value + + # Initialize cv_bridge for converting ROS image messages to OpenCV format. + self.cv_bridge = CvBridge() + + # Build a list of subscribers conditionally based on enabled sensors. + subscribers = [] + mapping = {} # Will map sensor name to its index in the synchronizer arguments. + if self.enable_front_camera: + self.image_front_sub = Subscriber(self, CompressedImage, self.image_front_topic) + subscribers.append(self.image_front_sub) + mapping['front_image'] = len(subscribers) - 1 + self.mask_front_sub = Subscriber(self, Image, self.mask_front_topic) + subscribers.append(self.mask_front_sub) + mapping['front_mask'] = len(subscribers) - 1 + else: + self.image_front_sub = None + self.mask_front_sub = None + + if self.enable_back_camera: + self.image_back_sub = Subscriber(self, CompressedImage, self.image_back_topic) + subscribers.append(self.image_back_sub) + mapping['back_image'] = len(subscribers) - 1 + self.mask_back_sub = Subscriber(self, Image, self.mask_back_topic) + subscribers.append(self.mask_back_sub) + mapping['back_mask'] = len(subscribers) - 1 + else: + self.image_back_sub = None + self.mask_back_sub = None + + if self.enable_lidar: + self.lidar_sub = Subscriber(self, PointCloud2, self.lidar_topic) + subscribers.append(self.lidar_sub) + mapping['lidar'] = len(subscribers) - 1 + else: + self.lidar_sub = None + + # Save mapping for use in the callback. + self.subscriber_mapping = mapping + + # Create synchronizer only if at least one sensor is enabled. + if subscribers: + self.ts = ApproximateTimeSynchronizer( + subscribers, + queue_size=1, + slop=0.05, + ) + self.ts.registerCallback(self.listener_callback) + else: + self.get_logger().error("No sensors enabled; cannot create synchronizer.") + + # Create publishers for pose and database match index. + self.db_match_pose_pub = self.create_publisher(PoseStamped, "/place_recognition/pose", 10) + self.idx_pub = self.create_publisher(DatabaseMatchIndex, "/place_recognition/db_idx", 10) + self.estimated_pose_pub = self.create_publisher(PoseStamped, "/localization/pose", 10) + + # If enabled, create a subscriber for the global reference system. + if self.enable_global_reference: + from sensor_msgs.msg import NavSatFix + self.global_ref_sub = self.create_subscription(NavSatFix, self.global_ref_topic, self.global_ref_callback, 10) + else: + self.global_ref_sub = None + self.global_ref = None + + # Instantiate the localization pipeline from configuration. + cfg = OmegaConf.load(self.pipeline_cfg) + cfg.database_dir = os.path.abspath(os.path.join(os.path.expanduser('~'), cfg.database_dir)) + cfg.model_weights_path = os.path.abspath(os.path.join(os.path.expanduser('~'), cfg.model_weights_path)) + + self.pipeline = instantiate(cfg) + + # Check if the pipeline uses a SOC (scene object context) module. + if self.pipeline.pr_pipe.model.soc_module is not None: + self.load_soc = True + self.get_logger().info("self.load_soc is set to True.") + sensors_cfg = OmegaConf.load(os.path.join(get_package_share_directory("open_place_recognition"), "configs/sensors/husky.yaml")) + anno_cfg = OmegaConf.load(os.path.join(get_package_share_directory("open_place_recognition"), "configs/anno/oneformer.yaml")) + self.front_cam_proj = Projector(sensors_cfg.front_cam, sensors_cfg.lidar) + self.back_cam_proj = Projector(sensors_cfg.back_cam, sensors_cfg.lidar) + self.max_distance_soc = 50.0 + self.top_k_soc = self.pipeline.pr_pipe.model.soc_module.num_objects + self.special_classes = anno_cfg.special_classes + self.soc_coords_type = "euclidean" + else: + self.load_soc = False + + # Set up image and mask transformations based on the pipeline type. + if isinstance(self.pipeline, ArucoLocalizationPipeline): + self.image_transform = ImageTransformWithoutNormalize() + self.mask_transform = DefaultSemanticTransform(train=False, resize=None) + else: + self.image_transform = DefaultImageTransform(train=False, resize=self.image_resize) + self.mask_transform = DefaultSemanticTransform(train=False, resize=self.image_resize) + + # Dynamic class index to be excluded. + self._ade20k_dynamic_idx = [12] + + # Transformation matrices for lidar to camera conversions. + self.lidar2front = np.array([ + [ 0.01509615, -0.99976457, -0.01558544, 0.04632156], + [ 0.00871086, 0.01571812, -0.99983852, -0.13278588], + [ 0.9998481, 0.01495794, 0.0089461, -0.06092749], + [ 0., 0., 0., 1. ] + ]) + self.lidar2back = np.array([ + [-1.50409674e-02, 9.99886421e-01, 9.55906151e-04, 1.82703304e-02], + [-1.30440106e-02, 7.59716299e-04, -9.99914635e-01, -1.41787545e-01], + [-9.99801792e-01, -1.50521522e-02, 1.30311022e-02, -6.72336358e-02], + [ 0., 0., 0., 1. ] + ]) + self.front_matrix = np.array([ + [683.6199340820312, 0.0, 615.1160278320312], + [0.0, 683.6199340820312, 345.32354736328125], + [0.0, 0.0, 1.0] + ]) + self.front_dist = np.array([0.0, 0.0, 0.0, 0.0, 0.0]) + self.back_matrix = np.array([ + [910.4178466796875, 0.0, 648.44140625], + [0.0, 910.4166870117188, 354.0118408203125], + [0.0, 0.0, 1.0] + ]) + self.back_dist = np.array([0.0, 0.0, 0.0, 0.0, 0.0]) + + self.get_logger().info(f"Initialized {self.__class__.__name__} node.") + + def global_ref_callback(self, msg) -> None: + """Callback to update the global reference message.""" + self.global_ref = msg + self.get_logger().debug(f"Received global reference message: {msg}") + + def _prepare_input( + self, + images: np.ndarray | list[np.ndarray] = None, + masks: np.ndarray | list[np.ndarray] = None, + pointcloud: np.ndarray = None, + ) -> dict[str, Tensor]: + """ + Prepare and transform input data for the pipeline. + + Args: + images: A single image or list of images (cv2 format). + masks: A single mask or list of masks. + pointcloud: Lidar pointcloud data. + + Returns: + A dictionary with transformed images, masks, and pointcloud tensors. + """ + input_data: dict[str, Tensor] = {} + + # Process image inputs using the configured image transform. + if images is not None and isinstance(images, list): + for i, image in enumerate(images): + if image is None: + self.get_logger().info(f"Image {i} is disabled or not available.") + continue + img_processed = image.copy() + if self.exclude_dynamic_classes and masks is not None and i < len(masks) and masks[i] is not None: + for dyn_idx in self._ade20k_dynamic_idx: + img_processed = np.where(masks[i][:, :, np.newaxis] == dyn_idx, 0, img_processed) + input_data[f"image_{i}"] = self.image_transform(img_processed) + elif isinstance(images, np.ndarray): + img_processed = images.copy() + if self.exclude_dynamic_classes and masks is not None: + for dyn_idx in self._ade20k_dynamic_idx: + img_processed = np.where(masks == dyn_idx, 0, img_processed) + input_data["image_0"] = self.image_transform(img_processed) + else: + self.get_logger().warning(f"Invalid type for images in '_prepare_input': {type(images)}") + + # Process mask inputs using the configured mask transform. + if masks is not None and isinstance(masks, list): + for i, mask in enumerate(masks): + if mask is None: + self.get_logger().info(f"Mask {i} is disabled or not available.") + continue + input_data[f"mask_{i}"] = self.mask_transform(mask) + elif isinstance(masks, np.ndarray): + input_data["mask_0"] = self.mask_transform(masks) + else: + self.get_logger().warning(f"Invalid type for masks in '_prepare_input': {type(masks)}") + + # Process pointcloud data. + if pointcloud is not None: + if self.exclude_dynamic_classes and masks is not None: + if isinstance(masks, list): + for mask in masks: + pointcloud = self._remove_dynamic_points(pointcloud, mask, + self.lidar2back, self.back_matrix, self.back_dist) + elif isinstance(masks, np.ndarray): + pointcloud = self._remove_dynamic_points(pointcloud, masks, + self.lidar2back, self.back_matrix, self.back_dist) + pc_tensor = torch.tensor(pointcloud).contiguous() + pc_tensor = pc_tensor[~torch.any(pc_tensor.isnan(), dim=1)] + input_data["pointcloud_lidar_coords"] = pc_tensor[:, :3] + if pc_tensor.shape[1] > 3: + input_data["pointcloud_lidar_feats"] = pc_tensor[:, 3].unsqueeze(1) + else: + input_data["pointcloud_lidar_feats"] = torch.ones_like(pc_tensor[:, :1]) + + # Process SOC (scene object context) if enabled and if masks are available. + if self.load_soc and masks is not None and isinstance(masks, list) and len(masks) >= 2: + input_data["soc"] = self._get_soc(mask_front=masks[0], mask_back=masks[1], lidar_scan=pointcloud) + + return input_data + + def _get_soc(self, mask_front: np.ndarray, mask_back: np.ndarray, lidar_scan: np.ndarray) -> Tensor: + """ + Compute the scene object context (SOC) tensor based on the provided masks and lidar scan. + + Args: + mask_front: Front camera semantic mask. + mask_back: Back camera semantic mask. + lidar_scan: Lidar pointcloud data. + + Returns: + A PyTorch tensor representing packed objects. + """ + coords_front, _, in_image_front = self.front_cam_proj(lidar_scan) + coords_back, _, in_image_back = self.back_cam_proj(lidar_scan) + point_labels = np.zeros(len(lidar_scan), dtype=np.uint8) + point_labels[in_image_front] = get_points_labels_by_mask(coords_front, mask_front) + point_labels[in_image_back] = get_points_labels_by_mask(coords_back, mask_back) + instances_front = semantic_mask_to_instances(mask_front, area_threshold=10, labels_whitelist=self.special_classes) + instances_back = semantic_mask_to_instances(mask_back, area_threshold=10, labels_whitelist=self.special_classes) + objects_front = instance_masks_to_objects(instances_front, coords_front, + point_labels[in_image_front], lidar_scan[in_image_front]) + objects_back = instance_masks_to_objects(instances_back, coords_back, + point_labels[in_image_back], lidar_scan[in_image_back]) + objects = {**objects_front, **objects_back} + packed_objects = pack_objects(objects, self.top_k_soc, self.max_distance_soc, self.special_classes) + + if self.soc_coords_type == "cylindrical_3d": + packed_objects = np.concatenate(( + np.linalg.norm(packed_objects, axis=-1, keepdims=True), + np.arctan2(packed_objects[..., 1], packed_objects[..., 0])[..., None], + packed_objects[..., 2:], + ), axis=-1) + elif self.soc_coords_type == "cylindrical_2d": + packed_objects = np.concatenate(( + np.linalg.norm(packed_objects[..., :2], axis=-1, keepdims=True), + np.arctan2(packed_objects[..., 1], packed_objects[..., 0])[..., None], + packed_objects[..., 2:], + ), axis=-1) + elif self.soc_coords_type == "euclidean": + pass + elif self.soc_coords_type == "spherical": + packed_objects = np.concatenate(( + np.linalg.norm(packed_objects, axis=-1, keepdims=True), + np.arccos(packed_objects[..., 2] / np.linalg.norm(packed_objects, axis=-1, keepdims=True)), + np.arctan2(packed_objects[..., 1], packed_objects[..., 0])[..., None], + ), axis=-1) + else: + raise ValueError(f"Unknown soc_coords_type: {self.soc_coords_type!r}") + objects_tensor = torch.from_numpy(packed_objects).float() + return objects_tensor + + def _remove_dynamic_points(self, pointcloud: np.ndarray, semantic_map: np.ndarray, + lidar2sensor: np.ndarray, sensor_intrinsics: np.ndarray, + sensor_dist: np.ndarray) -> np.ndarray: + """ + Remove points corresponding to dynamic objects from the pointcloud. + + Args: + pointcloud: The original pointcloud data. + semantic_map: The semantic segmentation mask. + lidar2sensor: Transformation matrix from lidar to sensor frame. + sensor_intrinsics: Camera intrinsic matrix. + sensor_dist: Camera distortion coefficients. + + Returns: + The filtered pointcloud with dynamic points removed. + """ + pc_values = np.concatenate([pointcloud, np.ones((pointcloud.shape[0], 1))], axis=1).T + camera_values = lidar2sensor @ pc_values + camera_values = camera_values.T[:, :3] + points_2d, _ = cv2.projectPoints( + camera_values, + np.zeros((3, 1), np.float32), + np.zeros((3, 1), np.float32), + sensor_intrinsics, + sensor_dist + ) + points_2d = points_2d[:, 0, :] + classes_in_map = set(np.unique(semantic_map)) + dynamic_classes = set(self._ade20k_dynamic_idx) + if classes_in_map.intersection(dynamic_classes): + valid = (~np.isnan(points_2d[:, 0])) & (~np.isnan(points_2d[:, 1])) + in_bounds_x = (points_2d[:, 0] >= 0) & (points_2d[:, 0] < 1280) + in_bounds_y = (points_2d[:, 1] >= 0) & (points_2d[:, 1] < 720) + look_forward = (camera_values[:, 2] > 0) + overall_mask = valid & in_bounds_x & in_bounds_y & look_forward + indices = np.where(overall_mask)[0] + mask_for_points = np.full((points_2d.shape[0], 3), True) + dynamic_idx_array = np.array(self._ade20k_dynamic_idx) + semantic_values = semantic_map[ + np.floor(points_2d[indices, 1]).astype(int), + np.floor(points_2d[indices, 0]).astype(int) + ] + matching_indices = np.where(np.isin(semantic_values, dynamic_idx_array)) + mask_for_points[indices[matching_indices[0]]] = np.array([False, False, False]) + return pointcloud[mask_for_points].reshape((-1, 3)) + else: + return pointcloud + + def _create_pose_msg(self, pose: np.ndarray, timestamp: Time) -> PoseStamped: + """ + Create a PoseStamped message from a pose array. + + Args: + pose: A 7-element array [x, y, z, qx, qy, qz, qw]. + timestamp: The message timestamp. + + Returns: + A populated PoseStamped message. + """ + pose_msg = PoseStamped() + pose_msg.header.stamp = timestamp + pose_msg.pose.position.x = pose[0] + pose_msg.pose.position.y = pose[1] + pose_msg.pose.position.z = pose[2] + pose_msg.pose.orientation.x = pose[3] + pose_msg.pose.orientation.y = pose[4] + pose_msg.pose.orientation.z = pose[5] + pose_msg.pose.orientation.w = pose[6] + return pose_msg + + def _create_idx_msg(self, idx: int, timestamp: Time) -> DatabaseMatchIndex: + """ + Create a DatabaseMatchIndex message. + + Args: + idx: The index value. + timestamp: The message timestamp. + + Returns: + A populated DatabaseMatchIndex message. + """ + idx_msg = DatabaseMatchIndex() + idx_msg.header.stamp = timestamp + idx_msg.index = idx + return idx_msg + + def listener_callback(self, *msgs) -> None: + """ + Callback function invoked when synchronized messages are received. + + Converts messages to OpenCV images and numpy arrays, prepares input data, + runs inference through the pipeline, and publishes the results. + """ + self.get_logger().info("Received synchronized messages.") + t_start = self.get_clock().now() + + # Extract messages from the synchronizer based on our mapping. + mapping = self.subscriber_mapping + front_image_msg = msgs[mapping['front_image']] if 'front_image' in mapping else None + front_mask_msg = msgs[mapping['front_mask']] if 'front_mask' in mapping else None + back_image_msg = msgs[mapping['back_image']] if 'back_image' in mapping else None + back_mask_msg = msgs[mapping['back_mask']] if 'back_mask' in mapping else None + lidar_msg = msgs[mapping['lidar']] if 'lidar' in mapping else None + + # Convert image and mask messages to OpenCV format if available. + front_image = self.cv_bridge.compressed_imgmsg_to_cv2(front_image_msg) if front_image_msg is not None else None + back_image = self.cv_bridge.compressed_imgmsg_to_cv2(back_image_msg) if back_image_msg is not None else None + front_mask = self.cv_bridge.imgmsg_to_cv2(front_mask_msg) if front_mask_msg is not None else None + back_mask = self.cv_bridge.imgmsg_to_cv2(back_mask_msg) if back_mask_msg is not None else None + + # Convert lidar message to a numpy pointcloud if available. + if lidar_msg is not None: + points = read_points(lidar_msg, field_names=("x", "y", "z")) + pointcloud = np.array([points["x"], points["y"], points["z"]]).T + else: + pointcloud = None + + # Prepare input data for the pipeline. + input_data = self._prepare_input( + images=[front_image, back_image], + masks=[front_mask, back_mask], + pointcloud=pointcloud + ) + + # Run inference. + output = self.pipeline.infer(input_data) + t_taken = self.get_clock().now() - t_start + self.get_logger().debug(f"Localization inference took: {t_taken.nanoseconds / 1e6} ms.") + self.get_logger().info(f"output['db_match_pose'] = {output['db_match_pose']}") + + # Create and publish messages. + db_match_pose = output["db_match_pose"].tolist() + estimated_pose = output["estimated_pose"] + db_idx = int(output["db_idx"]) + + db_match_pose_msg = self._create_pose_msg( + db_match_pose, + lidar_msg.header.stamp if lidar_msg is not None else self.get_clock().now().to_msg() + ) + estimated_pose_msg = self._create_pose_msg( + estimated_pose, + lidar_msg.header.stamp if lidar_msg is not None else self.get_clock().now().to_msg() + ) + idx_msg = self._create_idx_msg( + db_idx, + lidar_msg.header.stamp if lidar_msg is not None else self.get_clock().now().to_msg() + ) + + self.db_match_pose_pub.publish(db_match_pose_msg) + self.get_logger().info(f"Published db match pose message: {db_match_pose_msg.pose}") + self.estimated_pose_pub.publish(estimated_pose_msg) + self.get_logger().info(f"Published estimated pose message: {estimated_pose_msg.pose}") + self.idx_pub.publish(idx_msg) + self.get_logger().info(f"Published database index message: {idx_msg.index}") + + +def main(args=None): + """Main function to initialize and spin the localization node.""" + rclpy.init(args=args) + loc_node = LocalizationNode() + rclpy.spin(loc_node) + loc_node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/open_place_recognition/src/place_recognition_node.py b/open_place_recognition/src/place_recognition_node.py new file mode 100755 index 0000000..eb19f3e --- /dev/null +++ b/open_place_recognition/src/place_recognition_node.py @@ -0,0 +1,367 @@ +#!/usr/bin/env python3 +""" +Place Recognition Node + +This node subscribes to front/back camera images, semantic masks, and lidar pointclouds. +It synchronizes these messages, prepares the input for the place recognition pipeline, +and publishes the resulting pose and database match index. +""" + +import os +import numpy as np +import torch +import rclpy +from cv_bridge import CvBridge +from hydra.utils import instantiate +from message_filters import ApproximateTimeSynchronizer, Subscriber +from omegaconf import OmegaConf +from rclpy.node import Node +from rcl_interfaces.msg import ParameterDescriptor +from builtin_interfaces.msg import Time +from geometry_msgs.msg import PoseStamped +from sensor_msgs.msg import Image, CompressedImage, PointCloud2, NavSatFix +from sensor_msgs_py.point_cloud2 import read_points +from std_msgs.msg import Int32 +from torch import Tensor +from ament_index_python.packages import get_package_share_directory + +# Import custom message and processing functions +from opr_interfaces.msg import DatabaseMatchIndex +from opr.datasets.augmentations import DefaultImageTransform, DefaultSemanticTransform +from opr.datasets.projection import Projector +from opr.datasets.soc_utils import ( + get_points_labels_by_mask, + instance_masks_to_objects, + pack_objects, + semantic_mask_to_instances, +) +from opr.pipelines.place_recognition import PlaceRecognitionPipeline + +class PlaceRecognitionNode(Node): + """ROS2 Node for Place Recognition using camera images, semantic masks, and lidar data.""" + + def __init__(self): + super().__init__("place_recognition") + # Declare required parameters directly in __init__ + self.declare_parameter("image_front_topic", "", ParameterDescriptor(description="Front camera image topic.")) + self.declare_parameter("image_back_topic", "", ParameterDescriptor(description="Back camera image topic.")) + self.declare_parameter("mask_front_topic", "", ParameterDescriptor(description="Front semantic segmentation mask topic.")) + self.declare_parameter("mask_back_topic", "", ParameterDescriptor(description="Back semantic segmentation mask topic.")) + self.declare_parameter("lidar_topic", "", ParameterDescriptor(description="Lidar pointcloud topic.")) + self.declare_parameter("pipeline_cfg", "", ParameterDescriptor(description="Path to the pipeline configuration file.")) + self.declare_parameter("image_resize", [], ParameterDescriptor(description="Image resize dimensions.")) + self.declare_parameter("enable_front_camera", True, ParameterDescriptor(description="Enable front camera.")) + self.declare_parameter("enable_back_camera", True, ParameterDescriptor(description="Enable back camera.")) + self.declare_parameter("enable_lidar", True, ParameterDescriptor(description="Enable lidar sensor.")) + self.declare_parameter("global_ref_topic", "", ParameterDescriptor(description="Global reference system topic (e.g. GPS/Barometer, WGS84).")) + self.declare_parameter("enable_global_ref", True, ParameterDescriptor(description="Enable global reference subscription.")) + self.declare_parameter("reserve", False, ParameterDescriptor(description="Reserve variable for future use.")) + + # Retrieve topics and configuration from parameters. + image_front_topic = self.get_parameter("image_front_topic").get_parameter_value().string_value + image_back_topic = self.get_parameter("image_back_topic").get_parameter_value().string_value + mask_front_topic = self.get_parameter("mask_front_topic").get_parameter_value().string_value + mask_back_topic = self.get_parameter("mask_back_topic").get_parameter_value().string_value + lidar_topic = self.get_parameter("lidar_topic").get_parameter_value().string_value + pipeline_cfg = self.get_parameter("pipeline_cfg").get_parameter_value().string_value + image_resize = self.get_parameter("image_resize").get_parameter_value().integer_array_value + + # Retrieve sensor enable/disable parameters and global reference topic. + self.enable_front_camera = self.get_parameter("enable_front_camera").get_parameter_value().bool_value + self.enable_back_camera = self.get_parameter("enable_back_camera").get_parameter_value().bool_value + self.enable_lidar = self.get_parameter("enable_lidar").get_parameter_value().bool_value + self.enable_global_ref = self.get_parameter("enable_global_ref").get_parameter_value().bool_value + self.global_ref_topic = self.get_parameter("global_ref_topic").get_parameter_value().string_value + self.reserve = self.get_parameter("reserve").get_parameter_value().bool_value + + # Initialize CvBridge for image conversions. + self.cv_bridge = CvBridge() + + # Create subscribers and map sensor names to synchronizer indices. + subscribers = [] + mapping = {} + if self.enable_front_camera: + self.image_front_sub = Subscriber(self, CompressedImage, image_front_topic) + subscribers.append(self.image_front_sub) + mapping["front_image"] = len(subscribers) - 1 + + self.mask_front_sub = Subscriber(self, Image, mask_front_topic) + subscribers.append(self.mask_front_sub) + mapping["front_mask"] = len(subscribers) - 1 + else: + self.image_front_sub = None + self.mask_front_sub = None + + if self.enable_back_camera: + self.image_back_sub = Subscriber(self, CompressedImage, image_back_topic) + subscribers.append(self.image_back_sub) + mapping["back_image"] = len(subscribers) - 1 + + self.mask_back_sub = Subscriber(self, Image, mask_back_topic) + subscribers.append(self.mask_back_sub) + mapping["back_mask"] = len(subscribers) - 1 + else: + self.image_back_sub = None + self.mask_back_sub = None + + if self.enable_lidar: + self.lidar_sub = Subscriber(self, PointCloud2, lidar_topic) + subscribers.append(self.lidar_sub) + mapping["lidar"] = len(subscribers) - 1 + else: + self.lidar_sub = None + + # Save the mapping for use in the callback. + self.subscriber_mapping = mapping + + # Create the synchronizer if any subscribers exist. + if subscribers: + self.ts = ApproximateTimeSynchronizer(subscribers, queue_size=1, slop=1.05) + self.ts.registerCallback(self.listener_callback) + else: + self.get_logger().error("No sensor subscribers created; check sensor enable parameters.") + + # Create publishers for pose and database match index. + self.pose_pub = self.create_publisher(PoseStamped, "/place_recognition/pose", 10) + self.idx_pub = self.create_publisher(DatabaseMatchIndex, "/place_recognition/db_idx", 10) + + # Subscribe to global reference system messages if enabled. + if self.enable_global_ref: + self.global_ref_sub = self.create_subscription(NavSatFix, self.global_ref_topic, self.global_ref_callback, 10) + else: + self.global_ref_sub = None + self.global_ref = None + + # Instantiate the place recognition pipeline from configuration. + pipeline_config = OmegaConf.load(pipeline_cfg) + self.pr_pipe = instantiate(pipeline_config) + + # Check for Scene Object Context (SOC) module support. + if self.pr_pipe.model.soc_module is not None: + self.load_soc = True + self.get_logger().info("self.load_soc is set to True.") + sensors_cfg = OmegaConf.load(os.path.join(get_package_share_directory("open_place_recognition"), "configs/sensors/husky.yaml")) + anno_cfg = OmegaConf.load(os.path.join(get_package_share_directory("open_place_recognition"), "configs/anno/oneformer.yaml")) + self.front_cam_proj = Projector(sensors_cfg.front_cam, sensors_cfg.lidar) + self.back_cam_proj = Projector(sensors_cfg.back_cam, sensors_cfg.lidar) + self.max_distance_soc = 50.0 + self.top_k_soc = self.pr_pipe.model.soc_module.num_objects + self.special_classes = anno_cfg.special_classes + self.soc_coords_type = "euclidean" + else: + self.load_soc = False + + # Set up image and mask transformations. + self.image_transform = DefaultImageTransform(train=False, resize=image_resize) + self.mask_transform = DefaultSemanticTransform(train=False, resize=image_resize) + + self.get_logger().info(f"Initialized {self.__class__.__name__} node.") + + def global_ref_callback(self, msg: NavSatFix) -> None: + """Callback to update the global reference system message.""" + self.global_ref = msg + self.get_logger().debug(f"Received global reference message: {msg}") + + def _prepare_input( + self, + images: np.ndarray | list[np.ndarray] = None, + masks: np.ndarray | list[np.ndarray] = None, + pointcloud: np.ndarray = None, + ) -> dict[str, Tensor]: + """ + Prepare and transform input data for the pipeline. + + Args: + images: Single image or list of images (in numpy format). + masks: Single mask or list of masks. + pointcloud: Lidar pointcloud data as a numpy array. + + Returns: + Dictionary with transformed images, masks, and pointcloud tensors. + """ + input_data: dict[str, Tensor] = {} + + if images is not None: + if isinstance(images, list): + for i, image in enumerate(images): + if image is not None: + input_data[f"image_{i}"] = self.image_transform(image) + else: + self.get_logger().info(f"Image {i} is disabled or not available.") + elif isinstance(images, np.ndarray): + input_data["image_0"] = self.image_transform(images) + else: + self.get_logger().warning(f"Invalid type for images in '_prepare_input': {type(images)}") + + if masks is not None: + if isinstance(masks, list): + for i, mask in enumerate(masks): + if mask is not None: + input_data[f"mask_{i}"] = self.mask_transform(mask) + else: + self.get_logger().info(f"Mask {i} is disabled or not available.") + elif isinstance(masks, np.ndarray): + input_data["mask_0"] = self.mask_transform(masks) + else: + self.get_logger().warning(f"Invalid type for masks in '_prepare_input': {type(masks)}") + + if pointcloud is not None: + pointcloud_tensor = torch.tensor(pointcloud).contiguous() + input_data["pointcloud_lidar_coords"] = pointcloud_tensor[:, :3] + if pointcloud_tensor.shape[1] > 3: + input_data["pointcloud_lidar_feats"] = pointcloud_tensor[:, 3].unsqueeze(1) + else: + input_data["pointcloud_lidar_feats"] = torch.ones_like(pointcloud_tensor[:, :1]) + + if self.load_soc and masks is not None and isinstance(masks, list) and len(masks) >= 2: + input_data["soc"] = self._get_soc(mask_front=masks[0], mask_back=masks[1], lidar_scan=pointcloud) + + return input_data + + def _get_soc(self, mask_front: np.ndarray, mask_back: np.ndarray, lidar_scan: np.ndarray) -> Tensor: + """ + Compute the Scene Object Context (SOC) tensor based on the provided masks and lidar scan. + + Args: + mask_front: Semantic mask from the front camera. + mask_back: Semantic mask from the back camera. + lidar_scan: Lidar pointcloud data. + + Returns: + A PyTorch tensor representing packed objects. + """ + coords_front, _, in_image_front = self.front_cam_proj(lidar_scan) + coords_back, _, in_image_back = self.back_cam_proj(lidar_scan) + point_labels = np.zeros(len(lidar_scan), dtype=np.uint8) + point_labels[in_image_front] = get_points_labels_by_mask(coords_front, mask_front) + point_labels[in_image_back] = get_points_labels_by_mask(coords_back, mask_back) + instances_front = semantic_mask_to_instances(mask_front, area_threshold=10, labels_whitelist=self.special_classes) + instances_back = semantic_mask_to_instances(mask_back, area_threshold=10, labels_whitelist=self.special_classes) + objects_front = instance_masks_to_objects(instances_front, coords_front, + point_labels[in_image_front], lidar_scan[in_image_front]) + objects_back = instance_masks_to_objects(instances_back, coords_back, + point_labels[in_image_back], lidar_scan[in_image_back]) + objects = {**objects_front, **objects_back} + packed_objects = pack_objects(objects, self.top_k_soc, self.max_distance_soc, self.special_classes) + + if self.soc_coords_type == "cylindrical_3d": + packed_objects = np.concatenate(( + np.linalg.norm(packed_objects, axis=-1, keepdims=True), + np.arctan2(packed_objects[..., 1], packed_objects[..., 0])[..., None], + packed_objects[..., 2:], + ), axis=-1) + elif self.soc_coords_type == "cylindrical_2d": + packed_objects = np.concatenate(( + np.linalg.norm(packed_objects[..., :2], axis=-1, keepdims=True), + np.arctan2(packed_objects[..., 1], packed_objects[..., 0])[..., None], + packed_objects[..., 2:], + ), axis=-1) + elif self.soc_coords_type == "euclidean": + pass + elif self.soc_coords_type == "spherical": + packed_objects = np.concatenate(( + np.linalg.norm(packed_objects, axis=-1, keepdims=True), + np.arccos(packed_objects[..., 2] / np.linalg.norm(packed_objects, axis=-1, keepdims=True)), + np.arctan2(packed_objects[..., 1], packed_objects[..., 0])[..., None], + ), axis=-1) + else: + raise ValueError(f"Unknown soc_coords_type: {self.soc_coords_type!r}") + objects_tensor = torch.from_numpy(packed_objects).float() + return objects_tensor + + def _create_pose_msg(self, pose: np.ndarray, timestamp: Time) -> PoseStamped: + """ + Create a PoseStamped message from a pose array. + + Args: + pose: A 7-element array [x, y, z, qx, qy, qz, qw]. + timestamp: The message timestamp. + + Returns: + A populated PoseStamped message. + """ + pose_msg = PoseStamped() + pose_msg.header.stamp = timestamp + pose_msg.pose.position.x = pose[0] + pose_msg.pose.position.y = pose[1] + pose_msg.pose.position.z = pose[2] + pose_msg.pose.orientation.x = pose[3] + pose_msg.pose.orientation.y = pose[4] + pose_msg.pose.orientation.z = pose[5] + pose_msg.pose.orientation.w = pose[6] + return pose_msg + + def _create_idx_msg(self, idx: int, timestamp: Time) -> DatabaseMatchIndex: + """ + Create a DatabaseMatchIndex message. + + Args: + idx: The index value. + timestamp: The message timestamp. + + Returns: + A populated DatabaseMatchIndex message with the provided index. + """ + idx_msg = DatabaseMatchIndex() + idx_msg.header.stamp = timestamp + idx_msg.index = idx + return idx_msg + + def listener_callback(self, *msgs) -> None: + """ + Callback for synchronized sensor messages. + + Converts incoming messages to OpenCV and numpy formats, prepares input data, + runs inference through the place recognition pipeline, and publishes the results. + """ + self.get_logger().info("Received synchronized messages.") + t_start = self.get_clock().now() + + mapping = self.subscriber_mapping + front_image_msg = msgs[mapping["front_image"]] if "front_image" in mapping else None + front_mask_msg = msgs[mapping["front_mask"]] if "front_mask" in mapping else None + back_image_msg = msgs[mapping["back_image"]] if "back_image" in mapping else None + back_mask_msg = msgs[mapping["back_mask"]] if "back_mask" in mapping else None + lidar_msg = msgs[mapping["lidar"]] if "lidar" in mapping else None + + front_image = self.cv_bridge.compressed_imgmsg_to_cv2(front_image_msg) if front_image_msg is not None else None + back_image = self.cv_bridge.compressed_imgmsg_to_cv2(back_image_msg) if back_image_msg is not None else None + front_mask = self.cv_bridge.imgmsg_to_cv2(front_mask_msg) if front_mask_msg is not None else None + back_mask = self.cv_bridge.imgmsg_to_cv2(back_mask_msg) if back_mask_msg is not None else None + + if lidar_msg is not None: + points = read_points(lidar_msg, field_names=("x", "y", "z")) + pointcloud = np.array([points["x"], points["y"], points["z"]]).T + else: + pointcloud = None + + input_data = self._prepare_input( + images=[front_image, back_image], + masks=[front_mask, back_mask], + pointcloud=pointcloud + ) + + output = self.pr_pipe.infer(input_data) + t_taken = self.get_clock().now() - t_start + self.get_logger().info(f"Place recognition inference took: {t_taken.nanoseconds / 1e6} ms.") + + timestamp = lidar_msg.header.stamp if lidar_msg is not None else self.get_clock().now().to_msg() + pose_msg = self._create_pose_msg(output["pose"], timestamp) + idx_msg = self._create_idx_msg(int(output["idx"]), timestamp) + self.pose_pub.publish(pose_msg) + self.get_logger().info(f"Published pose message: {pose_msg.pose}") + self.idx_pub.publish(idx_msg) + self.get_logger().info(f"Published database index message: {idx_msg.index}") + + +def main(args=None): + """Main entry point for the Place Recognition node.""" + rclpy.init(args=args) + pr_node = PlaceRecognitionNode() + rclpy.spin(pr_node) + pr_node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/src/open_place_recognition/open_place_recognition/depth_estimation.py b/open_place_recognition/src/test_depth_estimation_node.py old mode 100644 new mode 100755 similarity index 99% rename from src/open_place_recognition/open_place_recognition/depth_estimation.py rename to open_place_recognition/src/test_depth_estimation_node.py index 7f87c34..0e0f99f --- a/src/open_place_recognition/open_place_recognition/depth_estimation.py +++ b/open_place_recognition/src/test_depth_estimation_node.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 from rclpy.node import Node import numpy as np import rclpy diff --git a/open_place_recognition/src/test_opr_odom_node.py b/open_place_recognition/src/test_opr_odom_node.py new file mode 100755 index 0000000..ceb1c93 --- /dev/null +++ b/open_place_recognition/src/test_opr_odom_node.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +import rclpy +from rclpy.node import Node +import os +import sys +from ament_index_python.packages import get_package_share_directory + +class ModelOPRNode(Node): + def __init__(self): + super().__init__('model_opr_node') + # Get parameter (only map_name is needed) + self.declare_parameter('map_name', 'default_map') + map_name = self.get_parameter('map_name').value + + # Get package share directory and build the weights path + package_dir = get_package_share_directory('orca_opr') + weights_path = os.path.join(package_dir, 'weights') + + if not os.path.exists(weights_path): + self.get_logger().error(f"Weights directory {weights_path} does not exist. Please create it and try again.") + sys.exit(1) + + dummy_model_file = os.path.join(weights_path, f"{map_name}.pt") + if not os.path.exists(dummy_model_file): + self.get_logger().error(f"Model file {dummy_model_file} does not exist. Please run the training node first.") + sys.exit(1) + else: + self.get_logger().info(f"Model file {dummy_model_file} found. Loading model...") + # Simulate model loading (in future, actual torch code will be used) + self.get_logger().info("Model loaded successfully.") + +def main(args=None): + rclpy.init(args=args) + node = ModelOPRNode() + rclpy.spin_once(node, timeout_sec=1) + node.destroy_node() + rclpy.shutdown() + +if __name__ == '__main__': + main() diff --git a/src/open_place_recognition/open_place_recognition/visualizer.py b/open_place_recognition/src/test_visualizer_node.py old mode 100644 new mode 100755 similarity index 99% rename from src/open_place_recognition/open_place_recognition/visualizer.py rename to open_place_recognition/src/test_visualizer_node.py index d5f1b33..c485667 --- a/src/open_place_recognition/open_place_recognition/visualizer.py +++ b/open_place_recognition/src/test_visualizer_node.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 import os from typing import Tuple diff --git a/src/opr_interfaces/CMakeLists.txt b/opr_interfaces/CMakeLists.txt similarity index 100% rename from src/opr_interfaces/CMakeLists.txt rename to opr_interfaces/CMakeLists.txt diff --git a/src/opr_interfaces/msg/DatabaseMatchIndex.msg b/opr_interfaces/msg/DatabaseMatchIndex.msg similarity index 100% rename from src/opr_interfaces/msg/DatabaseMatchIndex.msg rename to opr_interfaces/msg/DatabaseMatchIndex.msg diff --git a/src/opr_interfaces/package.xml b/opr_interfaces/package.xml similarity index 100% rename from src/opr_interfaces/package.xml rename to opr_interfaces/package.xml diff --git a/src/open_place_recognition/launch/depth_estimation.launch.py b/src/open_place_recognition/launch/depth_estimation.launch.py deleted file mode 100644 index 643b12b..0000000 --- a/src/open_place_recognition/launch/depth_estimation.launch.py +++ /dev/null @@ -1,22 +0,0 @@ -from launch import LaunchDescription -from launch_ros.actions import Node - -def generate_launch_description(): - return LaunchDescription([ - Node( - package='open_place_recognition', - executable='depth_estimation', - name='depth_estimation_with_lidar', - output='screen', - emulate_tty=True, - parameters=[ - {"image_front_topic": "/zed_node/left/image_rect_color/compressed", - "camera_info_front_topic": "/zed_node/left/camera_info", - "lidar_topic": "/velodyne_points", - "publish_point_cloud_form_depth": True, - "model_weights_path": "/home/docker_opr_ros2/ros2_ws/dependencies/OpenPlaceRecognition/weights/depth_estimation/res50.pth", - "device": "cuda", - "image_resize": [640, 480]} - ] - ) - ]) diff --git a/src/open_place_recognition/launch/localization_launch.py b/src/open_place_recognition/launch/localization_launch.py deleted file mode 100644 index 26b6a1a..0000000 --- a/src/open_place_recognition/launch/localization_launch.py +++ /dev/null @@ -1,25 +0,0 @@ -from launch import LaunchDescription -from launch_ros.actions import Node - -def generate_launch_description(): - return LaunchDescription([ - Node( - package='open_place_recognition', - executable='localization', - name='hierarchical_localization', - output='screen', - emulate_tty=True, - parameters=[ - { - "image_front_topic": "/zed_node/left/image_rect_color/compressed", - "image_back_topic": "/realsense_back/color/image_raw/compressed", - "mask_front_topic": "/zed_node/left/semantic_segmentation", - "mask_back_topic": "/realsense_back/semantic_segmentation", - "lidar_topic": "/velodyne_points", - "pipeline_cfg": "/home/docker_opr_ros2/ros2_ws/src/open_place_recognition/configs/pipelines/localization_pipeline.yaml", - # "pipeline_cfg": "/home/docker_opr_ros2/ros2_ws/src/open_place_recognition/configs/pipelines/aruco_localization_pipeline.yaml", - "exclude_dynamic_classes": False, - "image_resize": [320, 192]} - ] - ) - ]) diff --git a/src/open_place_recognition/launch/place_recognition_launch.py b/src/open_place_recognition/launch/place_recognition_launch.py deleted file mode 100644 index e65137d..0000000 --- a/src/open_place_recognition/launch/place_recognition_launch.py +++ /dev/null @@ -1,25 +0,0 @@ -from launch import LaunchDescription -from launch_ros.actions import Node - -def generate_launch_description(): - return LaunchDescription([ - Node( - package='open_place_recognition', - executable='place_recognition', - name='multimodal_multicamera_lidar_place_recognition', - output='screen', - emulate_tty=True, - parameters=[ - {"image_front_topic": "/zed_node/left/image_rect_color/compressed", - "image_back_topic": "/realsense_back/color/image_raw/compressed", - "mask_front_topic": "/zed_node/left/semantic_segmentation", - "mask_back_topic": "/realsense_back/semantic_segmentation", - "lidar_topic": "/velodyne_points", - "pipeline_cfg": "/home/docker_opr_ros2/ros2_ws/src/open_place_recognition/configs/pipelines/place_recognition/multimodal_pr.yaml", - # "pipeline_cfg": "/home/docker_opr_ros2/ros2_ws/src/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_pr.yaml", - # "pipeline_cfg": "/home/docker_opr_ros2/ros2_ws/src/open_place_recognition/configs/pipelines/place_recognition/multimodal_with_soc_outdoor_pr.yaml", - # "pipeline_cfg": "/home/docker_opr_ros2/ros2_ws/src/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_with_soc_outdoor_pr.yaml", - "image_resize": [320, 192]} - ] - ) - ]) diff --git a/src/open_place_recognition/open_place_recognition/localization.py b/src/open_place_recognition/open_place_recognition/localization.py deleted file mode 100644 index 2171707..0000000 --- a/src/open_place_recognition/open_place_recognition/localization.py +++ /dev/null @@ -1,397 +0,0 @@ -import cv2 -import numpy as np -import rclpy -import torch -from cv_bridge import CvBridge -from hydra.utils import instantiate -from message_filters import ApproximateTimeSynchronizer, Subscriber -from omegaconf import OmegaConf -from rclpy.node import Node -from rcl_interfaces.msg import ParameterDescriptor -from builtin_interfaces.msg import Time -from geometry_msgs.msg import PoseStamped -from sensor_msgs.msg import Image, CompressedImage, PointCloud2 -from sensor_msgs_py.point_cloud2 import read_points -from std_msgs.msg import Int32 -from torch import Tensor -import albumentations as A -from albumentations.pytorch import ToTensorV2 - -from opr.pipelines.localization import ArucoLocalizationPipeline -from opr_interfaces.msg import DatabaseMatchIndex -from opr.datasets.augmentations import DefaultImageTransform, DefaultSemanticTransform -from opr.datasets.projection import Projector -from opr.datasets.soc_utils import ( - get_points_labels_by_mask, - instance_masks_to_objects, - pack_objects, - semantic_mask_to_instances, -) - - -TOPIC = "/zed_node/left/image_rect_color/compressed" -DATABASE_DIR = "/path/to/database" -MODEL_CFG = "/path/to/model/config.yaml" -MODEL_WEIGHTS_PATH = "/path/to/model/weights.pth" -DEVICE = "cuda" -IMAGE_RESIZE = (320, 192) - - -class ImageTransformWithoutNormalize: - def __call__(self, img: np.ndarray): - """Applies transformations to the given image. - - Args: - img (np.ndarray): The image in the cv2 format. - - Returns: - Tensor: Augmented PyTorch tensor in the channel-first format. - """ - return A.Compose([ToTensorV2()])(image=img)["image"] - - -class LocalizationNode(Node): - - def __init__(self): - super().__init__("localization") - self._declare_parameters() - - image_front_topic = self.get_parameter("image_front_topic").get_parameter_value().string_value - image_back_topic = self.get_parameter("image_back_topic").get_parameter_value().string_value - mask_front_topic = self.get_parameter("mask_front_topic").get_parameter_value().string_value - mask_back_topic = self.get_parameter("mask_back_topic").get_parameter_value().string_value - lidar_topic = self.get_parameter("lidar_topic").get_parameter_value().string_value - pipeline_cfg = self.get_parameter("pipeline_cfg").get_parameter_value().string_value - exclude_dynamic_classes = self.get_parameter("exclude_dynamic_classes").get_parameter_value().bool_value - image_resize = self.get_parameter("image_resize").get_parameter_value().integer_array_value - - self.cv_bridge = CvBridge() - - self.image_front_sub = Subscriber(self, CompressedImage, image_front_topic) - self.image_back_sub = Subscriber(self, CompressedImage, image_back_topic) - self.mask_front_sub = Subscriber(self, Image, mask_front_topic) - self.mask_back_sub = Subscriber(self, Image, mask_back_topic) - self.lidar_sub = Subscriber(self, PointCloud2, lidar_topic) - - self.ts = ApproximateTimeSynchronizer( - [self.image_front_sub, self.image_back_sub, self.mask_front_sub, self.mask_back_sub, self.lidar_sub], - queue_size=1, - slop=0.05, - ) - self.ts.registerCallback(self.listener_callback) - - self.db_match_pose_pub = self.create_publisher(PoseStamped, "/place_recognition/pose", 10) - self.idx_pub = self.create_publisher(DatabaseMatchIndex, "/place_recognition/db_idx", 10) - self.estimated_pose_pub = self.create_publisher(PoseStamped, "/localization/pose", 10) - - self.pipeline = instantiate(OmegaConf.load(pipeline_cfg)) - - if self.pipeline.pr_pipe.model.soc_module is not None: - self.load_soc = True - self.get_logger().info(f"self.load_soc is set to True.") - sensors_cfg = OmegaConf.load("/home/docker_opr_ros2/ros2_ws/src/open_place_recognition/configs/sensors/husky.yaml") - anno_cfg = OmegaConf.load("/home/docker_opr_ros2/ros2_ws/src/open_place_recognition/configs/anno/oneformer.yaml") - self.front_cam_proj = Projector(sensors_cfg.front_cam, sensors_cfg.lidar) - self.back_cam_proj = Projector(sensors_cfg.back_cam, sensors_cfg.lidar) - self.max_distance_soc = 50.0 - self.top_k_soc = self.pipeline.pr_pipe.model.soc_module.num_objects - self.special_classes = anno_cfg.special_classes - self.soc_coords_type = "euclidean" - else: - self.load_soc = False - - if isinstance(self.pipeline, ArucoLocalizationPipeline): - self.image_transform = ImageTransformWithoutNormalize() - self.mask_transform = DefaultSemanticTransform(train=False, resize=None) - else: - self.image_transform = DefaultImageTransform(train=False, resize=image_resize) - self.mask_transform = DefaultSemanticTransform(train=False, resize=image_resize) - - self._ade20k_dynamic_idx = [12] - self.exclude_dynamic_classes = exclude_dynamic_classes - - self.lidar2front = np.array([[ 0.01509615, -0.99976457, -0.01558544, 0.04632156], - [ 0.00871086, 0.01571812, -0.99983852, -0.13278588], - [ 0.9998481, 0.01495794, 0.0089461, -0.06092749], - [ 0. , 0. , 0. , 1. ]]) - self.lidar2back = np.array([[-1.50409674e-02, 9.99886421e-01, 9.55906151e-04, 1.82703304e-02], - [-1.30440106e-02, 7.59716299e-04, -9.99914635e-01, -1.41787545e-01], - [-9.99801792e-01, -1.50521522e-02, 1.30311022e-02, -6.72336358e-02], - [ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.00000000e+00]]) - self.front_matrix = np.array([[683.6199340820312, 0.0, 615.1160278320312, 0.0, 683.6199340820312, 345.32354736328125, 0.0, 0.0, 1.0]]).reshape((3,3)) - self.front_dist = np.array([0.0, 0.0, 0.0, 0.0, 0.0]) - self.back_matrix = np.array([[910.4178466796875, 0.0, 648.44140625, 0.0, 910.4166870117188, 354.0118408203125, 0.0, 0.0, 1.0]]).reshape((3,3)) - self.back_dist = np.array([0.0, 0.0, 0.0, 0.0, 0.0]) - - self.get_logger().info(f"Initialized {self.__class__.__name__} node.") - - def _declare_parameters(self) -> None: - self.declare_parameter( - "image_front_topic", - rclpy.Parameter.Type.STRING, #"/zed_node/left/image_rect_color/compressed", - ParameterDescriptor(description="Front camera image topic.") - ) - self.declare_parameter( - "image_back_topic", - rclpy.Parameter.Type.STRING, #"/realsense_back/color/image_raw/compressed", - ParameterDescriptor(description="Back camera image topic.") - ) - self.declare_parameter( - "mask_front_topic", - rclpy.Parameter.Type.STRING, #"/zed_node/left/semantic_segmentation", - ParameterDescriptor(description="Front semantic segmentation mask topic.") - ) - self.declare_parameter( - "mask_back_topic", - rclpy.Parameter.Type.STRING, #"/realsense_back/semantic_segmentation", - ParameterDescriptor(description="Back semantic segmentation mask topic.") - ) - self.declare_parameter( - "lidar_topic", - rclpy.Parameter.Type.STRING, #"/velodyne_points", - ParameterDescriptor(description="Lidar pointcloud topic.") - ) - self.declare_parameter( - "pipeline_cfg", - rclpy.Parameter.Type.STRING, #"", - ParameterDescriptor(description="Path to the pipeline configuration file.") - ) - self.declare_parameter( - "exclude_dynamic_classes", - rclpy.Parameter.Type.BOOL, - ParameterDescriptor(description="Exclude dynamic objects from the input data.") - ) - self.declare_parameter( - "image_resize", - rclpy.Parameter.Type.INTEGER_ARRAY, #(320, 192), - ParameterDescriptor(description="Image resize dimensions.") - ) - - def _prepare_input( - self, - images: np.ndarray | list[np.ndarray] = None, - masks: np.ndarray | list[np.ndarray] = None, - pointcloud: np.ndarray = None, - ) -> dict[str, Tensor]: - input_data = {} - if images is not None: - if isinstance(images, list): - for i, image in enumerate(images): - input_data[f"image_{i}"] = image - if self.exclude_dynamic_classes and masks is not None: - for index in self._ade20k_dynamic_idx: - input_data[f"image_{i}"] = np.where(masks[i][:, :, np.newaxis] == index, 0, input_data[f"image_{i}"]) - input_data[f"image_{i}"] = self.image_transform(input_data[f"image_{i}"]) - elif isinstance(images, np.ndarray): - input_data["image_0"] = images - if self.exclude_dynamic_classes and masks is not None: - for index in self._ade20k_dynamic_idx: - input_data["image_0"] = np.where(masks == index, 0, input_data["image_0"]) - input_data["image_0"] = self.image_transform(input_data["image_0"]) - else: - self.get_logger().warning(f"Invalid type for images in '_prepare_input': {type(images)}") - if masks is not None: - if isinstance(masks, list): - for i, mask in enumerate(masks): - input_data[f"mask_{i}"] = self.mask_transform(mask) - elif isinstance(masks, np.ndarray): - input_data["mask_0"] = self.mask_transform(masks) - else: - self.get_logger().warning(f"Invalid type for masks in '_prepare_input': {type(masks)}") - if pointcloud is not None: - if self.exclude_dynamic_classes and masks is not None: - if isinstance(masks, list): - for i, mask in enumerate(masks): - pointcloud = self._remove_dynamic_points(pointcloud, mask, self.lidar2back, self.back_matrix, self.back_dist) - elif isinstance(masks, np.ndarray): - pointcloud = self._remove_dynamic_points(pointcloud, masks, self.lidar2back, self.back_matrix, self.back_dist) - pointcloud = torch.tensor(pointcloud).contiguous() - pointcloud = pointcloud[~torch.any(pointcloud.isnan(), dim=1)] - input_data["pointcloud_lidar_coords"] = pointcloud[:, :3] - if pointcloud.shape[1] > 3: - input_data["pointcloud_lidar_feats"] = pointcloud[:, 3].unsqueeze(1) - else: - input_data["pointcloud_lidar_feats"] = torch.ones_like(pointcloud[:, :1]) - if self.load_soc: - input_data["soc"] = self._get_soc(mask_front=masks[0], mask_back=masks[1], lidar_scan=pointcloud) - return input_data - - def _get_soc(self, mask_front: np.ndarray, mask_back: np.ndarray, lidar_scan: np.ndarray) -> Tensor: - coords_front, _, in_image_front = self.front_cam_proj(lidar_scan) - coords_back, _, in_image_back = self.back_cam_proj(lidar_scan) - - point_labels = np.zeros(len(lidar_scan), dtype=np.uint8) - point_labels[in_image_front] = get_points_labels_by_mask(coords_front, mask_front) - point_labels[in_image_back] = get_points_labels_by_mask(coords_back, mask_back) - - instances_front = semantic_mask_to_instances( - mask_front, - area_threshold=10, - labels_whitelist=self.special_classes, - ) - instances_back = semantic_mask_to_instances( - mask_back, - area_threshold=10, - labels_whitelist=self.special_classes, - ) - - objects_front = instance_masks_to_objects( - instances_front, - coords_front, - point_labels[in_image_front], - lidar_scan[in_image_front], - ) - objects_back = instance_masks_to_objects( - instances_back, - coords_back, - point_labels[in_image_back], - lidar_scan[in_image_back], - ) - - objects = {**objects_front, **objects_back} - packed_objects = pack_objects(objects, self.top_k_soc, self.max_distance_soc, self.special_classes) - - if self.soc_coords_type == "cylindrical_3d": - packed_objects = np.concatenate( - ( - np.linalg.norm(packed_objects, axis=-1, keepdims=True), - np.arctan2(packed_objects[..., 1], packed_objects[..., 0])[..., None], - packed_objects[..., 2:], - ), - axis=-1, - ) - elif self.soc_coords_type == "cylindrical_2d": - packed_objects = np.concatenate( - ( - np.linalg.norm(packed_objects[..., :2], axis=-1, keepdims=True), - np.arctan2(packed_objects[..., 1], packed_objects[..., 0])[..., None], - packed_objects[..., 2:], - ), - axis=-1, - ) - elif self.soc_coords_type == "euclidean": - pass - elif self.soc_coords_type == "spherical": - packed_objects = np.concatenate( - ( - np.linalg.norm(packed_objects, axis=-1, keepdims=True), - np.arccos( - packed_objects[..., 2] / np.linalg.norm(packed_objects, axis=-1, keepdims=True) - ), - np.arctan2(packed_objects[..., 1], packed_objects[..., 0])[..., None], - ), - axis=-1, - ) - else: - raise ValueError(f"Unknown soc_coords_type: {self.soc_coords_type!r}") - - objects_tensor = torch.from_numpy(packed_objects).float() - - return objects_tensor - - def _remove_dynamic_points(self, pointcloud: np.ndarray, semantic_map: np.ndarray, lidar2sensor: np.ndarray, - sensor_intrinsics: np.ndarray, sensor_dist: np.ndarray) -> np.ndarray: - pc_values = np.concatenate([pointcloud, np.ones((pointcloud.shape[0], 1))],axis=1).T - camera_values = lidar2sensor @ pc_values - camera_values = np.transpose(camera_values)[:, :3] - - points_2d, _ = cv2.projectPoints(camera_values, - np.zeros((3, 1), np.float32), np.zeros((3, 1), np.float32), - sensor_intrinsics, - sensor_dist) - points_2d = points_2d[:, 0, :] - - classes = set(np.unique(semantic_map)) - dynamic_classes = set(self._ade20k_dynamic_idx) - if classes.intersection(dynamic_classes): - valid = (~np.isnan(points_2d[:,0])) & (~np.isnan(points_2d[:,1])) - in_bounds_x = (points_2d[:,0] >= 0) & (points_2d[:,0] < 1280) - in_bounds_y = (points_2d[:,1] >= 0) & (points_2d[:,1] < 720) - look_forward = (camera_values[:, 2] > 0) - mask = valid & in_bounds_x & in_bounds_y & look_forward - - indices = np.where(mask)[0] - mask_for_points = np.full((points_2d.shape[0], 3), True) - - dynamic_idx = np.array(self._ade20k_dynamic_idx) - semantic_values = semantic_map[np.floor(points_2d[indices, 1]).astype(int), np.floor(points_2d[indices, 0]).astype(int)] - - matching_indices = np.where(np.isin(semantic_values, dynamic_idx)) - - mask_for_points = np.full((points_2d.shape[0], 3), True) - mask_for_points[indices[matching_indices[0]]] = np.array([False, False, False]) - - return pointcloud[mask_for_points].reshape((-1, 3)) - else: - return pointcloud - - def _create_pose_msg(self, pose: np.ndarray, timestamp: Time) -> PoseStamped: - pose_msg = PoseStamped() - pose_msg.header.stamp = timestamp - pose_msg.pose.position.x = pose[0] - pose_msg.pose.position.y = pose[1] - pose_msg.pose.position.z = pose[2] - pose_msg.pose.orientation.x = pose[3] - pose_msg.pose.orientation.y = pose[4] - pose_msg.pose.orientation.z = pose[5] - pose_msg.pose.orientation.w = pose[6] - return pose_msg - - def _create_idx_msg(self, idx: int, timestamp: Time) -> DatabaseMatchIndex: - idx_msg = DatabaseMatchIndex() - idx_msg.header.stamp = timestamp - idx_msg.index = idx - return idx_msg - - def listener_callback( - self, - front_image_msg: CompressedImage, - back_image_msg: CompressedImage, - front_mask_msg: Image, - back_mask_msg: Image, - lidar_msg: PointCloud2, - ) -> None: - self.get_logger().info("Received synchronized messages.") - t_start = self.get_clock().now() - lidar_timestamp = lidar_msg.header.stamp - front_image = self.cv_bridge.compressed_imgmsg_to_cv2(front_image_msg) - back_image = self.cv_bridge.compressed_imgmsg_to_cv2(back_image_msg) - front_mask = self.cv_bridge.imgmsg_to_cv2(front_mask_msg) - back_mask = self.cv_bridge.imgmsg_to_cv2(back_mask_msg) - pointcloud = read_points(lidar_msg, field_names=("x", "y", "z")) - pointcloud = np.array([pointcloud["x"], pointcloud["y"], pointcloud["z"]]).T - input_data = self._prepare_input( - images=[front_image, back_image], masks=[front_mask, back_mask], pointcloud=pointcloud - ) - output = self.pipeline.infer(input_data) - t_taken = self.get_clock().now() - t_start - self.get_logger().debug(f"Localization inference took: {t_taken.nanoseconds / 1e6} ms.") - self.get_logger().info(f"output['db_match_pose'] = {output['db_match_pose']}") - output['db_match_pose'] = output['db_match_pose'].tolist() - db_match_pose_msg = self._create_pose_msg(output["db_match_pose"], lidar_timestamp) - estimated_pose_msg = self._create_pose_msg(output["estimated_pose"], lidar_timestamp) - idx_msg = self._create_idx_msg(int(output["db_idx"]), lidar_timestamp) - self.db_match_pose_pub.publish(db_match_pose_msg) - self.get_logger().info(f"Published db match pose message: {db_match_pose_msg.pose}") - self.estimated_pose_pub.publish(estimated_pose_msg) - self.get_logger().info(f"Published estimated pose message: {estimated_pose_msg.pose}") - self.idx_pub.publish(idx_msg) - self.get_logger().info(f"Published database index message: {idx_msg.index}") - - -def main(args=None): - rclpy.init(args=args) - - loc_node = LocalizationNode() - - rclpy.spin(loc_node) - - # Destroy the node explicitly - # (optional - otherwise it will be done automatically - # when the garbage collector destroys the node object) - loc_node.destroy_node() - rclpy.shutdown() - - -if __name__ == '__main__': - main() diff --git a/src/open_place_recognition/open_place_recognition/place_recognition.py b/src/open_place_recognition/open_place_recognition/place_recognition.py deleted file mode 100644 index e3a4294..0000000 --- a/src/open_place_recognition/open_place_recognition/place_recognition.py +++ /dev/null @@ -1,299 +0,0 @@ -import numpy as np -import rclpy -import torch -from cv_bridge import CvBridge -from hydra.utils import instantiate -from message_filters import ApproximateTimeSynchronizer, Subscriber -from omegaconf import OmegaConf -from rclpy.node import Node -from rcl_interfaces.msg import ParameterDescriptor -from builtin_interfaces.msg import Time -from geometry_msgs.msg import PoseStamped -from sensor_msgs.msg import Image, CompressedImage, PointCloud2 -from sensor_msgs_py.point_cloud2 import read_points -from std_msgs.msg import Int32 -from torch import Tensor - -from opr_interfaces.msg import DatabaseMatchIndex -from opr.datasets.augmentations import DefaultImageTransform, DefaultSemanticTransform -from opr.datasets.projection import Projector -from opr.datasets.soc_utils import ( - get_points_labels_by_mask, - instance_masks_to_objects, - pack_objects, - semantic_mask_to_instances, -) -from opr.pipelines.place_recognition import PlaceRecognitionPipeline - - -TOPIC = "/zed_node/left/image_rect_color/compressed" -DATABASE_DIR = "/path/to/database" -MODEL_CFG = "/path/to/model/config.yaml" -MODEL_WEIGHTS_PATH = "/path/to/model/weights.pth" -DEVICE = "cuda" -IMAGE_RESIZE = (320, 192) - - -class PlaceRecognitionNode(Node): - - def __init__(self): - super().__init__("place_recognition") - self._declare_parameters() - - image_front_topic = self.get_parameter("image_front_topic").get_parameter_value().string_value - image_back_topic = self.get_parameter("image_back_topic").get_parameter_value().string_value - mask_front_topic = self.get_parameter("mask_front_topic").get_parameter_value().string_value - mask_back_topic = self.get_parameter("mask_back_topic").get_parameter_value().string_value - lidar_topic = self.get_parameter("lidar_topic").get_parameter_value().string_value - pipeline_cfg = self.get_parameter("pipeline_cfg").get_parameter_value().string_value - image_resize = self.get_parameter("image_resize").get_parameter_value().integer_array_value - - self.cv_bridge = CvBridge() - - self.image_front_sub = Subscriber(self, CompressedImage, image_front_topic) - self.image_back_sub = Subscriber(self, CompressedImage, image_back_topic) - self.mask_front_sub = Subscriber(self, Image, mask_front_topic) - self.mask_back_sub = Subscriber(self, Image, mask_back_topic) - self.lidar_sub = Subscriber(self, PointCloud2, lidar_topic) - - self.ts = ApproximateTimeSynchronizer( - [self.image_front_sub, self.image_back_sub, self.mask_front_sub, self.mask_back_sub, self.lidar_sub], - queue_size=1, - slop=0.05, - ) - self.ts.registerCallback(self.listener_callback) - - self.pose_pub = self.create_publisher(PoseStamped, "/place_recognition/pose", 10) - self.idx_pub = self.create_publisher(DatabaseMatchIndex, "/place_recognition/db_idx", 10) - - pipeline_config = OmegaConf.load(pipeline_cfg) - self.pr_pipe = instantiate(pipeline_config) - - if self.pr_pipe.model.soc_module is not None: - self.load_soc = True - self.get_logger().info(f"self.load_soc is set to True.") - sensors_cfg = OmegaConf.load("/home/docker_opr_ros2/ros2_ws/src/open_place_recognition/configs/sensors/husky.yaml") - anno_cfg = OmegaConf.load("/home/docker_opr_ros2/ros2_ws/src/open_place_recognition/configs/anno/oneformer.yaml") - self.front_cam_proj = Projector(sensors_cfg.front_cam, sensors_cfg.lidar) - self.back_cam_proj = Projector(sensors_cfg.back_cam, sensors_cfg.lidar) - self.max_distance_soc = 50.0 - self.top_k_soc = self.pr_pipe.model.soc_module.num_objects - self.special_classes = anno_cfg.special_classes - self.soc_coords_type = "euclidean" - else: - self.load_soc = False - - self.image_transform = DefaultImageTransform(train=False, resize=image_resize) - self.mask_transform = DefaultSemanticTransform(train=False, resize=image_resize) - - self.get_logger().info(f"Initialized {self.__class__.__name__} node.") - - def _declare_parameters(self) -> None: - self.declare_parameter( - "image_front_topic", - rclpy.Parameter.Type.STRING, #"/zed_node/left/image_rect_color/compressed", - ParameterDescriptor(description="Front camera image topic.") - ) - self.declare_parameter( - "image_back_topic", - rclpy.Parameter.Type.STRING, #"/realsense_back/color/image_raw/compressed", - ParameterDescriptor(description="Back camera image topic.") - ) - self.declare_parameter( - "mask_front_topic", - rclpy.Parameter.Type.STRING, #"/zed_node/left/semantic_segmentation", - ParameterDescriptor(description="Front semantic segmentation mask topic.") - ) - self.declare_parameter( - "mask_back_topic", - rclpy.Parameter.Type.STRING, #"/realsense_back/semantic_segmentation", - ParameterDescriptor(description="Back semantic segmentation mask topic.") - ) - self.declare_parameter( - "lidar_topic", - rclpy.Parameter.Type.STRING, #"/velodyne_points", - ParameterDescriptor(description="Lidar pointcloud topic.") - ) - self.declare_parameter( - "pipeline_cfg", - rclpy.Parameter.Type.STRING, #"", - ParameterDescriptor(description="Path to the pipeline configuration file.") - ) - self.declare_parameter( - "image_resize", - rclpy.Parameter.Type.INTEGER_ARRAY, #(320, 192), - ParameterDescriptor(description="Image resize dimensions.") - ) - - def _prepare_input( - self, - images: np.ndarray | list[np.ndarray] = None, - masks: np.ndarray | list[np.ndarray] = None, - pointcloud: np.ndarray = None, - ) -> dict[str, Tensor]: - input_data = {} - if images is not None: - if isinstance(images, list): - for i, image in enumerate(images): - input_data[f"image_{i}"] = self.image_transform(image) - elif isinstance(images, np.ndarray): - input_data["image_0"] = self.image_transform(images) - else: - self.get_logger().warning(f"Invalid type for images in '_prepare_input': {type(images)}") - if masks is not None: - if isinstance(masks, list): - for i, mask in enumerate(masks): - input_data[f"mask_{i}"] = self.mask_transform(mask) - elif isinstance(masks, np.ndarray): - input_data["mask_0"] = self.mask_transform(masks) - else: - self.get_logger().warning(f"Invalid type for masks in '_prepare_input': {type(masks)}") - if pointcloud is not None: - pointcloud = torch.tensor(pointcloud).contiguous() - input_data["pointcloud_lidar_coords"] = pointcloud[:, :3] - if pointcloud.shape[1] > 3: - input_data["pointcloud_lidar_feats"] = pointcloud[:, 3].unsqueeze(1) - else: - input_data["pointcloud_lidar_feats"] = torch.ones_like(pointcloud[:, :1]) - if self.load_soc: - input_data["soc"] = self._get_soc(mask_front=masks[0], mask_back=masks[1], lidar_scan=pointcloud) - return input_data - - def _get_soc(self, mask_front: np.ndarray, mask_back: np.ndarray, lidar_scan: np.ndarray) -> Tensor: - coords_front, _, in_image_front = self.front_cam_proj(lidar_scan) - coords_back, _, in_image_back = self.back_cam_proj(lidar_scan) - - point_labels = np.zeros(len(lidar_scan), dtype=np.uint8) - point_labels[in_image_front] = get_points_labels_by_mask(coords_front, mask_front) - point_labels[in_image_back] = get_points_labels_by_mask(coords_back, mask_back) - - instances_front = semantic_mask_to_instances( - mask_front, - area_threshold=10, - labels_whitelist=self.special_classes, - ) - instances_back = semantic_mask_to_instances( - mask_back, - area_threshold=10, - labels_whitelist=self.special_classes, - ) - - objects_front = instance_masks_to_objects( - instances_front, - coords_front, - point_labels[in_image_front], - lidar_scan[in_image_front], - ) - objects_back = instance_masks_to_objects( - instances_back, - coords_back, - point_labels[in_image_back], - lidar_scan[in_image_back], - ) - - objects = {**objects_front, **objects_back} - packed_objects = pack_objects(objects, self.top_k_soc, self.max_distance_soc, self.special_classes) - - if self.soc_coords_type == "cylindrical_3d": - packed_objects = np.concatenate( - ( - np.linalg.norm(packed_objects, axis=-1, keepdims=True), - np.arctan2(packed_objects[..., 1], packed_objects[..., 0])[..., None], - packed_objects[..., 2:], - ), - axis=-1, - ) - elif self.soc_coords_type == "cylindrical_2d": - packed_objects = np.concatenate( - ( - np.linalg.norm(packed_objects[..., :2], axis=-1, keepdims=True), - np.arctan2(packed_objects[..., 1], packed_objects[..., 0])[..., None], - packed_objects[..., 2:], - ), - axis=-1, - ) - elif self.soc_coords_type == "euclidean": - pass - elif self.soc_coords_type == "spherical": - packed_objects = np.concatenate( - ( - np.linalg.norm(packed_objects, axis=-1, keepdims=True), - np.arccos( - packed_objects[..., 2] / np.linalg.norm(packed_objects, axis=-1, keepdims=True) - ), - np.arctan2(packed_objects[..., 1], packed_objects[..., 0])[..., None], - ), - axis=-1, - ) - else: - raise ValueError(f"Unknown soc_coords_type: {self.soc_coords_type!r}") - - objects_tensor = torch.from_numpy(packed_objects).float() - - return objects_tensor - - def _create_pose_msg(self, pose: np.ndarray, timestamp: Time) -> PoseStamped: - pose_msg = PoseStamped() - pose_msg.header.stamp = timestamp - pose_msg.pose.position.x = pose[0] - pose_msg.pose.position.y = pose[1] - pose_msg.pose.position.z = pose[2] - pose_msg.pose.orientation.x = pose[3] - pose_msg.pose.orientation.y = pose[4] - pose_msg.pose.orientation.z = pose[5] - pose_msg.pose.orientation.w = pose[6] - return pose_msg - - def _create_idx_msg(self, idx: int, timestamp: Time) -> DatabaseMatchIndex: - idx_msg = DatabaseMatchIndex() - idx_msg.header.stamp = timestamp - idx_msg.index = idx - return idx_msg - - def listener_callback( - self, - front_image_msg: CompressedImage, - back_image_msg: CompressedImage, - front_mask_msg: Image, - back_mask_msg: Image, - lidar_msg: PointCloud2, - ) -> None: - self.get_logger().info("Received synchronized messages.") - t_start = self.get_clock().now() - lidar_timestamp = lidar_msg.header.stamp - front_image = self.cv_bridge.compressed_imgmsg_to_cv2(front_image_msg) - back_image = self.cv_bridge.compressed_imgmsg_to_cv2(back_image_msg) - front_mask = self.cv_bridge.imgmsg_to_cv2(front_mask_msg) - back_mask = self.cv_bridge.imgmsg_to_cv2(back_mask_msg) - pointcloud = read_points(lidar_msg, field_names=("x", "y", "z")) - pointcloud = np.array([pointcloud["x"], pointcloud["y"], pointcloud["z"]]).T - input_data = self._prepare_input( - images=[front_image, back_image], masks=[front_mask, back_mask], pointcloud=pointcloud - ) - output = self.pr_pipe.infer(input_data) - t_taken = self.get_clock().now() - t_start - self.get_logger().debug(f"Place recognition inference took: {t_taken.nanoseconds / 1e6} ms.") - pose_msg = self._create_pose_msg(output["pose"], lidar_timestamp) - idx_msg = self._create_idx_msg(int(output["idx"]), lidar_timestamp) - self.pose_pub.publish(pose_msg) - self.get_logger().info(f"Published pose message: {pose_msg.pose}") - self.idx_pub.publish(idx_msg) - self.get_logger().info(f"Published database index message: {idx_msg.index}") - - -def main(args=None): - rclpy.init(args=args) - - pr_node = PlaceRecognitionNode() - - rclpy.spin(pr_node) - - # Destroy the node explicitly - # (optional - otherwise it will be done automatically - # when the garbage collector destroys the node object) - pr_node.destroy_node() - rclpy.shutdown() - - -if __name__ == '__main__': - main() diff --git a/src/open_place_recognition/resource/open_place_recognition b/src/open_place_recognition/resource/open_place_recognition deleted file mode 100644 index e69de29..0000000 diff --git a/src/open_place_recognition/setup.cfg b/src/open_place_recognition/setup.cfg deleted file mode 100644 index af4ef08..0000000 --- a/src/open_place_recognition/setup.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[develop] -script_dir=$base/lib/open_place_recognition -[install] -install_scripts=$base/lib/open_place_recognition diff --git a/src/open_place_recognition/setup.py b/src/open_place_recognition/setup.py deleted file mode 100644 index 5715a06..0000000 --- a/src/open_place_recognition/setup.py +++ /dev/null @@ -1,32 +0,0 @@ -import os -from glob import glob -from setuptools import find_packages, setup - -package_name = 'open_place_recognition' - -setup( - name=package_name, - version='0.0.0', - packages=find_packages(exclude=['test']), - data_files=[ - ('share/ament_index/resource_index/packages', - ['resource/' + package_name]), - ('share/' + package_name, ['package.xml']), - (os.path.join('share', package_name), glob('launch/*launch.[pxy][yma]*')), - ], - install_requires=['setuptools'], - zip_safe=True, - maintainer='docker_opr_ros2', - maintainer_email='amelekhin96@gmail.com', - description='TODO: Package description', - license='TODO: License declaration', - tests_require=['pytest'], - entry_points={ - 'console_scripts': [ - 'place_recognition = open_place_recognition.place_recognition:main', - 'visualizer = open_place_recognition.visualizer:main', - 'localization = open_place_recognition.localization:main', - 'depth_estimation = open_place_recognition.depth_estimation:main' - ], - }, -) diff --git a/src/open_place_recognition/test/test_copyright.py b/src/open_place_recognition/test/test_copyright.py deleted file mode 100644 index 97a3919..0000000 --- a/src/open_place_recognition/test/test_copyright.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2015 Open Source Robotics Foundation, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from ament_copyright.main import main -import pytest - - -# Remove the `skip` decorator once the source file(s) have a copyright header -@pytest.mark.skip(reason='No copyright header has been placed in the generated source file.') -@pytest.mark.copyright -@pytest.mark.linter -def test_copyright(): - rc = main(argv=['.', 'test']) - assert rc == 0, 'Found errors' diff --git a/src/open_place_recognition/test/test_flake8.py b/src/open_place_recognition/test/test_flake8.py deleted file mode 100644 index 27ee107..0000000 --- a/src/open_place_recognition/test/test_flake8.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2017 Open Source Robotics Foundation, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from ament_flake8.main import main_with_errors -import pytest - - -@pytest.mark.flake8 -@pytest.mark.linter -def test_flake8(): - rc, errors = main_with_errors(argv=[]) - assert rc == 0, \ - 'Found %d code style errors / warnings:\n' % len(errors) + \ - '\n'.join(errors) diff --git a/src/open_place_recognition/test/test_pep257.py b/src/open_place_recognition/test/test_pep257.py deleted file mode 100644 index b234a38..0000000 --- a/src/open_place_recognition/test/test_pep257.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2015 Open Source Robotics Foundation, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from ament_pep257.main import main -import pytest - - -@pytest.mark.linter -@pytest.mark.pep257 -def test_pep257(): - rc = main(argv=['.', 'test']) - assert rc == 0, 'Found code style errors / warnings' From 1fd6375dea401c3ec5900b562b400669760f78e1 Mon Sep 17 00:00:00 2001 From: TPODAvia Date: Mon, 31 Mar 2025 17:50:08 +0300 Subject: [PATCH 2/5] removing all hardcoded path for ros --- ERRORS.md | 38 + open_place_recognition/CMakeLists.txt | 1 - .../place_recognition/multimodal_pr.yaml | 2 +- .../multimodal_semantic_pr.yaml | 2 +- ...ltimodal_semantic_with_soc_outdoor_pr.yaml | 2 +- .../multimodal_with_soc_outdoor_pr.yaml | 2 +- .../place_recognition/text_labels_pr.yaml | 2 +- .../launch/dataset_from_bag.launch.py | 50 +- .../launch/dataset_train.launch.py | 82 +- .../launch/localization.launch.py | 6 +- .../launch/place_recognition.launch.py | 8 +- .../launch/test_opr_odometry.launch.py | 37 - .../rviz/depth_estimation_outdoor.rviz | 117 +- .../scripts/dataset_create.py | 388 --- .../scripts/dataset_train.py | 95 - .../scripts/node_1_9_scan.pcd | 3069 ----------------- .../src/dataset_from_rosbag_node.py | 743 ++-- .../src/dataset_publisher_node.py | 28 +- .../src/dataset_train_node.py | 232 +- .../src/localization_node.py | 49 +- .../src/place_recognition_node.py | 94 +- .../src/test_opr_odom_node.py | 40 - 22 files changed, 930 insertions(+), 4157 deletions(-) create mode 100644 ERRORS.md delete mode 100644 open_place_recognition/launch/test_opr_odometry.launch.py delete mode 100755 open_place_recognition/scripts/dataset_create.py delete mode 100755 open_place_recognition/scripts/dataset_train.py delete mode 100644 open_place_recognition/scripts/node_1_9_scan.pcd delete mode 100755 open_place_recognition/src/test_opr_odom_node.py diff --git a/ERRORS.md b/ERRORS.md new file mode 100644 index 0000000..f18f303 --- /dev/null +++ b/ERRORS.md @@ -0,0 +1,38 @@ +[place_recognition_node.py-1] 2025-03-31 14:33:42.986 | WARNING | opr.models.place_recognition.pointmamba::16 - The 'pointmamba' package is not installed. Please install it manually if neccessary. +[place_recognition_node.py-1] [INFO] [1743431623.286569389] [multimodal_multicamera_lidar_place_recognition]: Initialized PlaceRecognitionNode node. +[place_recognition_node.py-1] [INFO] [1743431696.078611049] [multimodal_multicamera_lidar_place_recognition]: Received synchronized messages. +[place_recognition_node.py-1] Traceback (most recent call last): +[place_recognition_node.py-1] File "/home/docker_opr_ros2/ros2_ws/install/open_place_recognition/lib/open_place_recognition/place_recognition_node.py", line 377, in +[place_recognition_node.py-1] main() +[place_recognition_node.py-1] File "/home/docker_opr_ros2/ros2_ws/install/open_place_recognition/lib/open_place_recognition/place_recognition_node.py", line 371, in main +[place_recognition_node.py-1] rclpy.spin(pr_node) +[place_recognition_node.py-1] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/__init__.py", line 226, in spin +[place_recognition_node.py-1] executor.spin_once() +[place_recognition_node.py-1] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 739, in spin_once +[place_recognition_node.py-1] self._spin_once_impl(timeout_sec) +[place_recognition_node.py-1] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 736, in _spin_once_impl +[place_recognition_node.py-1] raise handler.exception() +[place_recognition_node.py-1] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/task.py", line 239, in __call__ +[place_recognition_node.py-1] self._handler.send(None) +[place_recognition_node.py-1] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 437, in handler +[place_recognition_node.py-1] await call_coroutine(entity, arg) +[place_recognition_node.py-1] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 362, in _execute_subscription +[place_recognition_node.py-1] await await_or_execute(sub.callback, msg) +[place_recognition_node.py-1] File "/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/executors.py", line 107, in await_or_execute +[place_recognition_node.py-1] return callback(*args) +[place_recognition_node.py-1] File "/opt/ros/humble/local/lib/python3.10/dist-packages/message_filters/__init__.py", line 83, in callback +[place_recognition_node.py-1] self.signalMessage(msg) +[place_recognition_node.py-1] File "/opt/ros/humble/local/lib/python3.10/dist-packages/message_filters/__init__.py", line 64, in signalMessage +[place_recognition_node.py-1] cb(*(msg + args)) +[place_recognition_node.py-1] File "/opt/ros/humble/local/lib/python3.10/dist-packages/message_filters/__init__.py", line 313, in add +[place_recognition_node.py-1] self.signalMessage(*msgs) +[place_recognition_node.py-1] File "/opt/ros/humble/local/lib/python3.10/dist-packages/message_filters/__init__.py", line 64, in signalMessage +[place_recognition_node.py-1] cb(*(msg + args)) +[place_recognition_node.py-1] File "/home/docker_opr_ros2/ros2_ws/install/open_place_recognition/lib/open_place_recognition/place_recognition_node.py", line 354, in listener_callback +[place_recognition_node.py-1] output = self.pipeline.infer(input_data) +[place_recognition_node.py-1] File "/home/docker_opr_ros2/OpenPlaceRecognition/src/opr/pipelines/place_recognition/base.py", line 124, in infer +[place_recognition_node.py-1] _, pred_i = self.database_index.search(descriptor, 1) +[place_recognition_node.py-1] File "/usr/local/lib/python3.10/dist-packages/faiss-1.7.4-py3.10.egg/faiss/class_wrappers.py", line 329, in replacement_search +[place_recognition_node.py-1] assert d == self.d +[place_recognition_node.py-1] AssertionError +[ERROR] [place_recognition_node.py-1]: process has died [pid 2597, exit code 1, cmd '/home/docker_opr_ros2/ros2_ws/install/open_place_recognition/lib/open_place_recognition/place_recognition_node.py --ros-args -r __node:=multimodal_multicamera_lidar_place_recognition --params-file /tmp/launch_params_wdk5sjdl']. \ No newline at end of file diff --git a/open_place_recognition/CMakeLists.txt b/open_place_recognition/CMakeLists.txt index 4c3bd73..5fc8046 100644 --- a/open_place_recognition/CMakeLists.txt +++ b/open_place_recognition/CMakeLists.txt @@ -27,7 +27,6 @@ install(PROGRAMS src/localization_node.py src/place_recognition_node.py # src/test_depth_estimation_node.py -# src/test_opr_odom_node.py # src/test_visualizer_node.py DESTINATION lib/${PROJECT_NAME} ) diff --git a/open_place_recognition/configs/pipelines/place_recognition/multimodal_pr.yaml b/open_place_recognition/configs/pipelines/place_recognition/multimodal_pr.yaml index 4128a21..d39ff44 100644 --- a/open_place_recognition/configs/pipelines/place_recognition/multimodal_pr.yaml +++ b/open_place_recognition/configs/pipelines/place_recognition/multimodal_pr.yaml @@ -28,6 +28,6 @@ model: fusion_module: _target_: opr.modules.Concat -model_weights_path: OpenPlaceRecognition/weights/place_recognition/multi-image_lidar_late-fusion_nclt.pth +model_weights_path: weights/place_recognition/multi-image_lidar_late-fusion_nclt.pth device: cuda pointcloud_quantization_size: 0.5 \ No newline at end of file diff --git a/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_pr.yaml b/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_pr.yaml index a2f3cda..cd848be 100644 --- a/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_pr.yaml +++ b/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_pr.yaml @@ -42,6 +42,6 @@ model: _target_: opr.modules.Concat # database_dir: /home/docker_opr_ros2/Datasets/itlpcampus_nature_exps/databases/indoor_floor_5 -model_weights_path: OpenPlaceRecognition/weights/place_recognition/multi-image_multi-semantic_lidar_late-fusion_nclt.pth +model_weights_path: weights/place_recognition/multi-image_multi-semantic_lidar_late-fusion_nclt.pth device: cuda pointcloud_quantization_size: 0.5 diff --git a/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_with_soc_outdoor_pr.yaml b/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_with_soc_outdoor_pr.yaml index a49a74f..cf7389f 100644 --- a/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_with_soc_outdoor_pr.yaml +++ b/open_place_recognition/configs/pipelines/place_recognition/multimodal_semantic_with_soc_outdoor_pr.yaml @@ -50,6 +50,6 @@ model: _target_: opr.modules.Concat # database_dir: /home/docker_opr_ros2/Datasets/itlpcampus_nature_exps/databases/outdoor_2023-04-11-day -model_weights_path: OpenPlaceRecognition/weights/place_recognition/multimodal_semantic_with_soc_outdoor_nclt.pth +model_weights_path: weights/place_recognition/multimodal_semantic_with_soc_outdoor_nclt.pth device: cuda pointcloud_quantization_size: 0.5 diff --git a/open_place_recognition/configs/pipelines/place_recognition/multimodal_with_soc_outdoor_pr.yaml b/open_place_recognition/configs/pipelines/place_recognition/multimodal_with_soc_outdoor_pr.yaml index e63420e..1818053 100644 --- a/open_place_recognition/configs/pipelines/place_recognition/multimodal_with_soc_outdoor_pr.yaml +++ b/open_place_recognition/configs/pipelines/place_recognition/multimodal_with_soc_outdoor_pr.yaml @@ -37,6 +37,6 @@ model: _target_: opr.modules.Concat # database_dir: /home/docker_opr_ros2/Datasets/itlpcampus_nature_exps/databases/outdoor_2023-04-11-day -model_weights_path: OpenPlaceRecognition/weights/place_recognition/multimodal_with_soc_outdoor_nclt.pth +model_weights_path: weights/place_recognition/multimodal_with_soc_outdoor_nclt.pth device: cuda pointcloud_quantization_size: 0.5 diff --git a/open_place_recognition/configs/pipelines/place_recognition/text_labels_pr.yaml b/open_place_recognition/configs/pipelines/place_recognition/text_labels_pr.yaml index b300397..bcfd564 100644 --- a/open_place_recognition/configs/pipelines/place_recognition/text_labels_pr.yaml +++ b/open_place_recognition/configs/pipelines/place_recognition/text_labels_pr.yaml @@ -31,6 +31,6 @@ model: _target_: opr.modules.Concat # database_dir: /home/docker_opr_ros2/Datasets/itlpcampus_nature_exps/databases/indoor_floor_5 -model_weights_path: OpenPlaceRecognition/weights/place_recognition/multi-image_lidar_late-fusion_nclt.pth +model_weights_path: weights/place_recognition/multi-image_lidar_late-fusion_nclt.pth device: cuda pointcloud_quantization_size: 0.5 diff --git a/open_place_recognition/launch/dataset_from_bag.launch.py b/open_place_recognition/launch/dataset_from_bag.launch.py index 717e71f..e9b8611 100644 --- a/open_place_recognition/launch/dataset_from_bag.launch.py +++ b/open_place_recognition/launch/dataset_from_bag.launch.py @@ -1,36 +1,26 @@ -#!/usr/bin/env python3 - +# launch/convert.launch.py import os -from launch import LaunchDescription -from launch_ros.actions import Node -from launch.actions import ExecuteProcess +import launch +import launch_ros.actions -def generate_launch_description(): - rosbag_file = os.path.expanduser('~/.ros/opr_dataset') # Adjust this path as needed. +home_dir = os.path.expanduser("~") - return LaunchDescription([ - Node( - package='open_place_recognition', - executable='dataset_from_rosbag_node.py', - name='dataset_from_rosbag_node', - output='screen', +def generate_launch_description(): + return launch.LaunchDescription([ + launch_ros.actions.Node( + package='your_package_name', + executable='bag_converter_node', + name='bag_converter_node', parameters=[ - {"front_camera_topic": "/front_cam/camera_depth/image_raw"}, - {"back_camera_topic": "/back_cam//camera_depth/image_raw"}, - {"lidar_topic": "/lidar/points2_raw"}, - {"pose_topic": "/my_pose_topic"}, - {"output_path": "~/.ros/opr_dataset"}, - {"track_name": "my_experiment_01"}, - # Optionally pass the rosbag file path as a parameter if your node needs it: - {"rosbag_file": rosbag_file} - ] - ), - # ExecuteProcess to run ros2 bag play using the specified rosbag directory - ExecuteProcess( - cmd=['ros2', 'bag', 'play', rosbag_file], - output='screen' + {"input_dir": os.path.join(home_dir, 'ros2_bags')}, + {"trajectory_file": os.path.join(home_dir, 'ros2_bags/trajectory.db3')}, + {"out_dir": os.path.expanduser('~/.ros/opr_dataset')}, + {"distance_threshold": 5.0}, + {"max_diff": 60000000}, + {"front_cam_topic": "/front/depth_camera/image_raw"}, + {"back_cam_topic": "/back/depth_camera/image_raw"}, + {"lidar_topic": "/lidar/points2_raw"}, + {"trajectory_topic": "/global_trajectory_0"}, + ], ) ]) - -if __name__ == '__main__': - generate_launch_description() diff --git a/open_place_recognition/launch/dataset_train.launch.py b/open_place_recognition/launch/dataset_train.launch.py index e07a8b0..5175ffb 100644 --- a/open_place_recognition/launch/dataset_train.launch.py +++ b/open_place_recognition/launch/dataset_train.launch.py @@ -1,43 +1,71 @@ #!/usr/bin/env python3 import os -import sys -from ament_index_python.packages import get_package_share_directory - from launch import LaunchDescription -from launch.actions import OpaqueFunction, DeclareLaunchArgument +from launch.actions import DeclareLaunchArgument from launch.substitutions import LaunchConfiguration from launch_ros.actions import Node def generate_launch_description(): - dataset_path = LaunchConfiguration('dataset_path') - map_name = LaunchConfiguration('map_name') - output_path = LaunchConfiguration('output_path') - + + dataset_path_arg = DeclareLaunchArgument( + 'dataset_path', + default_value=f'{os.path.expanduser("~")}/Datasets/itlp_campus_outdoor/01_2023-02-21', + description='Root directory of the database track (3D data).' + ) + output_path_arg = DeclareLaunchArgument( + 'output_path', + default_value=f'{os.path.expanduser("~")}/Datasets/itlp_campus_outdoor/01_2023-02-21', + description='Where to save the index.faiss and any outputs.' + ) + batch_size_arg = DeclareLaunchArgument( + 'batch_size', + default_value='64', + description='Batch size for the DataLoader.' + ) + num_workers_arg = DeclareLaunchArgument( + 'num_workers', + default_value='4', + description='Number of CPU workers for DataLoader.' + ) + device_arg = DeclareLaunchArgument( + 'device', + default_value='cuda', + description='Device to run the model on (cuda or cpu).' + ) + model_config_path_arg = DeclareLaunchArgument( + 'model_config_path', + default_value=f'{os.path.expanduser("~")}/OpenPlaceRecognition/configs/model/place_recognition/minkloc3d.yaml', + description='Path to MinkLoc3D Hydra config.' + ) + weights_path_arg = DeclareLaunchArgument( + 'weights_path', + default_value=f'{os.path.expanduser("~")}/OpenPlaceRecognition/weights/place_recognition/minkloc3d_nclt.pth', + description='Path to the MinkLoc3D pre-trained weights.' + ) + return LaunchDescription([ - DeclareLaunchArgument( - 'dataset_path', - default_value='~/.ros/opr_dataset', - description='Path to the dataset directory' - ), - DeclareLaunchArgument( - 'map_name', - default_value='my_map', - description='Map name for dataset training' - ), - DeclareLaunchArgument( - 'output_path', - default_value='~/.ros/opr_dataset', - description='Map name for dataset creation' - ), + dataset_path_arg, + output_path_arg, + batch_size_arg, + num_workers_arg, + device_arg, + model_config_path_arg, + weights_path_arg, + Node( - package='orca_opr', + package='open_place_recognition', executable='dataset_train_node.py', name='dataset_train_node', output='screen', parameters=[{ - 'dataset_path': dataset_path, - 'map_name': map_name, - 'output_path': output_path, + 'dataset_path': LaunchConfiguration('dataset_path'), + 'output_path': LaunchConfiguration('output_path'), + 'dataset_path': LaunchConfiguration('dataset_path'), + 'batch_size': LaunchConfiguration('batch_size'), + 'num_workers': LaunchConfiguration('num_workers'), + 'device': LaunchConfiguration('device'), + 'model_config_path': LaunchConfiguration('model_config_path'), + 'weights_path': LaunchConfiguration('weights_path'), }], ) ]) diff --git a/open_place_recognition/launch/localization.launch.py b/open_place_recognition/launch/localization.launch.py index c0ef752..f7abab4 100644 --- a/open_place_recognition/launch/localization.launch.py +++ b/open_place_recognition/launch/localization.launch.py @@ -43,7 +43,7 @@ def generate_launch_description(): ), # Global reference system (e.g. GPS, barometer) parameters DeclareLaunchArgument( - 'enable_global_reference', + 'enable_global_ref', default_value='true', description='Enable subscription to global reference system (e.g. GPS, barometer).' ), @@ -54,7 +54,7 @@ def generate_launch_description(): ), DeclareLaunchArgument( 'dataset_dir', - default_value=os.path.join(os.path.expanduser("~"), "Datasets", "06_2023-08-18-night"), + default_value=os.path.join(os.path.expanduser("~"), "Datasets/itlp_campus_outdoor/01_2023-02-21"), description='Path to the dataset directory (database path)' ), DeclareLaunchArgument( @@ -109,7 +109,7 @@ def generate_launch_description(): "enable_front_camera": LaunchConfiguration("enable_front_camera"), "enable_back_camera": LaunchConfiguration("enable_back_camera"), "enable_lidar": LaunchConfiguration("enable_lidar"), - "enable_global_reference": LaunchConfiguration("enable_global_reference"), + "enable_global_ref": LaunchConfiguration("enable_global_ref"), "global_ref_topic": LaunchConfiguration("global_ref_topic"), "reserve": LaunchConfiguration("reserve"), } diff --git a/open_place_recognition/launch/place_recognition.launch.py b/open_place_recognition/launch/place_recognition.launch.py index 18156dc..258c71e 100644 --- a/open_place_recognition/launch/place_recognition.launch.py +++ b/open_place_recognition/launch/place_recognition.launch.py @@ -41,7 +41,7 @@ def generate_launch_description(): ), DeclareLaunchArgument( 'dataset_dir', - default_value=os.path.join(os.path.expanduser("~"), "Datasets", "06_2023-08-18-night"), + default_value=os.path.join(os.path.expanduser("~"), "Datasets/itlp_campus_outdoor/01_2023-02-21"), description='Path to the dataset directory (database path)' ), DeclareLaunchArgument( @@ -70,6 +70,11 @@ def generate_launch_description(): default_value='true', description='Enable lidar sensor.' ), + DeclareLaunchArgument( + 'enable_global_ref', + default_value='true', + description='Enable global reference system' + ), DeclareLaunchArgument( 'global_ref_topic', default_value='/global_ref', @@ -95,6 +100,7 @@ def generate_launch_description(): "enable_front_camera": LaunchConfiguration("enable_front_camera"), "enable_back_camera": LaunchConfiguration("enable_back_camera"), "enable_lidar": LaunchConfiguration("enable_lidar"), + "enable_global_ref": LaunchConfiguration("enable_global_ref"), "global_ref_topic": LaunchConfiguration("global_ref_topic"), "reserve": LaunchConfiguration("reserve"), } diff --git a/open_place_recognition/launch/test_opr_odometry.launch.py b/open_place_recognition/launch/test_opr_odometry.launch.py deleted file mode 100644 index 2622bb6..0000000 --- a/open_place_recognition/launch/test_opr_odometry.launch.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python3 -import os -import sys -from ament_index_python.packages import get_package_share_directory - -from launch import LaunchDescription -from launch.actions import OpaqueFunction, DeclareLaunchArgument -from launch.substitutions import LaunchConfiguration -from launch_ros.actions import Node - -def generate_launch_description(): - # Even though the model node only uses 'map_name', we declare it here. - map_name = LaunchConfiguration('map_name') - weight_path = LaunchConfiguration('weight_path') - - return LaunchDescription([ - DeclareLaunchArgument( - 'map_name', - default_value='my_map', - description='Map name for model operation' - ), - DeclareLaunchArgument( - 'weight_path', - default_value='~/Sync/3d_map', - description='Map name for model operation' - ), - Node( - package='orca_opr', - executable='test_opr_odom_node.py', - name='opr_odom_node', - output='screen', - parameters=[{ - 'map_name': map_name, - 'weight_path': weight_path, - }], - ) - ]) diff --git a/open_place_recognition/rviz/depth_estimation_outdoor.rviz b/open_place_recognition/rviz/depth_estimation_outdoor.rviz index 3e0839d..1ecd00a 100644 --- a/open_place_recognition/rviz/depth_estimation_outdoor.rviz +++ b/open_place_recognition/rviz/depth_estimation_outdoor.rviz @@ -1,13 +1,16 @@ Panels: - Class: rviz_common/Displays - Help Height: 78 + Help Height: 0 Name: Displays Property Tree Widget: Expanded: - /Global Options1 - /Status1 - Splitter Ratio: 0.5 - Tree Height: 152 + - /Camera1 + - /PointCloud21 + - /Camera2 + Splitter Ratio: 0.3187499940395355 + Tree Height: 167 - Class: rviz_common/Selection Name: Selection - Class: rviz_common/Tool Properties @@ -25,7 +28,7 @@ Panels: Experimental: false Name: Time SyncMode: 0 - SyncSource: Lidar point cloud + SyncSource: PointCloud2 Visualization Manager: Class: "" Displays: @@ -47,34 +50,25 @@ Visualization Manager: Plane Cell Count: 10 Reference Frame: Value: true - - Class: rviz_default_plugins/Image + - Class: rviz_default_plugins/Camera Enabled: true - Max Value: 1 - Median window: 5 - Min Value: 0 - Name: Image - Normalize Range: true + Far Plane Distance: 100 + Image Rendering: background and overlay + Name: Camera + Overlay Alpha: 0.5 Topic: Depth: 5 Durability Policy: Volatile History Policy: Keep Last Reliability Policy: Reliable - Value: /zed_node/left/image_rect_color - Value: true - - Class: rviz_default_plugins/Image - Enabled: true - Max Value: 1 - Median window: 5 - Min Value: 0 - Name: Image - Normalize Range: true - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /depth_estimation/depth + Value: /realsense_back/color/image_raw/compressed Value: true + Visibility: + Camera: true + Grid: true + PointCloud2: true + Value: true + Zoom Factor: 1 - Alpha: 1 Autocompute Intensity Bounds: true Autocompute Value Bounds: @@ -87,13 +81,13 @@ Visualization Manager: Color: 255; 255; 255 Color Transformer: Intensity Decay Time: 0 - Enabled: false + Enabled: true Invert Rainbow: false Max Color: 255; 255; 255 - Max Intensity: 4096 + Max Intensity: 0.729411780834198 Min Color: 0; 0; 0 Min Intensity: 0 - Name: DE point cloud + Name: PointCloud2 Position Transformer: XYZ Selectable: true Size (Pixels): 3 @@ -105,44 +99,29 @@ Visualization Manager: Filter size: 10 History Policy: Keep Last Reliability Policy: Reliable - Value: /depth_estimation/point_cloud_from_depth + Value: /velodyne_points Use Fixed Frame: true Use rainbow: true - Value: false - - Alpha: 1 - Autocompute Intensity Bounds: true - Autocompute Value Bounds: - Max Value: 10 - Min Value: -10 - Value: true - Axis: Z - Channel Name: intensity - Class: rviz_default_plugins/PointCloud2 - Color: 255; 255; 255 - Color Transformer: Intensity - Decay Time: 0 + Value: true + - Class: rviz_default_plugins/Camera Enabled: true - Invert Rainbow: false - Max Color: 255; 255; 255 - Max Intensity: 141 - Min Color: 0; 0; 0 - Min Intensity: 1 - Name: Lidar point cloud - Position Transformer: XYZ - Selectable: true - Size (Pixels): 3 - Size (m): 0.009999999776482582 - Style: Flat Squares + Far Plane Distance: 100 + Image Rendering: background and overlay + Name: Camera + Overlay Alpha: 0.5 Topic: Depth: 5 Durability Policy: Volatile - Filter size: 10 History Policy: Keep Last Reliability Policy: Reliable - Value: /velodyne_points - Use Fixed Frame: true - Use rainbow: true + Value: /zed_node/left/image_rect_color/compressed Value: true + Visibility: + Camera: true + Grid: true + PointCloud2: true + Value: true + Zoom Factor: 1 Enabled: true Global Options: Background Color: 48; 48; 48 @@ -189,7 +168,7 @@ Visualization Manager: Views: Current: Class: rviz_default_plugins/Orbit - Distance: 38.87355041503906 + Distance: 7.723052024841309 Enable Stereo Rendering: Stereo Eye Separation: 0.05999999865889549 Stereo Focal Distance: 1 @@ -204,20 +183,20 @@ Visualization Manager: Invert Z Axis: false Name: Current View Near Clip Distance: 0.009999999776482582 - Pitch: 0.7347962856292725 + Pitch: 0.8153980374336243 Target Frame: Value: Orbit (rviz) - Yaw: 2.868584156036377 + Yaw: 3.248584270477295 Saved: ~ Window Geometry: + Camera: + collapsed: false Displays: collapsed: false - Height: 1016 + Height: 776 Hide Left Dock: false - Hide Right Dock: false - Image: - collapsed: false - QMainWindow State: 000000ff00000000fd0000000400000000000001dc0000035efc020000000afb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003b00000121000000c700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d0061006700650100000162000001180000002800fffffffb0000000a0049006d0061006700650100000280000001190000002800ffffff000000010000010f0000035efc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003b0000035e000000a000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000007380000003efc0100000002fb0000000800540069006d00650100000000000007380000025300fffffffb0000000800540069006d00650100000000000004500000000000000000000004410000035e00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + Hide Right Dock: true + QMainWindow State: 000000ff00000000fd0000000400000000000002820000026efc020000000dfb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003b000000e2000000c700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d0061006700650000000233000000bc0000000000000000fb0000000c00430061006d0065007200610100000123000000c00000002800fffffffb0000000c00430061006d00650072006101000001e9000000c00000002800fffffffb0000000c00430061006d00650072006101000001b7000000ab0000000000000000fb0000000c00430061006d00650072006101000001f3000000b60000000000000000000000010000010000000227fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003b00000227000000a000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000006c90000003efc0100000002fb0000000800540069006d00650100000000000006c90000025300fffffffb0000000800540069006d00650100000000000004500000000000000000000004410000026e00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 Selection: collapsed: false Time: @@ -225,7 +204,7 @@ Window Geometry: Tool Properties: collapsed: false Views: - collapsed: false - Width: 1848 - X: 72 - Y: 27 + collapsed: true + Width: 1737 + X: 105 + Y: 57 diff --git a/open_place_recognition/scripts/dataset_create.py b/open_place_recognition/scripts/dataset_create.py deleted file mode 100755 index 5f9897b..0000000 --- a/open_place_recognition/scripts/dataset_create.py +++ /dev/null @@ -1,388 +0,0 @@ -#!/usr/bin/env python3 -""" -Script to extract data from an RTAB-Map database (rtabmap.db) for AI training. -It extracts: - - Node data from the Node table: - • Pose (as a 3x4 float matrix) converted to a quaternion (for CSV) - and saved as a raw text file in the "pose" folder. - • Velocity (6 floats) saved in the "velocity" folder. - • GPS (6 doubles) saved in the "gps" folder. - - Sensor data from the Data table: - • RGB images (from the "image" column) saved in "rgb". - • Depth images (from the "depth" column) saved in "depth". - • Calibration data (from the "calibration" column) saved in "calib". - • Laser scan data (from the "scan" column) saved in "scan". - • Scan info (from the "scan_info" column) saved in "scan_info". - - A CSV file with node pose (as quaternion) and sensor timestamps. - -Usage: - python extract_rtabmap_all.py /path/to/rtabmap.db [optional: output_dir] - -Requires: - - Python 3.x - - sqlite3 (built-in) - - (Optional) OpenCV (cv2) and numpy to decode and save images. -""" - -import os -import sys -import struct -import math -import sqlite3 - -# Optional: install with `pip install opencv-python numpy` -try: - import cv2 - import numpy as np - OPENCV_AVAILABLE = True -except ImportError: - OPENCV_AVAILABLE = False - -def rotation_matrix_to_quaternion(R): - """ - Convert a 3x3 rotation matrix R (list of 3 lists of 3 floats) - into a quaternion (qx, qy, qz, qw). - """ - m00, m01, m02 = R[0] - m10, m11, m12 = R[1] - m20, m21, m22 = R[2] - trace = m00 + m11 + m22 - - if trace > 0: - s = math.sqrt(trace + 1.0) * 2 # S = 4*qw - qw = 0.25 * s - qx = (m21 - m12) / s - qy = (m02 - m20) / s - qz = (m10 - m01) / s - elif (m00 > m11) and (m00 > m22): - s = math.sqrt(1.0 + m00 - m11 - m22) * 2 # S = 4*qx - qw = (m21 - m12) / s - qx = 0.25 * s - qy = (m01 + m10) / s - qz = (m02 + m20) / s - elif m11 > m22: - s = math.sqrt(1.0 + m11 - m00 - m22) * 2 # S = 4*qy - qw = (m02 - m20) / s - qx = (m01 + m10) / s - qy = 0.25 * s - qz = (m12 + m21) / s - else: - s = math.sqrt(1.0 + m22 - m00 - m11) * 2 # S = 4*qz - qw = (m10 - m01) / s - qx = (m02 + m20) / s - qy = (m12 + m21) / s - qz = 0.25 * s - - return (qx, qy, qz, qw) - -class RtabMapDatasetExtractor: - """ - Extracts dataset from an RTAB-Map database for AI training. - It extracts node poses, velocity, gps (from the Node table) and sensor data - (RGB, depth, calibration, scan, scan_info from the Data table). Each type is saved - in its own folder. - """ - def __init__(self, db_path="~/Sync/3d_map/rtabmap.db", output_dir="~/.ros/opr_dataset"): - self.db_path = os.path.expanduser(db_path) - self.output_dir = os.path.expanduser(output_dir) - # Use the base name of the DB as the map name. - self.map_name = os.path.splitext(os.path.basename(self.db_path))[0] - - def run(self): - if not os.path.isfile(self.db_path): - print(f"[ERROR] Database not found: {self.db_path}") - sys.exit(1) - - # Create output directories. - map_out = os.path.join(self.output_dir, self.map_name) - folders = { - "rgb": os.path.join(map_out, "rgb"), - "depth": os.path.join(map_out, "depth"), - "calib": os.path.join(map_out, "calib"), - "scan": os.path.join(map_out, "scan"), - "scan_info": os.path.join(map_out, "scan_info"), - "pose": os.path.join(map_out, "pose"), - "velocity": os.path.join(map_out, "velocity"), - "gps": os.path.join(map_out, "gps") - } - for folder in folders.values(): - os.makedirs(folder, exist_ok=True) - - csv_file = os.path.join(map_out, "tracker.csv") - - print(f"[INFO] Reading RTAB-Map DB: {self.db_path}") - node_data = self._extract_node_data() - if not node_data: - print("[WARN] No node data found in the DB!") - - # Extract sensor data from Data table. - self._attach_sensor_data(node_data, folders) - # Write additional node data to separate folders. - self._write_node_extras(node_data, folders) - # Write CSV file. - print(f"[INFO] Writing CSV data to: {csv_file}") - self._write_csv(csv_file, node_data) - print(f"[DONE] Dataset extraction complete. See '{map_out}'.") - - def _extract_node_data(self): - """ - Query the Node table to extract: - - id, map_id, stamp, pose, velocity, gps. - The pose is stored as a 3x4 float matrix (12 floats). The rotation (first 9) - is converted to a quaternion. Also store the raw 12-float pose. - The velocity is 6 floats and gps is 6 doubles. - """ - node_dict = {} - try: - conn = sqlite3.connect(self.db_path) - c = conn.cursor() - query = """ - SELECT id, map_id, stamp, pose, velocity, gps - FROM Node - ORDER BY stamp ASC - """ - c.execute(query) - rows = c.fetchall() - for row in rows: - node_id, map_id, stamp, pose_blob, velocity_blob, gps_blob = row - timestamp = int(stamp) - try: - # Unpack pose as 12 floats. - raw_pose = struct.unpack('12f', pose_blob) - # Build rotation matrix from values [0,1,2], [4,5,6], [8,9,10] - R = [ - [raw_pose[0], raw_pose[1], raw_pose[2]], - [raw_pose[4], raw_pose[5], raw_pose[6]], - [raw_pose[8], raw_pose[9], raw_pose[10]] - ] - # Translation: indices 3,7,11. - tx, ty, tz = raw_pose[3], raw_pose[7], raw_pose[11] - qx, qy, qz, qw = rotation_matrix_to_quaternion(R) - except Exception as e: - print(f"[ERROR] Failed to unpack pose for node {node_id}: {e}") - continue - - # Extract velocity if available. - velocity_val = None - if velocity_blob: - try: - velocity_val = struct.unpack('6f', velocity_blob) - except Exception as e: - print(f"[WARN] Failed to unpack velocity for node {node_id}: {e}") - - # Extract gps if available. - gps_val = None - if gps_blob: - try: - gps_val = struct.unpack('6d', gps_blob) - except Exception as e: - print(f"[WARN] Failed to unpack GPS for node {node_id}: {e}") - - node_dict[node_id] = { - "floor": map_id, - "timestamp": timestamp, - "tx": tx, "ty": ty, "tz": tz, - "qx": qx, "qy": qy, "qz": qz, "qw": qw, - "raw_pose": raw_pose, - "velocity": velocity_val, - "gps": gps_val, - # Placeholders for sensor timestamps. - "rgb_ts": 0, - "depth_ts": 0, - "calib_ts": 0, - "scan_ts": 0, - "scan_info_ts": 0 - } - conn.close() - except sqlite3.Error as e: - print(f"[ERROR] SQLite error while reading Node table: {e}") - return node_dict - - def _attach_sensor_data(self, node_dict, folders): - """ - Query the Data table to extract sensor data. - Uses columns: - - image: compressed RGB image - - depth: compressed depth image - - calibration: calibration data - - scan: laser scan data - - scan_info: scan information data - Data.id is assumed to match Node.id. - """ - if not node_dict: - return - try: - conn = sqlite3.connect(self.db_path) - c = conn.cursor() - c.execute("SELECT * FROM Data") - rows = c.fetchall() - cols = [desc[0] for desc in c.description] - # Get indices. - try: - data_id_idx = cols.index("id") - stamp_idx = cols.index("time_enter") if "time_enter" in cols else None - except ValueError: - print("[WARN] Required columns missing in Data table.") - conn.close() - return - - image_idx = cols.index("image") if "image" in cols else None - depth_idx = cols.index("depth") if "depth" in cols else None - calib_idx = cols.index("calibration") if "calibration" in cols else None - scan_idx = cols.index("scan") if "scan" in cols else None - scan_info_idx = cols.index("scan_info") if "scan_info" in cols else None - - for row in rows: - data_node_id = row[data_id_idx] # assume Data.id == Node.id - if data_node_id not in node_dict: - continue - # Use Data.time_enter if available. - if stamp_idx is not None and row[stamp_idx]: - try: - data_ts = float(row[stamp_idx]) - except Exception: - data_ts = node_dict[data_node_id]["timestamp"] - else: - data_ts = node_dict[data_node_id]["timestamp"] - - # Extract RGB image. - if image_idx is not None: - img_blob = row[image_idx] - if img_blob and OPENCV_AVAILABLE: - np_arr = np.frombuffer(img_blob, dtype=np.uint8) - rgb_img = cv2.imdecode(np_arr, cv2.IMREAD_COLOR) - if rgb_img is not None: - fname = f"node_{data_node_id}_{int(data_ts)}_rgb.jpg" - cv2.imwrite(os.path.join(folders["rgb"], fname), rgb_img) - if node_dict[data_node_id]["rgb_ts"] == 0: - node_dict[data_node_id]["rgb_ts"] = int(data_ts) - - # Extract depth image. - if depth_idx is not None: - depth_blob = row[depth_idx] - if depth_blob and OPENCV_AVAILABLE: - np_arr = np.frombuffer(depth_blob, dtype=np.uint8) - depth_img = cv2.imdecode(np_arr, cv2.IMREAD_UNCHANGED) - if depth_img is not None: - fname = f"node_{data_node_id}_{int(data_ts)}_depth.png" - cv2.imwrite(os.path.join(folders["depth"], fname), depth_img) - if node_dict[data_node_id]["depth_ts"] == 0: - node_dict[data_node_id]["depth_ts"] = int(data_ts) - - # Extract calibration data. - if calib_idx is not None: - calib_blob = row[calib_idx] - if calib_blob: - try: - calib_text = calib_blob.decode('utf-8') - except Exception: - calib_text = str(calib_blob) - fname = f"node_{data_node_id}_{int(data_ts)}_calib.txt" - with open(os.path.join(folders["calib"], fname), 'w') as f: - f.write(calib_text) - if node_dict[data_node_id]["calib_ts"] == 0: - node_dict[data_node_id]["calib_ts"] = int(data_ts) - - # Extract scan data. - if scan_idx is not None: - scan_blob = row[scan_idx] - if scan_blob: - fname = f"node_{data_node_id}_{int(data_ts)}_scan.bin" - with open(os.path.join(folders["scan"], fname), 'wb') as f: - f.write(scan_blob) - if node_dict[data_node_id]["scan_ts"] == 0: - node_dict[data_node_id]["scan_ts"] = int(data_ts) - - # Extract scan_info data. - if scan_info_idx is not None: - si_blob = row[scan_info_idx] - if si_blob: - # Attempt to decode as text; if not, write as binary. - try: - si_text = si_blob.decode('utf-8') - fname = f"node_{data_node_id}_{int(data_ts)}_scan_info.txt" - with open(os.path.join(folders["scan_info"], fname), 'w') as f: - f.write(si_text) - except Exception: - fname = f"node_{data_node_id}_{int(data_ts)}_scan_info.bin" - with open(os.path.join(folders["scan_info"], fname), 'wb') as f: - f.write(si_blob) - if node_dict[data_node_id]["scan_info_ts"] == 0: - node_dict[data_node_id]["scan_info_ts"] = int(data_ts) - conn.close() - except sqlite3.OperationalError as e: - print(f"[WARN] Data table query failed: {e}. Skipping sensor data extraction.") - except sqlite3.Error as e: - print(f"[ERROR] SQLite error while reading Data table: {e}") - - def _write_node_extras(self, node_dict, folders): - """ - Write additional node data (raw pose, velocity, gps) to separate folders. - - In folder "pose": write the 12 float values (raw pose) as a text file. - - In folder "velocity": write 6 float values if available. - - In folder "gps": write 6 double values if available. - """ - # Write raw pose. - for node_id, data in node_dict.items(): - if "raw_pose" in data: - fname = f"node_{node_id}_pose.txt" - with open(os.path.join(folders["pose"], fname), 'w') as f: - f.write(" ".join(f"{v:.6f}" for v in data["raw_pose"])) - # Write velocity. - if data.get("velocity"): - fname = f"node_{node_id}_velocity.txt" - with open(os.path.join(folders["velocity"], fname), 'w') as f: - f.write(" ".join(f"{v:.6f}" for v in data["velocity"])) - # Write GPS. - if data.get("gps"): - fname = f"node_{node_id}_gps.txt" - with open(os.path.join(folders["gps"], fname), 'w') as f: - f.write(" ".join(f"{v:.6f}" for v in data["gps"])) - - def _write_csv(self, csv_file_path, node_dict): - """ - Write a CSV file with columns: - track, floor, timestamp, rgb_ts, depth_ts, calib_ts, scan_ts, scan_info_ts, - tx, ty, tz, qx, qy, qz, qw - """ - if not node_dict: - print("[WARN] Node dictionary empty, no data to write to CSV.") - return - sorted_nodes = sorted(node_dict.values(), key=lambda x: x["timestamp"]) - os.makedirs(os.path.dirname(csv_file_path), exist_ok=True) - with open(csv_file_path, 'w') as f: - header = ("track,floor,timestamp,rgb_ts,depth_ts,calib_ts,scan_ts,scan_info_ts," - "tx,ty,tz,qx,qy,qz,qw\n") - f.write(header) - track = f"00_{self.map_name}" - for node in sorted_nodes: - row = ( - f"{track}," - f"{node['floor']}," - f"{node['timestamp']}," - f"{node['rgb_ts']}," - f"{node['depth_ts']}," - f"{node['calib_ts']}," - f"{node['scan_ts']}," - f"{node['scan_info_ts']}," - f"{node['tx']}," - f"{node['ty']}," - f"{node['tz']}," - f"{node['qx']}," - f"{node['qy']}," - f"{node['qz']}," - f"{node['qw']}\n" - ) - f.write(row) - -def main(): - if len(sys.argv) < 2: - print("Usage: python extract_rtabmap_all.py [db_path] [optional: output_dir]") - sys.exit(1) - db_path = sys.argv[1] - output_dir = sys.argv[2] if len(sys.argv) > 2 else "~/.ros/opr_dataset" - extractor = RtabMapDatasetExtractor(db_path=db_path, output_dir=output_dir) - extractor.run() - -if __name__ == '__main__': - main() diff --git a/open_place_recognition/scripts/dataset_train.py b/open_place_recognition/scripts/dataset_train.py deleted file mode 100755 index 82626fe..0000000 --- a/open_place_recognition/scripts/dataset_train.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python3 -import os -import sys -import time -import csv - -class DatasetTrain: - def __init__(self, dataset_path="datasets", map_name="default_map", output_path="~/.ros/opr_dataset"): - # Expand paths for consistency. - self.dataset_path = os.path.expanduser(dataset_path) - self.map_name = map_name - self.output_path = os.path.expanduser(output_path) - - # We assume that the dataset (extracted from RTAB-Map) is stored under: - # // - self.dataset_map_dir = os.path.join(self.dataset_path, self.map_name) - if not os.path.exists(self.dataset_map_dir): - print(f"[ERROR] Dataset directory {self.dataset_map_dir} does not exist.") - print("Please extract your RTAB-Map database to create this folder and try again.") - sys.exit(1) - if not os.path.exists(self.output_path): - print(f"[ERROR] Output directory {self.output_path} does not exist.") - print("Please create it and try again.") - sys.exit(1) - - # Start the training process. - if not self.run_torch_training(self.dataset_map_dir, self.output_path, self.map_name): - print(f"[ERROR] Error during training for map {self.map_name}") - sys.exit(1) - - def run_torch_training(self, dataset_map_dir: str, output_path: str, map_name: str): - """ - Loads the dataset from dataset_map_dir and performs training for map_name. - This dummy version reads tracker.csv to determine the number of nodes, - simulates training (using sleep), and writes out a dummy model file. - """ - print(f"[TRAINER] Starting training on dataset: {dataset_map_dir} for map: {map_name}") - - tracker_csv = os.path.join(dataset_map_dir, "tracker.csv") - if not os.path.exists(tracker_csv): - print(f"[ERROR] tracker.csv not found in {dataset_map_dir}.") - return False - - # Read the tracker CSV file and count the number of nodes. - try: - with open(tracker_csv, 'r') as csv_file: - reader = csv.DictReader(csv_file) - node_count = sum(1 for _ in reader) - except Exception as e: - print(f"[ERROR] Failed to read tracker.csv: {e}") - return False - - print(f"[TRAINER] Found {node_count} nodes in the dataset.") - - # Here you would load images, pose, velocity, gps, scan, etc. for training. - # For now we simulate training with a sleep. - training_time = min(max(node_count / 10.0, 1), 10) # simulate between 1 and 10 seconds - print(f"[TRAINER] Simulating training for {training_time:.1f} seconds...") - time.sleep(training_time) - - # Write out a dummy model file. - dummy_model_file = os.path.join(output_path, f"{map_name}.pt") - try: - with open(dummy_model_file, 'w') as f: - f.write("dummy model weights") - except Exception as e: - print(f"[ERROR] Failed to write dummy model file: {e}") - return False - - print(f"[TRAINER] Dummy model file created at: {dummy_model_file}") - print(f"[TRAINER] Finished training for map: {map_name} using dataset: {dataset_map_dir}") - return True - -def main(): - """ - Usage: - python train_dataset.py [dataset_path] [map_name] [optional: output_path] - - For example, if you extracted your RTAB-Map database into: - ~/.ros/opr_dataset/rtabmap - then you might run: - python train_dataset.py ~/.ros/opr_dataset rtabmap - """ - if len(sys.argv) < 3: - print("Usage: python train_dataset.py [dataset_path] [map_name] [optional: output_path]") - sys.exit(1) - - dataset_path = sys.argv[1] - map_name = sys.argv[2] - output_path = sys.argv[3] if len(sys.argv) > 3 else "~/.ros/opr_dataset" - - DatasetTrain(dataset_path, map_name, output_path) - -if __name__ == '__main__': - main() diff --git a/open_place_recognition/scripts/node_1_9_scan.pcd b/open_place_recognition/scripts/node_1_9_scan.pcd deleted file mode 100644 index 322a659..0000000 --- a/open_place_recognition/scripts/node_1_9_scan.pcd +++ /dev/null @@ -1,3069 +0,0 @@ -# .PCD v0.7 - Point Cloud Data file format -VERSION 0.7 -FIELDS x y z intensity -SIZE 4 4 4 4 -TYPE F F F F -COUNT 1 1 1 1 -WIDTH 3058 -HEIGHT 1 -VIEWPOINT 0 0 0 1 0 0 0 -POINTS 3058 -DATA ascii -0.24398112297058105 0.7587628364562988 -0.21202565729618073 0.0 -0.22803637385368347 0.7402730584144592 -0.2060602307319641 0.0 -0.21296194195747375 0.7227921485900879 -0.2004505842924118 0.0 -0.19868457317352295 0.706235945224762 -0.1951671540737152 0.0 -0.18513846397399902 0.690527617931366 -0.19018299877643585 0.0 -0.17226503789424896 0.6755990982055664 -0.18547432124614716 0.0 -0.1600119024515152 0.6613900065422058 -0.18101990222930908 0.0 -0.14833176136016846 0.6478452682495117 -0.1768004596233368 0.0 -0.13718228042125702 0.6349166631698608 -0.1727989912033081 0.0 -0.12652447819709778 0.6225570440292358 -0.16899922490119934 0.0 -0.11632397770881653 0.6107286214828491 -0.16538769006729126 0.0 -0.10654889047145844 0.5993934869766235 -0.1619512438774109 0.0 -0.09717018902301788 0.5885171890258789 -0.15867789089679718 0.0 -0.08854358643293381 0.5805737972259521 -0.15623097121715546 0.0 -0.08126898109912872 0.5806673765182495 -0.1559755951166153 0.0 -0.07401704788208008 0.5807607769966125 -0.15574456751346588 0.0 -0.06678546220064163 0.5808539390563965 -0.1555376797914505 0.0 -0.05957195907831192 0.5809465646743774 -0.15535469353199005 0.0 -0.05237434804439545 0.581039309501648 -0.15519563853740692 0.0 -0.04519035294651985 0.581131637096405 -0.15506024658679962 0.0 -0.03801780939102173 0.5812239050865173 -0.15494850277900696 0.0 -0.030854513868689537 0.5813159942626953 -0.154860258102417 0.0 -0.023698294535279274 0.5814081430435181 -0.15479551255702972 0.0 -0.01654697395861149 0.5815001130104065 -0.1547541618347168 0.0 -0.009398393332958221 0.5815920829772949 -0.1547362208366394 0.0 -0.0022503924556076527 0.5816841721534729 -0.15474167466163635 0.0 --0.004899190738797188 0.5817760825157166 -0.15477046370506287 0.0 --0.01205251645296812 0.5818681716918945 -0.15482266247272491 0.0 --0.019211744889616966 0.5819600820541382 -0.1548982560634613 0.0 --0.026379061862826347 0.5820523500442505 -0.15499739348888397 0.0 --0.033556632697582245 0.5821446180343628 -0.15512007474899292 0.0 --0.04074668139219284 0.5822373032569885 -0.15526647865772247 0.0 --0.04795138165354729 0.5823298096656799 -0.15543659031391144 0.0 --0.05517297983169556 0.58242267370224 -0.15563060343265533 0.0 --0.062413737177848816 0.5825158357620239 -0.15584871172904968 0.0 --0.06967592984437943 0.5826094746589661 -0.15609107911586761 0.0 --0.07696182280778885 0.5827031135559082 -0.1563577800989151 0.0 --0.08427376300096512 0.5827971696853638 -0.15664911270141602 0.0 --0.09161409735679626 0.5828914642333984 -0.1569652557373047 0.0 --0.09898526966571808 0.5829864144325256 -0.15730653703212738 0.0 --0.10638967156410217 0.5830816626548767 -0.15767315030097961 0.0 --0.11382976919412613 0.5831772685050964 -0.15806536376476288 0.0 --0.12130811810493469 0.5832734107971191 -0.1584835648536682 0.0 --0.12882733345031738 0.5833702683448792 -0.15892808139324188 0.0 --0.13638992607593536 0.5834674835205078 -0.15939918160438538 0.0 --0.14399869740009308 0.5835654735565186 -0.15989737212657928 0.0 --0.15165628492832184 0.5836638808250427 -0.1604229360818863 0.0 --0.15936559438705444 0.5837631821632385 -0.16097640991210938 0.0 --0.16712944209575653 0.5838630795478821 -0.16155818104743958 0.0 --0.17495079338550568 0.5839636921882629 -0.1621687412261963 0.0 --0.18283265829086304 0.5840650200843811 -0.1628086119890213 0.0 --0.19077813625335693 0.5841671228408813 -0.1634782999753952 0.0 --0.1987905651330948 0.5842702984809875 -0.1641785055398941 0.0 --0.2068730592727661 0.5843741297721863 -0.16490967571735382 0.0 --0.21502913534641266 0.584479033946991 -0.16567254066467285 0.0 --0.22326235473155975 0.5845850706100464 -0.1664678156375885 0.0 --0.23157615959644318 0.5846920013427734 -0.16729608178138733 0.0 --0.23997440934181213 0.5848000049591064 -0.1681581735610962 0.0 --0.24846096336841583 0.5849091410636902 -0.16905488073825836 0.0 --0.25703978538513184 0.5850194692611694 -0.16998697817325592 0.0 --0.2657150328159332 0.5851309895515442 -0.1709553748369217 0.0 --0.2744911313056946 0.5852439999580383 -0.17196105420589447 0.0 --0.2833724021911621 0.5853582620620728 -0.1730048805475235 0.0 --0.2923634648323059 0.5854739546775818 -0.17408789694309235 0.0 --0.30146917700767517 0.5855909585952759 -0.17521117627620697 0.0 --0.3106946647167206 0.5857097506523132 -0.17637591063976288 0.0 --0.3200449049472809 0.5858299136161804 -0.17758315801620483 0.0 --0.32952558994293213 0.5859518647193909 -0.17883430421352386 0.0 --0.33914217352867126 0.586075484752655 -0.18013054132461548 0.0 --0.34890079498291016 0.5862011313438416 -0.18147340416908264 0.0 --0.3588074743747711 0.5863285660743713 -0.1828642189502716 0.0 --0.3688686192035675 0.5864579677581787 -0.18430455029010773 0.0 --0.3790910542011261 0.5865892767906189 -0.18579600751399994 0.0 --0.3894820511341095 0.5867230892181396 -0.1873404085636139 0.0 --0.40004873275756836 0.5868589878082275 -0.1889394372701645 0.0 --0.4107990860939026 0.586997389793396 -0.19059506058692932 0.0 --0.42174094915390015 0.5871379375457764 -0.19230917096138 0.0 --0.4328833520412445 0.587281346321106 -0.1940840780735016 0.0 --0.4442349970340729 0.5874274373054504 -0.1959218829870224 0.0 --0.4558054208755493 0.5875762701034546 -0.19782496988773346 0.0 --0.46760451793670654 0.5877278447151184 -0.19979581236839294 0.0 --0.4796431064605713 0.5878828167915344 -0.2018372118473053 0.0 --0.49193185567855835 0.5880406498908997 -0.20395174622535706 0.0 --0.5044829845428467 0.588202178478241 -0.20614264905452728 0.0 --0.5173085927963257 0.5883671045303345 -0.20841290056705475 0.0 --0.530421793460846 0.5885357856750488 -0.21076591312885284 0.0 --0.5438365340232849 0.5887082815170288 -0.2132052183151245 0.0 --0.5575677752494812 0.5888851284980774 -0.21573469042778015 0.0 --0.571630597114563 0.5890659689903259 -0.21835818886756897 0.0 --0.5860419273376465 0.5892512798309326 -0.22108009457588196 0.0 --0.6008191704750061 0.589441180229187 -0.22390490770339966 0.0 --0.6159815192222595 0.5896363258361816 -0.2268376499414444 0.0 --0.6315486431121826 0.5898365378379822 -0.2298833727836609 0.0 --0.6475417613983154 0.5900421142578125 -0.23304763436317444 0.0 -0.2439812868833542 0.7587633728981018 -0.18269899487495422 0.0 -0.22803650796413422 0.7402734756469727 -0.17755864560604095 0.0 -0.2129622846841812 0.7227933406829834 -0.172725111246109 0.0 -0.19868463277816772 0.7062361836433411 -0.168172225356102 0.0 -0.18513862788677216 0.690528154373169 -0.16387756168842316 0.0 -0.17226524651050568 0.6755998730659485 -0.15982022881507874 0.0 -0.16001208126544952 0.6613907217979431 -0.1559819132089615 0.0 -0.14833205938339233 0.6478465795516968 -0.15234622359275818 0.0 -0.13718241453170776 0.6349172592163086 -0.14889806509017944 0.0 -0.12652461230754852 0.6225578188896179 -0.14562389254570007 0.0 -0.11632410436868668 0.6107292771339417 -0.14251188933849335 0.0 -0.10654892027378082 0.5993936657905579 -0.13955064117908478 0.0 -0.09717029333114624 0.5885178446769714 -0.1367301642894745 0.0 -0.08854365348815918 0.5805742144584656 -0.13462163507938385 0.0 -0.0812690407037735 0.5806677937507629 -0.1344015747308731 0.0 -0.07401707768440247 0.5807610750198364 -0.1342024803161621 0.0 -0.06678549200296402 0.5808541774749756 -0.13402420282363892 0.0 -0.059571992605924606 0.5809468626976013 -0.133866548538208 0.0 -0.05237436667084694 0.581039547920227 -0.1337294727563858 0.0 -0.045190371572971344 0.5811318755149841 -0.13361279666423798 0.0 -0.03801783546805382 0.5812243223190308 -0.13351655006408691 0.0 -0.03085453435778618 0.5813164114952087 -0.1334405243396759 0.0 -0.02369830384850502 0.5814083814620972 -0.13338468968868256 0.0 -0.016546985134482384 0.5815004706382751 -0.13334910571575165 0.0 -0.009398400783538818 0.5815925002098083 -0.13333363831043243 0.0 -0.00225039292126894 0.5816842317581177 -0.13333827257156372 0.0 --0.004899193532764912 0.5817764401435852 -0.13336312770843506 0.0 --0.012052521109580994 0.5818683505058289 -0.1334080696105957 0.0 --0.01921175979077816 0.5819605588912964 -0.13347327709197998 0.0 --0.026379074901342392 0.5820526480674744 -0.13355866074562073 0.0 --0.03355666249990463 0.582145094871521 -0.13366441428661346 0.0 --0.04074670001864433 0.5822375416755676 -0.133790522813797 0.0 --0.04795141518115997 0.5823302268981934 -0.13393713533878326 0.0 --0.05517302080988884 0.5824230909347534 -0.13410431146621704 0.0 --0.062413789331912994 0.5825163722038269 -0.13429227471351624 0.0 --0.06967595964670181 0.5826097130775452 -0.13450105488300323 0.0 --0.07696185261011124 0.5827034115791321 -0.13473087549209595 0.0 --0.0842737928032875 0.5827974081039429 -0.1349819004535675 0.0 --0.09161417186260223 0.5828919410705566 -0.135254368185997 0.0 --0.09898534417152405 0.5829868316650391 -0.1355484426021576 0.0 --0.10638973861932755 0.5830820798873901 -0.13586433231830597 0.0 --0.11382986605167389 0.5831778049468994 -0.13620233535766602 0.0 --0.12130822241306305 0.5832739472389221 -0.13656267523765564 0.0 --0.12882739305496216 0.5833706259727478 -0.1369456797838211 0.0 --0.13638998568058014 0.5834677815437317 -0.1373516172170639 0.0 --0.14399877190589905 0.5835658311843872 -0.13778090476989746 0.0 --0.1516563594341278 0.5836641788482666 -0.13823376595973969 0.0 --0.15936563909053802 0.5837633609771729 -0.1387106478214264 0.0 --0.1671295315027237 0.583863377571106 -0.1392119824886322 0.0 --0.17495082318782806 0.5839638113975525 -0.1397380530834198 0.0 --0.1828327625989914 0.5840653777122498 -0.14028945565223694 0.0 --0.19077825546264648 0.5841674208641052 -0.14086653292179108 0.0 --0.19879066944122314 0.5842705965042114 -0.14146986603736877 0.0 --0.20687316358089447 0.5843744277954102 -0.14209990203380585 0.0 --0.21502932906150818 0.584479570388794 -0.14275731146335602 0.0 --0.2232624590396881 0.5845853686332703 -0.1434425264596939 0.0 --0.23157626390457153 0.5846922397613525 -0.14415621757507324 0.0 --0.23997454345226288 0.5848003029823303 -0.14489908516407013 0.0 --0.24846108257770538 0.5849094390869141 -0.1456717550754547 0.0 --0.25703996419906616 0.5850198268890381 -0.1464749574661255 0.0 --0.26571521162986755 0.5851313471794128 -0.14730940759181976 0.0 --0.27449122071266174 0.5852442383766174 -0.1481759399175644 0.0 --0.28337252140045166 0.5853585600852966 -0.14907540380954742 0.0 --0.29236358404159546 0.5854741334915161 -0.15000861883163452 0.0 --0.3014693260192871 0.5855912566184998 -0.1509765386581421 0.0 --0.3106948137283325 0.5857100486755371 -0.15198016166687012 0.0 --0.3200451135635376 0.5858302712440491 -0.1530204564332962 0.0 --0.32952582836151123 0.5859523415565491 -0.15409855544567108 0.0 --0.3391423523426056 0.5860757827758789 -0.15521547198295593 0.0 --0.3489009141921997 0.5862013101577759 -0.1563725620508194 0.0 --0.35880759358406067 0.5863288044929504 -0.15757101774215698 0.0 --0.3688688576221466 0.5864582657814026 -0.15881216526031494 0.0 --0.37909135222435 0.5865897536277771 -0.16009736061096191 0.0 --0.38948220014572144 0.5867233276367188 -0.1614280790090561 0.0 --0.40004900097846985 0.5868593454360962 -0.16280597448349 0.0 --0.4107992649078369 0.5869976282119751 -0.16423256695270538 0.0 --0.42174115777015686 0.5871382355690002 -0.16570959985256195 0.0 --0.4328835904598236 0.5872817039489746 -0.1672389954328537 0.0 --0.4442351162433624 0.58742755651474 -0.16882255673408508 0.0 --0.45580562949180603 0.5875765085220337 -0.1704624593257904 0.0 --0.46760478615760803 0.5877282023429871 -0.17216072976589203 0.0 --0.479643315076828 0.5878830552101135 -0.17391972243785858 0.0 --0.4919322729110718 0.5880411863327026 -0.17574186623096466 0.0 --0.5044832229614258 0.5882024765014648 -0.17762966454029083 0.0 --0.5173088908195496 0.5883675217628479 -0.17958593368530273 0.0 --0.5304222106933594 0.588536262512207 -0.1816135048866272 0.0 --0.5438369512557983 0.588708758354187 -0.18371541798114777 0.0 --0.5575679540634155 0.5888853073120117 -0.1858949363231659 0.0 --0.5716309547424316 0.5890663266181946 -0.1881556212902069 0.0 --0.5860421061515808 0.5892515182495117 -0.19050098955631256 0.0 --0.6008197069168091 0.5894417762756348 -0.19293519854545593 0.0 --0.615981936454773 0.5896367430686951 -0.19546224176883698 0.0 --0.6315489411354065 0.589836835861206 -0.19808664917945862 0.0 --0.6475423574447632 0.5900426506996155 -0.20081332325935364 0.0 --0.6639845967292786 0.5902541279792786 -0.20364724099636078 0.0 --0.6809002757072449 0.5904718041419983 -0.20659399032592773 0.0 --0.6983150243759155 0.5906956791877747 -0.20965930819511414 0.0 --0.7162573933601379 0.5909265279769897 -0.2128496766090393 0.0 --0.7347567081451416 0.5911642909049988 -0.21617166697978973 0.0 --0.758976399898529 0.595434844493866 -0.22112758457660675 0.0 --0.7862435579299927 0.6013650894165039 -0.22690139710903168 0.0 --0.8149780631065369 0.6076148748397827 -0.23302114009857178 0.0 -1.2174038887023926 0.007480814587324858 -0.23497708141803741 0.0 -1.2163046598434448 0.05235005170106888 -0.2349778264760971 0.0 -0.24398192763328552 0.7587653398513794 -0.15383517742156982 0.0 -0.2280370444059372 0.7402752041816711 -0.14950691163539886 0.0 -0.2129625678062439 0.7227942943572998 -0.1454368382692337 0.0 -0.1986851841211319 0.7062380909919739 -0.14160345494747162 0.0 -0.1851390302181244 0.6905297040939331 -0.13798721134662628 0.0 -0.17226563394069672 0.6756013631820679 -0.1345708817243576 0.0 -0.160012349486351 0.6613918542861938 -0.13133889436721802 0.0 -0.14833232760429382 0.6478477120399475 -0.12827759981155396 0.0 -0.13718250393867493 0.6349176168441772 -0.12537404894828796 0.0 -0.12652488052845 0.6225590705871582 -0.12261735647916794 0.0 -0.11632433533668518 0.6107304692268372 -0.11999698728322983 0.0 -0.10654906183481216 0.5993945002555847 -0.11750350892543793 0.0 -0.09717050194740295 0.5885190367698669 -0.11512871086597443 0.0 -0.08854372054338455 0.5805746912956238 -0.11335314810276031 0.0 -0.08126908540725708 0.5806680917739868 -0.11316782981157303 0.0 -0.07401713728904724 0.5807614922523499 -0.11300020664930344 0.0 -0.066785529255867 0.5808544754981995 -0.11285007745027542 0.0 -0.059572044759988785 0.5809473991394043 -0.11271736770868301 0.0 -0.052374400198459625 0.5810399055480957 -0.11260191351175308 0.0 -0.04519041255116463 0.5811324119567871 -0.11250371485948563 0.0 -0.03801786154508591 0.5812247395515442 -0.1124226376414299 0.0 -0.03085455670952797 0.5813168287277222 -0.11235862225294113 0.0 -0.023698318749666214 0.5814087390899658 -0.11231160908937454 0.0 -0.01654699072241783 0.5815007090568542 -0.11228161305189133 0.0 -0.009398404508829117 0.5815927982330322 -0.1122686043381691 0.0 -0.002250394318252802 0.5816846489906311 -0.11227253079414368 0.0 --0.004899195861071348 0.5817766785621643 -0.11229342967271805 0.0 --0.012052525766193867 0.581868588924408 -0.11233127862215042 0.0 --0.019211765378713608 0.5819606781005859 -0.11238615214824677 0.0 --0.026379093527793884 0.5820530652999878 -0.11245810985565186 0.0 --0.03355667367577553 0.5821452736854553 -0.11254710704088211 0.0 --0.040746718645095825 0.5822378396987915 -0.11265330761671066 0.0 --0.04795144125819206 0.582330584526062 -0.11277676373720169 0.0 --0.05517305061221123 0.5824233889579773 -0.11291753500699997 0.0 --0.06241380423307419 0.5825164914131165 -0.11307576298713684 0.0 --0.0696759894490242 0.5826098918914795 -0.11325156688690186 0.0 --0.07696191221475601 0.5827037692070007 -0.11344511806964874 0.0 --0.08427385985851288 0.5827978849411011 -0.11365649849176407 0.0 --0.09161421656608582 0.5828922390937805 -0.11388588696718216 0.0 --0.09898537397384644 0.5829870104789734 -0.11413347721099854 0.0 --0.10638979822397232 0.583082377910614 -0.1143994852900505 0.0 --0.11382993310689926 0.5831781029701233 -0.1146840900182724 0.0 --0.12130827456712723 0.5832741856575012 -0.11498748511075974 0.0 --0.12882748246192932 0.5833709836006165 -0.11531000584363937 0.0 --0.1363900899887085 0.5834681987762451 -0.11565181612968445 0.0 --0.1439988613128662 0.5835661888122559 -0.11601327359676361 0.0 --0.15165647864341736 0.5836646556854248 -0.11639460176229477 0.0 --0.15936575829982758 0.5837637782096863 -0.11679614335298538 0.0 --0.16712959110736847 0.5838636159896851 -0.11721822619438171 0.0 --0.1749510020017624 0.5839644074440002 -0.1176612600684166 0.0 --0.18283288180828094 0.5840657353401184 -0.11812551319599152 0.0 --0.19077837467193604 0.5841678380966187 -0.1186114102602005 0.0 --0.1987907439470291 0.5842708349227905 -0.11911939829587936 0.0 --0.20687329769134521 0.5843747854232788 -0.11964992433786392 0.0 --0.21502947807312012 0.5844799280166626 -0.12020347267389297 0.0 --0.22326259315013885 0.5845857262611389 -0.12078043073415756 0.0 --0.23157645761966705 0.5846927165985107 -0.12138140201568604 0.0 --0.23997467756271362 0.5848006010055542 -0.1220068708062172 0.0 --0.24846121668815613 0.5849097371101379 -0.12265745550394058 0.0 --0.2570400834083557 0.585020124912262 -0.12333376705646515 0.0 --0.2657153904438019 0.5851317644119263 -0.12403640151023865 0.0 --0.27449148893356323 0.5852447748184204 -0.12476605921983719 0.0 --0.28337275981903076 0.5853590369224548 -0.1255234181880951 0.0 --0.29236382246017456 0.5854746103286743 -0.12630918622016907 0.0 --0.3014695346355438 0.5855916738510132 -0.12712417542934418 0.0 --0.3106950521469116 0.5857104659080505 -0.12796925008296967 0.0 --0.3200452923774719 0.585830569267273 -0.12884515523910522 0.0 --0.32952603697776794 0.5859526991844177 -0.12975294888019562 0.0 --0.33914270997047424 0.5860763788223267 -0.1306934654712677 0.0 --0.34890124201774597 0.5862019062042236 -0.13166773319244385 0.0 --0.35880786180496216 0.5863292813301086 -0.13267682492733002 0.0 --0.36886903643608093 0.5864585638046265 -0.13372184336185455 0.0 --0.3790915906429291 0.5865901112556458 -0.13480401039123535 0.0 --0.3894824683666229 0.5867236852645874 -0.13592450320720673 0.0 --0.4000492990016937 0.5868598222732544 -0.1370847225189209 0.0 --0.4107995331287384 0.5869980454444885 -0.13828592002391815 0.0 --0.4217416048049927 0.587138831615448 -0.13952964544296265 0.0 --0.43288397789001465 0.5872822403907776 -0.14081740379333496 0.0 --0.44423550367355347 0.587428092956543 -0.14215077459812164 0.0 --0.4558059275150299 0.5875768661499023 -0.14353156089782715 0.0 --0.4676051735877991 0.58772873878479 -0.14496155083179474 0.0 --0.4796438217163086 0.587883710861206 -0.1464426964521408 0.0 --0.49193263053894043 0.5880416035652161 -0.14797692000865936 0.0 --0.504483699798584 0.5882030129432678 -0.14956648647785187 0.0 --0.5173093676567078 0.5883679986000061 -0.15121367573738098 0.0 --0.5304226875305176 0.5885367393493652 -0.1529209166765213 0.0 --0.543837308883667 0.5887091159820557 -0.1546907126903534 0.0 --0.5575685501098633 0.5888859629631042 -0.15652596950531006 0.0 --0.5716314911842346 0.5890668630599976 -0.15842947363853455 0.0 --0.5860428214073181 0.5892521739006042 -0.16040435433387756 0.0 --0.6008203029632568 0.5894423127174377 -0.16245394945144653 0.0 --0.6159823536872864 0.5896371006965637 -0.16458170115947723 0.0 --0.6315494775772095 0.589837372303009 -0.16679152846336365 0.0 --0.6475429534912109 0.5900431871414185 -0.16908742487430573 0.0 --0.6639850735664368 0.590254545211792 -0.17147359251976013 0.0 --0.6809006929397583 0.5904721617698669 -0.1739547699689865 0.0 --0.6983156800270081 0.5906962156295776 -0.17653585970401764 0.0 --0.7162579894065857 0.590927004814148 -0.17922216653823853 0.0 --0.7347576022148132 0.5911650061607361 -0.1820194125175476 0.0 --0.7589768767356873 0.5954352021217346 -0.18619222939014435 0.0 --0.7862444519996643 0.6013657450675964 -0.19105395674705505 0.0 --0.814978837966919 0.6076154708862305 -0.19620683789253235 0.0 --0.8453105688095093 0.6142123937606812 -0.201676607131958 0.0 --0.8773871064186096 0.6211888790130615 -0.20749236643314362 0.0 --0.9113733768463135 0.6285805702209473 -0.21368663012981415 0.0 --0.9474576711654663 0.6364288926124573 -0.22029659152030945 0.0 --0.9858512878417969 0.6447793245315552 -0.22736389935016632 0.0 --1.026795744895935 0.6536843180656433 -0.2349362075328827 0.0 -1.2275879383087158 -0.05283568799495697 -0.19325122237205505 0.0 -1.2043110132217407 -0.0370129831135273 -0.18950095772743225 0.0 -1.1941213607788086 -0.02201545611023903 -0.18784083425998688 0.0 -1.1891433000564575 -0.00730715598911047 -0.18702949583530426 0.0 -1.1878939867019653 0.007299480028450489 -0.18683302402496338 0.0 -1.190101146697998 0.02194133587181568 -0.18720842897891998 0.0 -1.1963084936141968 0.03676703944802284 -0.18824175000190735 0.0 -1.2087690830230713 0.05202571675181389 -0.19028867781162262 0.0 -0.24398256838321686 0.7587673664093018 -0.1253550797700882 0.0 -0.228037491440773 0.7402766942977905 -0.12182803452014923 0.0 -0.2129630446434021 0.7227959036827087 -0.11851150542497635 0.0 -0.19868558645248413 0.7062395215034485 -0.11538778990507126 0.0 -0.1851392537355423 0.69053053855896 -0.11244094371795654 0.0 -0.1722659468650818 0.6756026148796082 -0.1096571609377861 0.0 -0.16001272201538086 0.661393404006958 -0.10702358186244965 0.0 -0.14833250641822815 0.6478485465049744 -0.10452892631292343 0.0 -0.13718284666538239 0.634919285774231 -0.10216306149959564 0.0 -0.12652510404586792 0.6225602030754089 -0.09991664439439774 0.0 -0.11632443219423294 0.6107310056686401 -0.09778130799531937 0.0 -0.10654919594526291 0.599395215511322 -0.09574948996305466 0.0 -0.09717061370611191 0.5885196924209595 -0.09381434321403503 0.0 -0.08854376524686813 0.5805749893188477 -0.09236744791269302 0.0 -0.08126913756132126 0.5806685090065002 -0.09221645444631577 0.0 -0.07401715964078903 0.5807616710662842 -0.09207982569932938 0.0 -0.06678557395935059 0.5808548927307129 -0.09195751696825027 0.0 -0.05957207828760147 0.580947756767273 -0.09184937179088593 0.0 -0.052374422550201416 0.5810401439666748 -0.09175528585910797 0.0 -0.04519042372703552 0.5811325311660767 -0.09167524427175522 0.0 -0.0380178801715374 0.5812249779701233 -0.09160920232534409 0.0 -0.03085457719862461 0.5813171863555908 -0.09155705571174622 0.0 -0.023698333650827408 0.5814090967178345 -0.09151873737573624 0.0 -0.016547003760933876 0.5815011262893677 -0.09149430692195892 0.0 -0.009398410096764565 0.5815931558609009 -0.0914836972951889 0.0 -0.00225039548240602 0.581684947013855 -0.09148687869310379 0.0 --0.004899199120700359 0.5817770957946777 -0.09150393307209015 0.0 --0.012052536942064762 0.5818691253662109 -0.09153479337692261 0.0 --0.019211778417229652 0.5819610953330994 -0.09157948940992355 0.0 --0.02637910097837448 0.5820532441139221 -0.09163808822631836 0.0 --0.03355669602751732 0.5821456909179688 -0.0917106419801712 0.0 --0.04074674844741821 0.5822382569313049 -0.09179718792438507 0.0 --0.04795147106051445 0.5823309421539307 -0.09189777821302414 0.0 --0.05517307668924332 0.5824236869812012 -0.09201247245073318 0.0 --0.06241385266184807 0.5825169086456299 -0.09214143455028534 0.0 --0.06967604905366898 0.5826104283332825 -0.09228470176458359 0.0 --0.076961949467659 0.5827040672302246 -0.09244238585233688 0.0 --0.08427391201257706 0.5827982425689697 -0.09261464327573776 0.0 --0.09161427617073059 0.5828925967216492 -0.09280156344175339 0.0 --0.09898544102907181 0.5829874277114868 -0.09300332516431808 0.0 --0.1063898578286171 0.5830826759338379 -0.0932200700044632 0.0 --0.11382997781038284 0.5831783413887024 -0.09345196932554245 0.0 --0.1213083565235138 0.5832745432853699 -0.09369922429323196 0.0 --0.1288275420665741 0.5833712220191956 -0.09396200627088547 0.0 --0.13639016449451447 0.5834685564041138 -0.09424055367708206 0.0 --0.1439989060163498 0.5835663080215454 -0.09453506022691727 0.0 --0.1516565978527069 0.5836650729179382 -0.09484583884477615 0.0 --0.15936589241027832 0.5837642550468445 -0.09517304599285126 0.0 --0.16712971031665802 0.5838640332221985 -0.09551697969436646 0.0 --0.17495104670524597 0.5839645862579346 -0.09587795287370682 0.0 --0.1828329712152481 0.5840660333633423 -0.09625627845525742 0.0 --0.19077855348587036 0.5841683745384216 -0.09665225446224213 0.0 --0.19879089295864105 0.584271252155304 -0.09706617891788483 0.0 --0.20687349140644073 0.5843753814697266 -0.09749850630760193 0.0 --0.2150295376777649 0.5844801068305969 -0.09794950485229492 0.0 --0.2232627123594284 0.5845860242843628 -0.0984196737408638 0.0 --0.231576606631279 0.5846931338310242 -0.0989094004034996 0.0 --0.23997490108013153 0.584801197052002 -0.09941909462213516 0.0 --0.24846145510673523 0.5849103331565857 -0.09994924068450928 0.0 --0.25704026222229004 0.5850205421447754 -0.10050030797719955 0.0 --0.2657155990600586 0.5851321816444397 -0.10107287019491196 0.0 --0.2744916081428528 0.5852450132369995 -0.10166741162538528 0.0 --0.2833728790283203 0.5853593349456787 -0.10228455811738968 0.0 --0.2923639714717865 0.5854749083518982 -0.10292485356330872 0.0 --0.30146971344947815 0.5855920314788818 -0.10358896851539612 0.0 --0.3106951415538788 0.5857106447219849 -0.10427756607532501 0.0 --0.32004550099372864 0.5858309864997864 -0.1049913540482521 0.0 --0.3295261561870575 0.585952877998352 -0.1057310402393341 0.0 --0.3391428589820862 0.5860766768455505 -0.10649744421243668 0.0 --0.3489014208316803 0.5862022042274475 -0.10729134827852249 0.0 --0.35880807042121887 0.5863295793533325 -0.10811362415552139 0.0 --0.3688693046569824 0.5864590406417847 -0.1089651957154274 0.0 --0.37909191846847534 0.5865906476974487 -0.10984702408313751 0.0 --0.38948288559913635 0.5867243409156799 -0.11076010018587112 0.0 --0.40004962682724 0.5868602991104126 -0.1117054894566536 0.0 --0.4107997715473175 0.5869983434677124 -0.11268427968025208 0.0 --0.421741783618927 0.5871390700340271 -0.11369772255420685 0.0 --0.43288424611091614 0.5872825980186462 -0.11474710702896118 0.0 --0.4442359209060669 0.587428629398346 -0.11583366245031357 0.0 --0.45580634474754333 0.5875774025917053 -0.11695880442857742 0.0 --0.4676055908203125 0.5877292156219482 -0.11812405288219452 0.0 --0.4796440899372101 0.5878840088844299 -0.11933093518018723 0.0 --0.4919329583644867 0.5880420207977295 -0.12058113515377045 0.0 --0.5044841170310974 0.588203489780426 -0.12187643349170685 0.0 --0.517309844493866 0.5883685350418091 -0.12321869283914566 0.0 --0.530423104763031 0.5885372757911682 -0.12460985034704208 0.0 --0.5438379049301147 0.588709831237793 -0.12605203688144684 0.0 --0.5575689673423767 0.5888863801956177 -0.1275474727153778 0.0 --0.5716317296028137 0.5890671610832214 -0.1290985345840454 0.0 --0.586043119430542 0.5892525315284729 -0.130707785487175 0.0 --0.6008205413818359 0.5894425511360168 -0.13237792253494263 0.0 --0.6159828305244446 0.5896375775337219 -0.13411180675029755 0.0 --0.6315500140190125 0.5898378491401672 -0.13591252267360687 0.0 --0.6475434899330139 0.5900437235832214 -0.13778336346149445 0.0 --0.6639858484268188 0.5902552604675293 -0.13972781598567963 0.0 --0.6809014081954956 0.5904728174209595 -0.14174962043762207 0.0 --0.6983163356781006 0.5906968116760254 -0.1438528448343277 0.0 --0.7162584662437439 0.5909274220466614 -0.14604179561138153 0.0 --0.7347581386566162 0.5911654233932495 -0.14832116663455963 0.0 --0.7589776515960693 0.5954358577728271 -0.1517215073108673 0.0 --0.7862452268600464 0.6013663411140442 -0.15568313002586365 0.0 --0.814979612827301 0.6076160073280334 -0.15988202393054962 0.0 --0.8453113436698914 0.6142129898071289 -0.16433915495872498 0.0 --0.8773879408836365 0.621189534664154 -0.16907821595668793 0.0 --0.9113747477531433 0.6285815238952637 -0.1741258054971695 0.0 --0.9474589228630066 0.6364297270774841 -0.17951199412345886 0.0 --0.9858523011207581 0.6447799801826477 -0.18527084589004517 0.0 --1.0267971754074097 0.6536852121353149 -0.19144132733345032 0.0 --1.070570468902588 0.6632056832313538 -0.19806796312332153 0.0 --1.1174901723861694 0.6734105944633484 -0.20520195364952087 0.0 --1.1893832683563232 0.6969544291496277 -0.21681420505046844 0.0 -1.2183351516723633 -0.052437443286180496 -0.14869190752506256 0.0 -0.24397896230220795 0.7587561011314392 -0.09718213230371475 0.0 -0.2280343472957611 0.7402664422988892 -0.09444786608219147 0.0 -0.21295996010303497 0.7227854132652283 -0.09187664836645126 0.0 -0.19868271052837372 0.7062293291091919 -0.08945497870445251 0.0 -0.18513676524162292 0.690521240234375 -0.08717050403356552 0.0 -0.1722635179758072 0.6755930781364441 -0.08501230925321579 0.0 -0.16001048684120178 0.6613841652870178 -0.08297061920166016 0.0 -0.14833056926727295 0.6478400826454163 -0.08103670179843903 0.0 -0.13718102872371674 0.6349108219146729 -0.07920253276824951 0.0 -0.12652352452278137 0.6225523948669434 -0.07746104151010513 0.0 -0.11632287502288818 0.6107228398323059 -0.07580553740262985 0.0 -0.10654786974191666 0.5993877649307251 -0.07423043251037598 0.0 -0.09716934710741043 0.5885120630264282 -0.072730153799057 0.0 -0.0885433703660965 0.5805723667144775 -0.07160905748605728 0.0 -0.0812688022851944 0.5806660652160645 -0.0714920163154602 0.0 -0.07401687651872635 0.5807594656944275 -0.07138612121343613 0.0 -0.0667852982878685 0.5808525085449219 -0.07129127532243729 0.0 -0.05957183614373207 0.5809453725814819 -0.0712074339389801 0.0 -0.052374206483364105 0.5810377597808838 -0.07113449275493622 0.0 -0.045190248638391495 0.58113032579422 -0.07107245922088623 0.0 -0.038017719984054565 0.5812225341796875 -0.07102123647928238 0.0 -0.030854452401399612 0.5813148617744446 -0.07098081707954407 0.0 -0.023698246106505394 0.5814069509506226 -0.07095114141702652 0.0 -0.016546938568353653 0.581498920917511 -0.07093217968940735 0.0 -0.009398377500474453 0.5815910696983337 -0.07092398405075073 0.0 -0.0022503884974867105 0.5816830992698669 -0.0709264799952507 0.0 --0.004899181425571442 0.5817750096321106 -0.07093966752290726 0.0 --0.01205249410122633 0.5818670988082886 -0.07096359133720398 0.0 --0.019211718812584877 0.5819593071937561 -0.07099827378988266 0.0 --0.026379022747278214 0.5820515155792236 -0.0710437148809433 0.0 --0.03355658799409866 0.5821437835693359 -0.07109995186328888 0.0 --0.040746625512838364 0.5822364687919617 -0.07116705179214478 0.0 --0.047951314598321915 0.5823290348052979 -0.07124502211809158 0.0 --0.05517292767763138 0.582422137260437 -0.07133398205041885 0.0 --0.06241368502378464 0.5825153589248657 -0.07143396139144897 0.0 --0.06967584788799286 0.5826087594032288 -0.07154502719640732 0.0 --0.07696173340082169 0.5827024579048157 -0.07166727632284164 0.0 --0.08427367359399796 0.582796573638916 -0.07180081307888031 0.0 --0.0916140154004097 0.5828909873962402 -0.07194572687149048 0.0 --0.0989852100610733 0.582986056804657 -0.07210217416286469 0.0 --0.10638957470655441 0.5830811858177185 -0.07227019220590591 0.0 --0.11382970213890076 0.5831769108772278 -0.07244998961687088 0.0 --0.1213080957531929 0.5832732915878296 -0.07264170050621033 0.0 --0.1288272887468338 0.5833701491355896 -0.0728454440832138 0.0 --0.13638988137245178 0.5834673047065735 -0.07306137681007385 0.0 --0.1439986675977707 0.583565354347229 -0.07328972965478897 0.0 --0.15165627002716064 0.5836638808250427 -0.07353062927722931 0.0 --0.15936557948589325 0.5837631225585938 -0.07378431409597397 0.0 --0.16712939739227295 0.5838629007339478 -0.07405096292495728 0.0 --0.1749507486820221 0.5839635729789734 -0.07433082163333893 0.0 --0.1828327178955078 0.5840651988983154 -0.07462414354085922 0.0 --0.1907782256603241 0.5841674208641052 -0.07493111491203308 0.0 --0.19879063963890076 0.5842705368995667 -0.07525204867124557 0.0 --0.20687320828437805 0.5843745470046997 -0.0755872130393982 0.0 --0.2150292843580246 0.5844793915748596 -0.07593686878681183 0.0 --0.2232624739408493 0.584585428237915 -0.07630138099193573 0.0 --0.23157638311386108 0.5846925377845764 -0.07668105512857437 0.0 --0.23997458815574646 0.5848004221916199 -0.07707618176937103 0.0 --0.24846124649047852 0.5849098563194275 -0.07748721539974213 0.0 --0.2570401132106781 0.5850202441215515 -0.07791446894407272 0.0 --0.26571547985076904 0.5851319432258606 -0.07835835963487625 0.0 --0.27449148893356323 0.5852447748184204 -0.07881929725408554 0.0 --0.28337275981903076 0.5853590369224548 -0.079297736287117 0.0 --0.2923639118671417 0.5854747891426086 -0.07979416102170944 0.0 --0.30146974325180054 0.5855920314788818 -0.08030904829502106 0.0 --0.31069517135620117 0.5857107043266296 -0.08084289729595184 0.0 --0.3200455904006958 0.5858311057090759 -0.08139628171920776 0.0 --0.32952627539634705 0.5859531164169312 -0.08196975290775299 0.0 --0.33914297819137573 0.5860768556594849 -0.08256391435861588 0.0 --0.3489016592502594 0.5862025618553162 -0.08317942172288895 0.0 --0.35880836844444275 0.5863300561904907 -0.08381692320108414 0.0 --0.3688696622848511 0.5864595770835876 -0.08447712659835815 0.0 --0.3790922164916992 0.5865910649299622 -0.0851607695221901 0.0 --0.38948315382003784 0.5867247581481934 -0.08586864173412323 0.0 --0.4000500738620758 0.5868609547615051 -0.08660160005092621 0.0 --0.4108003079891205 0.5869991183280945 -0.0873604416847229 0.0 --0.42174243927001953 0.5871400237083435 -0.0881461650133133 0.0 --0.43288493156433105 0.5872835516929626 -0.0889597162604332 0.0 --0.4442366659641266 0.5874296426773071 -0.0898020938038826 0.0 --0.45580723881721497 0.5875785946846008 -0.09067440032958984 0.0 --0.46760645508766174 0.5877302885055542 -0.09157776832580566 0.0 --0.4796451926231384 0.5878853797912598 -0.09251347184181213 0.0 --0.4919341802597046 0.5880434513092041 -0.09348272532224655 0.0 --0.5044854879379272 0.588205099105835 -0.09448695927858353 0.0 --0.5173112750053406 0.5883702039718628 -0.09552757441997528 0.0 --0.5304246544837952 0.5885390043258667 -0.09660610556602478 0.0 --0.5438395142555237 0.5887115001678467 -0.09772418439388275 0.0 --0.5575708746910095 0.58888840675354 -0.09888360649347305 0.0 --0.57163405418396 0.5890694856643677 -0.10008614510297775 0.0 --0.586045503616333 0.5892548561096191 -0.10133375972509384 0.0 --0.6008232831954956 0.5894452333450317 -0.10262861102819443 0.0 --0.6159855127334595 0.5896401405334473 -0.10397281497716904 0.0 --0.631553053855896 0.5898406505584717 -0.10536890476942062 0.0 --0.6475464701652527 0.5900464057922363 -0.10681929439306259 0.0 --0.6639890074729919 0.5902580618858337 -0.10832679271697998 0.0 --0.680904746055603 0.5904756784439087 -0.10989425331354141 0.0 --0.6983202695846558 0.590700089931488 -0.11152490228414536 0.0 --0.716262936592102 0.5909311175346375 -0.11322199553251266 0.0 --0.7347627878189087 0.5911691784858704 -0.11498913913965225 0.0 --0.7589854001998901 0.5954418778419495 -0.11762577295303345 0.0 --0.7862538695335388 0.601373016834259 -0.12069722265005112 0.0 --0.814988911151886 0.6076229810714722 -0.12395257502794266 0.0 --0.8453214168548584 0.6142202615737915 -0.12740813195705414 0.0 --0.8773992657661438 0.621197521686554 -0.13108234107494354 0.0 --0.9113868474960327 0.6285898685455322 -0.13499566912651062 0.0 --0.9474725127220154 0.6364388465881348 -0.13917161524295807 0.0 --0.9858676195144653 0.64478999376297 -0.14363647997379303 0.0 --1.0268142223358154 0.6536960601806641 -0.14842048287391663 0.0 --1.0705891847610474 0.6632173657417297 -0.15355812013149261 0.0 --1.1175105571746826 0.6734228134155273 -0.15908905863761902 0.0 --1.189439058303833 0.6969871520996094 -0.1680966466665268 0.0 --1.318461298942566 0.7509788870811462 -0.18501226603984833 0.0 -1.219041347503662 -0.007490876596421003 -0.1059175580739975 0.0 -1.2171144485473633 0.0074790362268686295 -0.10575014352798462 0.0 -1.2206679582595825 0.022504881024360657 -0.10607490688562393 0.0 -0.24397911131381989 0.7587565779685974 -0.06924834102392197 0.0 -0.22803427278995514 0.7402662038803101 -0.06729993969202042 0.0 -0.21296021342277527 0.7227863073348999 -0.06546789407730103 0.0 -0.19868290424346924 0.7062300443649292 -0.06374228000640869 0.0 -0.18513672053813934 0.6905210614204407 -0.062114376574754715 0.0 -0.17226360738277435 0.6755934953689575 -0.06057657673954964 0.0 -0.16001057624816895 0.6613845229148865 -0.0591217465698719 0.0 -0.14833059906959534 0.6478402018547058 -0.05774368718266487 0.0 -0.13718105852603912 0.6349109411239624 -0.056436728686094284 0.0 -0.12652340531349182 0.6225518584251404 -0.05519574508070946 0.0 -0.11632301658391953 0.6107235550880432 -0.05401621386408806 0.0 -0.10654788464307785 0.5993878841400146 -0.05289379879832268 0.0 -0.09716944396495819 0.588512659072876 -0.05182480067014694 0.0 -0.08854334056377411 0.5805721879005432 -0.0510258749127388 0.0 -0.08126875013113022 0.5806657075881958 -0.05094246193766594 0.0 -0.07401682436466217 0.5807590484619141 -0.050867002457380295 0.0 -0.06678525358438492 0.5808520913124084 -0.0507994182407856 0.0 -0.05957179516553879 0.5809449553489685 -0.050739679485559464 0.0 -0.05237418785691261 0.5810375213623047 -0.05068771913647652 0.0 -0.0451902337372303 0.5811300873756409 -0.05064351484179497 0.0 -0.03801770880818367 0.5812223553657532 -0.050607018172740936 0.0 -0.03085443750023842 0.5813146233558655 -0.05057821050286293 0.0 -0.0236982349306345 0.5814067125320435 -0.05055706202983856 0.0 -0.016546931117773056 0.5814986228942871 -0.05054355785250664 0.0 -0.00939837098121643 0.5815907120704651 -0.050537701696157455 0.0 -0.002250386867672205 0.5816826820373535 -0.05053947865962982 0.0 --0.004899178631603718 0.5817746520042419 -0.05054888129234314 0.0 --0.012052489444613457 0.5818668007850647 -0.0505659393966198 0.0 --0.019211700186133385 0.5819587111473083 -0.050590626895427704 0.0 --0.02637900970876217 0.5820512175559998 -0.05062302574515343 0.0 --0.03355657681822777 0.5821436047554016 -0.05066310614347458 0.0 --0.04074658825993538 0.5822359323501587 -0.05071089416742325 0.0 --0.04795129597187042 0.5823287963867188 -0.0507664754986763 0.0 --0.05517289415001869 0.5824217796325684 -0.05082985758781433 0.0 --0.06241362914443016 0.5825148820877075 -0.05090108513832092 0.0 --0.06967578828334808 0.5826082825660706 -0.05098022520542145 0.0 --0.07696168124675751 0.5827020406723022 -0.05106734111905098 0.0 --0.08427361398935318 0.5827961564064026 -0.05116249620914459 0.0 --0.09161398559808731 0.5828908085823059 -0.05126577615737915 0.0 --0.09898513555526733 0.5829856395721436 -0.05137723684310913 0.0 --0.10638953000307083 0.5830808877944946 -0.051496975123882294 0.0 --0.11382965743541718 0.5831766724586487 -0.0516250915825367 0.0 --0.12130800634622574 0.5832728743553162 -0.0517616793513298 0.0 --0.12882716953754425 0.5833696126937866 -0.051906850188970566 0.0 --0.136389821767807 0.5834670066833496 -0.05206073820590973 0.0 --0.14399856328964233 0.5835649371147156 -0.05222344025969505 0.0 --0.1516561508178711 0.5836634039878845 -0.05239509418606758 0.0 --0.1593654304742813 0.5837625861167908 -0.05257585272192955 0.0 --0.16712933778762817 0.5838627219200134 -0.05276588350534439 0.0 --0.17495065927505493 0.5839632749557495 -0.05296529084444046 0.0 --0.1828325390815735 0.5840646624565125 -0.05317428335547447 0.0 --0.19077809154987335 0.584166944026947 -0.05339302867650986 0.0 --0.19879046082496643 0.5842700004577637 -0.05362170562148094 0.0 --0.20687304437160492 0.5843740701675415 -0.05386053025722504 0.0 --0.21502913534641266 0.584479033946991 -0.05410969257354736 0.0 --0.22326229512691498 0.5845849514007568 -0.054369423538446426 0.0 --0.23157623410224915 0.5846921801567078 -0.05463997274637222 0.0 --0.2399744838476181 0.5848001837730408 -0.05492153763771057 0.0 --0.2484610229730606 0.5849093198776245 -0.055214401334524155 0.0 --0.2570399045944214 0.5850197672843933 -0.055518846958875656 0.0 --0.26571524143218994 0.5851314067840576 -0.055835142731666565 0.0 --0.2744913399219513 0.5852444767951965 -0.05616360530257225 0.0 --0.2833726406097412 0.5853587985038757 -0.05650453642010689 0.0 --0.2923637628555298 0.5854745507240295 -0.05685826390981674 0.0 --0.30146947503089905 0.5855915546417236 -0.05722513049840927 0.0 --0.31069502234458923 0.5857104063034058 -0.057605545967817307 0.0 --0.3200454115867615 0.585830807685852 -0.0579998679459095 0.0 --0.32952600717544556 0.585952639579773 -0.05840848386287689 0.0 --0.3391427993774414 0.586076557636261 -0.05883187800645828 0.0 --0.3489013612270355 0.586202085018158 -0.059270452708005905 0.0 --0.35880815982818604 0.5863296985626221 -0.05972471833229065 0.0 --0.3688693046569824 0.5864589810371399 -0.060195133090019226 0.0 --0.37909191846847534 0.5865906476974487 -0.060682281851768494 0.0 --0.3894830048084259 0.5867245197296143 -0.06118670850992203 0.0 --0.4000498056411743 0.5868605375289917 -0.0617089718580246 0.0 --0.4108000099658966 0.586998701095581 -0.06224969029426575 0.0 --0.42174217104911804 0.5871396064758301 -0.06280956417322159 0.0 --0.4328845739364624 0.5872830748558044 -0.06338925659656525 0.0 --0.4442363679409027 0.5874292254447937 -0.06398951262235641 0.0 --0.45580679178237915 0.5875779986381531 -0.06461107730865479 0.0 --0.46760621666908264 0.5877299904823303 -0.065254807472229 0.0 --0.4796448051929474 0.5878849029541016 -0.06592153757810593 0.0 --0.49193382263183594 0.5880430340766907 -0.06661219149827957 0.0 --0.504485011100769 0.588204562664032 -0.06732775270938873 0.0 --0.5173107385635376 0.588369607925415 -0.06806925684213638 0.0 --0.5304242968559265 0.5885385870933533 -0.06883779913187027 0.0 --0.5438390970230103 0.5887110233306885 -0.06963448971509933 0.0 --0.5575703382492065 0.5888878107070923 -0.07046063244342804 0.0 --0.5716334581375122 0.5890688896179199 -0.07131751626729965 0.0 --0.5860449075698853 0.5892543196678162 -0.0722065195441246 0.0 --0.6008227467536926 0.5894446969032288 -0.07312918454408646 0.0 --0.615985095500946 0.5896397829055786 -0.07408703863620758 0.0 --0.6315523386001587 0.5898400545120239 -0.07508180290460587 0.0 --0.6475458741188049 0.5900458693504333 -0.07611530274152756 0.0 --0.6639885306358337 0.5902576446533203 -0.07718950510025024 0.0 --0.6809041500091553 0.5904752016067505 -0.0783063992857933 0.0 --0.6983194351196289 0.5906994342803955 -0.07946831732988358 0.0 --0.7162619829177856 0.5909303426742554 -0.0806775838136673 0.0 --0.7347620129585266 0.5911685228347778 -0.0819368064403534 0.0 --0.7589844465255737 0.5954411625862122 -0.0838155597448349 0.0 --0.786252498626709 0.6013719439506531 -0.0860041081905365 0.0 --0.8149877786636353 0.6076221466064453 -0.08832377940416336 0.0 --0.8453201651573181 0.6142193675041199 -0.09078606218099594 0.0 --0.877397358417511 0.6211961507797241 -0.09340409934520721 0.0 --0.9113855361938477 0.6285889744758606 -0.09619265049695969 0.0 --0.9474706053733826 0.6364375948905945 -0.09916820377111435 0.0 --0.9858652949333191 0.6447884440422058 -0.1023496612906456 0.0 --1.0268117189407349 0.6536944508552551 -0.10575854033231735 0.0 --1.0705865621566772 0.663215696811676 -0.10941941291093826 0.0 --1.117507815361023 0.6734212040901184 -0.11336053907871246 0.0 --1.1894320249557495 0.6969830393791199 -0.1197785809636116 0.0 --1.3184524774551392 0.7509738802909851 -0.1318318396806717 0.0 --3.8961386680603027 -0.39056235551834106 -0.2037983238697052 0.0 --3.8967628479003906 -0.43905800580978394 -0.20409780740737915 0.0 --3.897388458251953 -0.48770374059677124 -0.20442909002304077 0.0 --3.898016929626465 -0.5365151166915894 -0.20479245483875275 0.0 --3.8986477851867676 -0.5855077505111694 -0.20518817007541656 0.0 --3.899280071258545 -0.6346973180770874 -0.20561645925045013 0.0 --3.899916887283325 -0.6841004490852356 -0.20607782900333405 0.0 --3.900554895401001 -0.7337329983711243 -0.20657247304916382 0.0 --3.9011974334716797 -0.7836121916770935 -0.20710089802742004 0.0 --3.9018425941467285 -0.8337546586990356 -0.20766344666481018 0.0 --3.902491331100464 -0.8841779232025146 -0.20826059579849243 0.0 --3.903144121170044 -0.9348997473716736 -0.2088928371667862 0.0 --3.9038007259368896 -0.9859381318092346 -0.20956066250801086 0.0 --3.9044618606567383 -1.0373116731643677 -0.2102646380662918 0.0 --3.905128002166748 -1.0890395641326904 -0.21100537478923798 0.0 --3.9057986736297607 -1.1411410570144653 -0.21178342401981354 0.0 --3.9064741134643555 -1.1936359405517578 -0.21259944140911102 0.0 --3.9071550369262695 -1.2465451955795288 -0.21345415711402893 0.0 --3.907841205596924 -1.2998894453048706 -0.21434825658798218 0.0 --3.9085335731506348 -1.3536906242370605 -0.21528252959251404 0.0 --3.9092323780059814 -1.4079713821411133 -0.21625781059265137 0.0 --3.9099373817443848 -1.462754249572754 -0.21727491915225983 0.0 --3.910649299621582 -1.5180634260177612 -0.21833477914333344 0.0 --3.911367893218994 -1.573923110961914 -0.2194383144378662 0.0 --3.9120943546295166 -1.6303589344024658 -0.22058656811714172 0.0 --3.912828207015991 -1.6873972415924072 -0.22178055346012115 0.0 --3.9135706424713135 -1.7450653314590454 -0.22302143275737762 0.0 --3.9143214225769043 -1.8033909797668457 -0.22431033849716187 0.0 --3.9150803089141846 -1.8624035120010376 -0.22564846277236938 0.0 --3.9158496856689453 -1.9221338033676147 -0.2270372062921524 0.0 --3.916627883911133 -1.98261296749115 -0.2284778505563736 0.0 --3.9174160957336426 -2.0438735485076904 -0.22997182607650757 0.0 --3.918215036392212 -2.105950355529785 -0.23152068257331848 0.0 --3.919025182723999 -2.1688785552978516 -0.23312601447105408 0.0 --3.9198460578918457 -2.2326948642730713 -0.2347894161939621 0.0 --0.4775119125843048 -3.9928128719329834 -0.20929446816444397 0.0 --0.3783605694770813 -3.9940884113311768 -0.20881065726280212 0.0 --0.3289417028427124 -3.994724988937378 -0.20861682295799255 0.0 --0.27960705757141113 -3.995359420776367 -0.20845475792884827 0.0 --0.23034155368804932 -3.9959936141967773 -0.2083244025707245 0.0 --0.18113020062446594 -3.996626615524292 -0.20822562277317047 0.0 --0.13195806741714478 -3.9972596168518066 -0.20815838873386383 0.0 --0.08281027525663376 -3.997892141342163 -0.2081226110458374 0.0 --0.03367194905877113 -3.9985246658325195 -0.20811827480793 0.0 -0.015471750870347023 -3.999156951904297 -0.2081453651189804 0.0 -0.06463567912578583 -3.9997899532318115 -0.20820392668247223 0.0 -0.11383470892906189 -4.000422954559326 -0.20829397439956665 0.0 -0.1630837470293045 -4.001056671142578 -0.20841559767723083 0.0 -0.21239779889583588 -4.0016913414001465 -0.20856888592243195 0.0 -0.2617918848991394 -4.002326965332031 -0.20875394344329834 0.0 -0.3112812042236328 -4.002964019775391 -0.20897091925144196 0.0 -0.3608810603618622 -4.003602504730225 -0.2092200070619583 0.0 -0.4106067419052124 -4.004242420196533 -0.20950134098529816 0.0 -0.460473895072937 -4.004884243011475 -0.20981517434120178 0.0 -0.5104982256889343 -4.005527973175049 -0.2101617157459259 0.0 -0.5606957077980042 -4.006174087524414 -0.21054129302501678 0.0 -0.6110824346542358 -4.00682258605957 -0.21095412969589233 0.0 -0.6616747975349426 -4.007473468780518 -0.2114005833864212 0.0 -0.7124894857406616 -4.008127689361572 -0.21188101172447205 0.0 -0.7635433077812195 -4.008784294128418 -0.21239575743675232 0.0 -0.8148537278175354 -4.0094451904296875 -0.21294529736042023 0.0 -0.866438090801239 -4.0101094245910645 -0.21353000402450562 0.0 -0.9183142781257629 -4.010776519775391 -0.2141503393650055 0.0 -0.9705007672309875 -4.011448383331299 -0.21480685472488403 0.0 -1.023016095161438 -4.012124061584473 -0.21550002694129944 0.0 -1.0758793354034424 -4.01280403137207 -0.21623045206069946 0.0 -1.1291104555130005 -4.013489246368408 -0.21699874103069305 0.0 -1.1827292442321777 -4.014179229736328 -0.21780553460121155 0.0 -1.236756443977356 -4.0148749351501465 -0.21865150332450867 0.0 -1.2912131547927856 -4.015575408935547 -0.21953731775283813 0.0 -1.3461214303970337 -4.016282558441162 -0.2204638123512268 0.0 -1.4015034437179565 -4.016995429992676 -0.22143174707889557 0.0 -1.4573819637298584 -4.017714023590088 -0.2224419116973877 0.0 -1.5137816667556763 -4.018439769744873 -0.2234952747821808 0.0 -1.5707266330718994 -4.019172668457031 -0.22459276020526886 0.0 -1.6282423734664917 -4.019913196563721 -0.22573533654212952 0.0 -1.6863549947738647 -4.020660877227783 -0.22692401707172394 0.0 -1.7450917959213257 -4.021416664123535 -0.22815994918346405 0.0 -1.804481029510498 -4.022181034088135 -0.2294442504644394 0.0 -1.8645519018173218 -4.02295446395874 -0.23077815771102905 0.0 -1.9253344535827637 -4.023736953735352 -0.2321629375219345 0.0 -1.9868600368499756 -4.024528503417969 -0.23359991610050201 0.0 -3.487550973892212 -0.36564698815345764 -0.18251119554042816 0.0 -3.488107442855835 -0.3224201500415802 -0.18231916427612305 0.0 -3.1899988651275635 -0.25536876916885376 -0.16656075417995453 0.0 -3.1490776538848877 -0.21318022906780243 -0.1642749309539795 0.0 -3.1092581748962402 -0.1721278429031372 -0.16207510232925415 0.0 -3.070485830307007 -0.1321544647216797 -0.15995727479457855 0.0 -3.0327084064483643 -0.0932064801454544 -0.15791766345500946 0.0 -2.9958763122558594 -0.05523356422781944 -0.15595263242721558 0.0 -2.983647584915161 -0.018334191292524338 -0.1552926003932953 0.0 -2.9844863414764404 0.01833934523165226 -0.15533626079559326 0.0 -2.985325574874878 0.055039048194885254 -0.15540340542793274 0.0 -2.98616623878479 0.0917760580778122 -0.15549413859844208 0.0 -2.9870071411132812 0.12856152653694153 -0.15560846030712128 0.0 -2.9878499507904053 0.1654067039489746 -0.15574650466442108 0.0 -2.988694190979004 0.20232288539409637 -0.15590834617614746 0.0 -2.9895405769348145 0.2393215000629425 -0.15609414875507355 0.0 -2.990388870239258 0.2764139771461487 -0.1563040167093277 0.0 -2.991239309310913 0.3136119246482849 -0.15653811395168304 0.0 -2.992093563079834 0.3509272336959839 -0.1567966789007187 0.0 -2.9929494857788086 0.3883715271949768 -0.1570798009634018 0.0 -2.993809223175049 0.4259570837020874 -0.15738779306411743 0.0 -2.9946720600128174 0.4636959731578827 -0.15772084891796112 0.0 -2.9955391883850098 0.5016006827354431 -0.15807925164699554 0.0 -2.9964098930358887 0.5396837592124939 -0.1584632694721222 0.0 -2.9972856044769287 0.5779582262039185 -0.15887321531772614 0.0 -2.9981658458709717 0.6164370775222778 -0.15930944681167603 0.0 -2.9990508556365967 0.6551335453987122 -0.15977223217487335 0.0 -2.999941110610962 0.6940614581108093 -0.16026198863983154 0.0 -3.0008368492126465 0.7332346439361572 -0.16077911853790283 0.0 -3.0017385482788086 0.772667407989502 -0.16132403910160065 0.0 -3.0026466846466064 0.812374472618103 -0.161897212266922 0.0 -3.003561496734619 0.8523707389831543 -0.1624990999698639 0.0 -3.004483461380005 0.8926717042922974 -0.16313022375106812 0.0 -3.0054128170013428 0.9332931637763977 -0.16379110515117645 0.0 -3.0063493251800537 0.9742510318756104 -0.16448228061199188 0.0 -3.007293939590454 1.0155622959136963 -0.16520436108112335 0.0 -3.0082473754882812 1.0572444200515747 -0.16595801711082458 0.0 -3.009209394454956 1.09931480884552 -0.16674385964870453 0.0 -3.010181188583374 1.1417921781539917 -0.16756263375282288 0.0 -3.011162519454956 1.1846951246261597 -0.16841503977775574 0.0 -3.0121536254882812 1.2280433177947998 -0.169301837682724 0.0 -3.013155698776245 1.2718571424484253 -0.1702238917350769 0.0 -3.039585828781128 1.3272560834884644 -0.17262552678585052 0.0 -3.090146541595459 1.3947978019714355 -0.1764572262763977 0.0 -3.1430113315582275 1.4654169082641602 -0.18049079179763794 0.0 -3.198357105255127 1.539351224899292 -0.1847415715456009 0.0 -0.24398377537727356 0.7587711215019226 -0.041483115404844284 0.0 -0.22803883254528046 0.7402810454368591 -0.04031596705317497 0.0 -0.21296408772468567 0.7227994203567505 -0.03921840712428093 0.0 -0.1986866295337677 0.7062432169914246 -0.03818470239639282 0.0 -0.18514016270637512 0.6905339360237122 -0.03720950707793236 0.0 -0.17226676642894745 0.6756058931350708 -0.03628828004002571 0.0 -0.16001352667808533 0.6613966822624207 -0.03541676700115204 0.0 -0.14833307266235352 0.6478509902954102 -0.0345911830663681 0.0 -0.13718338310718536 0.6349217295646667 -0.03380826488137245 0.0 -0.12652558088302612 0.6225625276565552 -0.033064864575862885 0.0 -0.11632494628429413 0.610733687877655 -0.03235825151205063 0.0 -0.10654973983764648 0.5993982553482056 -0.03168589621782303 0.0 -0.09717098623514175 0.5885219573974609 -0.031045466661453247 0.0 -0.08854391425848007 0.5805759429931641 -0.030566588044166565 0.0 -0.0812692791223526 0.5806695222854614 -0.030516620725393295 0.0 -0.07401731610298157 0.5807629227638245 -0.030471421778202057 0.0 -0.06678569316864014 0.5808558464050293 -0.030430933460593224 0.0 -0.05957217887043953 0.5809487104415894 -0.0303951445966959 0.0 -0.05237452685832977 0.5810412764549255 -0.0303640179336071 0.0 -0.045190513134002686 0.5811336636543274 -0.030337529256939888 0.0 -0.03801793232560158 0.5812258124351501 -0.030315658077597618 0.0 -0.030854616314172745 0.5813179612159729 -0.030298396944999695 0.0 -0.023698370903730392 0.5814100503921509 -0.030285729095339775 0.0 -0.016547031700611115 0.5815021395683289 -0.030277647078037262 0.0 -0.009398425929248333 0.5815941095352173 -0.030274132266640663 0.0 -0.002250399673357606 0.5816860198974609 -0.030275192111730576 0.0 --0.004899207502603531 0.5817780494689941 -0.03028082847595215 0.0 --0.012052553705871105 0.5818699598312378 -0.030291033908724785 0.0 --0.01921180821955204 0.581961989402771 -0.030305828899145126 0.0 --0.026379145681858063 0.5820542573928833 -0.030325226485729218 0.0 --0.033556755632162094 0.5821467041969299 -0.030349239706993103 0.0 --0.04074681177735329 0.5822390913963318 -0.030377868562936783 0.0 --0.04795154184103012 0.5823318362236023 -0.03041115775704384 0.0 --0.05517318844795227 0.5824248194694519 -0.03044912964105606 0.0 --0.062413956969976425 0.5825179219245911 -0.030491793528199196 0.0 --0.06967616081237793 0.5826113820075989 -0.03053920716047287 0.0 --0.07696208357810974 0.5827051401138306 -0.030591389164328575 0.0 --0.08427403122186661 0.5827990174293518 -0.030648380517959595 0.0 --0.09161439538002014 0.5828933715820312 -0.030710237100720406 0.0 --0.09898560494184494 0.5829883813858032 -0.030777012929320335 0.0 --0.10639002919197083 0.5830836296081543 -0.03084873966872692 0.0 --0.11383016407489777 0.5831792950630188 -0.030925480648875237 0.0 --0.12130855768918991 0.5832754969596863 -0.031007302924990654 0.0 --0.12882773578166962 0.583372175693512 -0.03109426237642765 0.0 --0.13639043271541595 0.5834696292877197 -0.031186452135443687 0.0 --0.14399918913841248 0.5835674405097961 -0.0312839113175869 0.0 --0.15165682137012482 0.5836659669876099 -0.03138674423098564 0.0 --0.15936611592769623 0.5837650895118713 -0.03149501979351044 0.0 --0.16712996363639832 0.5838648676872253 -0.031608838587999344 0.0 --0.17495138943195343 0.5839656591415405 -0.03172830492258072 0.0 --0.18283326923847198 0.5840669870376587 -0.03185348957777023 0.0 --0.19077885150909424 0.5841692686080933 -0.03198453038930893 0.0 --0.1987912505865097 0.5842723250389099 -0.03212151303887367 0.0 --0.2068737894296646 0.5843762159347534 -0.03226456791162491 0.0 --0.2150299847126007 0.5844812989234924 -0.03241383656859398 0.0 --0.22326311469078064 0.5845870971679688 -0.032569415867328644 0.0 --0.23157697916030884 0.5846940279006958 -0.032731473445892334 0.0 --0.23997530341148376 0.5848021507263184 -0.03290014714002609 0.0 --0.24846188724040985 0.5849113464355469 -0.03307558596134186 0.0 --0.25704076886177063 0.5850217342376709 -0.03325795754790306 0.0 --0.2657160460948944 0.5851331949234009 -0.03344741836190224 0.0 --0.2744920551776886 0.5852459669113159 -0.033644165843725204 0.0 --0.2833734452724457 0.5853604078292847 -0.03384840488433838 0.0 --0.29236456751823425 0.5854761004447937 -0.03406029939651489 0.0 --0.3014702796936035 0.5855931043624878 -0.03428006172180176 0.0 --0.31069570779800415 0.5857117176055908 -0.034507934004068375 0.0 --0.3200460970401764 0.5858320593833923 -0.03474414721131325 0.0 --0.32952678203582764 0.5859540104866028 -0.034988924860954285 0.0 --0.33914342522621155 0.5860776901245117 -0.03524254262447357 0.0 --0.3489021062850952 0.5862033367156982 -0.0355052724480629 0.0 --0.35880881547927856 0.586330771446228 -0.03577738627791405 0.0 --0.3688700795173645 0.5864602327346802 -0.036059193313121796 0.0 --0.37909263372421265 0.5865917205810547 -0.036351002752780914 0.0 --0.38948357105255127 0.5867254137992859 -0.03665315732359886 0.0 --0.4000503122806549 0.5868613123893738 -0.03696600720286369 0.0 --0.410800576210022 0.5869995355606079 -0.03728992119431496 0.0 --0.42174258828163147 0.5871402025222778 -0.03762529790401459 0.0 --0.4328851103782654 0.5872837901115417 -0.03797256201505661 0.0 --0.44423672556877136 0.5874297022819519 -0.03833211958408356 0.0 --0.4558071494102478 0.5875784754753113 -0.03870445862412453 0.0 --0.46760648488998413 0.587730348110199 -0.03909007087349892 0.0 --0.47964513301849365 0.587885320186615 -0.039489470422267914 0.0 --0.49193403124809265 0.5880432724952698 -0.0399031899869442 0.0 --0.5044850707054138 0.5882046222686768 -0.040331825613975525 0.0 --0.5173108577728271 0.5883697271347046 -0.04077601060271263 0.0 --0.5304240584373474 0.5885382890701294 -0.04123637080192566 0.0 --0.5438389182090759 0.5887108445167542 -0.04171362519264221 0.0 --0.5575700402259827 0.5888875722885132 -0.042208511382341385 0.0 --0.5716331601142883 0.589068591594696 -0.042721811681985855 0.0 --0.5860444903373718 0.5892539024353027 -0.04325434938073158 0.0 --0.6008219718933105 0.5894439220428467 -0.04380703717470169 0.0 --0.6159842610359192 0.5896389484405518 -0.04438081756234169 0.0 --0.6315515637397766 0.5898392796516418 -0.04497672617435455 0.0 --0.6475450396537781 0.5900450944900513 -0.04559582844376564 0.0 --0.6639873385429382 0.5902565717697144 -0.04623928666114807 0.0 --0.6809030175209045 0.5904741883277893 -0.046908359974622726 0.0 --0.6983180046081543 0.5906981825828552 -0.04760436341166496 0.0 --0.7162603735923767 0.5909289717674255 -0.04832875356078148 0.0 --0.7347601056098938 0.5911670327186584 -0.049083054065704346 0.0 --0.7589795589447021 0.5954373478889465 -0.050208304077386856 0.0 --0.786247730255127 0.6013683080673218 -0.05151933804154396 0.0 --0.8149817585945129 0.6076176166534424 -0.052908822894096375 0.0 --0.845314085483551 0.6142149567604065 -0.05438382178544998 0.0 --0.877390444278717 0.6211912631988525 -0.055952075868844986 0.0 --0.9113772511482239 0.6285832524299622 -0.05762244015932083 0.0 --0.9474614858627319 0.6364314556121826 -0.059404853731393814 0.0 --0.9858554601669312 0.6447820067405701 -0.061310626566410065 0.0 --1.0268009901046753 0.6536877155303955 -0.06335262954235077 0.0 --1.0705742835998535 0.6632080674171448 -0.06554552912712097 0.0 --1.1174941062927246 0.6734129190444946 -0.06790633499622345 0.0 --1.1893916130065918 0.696959376335144 -0.07174937427043915 0.0 --1.3183989524841309 0.7509434223175049 -0.07896894961595535 0.0 --3.8636045455932617 2.13820743560791 -0.22982926666736603 0.0 --3.864391565322876 2.077021360397339 -0.22834034264087677 0.0 --3.865168333053589 2.016613721847534 -0.22690461575984955 0.0 --3.865935802459717 1.9569523334503174 -0.22552070021629333 0.0 --3.8666937351226807 1.8980052471160889 -0.2241872102022171 0.0 --3.867443799972534 1.8397427797317505 -0.22290289402008057 0.0 --3.868185043334961 1.782135248184204 -0.22166648507118225 0.0 --3.8689181804656982 1.7251546382904053 -0.22047683596611023 0.0 --3.8696436882019043 1.6687740087509155 -0.21933284401893616 0.0 --3.870361089706421 1.612966775894165 -0.2182334065437317 0.0 --3.871072292327881 1.5577082633972168 -0.217177614569664 0.0 --3.8717761039733887 1.5029733180999756 -0.2161644548177719 0.0 --3.872473955154419 1.448738694190979 -0.21519307792186737 0.0 --3.8731653690338135 1.3949812650680542 -0.21426258981227875 0.0 --3.8738515377044678 1.3416787385940552 -0.21337223052978516 0.0 --3.8745312690734863 1.2888092994689941 -0.21252118051052094 0.0 --3.875206470489502 1.2363522052764893 -0.21170875430107117 0.0 --3.8758761882781982 1.1842867136001587 -0.21093423664569855 0.0 --3.8765411376953125 1.1325929164886475 -0.21019700169563293 0.0 --3.8778579235076904 1.0302437543869019 -0.20883196592330933 0.0 --3.878509759902954 0.9795506596565247 -0.2082030177116394 0.0 --3.879803419113159 0.8790375590324402 -0.20704983174800873 0.0 --3.8911936283111572 -0.006197328679263592 -0.06745419651269913 0.0 --3.8918089866638184 -0.054030660539865494 -0.06747128069400787 0.0 --3.892425060272217 -0.10189545899629593 -0.0674985721707344 0.0 --3.8930413722991943 -0.14980623126029968 -0.06753609329462051 0.0 --3.893658399581909 -0.19777753949165344 -0.06758385896682739 0.0 --3.8942763805389404 -0.24582400918006897 -0.06764191389083862 0.0 --3.894895315170288 -0.2939603626728058 -0.06771031022071838 0.0 --3.8955163955688477 -0.3422015309333801 -0.06778910011053085 0.0 --3.9269351959228516 -3.9484405517578125 -0.09653470665216446 0.0 --3.832749128341675 -3.9496519565582275 -0.0954054519534111 0.0 --3.740726947784424 -3.9508352279663086 -0.09431637823581696 0.0 --3.6507692337036133 -3.9519927501678467 -0.0932658389210701 0.0 --3.5627801418304443 -3.953124761581421 -0.0922522097826004 0.0 --3.476670026779175 -3.9542324542999268 -0.09127402305603027 0.0 --3.3923544883728027 -3.955317497253418 -0.0903298631310463 0.0 --3.309752941131592 -3.9563798904418945 -0.08941838890314102 0.0 --3.2287893295288086 -3.957421064376831 -0.08853836357593536 0.0 --3.1493923664093018 -3.9584426879882812 -0.0876886248588562 0.0 --3.07149338722229 -3.9594452381134033 -0.0868680328130722 0.0 --2.9950265884399414 -3.960428237915039 -0.08607551455497742 0.0 --2.9199323654174805 -3.961394786834717 -0.08531012386083603 0.0 --2.8461499214172363 -3.962343692779541 -0.08457086980342865 0.0 --2.7736244201660156 -3.9632761478424072 -0.08385686576366425 0.0 --2.702303171157837 -3.9641942977905273 -0.08316729217767715 0.0 --2.632134437561035 -3.965096950531006 -0.08250132203102112 0.0 --2.563070297241211 -3.9659852981567383 -0.08185818791389465 0.0 --2.4950644969940186 -3.96686053276062 -0.08123718947172165 0.0 --2.428072690963745 -3.9677224159240723 -0.080637626349926 0.0 --2.3620519638061523 -3.968571186065674 -0.08005883544683456 0.0 --2.2969627380371094 -3.9694080352783203 -0.0795002207159996 0.0 --2.2327663898468018 -3.970233917236328 -0.07896120101213455 0.0 --2.1694254875183105 -3.9710497856140137 -0.07844122499227524 0.0 --2.106903076171875 -3.971853494644165 -0.0779397189617157 0.0 --2.045166254043579 -3.9726479053497314 -0.07745622098445892 0.0 --1.984181523323059 -3.9734325408935547 -0.07699023932218552 0.0 --1.9239170551300049 -3.974207878112793 -0.07654131948947906 0.0 --1.864342212677002 -3.9749739170074463 -0.07610902935266495 0.0 --1.8054279088974 -3.9757320880889893 -0.07569297403097153 0.0 --1.747145175933838 -3.9764814376831055 -0.07529273629188538 0.0 --1.689467191696167 -3.9772236347198486 -0.07490798085927963 0.0 --1.6323670148849487 -3.9779584407806396 -0.07453832775354385 0.0 --1.5758191347122192 -3.9786856174468994 -0.07418345659971237 0.0 --1.519798755645752 -3.9794065952301025 -0.07384305447340012 0.0 --1.4642815589904785 -3.9801201820373535 -0.07351679354906082 0.0 --1.4092447757720947 -3.9808287620544434 -0.07320443540811539 0.0 --1.3546652793884277 -3.9815304279327393 -0.07290566712617874 0.0 --1.3005216121673584 -3.982227325439453 -0.07262026518583298 0.0 --1.2467918395996094 -3.9829182624816895 -0.0723479613661766 0.0 --1.193455696105957 -3.983604669570923 -0.07208855450153351 0.0 --1.140492558479309 -3.984286069869995 -0.07184180617332458 0.0 --1.0878827571868896 -3.984962224960327 -0.07160750031471252 0.0 --1.0356072187423706 -3.9856348037719727 -0.07138548791408539 0.0 --0.9836471676826477 -3.9863035678863525 -0.07117556035518646 0.0 --0.9319838881492615 -3.9869682788848877 -0.07097755372524261 0.0 --0.8805995583534241 -3.9876291751861572 -0.07079129666090012 0.0 --0.829476535320282 -3.9882872104644775 -0.07061666995286942 0.0 --0.7785974144935608 -3.9889416694641113 -0.07045350968837738 0.0 --0.7279451489448547 -3.9895927906036377 -0.07030168175697327 0.0 --0.677503228187561 -3.9902420043945312 -0.07016108930110931 0.0 --0.6272550225257874 -3.9908881187438965 -0.07003161311149597 0.0 --0.5771844983100891 -3.991532802581787 -0.06991317123174667 0.0 --0.5272753834724426 -3.9921746253967285 -0.06980562955141068 0.0 --0.4775121212005615 -3.992814540863037 -0.0697089359164238 0.0 --0.4278790354728699 -3.993452787399292 -0.06962301582098007 0.0 --0.37836071848869324 -3.9940900802612305 -0.06954780220985413 0.0 --0.32894179224967957 -3.9947259426116943 -0.06948322802782059 0.0 --0.2796071171760559 -3.9953606128692627 -0.06942924857139587 0.0 --0.23034162819385529 -3.995994806289673 -0.0693858340382576 0.0 --0.18113026022911072 -3.9966280460357666 -0.06935293972492218 0.0 --0.13195808231830597 -3.997260093688965 -0.06933052837848663 0.0 --0.08281027525663376 -3.997892141342163 -0.06931859999895096 0.0 --0.033671945333480835 -3.9985244274139404 -0.06931715458631516 0.0 -0.015471750870347023 -3.999156951904297 -0.06932617723941803 0.0 -0.06463566422462463 -3.999788999557495 -0.06934567540884018 0.0 -0.1138346791267395 -4.00042200088501 -0.0693756639957428 0.0 -0.16308368742465973 -4.0010552406311035 -0.06941616535186768 0.0 -0.2123977243900299 -4.001689910888672 -0.0694672167301178 0.0 -0.26179179549217224 -4.002325534820557 -0.06952885538339615 0.0 -0.3112810254096985 -4.0029616355896 -0.06960111111402512 0.0 -0.3608808219432831 -4.003600120544434 -0.06968406587839127 0.0 -0.4106064438819885 -4.004239559173584 -0.06977776437997818 0.0 -0.46047353744506836 -4.004881381988525 -0.06988228857517242 0.0 -0.5104978084564209 -4.0055251121521 -0.06999770551919937 0.0 -0.560695230960846 -4.006170749664307 -0.07012412697076797 0.0 -0.6110818386077881 -4.006818771362305 -0.07026161998510361 0.0 -0.6616740822792053 -4.007469654083252 -0.07041031867265701 0.0 -0.7124887108802795 -4.008123397827148 -0.07057032734155655 0.0 -0.7635424733161926 -4.008780002593994 -0.07074177265167236 0.0 -0.8148527145385742 -4.0094404220581055 -0.0709247887134552 0.0 -0.8664368987083435 -4.010103702545166 -0.071119524538517 0.0 -0.9183130860328674 -4.01077127456665 -0.07132614403963089 0.0 -0.9704993367195129 -4.0114426612854 -0.07154479622840881 0.0 -1.0230145454406738 -4.012118339538574 -0.07177566736936569 0.0 -1.0758779048919678 -4.012798309326172 -0.07201895117759705 0.0 -1.1291086673736572 -4.013483047485352 -0.0722748339176178 0.0 -1.182727336883545 -4.0141730308532715 -0.07254354655742645 0.0 -1.236754298210144 -4.014867782592773 -0.07282529026269913 0.0 -1.2912108898162842 -4.015568256378174 -0.07312033325433731 0.0 -1.3461188077926636 -4.016274929046631 -0.07342890650033951 0.0 -1.4015007019042969 -4.016987323760986 -0.0737512856721878 0.0 -1.4573792219161987 -4.017706394195557 -0.07408773899078369 0.0 -1.513778567314148 -4.018431663513184 -0.07443857192993164 0.0 -1.5707231760025024 -4.019164085388184 -0.07480408996343613 0.0 -1.628238558769226 -4.019904136657715 -0.07518463581800461 0.0 -1.68635094165802 -4.020651340484619 -0.07558053731918335 0.0 -1.7450875043869019 -4.021407127380371 -0.0759921744465828 0.0 -1.8044763803482056 -4.0221710205078125 -0.07641992717981339 0.0 -1.8645471334457397 -4.022944450378418 -0.07686420530080795 0.0 -1.9253289699554443 -4.023725509643555 -0.07732540369033813 0.0 -1.9868545532226562 -4.02451753616333 -0.07780402153730392 0.0 -2.0491554737091064 -4.025318622589111 -0.07830047607421875 0.0 -2.112266778945923 -4.0261311531066895 -0.07881530374288559 0.0 -2.176222562789917 -4.026953220367432 -0.07934898883104324 0.0 -2.241060733795166 -4.027788162231445 -0.07990212738513947 0.0 -2.306819200515747 -4.028634071350098 -0.08047526329755783 0.0 -2.373537540435791 -4.029491901397705 -0.0810689926147461 0.0 -2.441258430480957 -4.0303635597229 -0.08168400079011917 0.0 -2.5100247859954834 -4.031247615814209 -0.0823209285736084 0.0 -2.5798826217651367 -4.032146453857422 -0.08298049867153168 0.0 -2.6508800983428955 -4.033059597015381 -0.0836634635925293 0.0 -2.723067045211792 -4.033988952636719 -0.08437062054872513 0.0 -2.7964954376220703 -4.034933567047119 -0.08510278910398483 0.0 -2.8712210655212402 -4.035894870758057 -0.08586085587739944 0.0 -2.9473013877868652 -4.0368733406066895 -0.08664575219154358 0.0 -3.024796724319458 -4.037869453430176 -0.08745845407247543 0.0 -3.1037726402282715 -4.038886070251465 -0.08830002695322037 0.0 -3.184295177459717 -4.03992223739624 -0.08917154371738434 0.0 -3.266435146331787 -4.04097843170166 -0.09007416665554047 0.0 -3.350268602371216 -4.042057514190674 -0.09100916236639023 0.0 -3.435873031616211 -4.043158054351807 -0.09197778254747391 0.0 -3.5233330726623535 -4.044283390045166 -0.09298144280910492 0.0 -3.612736225128174 -4.045433044433594 -0.09402161091566086 0.0 -3.704176425933838 -4.046609401702881 -0.09509983658790588 0.0 -3.797752857208252 -4.047813892364502 -0.0962177962064743 0.0 -3.8935701847076416 -4.049046993255615 -0.0973772257566452 0.0 -3.991739273071289 -4.050309181213379 -0.09857999533414841 0.0 -4.092379570007324 -4.051604270935059 -0.09982813149690628 0.0 -4.195616722106934 -4.052932262420654 -0.10112373530864716 0.0 -4.3015851974487305 -4.054295539855957 -0.10246909409761429 0.0 -4.410427570343018 -4.055695533752441 -0.10386663675308228 0.0 -4.522296905517578 -4.057134628295898 -0.10531894117593765 0.0 -4.637357711791992 -4.058615207672119 -0.10682882368564606 0.0 -4.755782604217529 -4.06013822555542 -0.10839921236038208 0.0 -4.877760410308838 -4.061707496643066 -0.11003334075212479 0.0 -5.003490924835205 -4.063324928283691 -0.11173461377620697 0.0 -5.1331915855407715 -4.0649943351745605 -0.11350676417350769 0.0 -5.267091751098633 -4.06671667098999 -0.11535370349884033 0.0 -5.40544319152832 -4.068495750427246 -0.11727975308895111 0.0 -5.548515796661377 -4.070336818695068 -0.11928955465555191 0.0 -5.696599960327148 -4.072242259979248 -0.12138808518648148 0.0 -5.850010871887207 -4.074215412139893 -0.12358076125383377 0.0 -6.009091377258301 -4.076262474060059 -0.12587349116802216 0.0 -6.1742095947265625 -4.078385829925537 -0.12827259302139282 0.0 -6.345772743225098 -4.080593109130859 -0.13078510761260986 0.0 -6.52421760559082 -4.082888603210449 -0.13341856002807617 0.0 -6.710025310516357 -4.08527946472168 -0.13618122041225433 0.0 -6.903720378875732 -4.087770938873291 -0.1390821784734726 0.0 -7.105878829956055 -4.090372085571289 -0.14213134348392487 0.0 -7.317131042480469 -4.0930891036987305 -0.14533963799476624 0.0 -7.538176536560059 -4.095932960510254 -0.14871911704540253 0.0 -7.769781589508057 -4.098912239074707 -0.15228302776813507 0.0 -8.012797355651855 -4.102038383483887 -0.1560460925102234 0.0 -8.268166542053223 -4.105323791503906 -0.16002462804317474 0.0 -8.5225191116333 -4.101840496063232 -0.16395936906337738 0.0 -8.505647659301758 -3.9657256603240967 -0.162684828042984 0.0 -8.489034652709961 -3.831690788269043 -0.16145415604114532 0.0 -8.472668647766113 -3.6996490955352783 -0.1602659970521927 0.0 -8.456537246704102 -3.5695159435272217 -0.15911900997161865 0.0 -8.443655967712402 -3.4424455165863037 -0.15806861221790314 0.0 -8.445197105407715 -3.322631597518921 -0.15732111036777496 0.0 -8.446723937988281 -3.203927755355835 -0.15660418570041656 0.0 -8.448238372802734 -3.0862834453582764 -0.1559172421693802 0.0 -8.449738502502441 -2.969648838043213 -0.1552596092224121 0.0 -8.451226234436035 -2.8539767265319824 -0.15463076531887054 0.0 -8.452702522277832 -2.7392208576202393 -0.15403017401695251 0.0 -8.454168319702148 -2.625335454940796 -0.15345731377601624 0.0 -8.455622673034668 -2.512277126312256 -0.1529117077589035 0.0 -8.457066535949707 -2.400002956390381 -0.1523928940296173 0.0 -8.458500862121582 -2.288470983505249 -0.15190045535564423 0.0 -8.45992660522461 -2.1776411533355713 -0.15143398940563202 0.0 -8.461344718933105 -2.0674736499786377 -0.15099312365055084 0.0 -8.462753295898438 -1.9579288959503174 -0.15057748556137085 0.0 -8.5535888671875 -1.7586582899093628 -0.15137869119644165 0.0 -8.554991722106934 -1.6496353149414062 -0.15103331208229065 0.0 -3.487548828125 -0.36564674973487854 -0.060788270086050034 0.0 -3.488105058670044 -0.3224199414253235 -0.06072431057691574 0.0 -3.1899986267089844 -0.25536873936653137 -0.05547575652599335 0.0 -3.1490769386291504 -0.21318016946315765 -0.05471440777182579 0.0 -3.1092581748962402 -0.1721278429031372 -0.05398173630237579 0.0 -3.070486068725586 -0.1321544647216797 -0.053276363760232925 0.0 -3.032707929611206 -0.09320646524429321 -0.05259702727198601 0.0 -2.9958760738372803 -0.055233560502529144 -0.05194254219532013 0.0 -2.9836459159851074 -0.018334180116653442 -0.051722683012485504 0.0 -2.9844844341278076 0.018339332193136215 -0.0517372228205204 0.0 -2.985323905944824 0.05503901466727257 -0.051759589463472366 0.0 -2.9861643314361572 0.09177599847316742 -0.05178980529308319 0.0 -2.9870049953460693 0.12856143712997437 -0.05182787775993347 0.0 -2.9878480434417725 0.16540659964084625 -0.05187385901808739 0.0 -2.98869252204895 0.20232278108596802 -0.05192777141928673 0.0 -2.9895384311676025 0.23932133615016937 -0.05198964849114418 0.0 -2.990386724472046 0.27641379833221436 -0.05205954983830452 0.0 -2.9912376403808594 0.3136117458343506 -0.05213752016425133 0.0 -2.992091417312622 0.3509269952774048 -0.05222363770008087 0.0 -2.992947578430176 0.3883712887763977 -0.05231793597340584 0.0 -2.993806838989258 0.42595675587654114 -0.05242051184177399 0.0 -2.9946703910827637 0.4636957049369812 -0.05253145471215248 0.0 -2.995537042617798 0.5016003251075745 -0.0526508167386055 0.0 -2.996407985687256 0.53968346118927 -0.05277872458100319 0.0 -2.997283697128296 0.5779578685760498 -0.052915267646312714 0.0 -2.9981637001037598 0.6164366006851196 -0.05306054651737213 0.0 -2.9990487098693848 0.6551331281661987 -0.05321468785405159 0.0 -2.99993896484375 0.6940609812736511 -0.05337781459093094 0.0 -3.0008349418640137 0.733234167098999 -0.053550053387880325 0.0 -3.001736879348755 0.7726669907569885 -0.05373154953122139 0.0 -3.0026450157165527 0.8123739957809448 -0.05392245575785637 0.0 -3.0035598278045654 0.8523702621459961 -0.0541229248046875 0.0 -3.004481077194214 0.8926709890365601 -0.05433311685919762 0.0 -3.0054101943969727 0.9332923293113708 -0.054553233087062836 0.0 -3.006347179412842 0.974250316619873 -0.05478344485163689 0.0 -3.007291793823242 1.015561580657959 -0.05502394959330559 0.0 -3.0082454681396484 1.057243824005127 -0.05527497082948685 0.0 -3.009207010269165 1.0993139743804932 -0.055536698549985886 0.0 -3.010179281234741 1.1417914628982544 -0.05580941215157509 0.0 -3.011159896850586 1.1846941709518433 -0.056093305349349976 0.0 -3.0121517181396484 1.228042483329773 -0.05638867989182472 0.0 -3.013153553009033 1.2718561887741089 -0.05669578164815903 0.0 -3.0395803451538086 1.3272535800933838 -0.05749562010169029 0.0 -3.0901412963867188 1.3947954177856445 -0.05877183750271797 0.0 -3.143005132675171 1.4654141664505005 -0.0601152628660202 0.0 -3.1983518600463867 1.5393487215042114 -0.06153107061982155 0.0 -6.466650009155273 3.210831880569458 -0.12515752017498016 0.0 -6.388558864593506 3.2705328464508057 -0.12441468983888626 0.0 -6.311376571655273 3.3295376300811768 -0.12369916588068008 0.0 -6.2350664138793945 3.3878769874572754 -0.12301032245159149 0.0 -6.139826774597168 3.434523344039917 -0.12195492535829544 0.0 -6.044660568237305 3.4795007705688477 -0.12090492993593216 0.0 -5.951106071472168 3.5237174034118652 -0.11989083141088486 0.0 -5.806712627410889 3.6338706016540527 -0.11874576658010483 0.0 -5.654122829437256 3.635833978652954 -0.11653034389019012 0.0 -5.507099628448486 3.6377251148223877 -0.11441302299499512 0.0 -5.365303039550781 3.6395492553710938 -0.11238794773817062 0.0 -5.228418350219727 3.641309976577759 -0.11044969409704208 0.0 -5.096156597137451 3.643012046813965 -0.10859331488609314 0.0 -4.968246936798096 3.6446571350097656 -0.10681413859128952 0.0 -4.844443321228027 3.6462502479553223 -0.10510796308517456 0.0 -4.724514484405518 3.6477928161621094 -0.1034708023071289 0.0 -4.608246803283691 3.6492884159088135 -0.10189902037382126 0.0 -4.4954423904418945 3.650739908218384 -0.10038921982049942 0.0 -4.385915279388428 3.652148723602295 -0.0989382192492485 0.0 -4.279494285583496 3.6535184383392334 -0.09754310548305511 0.0 -4.130281448364258 3.70544171333313 -0.09618936479091644 0.0 -4.030928134918213 3.7067196369171143 -0.09492933750152588 0.0 -3.9341301918029785 3.7079648971557617 -0.09371586889028549 0.0 -3.839761734008789 3.709179162979126 -0.09254683554172516 0.0 -3.74770450592041 3.7103633880615234 -0.0914202407002449 0.0 -3.657848358154297 3.711519241333008 -0.09033422917127609 0.0 -3.5700886249542236 3.7126479148864746 -0.08928702771663666 0.0 -3.484328269958496 3.713751792907715 -0.08827703446149826 0.0 -3.4266011714935303 3.7433741092681885 -0.0879734605550766 0.0 -3.387428045272827 3.793140172958374 -0.08815795928239822 0.0 -3.348083972930908 3.8431224822998047 -0.08835659176111221 0.0 -3.308556079864502 3.893338203430176 -0.0885695219039917 0.0 -3.268831968307495 3.943804979324341 -0.0887969583272934 0.0 -3.2288966178894043 3.9945387840270996 -0.08903902024030685 0.0 -3.216688394546509 5.166191101074219 -0.10549727082252502 0.0 -4.60235071182251 7.813288688659668 -0.15719486773014069 0.0 -4.474873065948486 7.81492805480957 -0.15610957145690918 0.0 -4.349124908447266 7.816545486450195 -0.15506243705749512 0.0 -4.225035190582275 7.818142890930176 -0.15405237674713135 0.0 -4.102531909942627 7.819718360900879 -0.1530783474445343 0.0 -3.9815502166748047 7.821274280548096 -0.15213938057422638 0.0 -3.862025499343872 7.822812080383301 -0.15123456716537476 0.0 -3.743896484375 7.824331283569336 -0.1503630429506302 0.0 -3.6271040439605713 7.82583475112915 -0.14952397346496582 0.0 -3.511590003967285 7.827320098876953 -0.1487165093421936 0.0 -3.397299289703369 7.828789710998535 -0.14793996512889862 0.0 -3.2946290969848633 7.855158805847168 -0.14766192436218262 0.0 -3.1958980560302734 7.8902459144592285 -0.14757199585437775 0.0 -0.24398423731327057 0.7587725520133972 -0.01381665002554655 0.0 -0.22803913056850433 0.7402819991111755 -0.013427902944386005 0.0 -0.21296457946300507 0.7228010892868042 -0.013062355108559132 0.0 -0.19868683815002441 0.7062439918518066 -0.012718047015368938 0.0 -0.18514062464237213 0.6905356049537659 -0.012393259443342686 0.0 -0.17226694524288177 0.6756065487861633 -0.012086411006748676 0.0 -0.16001370549201965 0.6613974571228027 -0.011796141974627972 0.0 -0.14833343029022217 0.6478525400161743 -0.011521181091666222 0.0 -0.13718362152576447 0.6349228620529175 -0.011260409839451313 0.0 -0.1265258491039276 0.6225638389587402 -0.01101281214505434 0.0 -0.11632511019706726 0.6107345819473267 -0.010777454823255539 0.0 -0.10654985159635544 0.5993989109992981 -0.010553511790931225 0.0 -0.09717115014791489 0.5885229706764221 -0.010340213775634766 0.0 -0.08854395896196365 0.5805762410163879 -0.0101807015016675 0.0 -0.08126932382583618 0.5806698203086853 -0.01016406062990427 0.0 -0.07401733100414276 0.580763041973114 -0.010149002075195312 0.0 -0.06678570806980133 0.5808560252189636 -0.010135517455637455 0.0 -0.059572212398052216 0.5809490084648132 -0.010123600251972675 0.0 -0.052374549210071564 0.5810415744781494 -0.010113232769072056 0.0 -0.045190535485744476 0.5811339616775513 -0.010104411281645298 0.0 -0.03801795467734337 0.581226110458374 -0.010097125545144081 0.0 -0.030854644253849983 0.5813184976577759 -0.010091381147503853 0.0 -0.023698389530181885 0.5814104676246643 -0.010087160393595695 0.0 -0.01654704101383686 0.5815024375915527 -0.010084466077387333 0.0 -0.00939843151718378 0.5815944075584412 -0.010083296336233616 0.0 -0.002250400837510824 0.5816863179206848 -0.01008364837616682 0.0 --0.00489920936524868 0.5817782878875732 -0.01008552499115467 0.0 --0.012052561156451702 0.5818703174591064 -0.010088926181197166 0.0 --0.019211821258068085 0.5819624066352844 -0.010093854740262032 0.0 --0.026379168033599854 0.5820547342300415 -0.010100315324962139 0.0 --0.03355676680803299 0.582146942615509 -0.010108308866620064 0.0 --0.04074683040380478 0.5822393894195557 -0.010117846541106701 0.0 --0.047951579093933105 0.5823322534561157 -0.010128935799002647 0.0 --0.055173203349113464 0.5824249982833862 -0.010141578502953053 0.0 --0.06241400167346001 0.5825183391571045 -0.010155793279409409 0.0 --0.06967619806528091 0.5826116800308228 -0.010171581991016865 0.0 --0.07696210592985153 0.5827053189277649 -0.010188961401581764 0.0 --0.08427409827709198 0.58279949426651 -0.01020794827491045 0.0 --0.09161447733640671 0.5828939080238342 -0.010228550992906094 0.0 --0.09898563474416733 0.5829885601997375 -0.010250785388052464 0.0 --0.1063900887966156 0.5830839276313782 -0.010274677537381649 0.0 --0.11383023858070374 0.5831796526908875 -0.010300238616764545 0.0 --0.12130863964557648 0.5832759141921997 -0.010327491909265518 0.0 --0.12882782518863678 0.5833725929260254 -0.010356455110013485 0.0 --0.13639050722122192 0.5834699869155884 -0.010387158021330833 0.0 --0.14399929344654083 0.5835678577423096 -0.010419621132314205 0.0 --0.1516568809747696 0.583666205406189 -0.010453866794705391 0.0 --0.1593661904335022 0.5837653279304504 -0.0104899313300848 0.0 --0.16713008284568787 0.5838652849197388 -0.010527842678129673 0.0 --0.1749514788389206 0.5839659571647644 -0.010567630641162395 0.0 --0.18283338844776154 0.5840674042701721 -0.01060932781547308 0.0 --0.190778911113739 0.5841694474220276 -0.010652968659996986 0.0 --0.19879136979579926 0.5842726230621338 -0.010698596946895123 0.0 --0.20687389373779297 0.5843765139579773 -0.01074624340981245 0.0 --0.2150300294160843 0.5844814777374268 -0.01079595647752285 0.0 --0.22326327860355377 0.5845875144004822 -0.010847779922187328 0.0 --0.231577068567276 0.5846942663192749 -0.01090175099670887 0.0 --0.23997539281845093 0.5848023891448975 -0.010957930237054825 0.0 --0.2484620362520218 0.5849117040634155 -0.011016366071999073 0.0 --0.2570408582687378 0.5850219130516052 -0.011077105067670345 0.0 --0.26571616530418396 0.5851334929466248 -0.011140210554003716 0.0 --0.2744922935962677 0.5852465033531189 -0.011205743998289108 0.0 --0.28337353467941284 0.5853606462478638 -0.01127376314252615 0.0 --0.2923647463321686 0.5854764580726624 -0.01134434062987566 0.0 --0.3014705181121826 0.585593581199646 -0.011417538858950138 0.0 --0.310696005821228 0.5857122540473938 -0.011493436992168427 0.0 --0.32004639506340027 0.5858325958251953 -0.011572110466659069 0.0 --0.3295270502567291 0.585954487323761 -0.011653638444840908 0.0 --0.33914363384246826 0.5860780477523804 -0.011738106608390808 0.0 --0.34890225529670715 0.5862035751342773 -0.01182560995221138 0.0 --0.3588089942932129 0.5863310694694519 -0.011916243471205235 0.0 --0.36887025833129883 0.586460530757904 -0.012010104022920132 0.0 --0.3790927827358246 0.5865919589996338 -0.012107294984161854 0.0 --0.38948383927345276 0.5867257714271545 -0.012207936495542526 0.0 --0.40005049109458923 0.5868616104125977 -0.01231213379651308 0.0 --0.4108008146286011 0.5869998335838318 -0.012420019134879112 0.0 --0.4217430055141449 0.5871407985687256 -0.012531726621091366 0.0 --0.4328853487968445 0.5872840881347656 -0.012647382915019989 0.0 --0.44423708319664 0.5874301791191101 -0.012767144478857517 0.0 --0.4558074176311493 0.5875788331031799 -0.012891153804957867 0.0 --0.4676068127155304 0.5877307653427124 -0.013019589707255363 0.0 --0.4796452820301056 0.5878854990005493 -0.013152611441910267 0.0 --0.4919344186782837 0.5880436897277832 -0.013290412724018097 0.0 --0.5044854879379272 0.5882051587104797 -0.013433178886771202 0.0 --0.5173112154006958 0.588370144367218 -0.013581120409071445 0.0 --0.5304244756698608 0.5885387659072876 -0.013734452426433563 0.0 --0.5438394546508789 0.5887114405632019 -0.013893412426114082 0.0 --0.5575703978538513 0.5888879299163818 -0.014058236964046955 0.0 --0.5716334581375122 0.5890689492225647 -0.014229198917746544 0.0 --0.5860450863838196 0.5892544984817505 -0.014406576752662659 0.0 --0.6008224487304688 0.5894443988800049 -0.014590654522180557 0.0 --0.6159849166870117 0.5896395444869995 -0.014781764708459377 0.0 --0.6315520405769348 0.5898396968841553 -0.014980236999690533 0.0 --0.647545337677002 0.5900453329086304 -0.015186435543000698 0.0 --0.6639878749847412 0.5902570486068726 -0.015400756150484085 0.0 --0.6809035539627075 0.5904746651649475 -0.015623601153492928 0.0 --0.6983185410499573 0.5906986594200134 -0.015855418518185616 0.0 --0.716261088848114 0.5909295678138733 -0.0160966906696558 0.0 --0.7347607016563416 0.5911675095558167 -0.016347920522093773 0.0 --0.7589804530143738 0.5954380035400391 -0.016722707077860832 0.0 --0.7862481474876404 0.6013686060905457 -0.0171593576669693 0.0 --0.8149828910827637 0.607618510723114 -0.017622165381908417 0.0 --0.8453149199485779 0.6142155528068542 -0.018113432452082634 0.0 --0.8773913383483887 0.6211919188499451 -0.018635762855410576 0.0 --0.9113785624504089 0.6285841464996338 -0.019192112609744072 0.0 --0.9474625587463379 0.6364321708679199 -0.019785771146416664 0.0 --0.9858567118644714 0.6447829008102417 -0.02042052336037159 0.0 --1.0268021821975708 0.653688371181488 -0.021100640296936035 0.0 --1.070575475692749 0.6632087826728821 -0.021831024438142776 0.0 --1.1174955368041992 0.6734137535095215 -0.022617332637310028 0.0 --1.1893928050994873 0.6969600319862366 -0.023897312581539154 0.0 --1.3184010982513428 0.7509446144104004 -0.026301929727196693 0.0 --3.863607168197632 2.1382088661193848 -0.07654841244220734 0.0 --3.864394187927246 2.0770227909088135 -0.07605250179767609 0.0 --3.865171432495117 2.016615390777588 -0.07557431608438492 0.0 --3.865938901901245 1.956954002380371 -0.07511338591575623 0.0 --3.866697072982788 1.8980069160461426 -0.0746692419052124 0.0 --3.8674466609954834 1.839744210243225 -0.07424147427082062 0.0 --3.86818790435791 1.7821365594863892 -0.07382967323064804 0.0 --3.8689208030700684 1.7251558303833008 -0.07343342900276184 0.0 --3.8696463108062744 1.668775200843811 -0.07305240631103516 0.0 --3.870363712310791 1.612967848777771 -0.07268621772527695 0.0 --3.871074914932251 1.5577092170715332 -0.07233457267284393 0.0 --3.871779203414917 1.502974510192871 -0.07199712842702866 0.0 --3.872476577758789 1.448739767074585 -0.07167358696460724 0.0 --3.873168468475342 1.3949823379516602 -0.07136368751525879 0.0 --3.873853921890259 1.341679573059082 -0.07106711715459824 0.0 --3.8745341300964355 1.2888102531433105 -0.07078366726636887 0.0 --3.875208854675293 1.2363529205322266 -0.07051306962966919 0.0 --3.8758790493011475 1.1842875480651855 -0.07025511562824249 0.0 --3.8765437602996826 1.1325937509536743 -0.07000955939292908 0.0 --3.877203941345215 1.0812523365020752 -0.06977622210979462 0.0 --3.8778605461120605 1.0302443504333496 -0.06955491006374359 0.0 --3.878512382507324 0.9795513153076172 -0.06934542953968048 0.0 --3.8791604042053223 0.9291550517082214 -0.06914762407541275 0.0 --3.87980580329895 0.8790380954742432 -0.06896133720874786 0.0 --3.8804469108581543 0.8291828036308289 -0.06878640502691269 0.0 --3.8810853958129883 0.7795724272727966 -0.06862270087003708 0.0 --3.881720781326294 0.730190098285675 -0.06847009062767029 0.0 --3.8823530673980713 0.6810195446014404 -0.06832844018936157 0.0 --3.8829829692840576 0.6320446133613586 -0.06819766759872437 0.0 --3.883610963821411 0.5832495093345642 -0.06807765364646912 0.0 --3.8842363357543945 0.5346183776855469 -0.06796830147504807 0.0 --3.8848602771759033 0.4861360192298889 -0.06786955147981644 0.0 --3.8854825496673584 0.4377870559692383 -0.06778129935264587 0.0 --3.8861021995544434 0.38955625891685486 -0.067703478038311 0.0 --3.886721611022949 0.3414289355278015 -0.06763605028390884 0.0 --3.8873391151428223 0.29339006543159485 -0.06757894903421402 0.0 --3.8879568576812744 0.24542509019374847 -0.06753215193748474 0.0 --3.888573169708252 0.1975192278623581 -0.06749559193849564 0.0 --3.889188766479492 0.1496579796075821 -0.06746925413608551 0.0 --3.889803647994995 0.10182683914899826 -0.06745311617851257 0.0 --3.8904192447662354 0.05401136726140976 -0.06744718551635742 0.0 --3.8910343647003174 0.006197074893862009 -0.06745143234729767 0.0 --3.8911962509155273 -0.0061973328702151775 0.06745424121618271 0.0 --3.8918113708496094 -0.05403069406747818 0.06747132539749146 0.0 --3.8924272060394287 -0.1018955186009407 0.06749860942363739 0.0 --3.8930435180664062 -0.14980632066726685 0.0675361305475235 0.0 --3.893660545349121 -0.1977776437997818 0.06758389621973038 0.0 --3.8942785263061523 -0.24582414329051971 0.06764195114374161 0.0 --3.894897937774658 -0.2939605712890625 0.06771035492420197 0.0 --3.8955185413360596 -0.34220170974731445 0.06778913736343384 0.0 --3.8961410522460938 -0.39056259393692017 0.0678783729672432 0.0 --3.8967645168304443 -0.43905821442604065 0.06797811388969421 0.0 --3.897390365600586 -0.48770397901535034 0.06808845698833466 0.0 --3.8980183601379395 -0.5365152955055237 0.06820946931838989 0.0 --3.898648500442505 -0.5855078101158142 0.06834125518798828 0.0 --3.8992815017700195 -0.6346975564956665 0.06848391890525818 0.0 --3.8999176025390625 -0.6841005682945251 0.06863757222890854 0.0 --3.9005556106567383 -0.7337331771850586 0.06880231946706772 0.0 --3.9011969566345215 -0.7836121320724487 0.06897830218076706 0.0 --3.9018423557281494 -0.8337545990943909 0.0691656693816185 0.0 --3.9024908542633057 -0.8841778039932251 0.06936455518007278 0.0 --3.9031434059143066 -0.9348995089530945 0.06957513093948364 0.0 --3.9038000106811523 -0.9859378933906555 0.0697975605726242 0.0 --3.904460906982422 -1.0373114347457886 0.0700320303440094 0.0 --3.905125856399536 -1.0890389680862427 0.07027871906757355 0.0 --3.905796527862549 -1.141140341758728 0.07053785771131516 0.0 --3.9064719676971436 -1.19363534450531 0.07080965489149094 0.0 --3.9071524143218994 -1.2465442419052124 0.07109431177377701 0.0 --3.907839059829712 -1.2998887300491333 0.07139211148023605 0.0 --3.908531427383423 -1.3536899089813232 0.07170329242944717 0.0 --3.909229278564453 -1.4079701900482178 0.07202810794115067 0.0 --3.909933567047119 -1.4627528190612793 0.0723668560385704 0.0 --3.9106452465057373 -1.5180617570877075 0.07271985709667206 0.0 --3.9113640785217285 -1.57392156124115 0.0730874091386795 0.0 --3.912090301513672 -1.6303573846817017 0.0734698548913002 0.0 --3.9128239154815674 -1.6873953342437744 0.07386752218008041 0.0 --3.9135656356811523 -1.745063066482544 0.07428080588579178 0.0 --3.914315938949585 -1.8033884763717651 0.07471008598804474 0.0 --3.9150755405426025 -1.8624011278152466 0.07515577971935272 0.0 --3.915843963623047 -1.922131061553955 0.07561831176280975 0.0 --3.9166219234466553 -1.9826098680496216 0.07609812915325165 0.0 --3.917409896850586 -2.043870449066162 0.0765957161784172 0.0 --3.918208360671997 -2.1059467792510986 0.07711157947778702 0.0 --3.919018030166626 -2.168874740600586 0.07764625549316406 0.0 --3.9198389053344727 -2.2326908111572266 0.07820027321577072 0.0 --3.9206721782684326 -2.2974343299865723 0.07877425104379654 0.0 --3.9215173721313477 -2.363144874572754 0.07936878502368927 0.0 --3.9223756790161133 -2.4298651218414307 0.07998453825712204 0.0 --3.9232475757598877 -2.4976391792297363 0.08062218874692917 0.0 --3.92413330078125 -2.5665128231048584 0.08128245919942856 0.0 --3.925034284591675 -2.6365346908569336 0.08196611702442169 0.0 --3.925950527191162 -2.7077553272247314 0.08267397433519363 0.0 --3.9268829822540283 -2.7802278995513916 0.08340686559677124 0.0 --3.9278318881988525 -2.8540079593658447 0.08416568487882614 0.0 --3.9287991523742676 -2.929154634475708 0.08495140820741653 0.0 --3.9297842979431152 -3.0057289600372314 0.08576500415802002 0.0 --3.930788278579712 -3.0837957859039307 0.08660753071308136 0.0 --3.9318125247955322 -3.163424015045166 0.08748012036085129 0.0 --3.9328579902648926 -3.244685649871826 0.08838396519422531 0.0 --3.933925151824951 -3.3276565074920654 0.08932030200958252 0.0 --3.9350154399871826 -3.412416934967041 0.09029047936201096 0.0 --3.9361298084259033 -3.4990525245666504 0.09129590541124344 0.0 --3.937270164489746 -3.587653160095215 0.09233809262514114 0.0 --3.938436269760132 -3.6783130168914795 0.09341860562562943 0.0 --3.9396300315856934 -3.7711341381073 0.09453915059566498 0.0 --3.9408531188964844 -3.8662235736846924 0.09570153057575226 0.0 --3.926931858062744 -3.948436975479126 0.0965346246957779 0.0 --3.8327465057373047 -3.9496493339538574 0.09540538489818573 0.0 --3.7407238483428955 -3.9508321285247803 0.09431630373001099 0.0 --3.650766372680664 -3.9519896507263184 0.09326576441526413 0.0 --3.562777519226074 -3.9531219005584717 0.09225215017795563 0.0 --3.476667881011963 -3.9542300701141357 0.0912739634513855 0.0 --3.3923518657684326 -3.9553141593933105 0.09032978862524033 0.0 --3.3097503185272217 -3.9563770294189453 0.08941832184791565 0.0 --3.228787422180176 -3.957418918609619 0.08853831887245178 0.0 --3.149390459060669 -3.958440065383911 0.08768856525421143 0.0 --3.07149076461792 -3.959441661834717 0.08686795830726624 0.0 --2.9950249195098877 -3.960425853729248 0.08607546985149384 0.0 --2.9199302196502686 -3.9613921642303467 0.08531006425619125 0.0 --2.8461482524871826 -3.96234130859375 0.08457081764936447 0.0 --2.773622989654541 -3.9632742404937744 0.08385682851076126 0.0 --2.702301502227783 -3.9641919136047363 0.08316724747419357 0.0 --2.6321327686309814 -3.9650943279266357 0.08250126242637634 0.0 --2.5630686283111572 -3.9659829139709473 0.08185814321041107 0.0 --2.4950625896453857 -3.966857433319092 0.08123712986707687 0.0 --2.4280707836151123 -3.967719554901123 0.08063756674528122 0.0 --2.3620505332946777 -3.9685685634613037 0.08005878329277039 0.0 --2.296961545944214 -3.9694058895111084 0.07950017601251602 0.0 --2.2327651977539062 -3.9702320098876953 0.07896115630865097 0.0 --2.1694235801696777 -3.9710464477539062 0.07844115793704987 0.0 --2.1069021224975586 -3.9718515872955322 0.07793967425823212 0.0 --2.0451648235321045 -3.9726450443267822 0.07745616137981415 0.0 --1.984180212020874 -3.9734299182891846 0.07699018716812134 0.0 --1.923915982246399 -3.974205732345581 0.07654127478599548 0.0 --1.8643412590026855 -3.9749717712402344 0.07610899209976196 0.0 --1.8054267168045044 -3.9757297039031982 0.07569292187690735 0.0 --1.7471442222595215 -3.9764792919158936 0.0752926915884018 0.0 --1.6894662380218506 -3.9772214889526367 0.07490793615579605 0.0 --1.6323659420013428 -3.9779558181762695 0.07453827559947968 0.0 --1.5758181810379028 -3.9786834716796875 0.07418341189622879 0.0 --1.5197975635528564 -3.9794037342071533 0.07384299486875534 0.0 --1.4642807245254517 -3.9801180362701416 0.07351675629615784 0.0 --1.4092438220977783 -3.9808261394500732 0.0732043907046318 0.0 --1.3546645641326904 -3.9815282821655273 0.07290562987327576 0.0 --1.3005207777023315 -3.982224941253662 0.07262022793292999 0.0 --1.246791124343872 -3.9829158782958984 0.07234792411327362 0.0 --1.1934549808502197 -3.983602285385132 0.07208850979804993 0.0 --1.1404918432235718 -3.984283447265625 0.0718417540192604 0.0 --1.0878822803497314 -3.9849603176116943 0.07160747051239014 0.0 --1.0356067419052124 -3.98563289642334 0.0713854506611824 0.0 --0.9836465716362 -3.9863011837005615 0.07117552310228348 0.0 --0.9319834113121033 -3.986966133117676 0.07097751647233963 0.0 --0.8805990815162659 -3.9876270294189453 0.07079125940799713 0.0 --0.8294760584831238 -3.9882848262786865 0.07061662524938583 0.0 --0.778596818447113 -3.988938808441162 0.0704534500837326 0.0 --0.7279447317123413 -3.989590644836426 0.07030164450407028 0.0 --0.6775029301643372 -3.9902400970458984 0.07016105949878693 0.0 --0.6272547245025635 -3.9908862113952637 0.07003158330917358 0.0 --0.5771841406822205 -3.991530418395996 0.06991312652826309 0.0 --0.5272750854492188 -3.9921722412109375 0.06980559229850769 0.0 --0.42787882685661316 -3.993450880050659 0.06962297856807709 0.0 -2.04915452003479 -4.0253167152404785 0.07830043137073517 0.0 -8.54526138305664 -1.8666865825653076 0.15162590146064758 0.0 -8.493124961853027 -1.5296978950500488 0.1495978832244873 0.0 -8.567780494689941 -1.4346681833267212 0.1505909115076065 0.0 -8.654045104980469 -1.3399951457977295 0.15180622041225433 0.0 -9.119654655456543 -1.297538161277771 0.15968197584152222 0.0 -9.874942779541016 -1.2813937664031982 0.17261801660060883 0.0 -11.105927467346191 -1.302557110786438 0.19384165108203888 0.0 -3.4875454902648926 -0.3656463921070099 0.06078821048140526 0.0 -3.4881017208099365 -0.3224196434020996 0.060724250972270966 0.0 -3.189971923828125 -0.25536662340164185 0.05547529086470604 0.0 -3.1490511894226074 -0.21317842602729797 0.05471396446228027 0.0 -3.1092333793640137 -0.17212645709514618 0.05398130416870117 0.0 -3.0704619884490967 -0.1321534365415573 0.0532759465277195 0.0 -3.032684326171875 -0.09320573508739471 0.05259661749005318 0.0 -2.9958531856536865 -0.05523313954472542 0.05194214731454849 0.0 -2.983644485473633 -0.018334170803427696 0.05172266066074371 0.0 -2.984483242034912 0.018339326605200768 0.05173720046877861 0.0 -2.985323190689087 0.05503900349140167 0.05175957828760147 0.0 -2.986163377761841 0.09177596867084503 0.051789790391922 0.0 -2.9870047569274902 0.12856142222881317 0.05182787403464317 0.0 -2.9878478050231934 0.16540658473968506 0.05187385529279709 0.0 -2.988692045211792 0.20232273638248444 0.05192776396870613 0.0 -2.9895389080047607 0.23932136595249176 0.05198965594172478 0.0 -2.990386962890625 0.27641379833221436 0.05205955356359482 0.0 -2.9912383556365967 0.31361183524131775 0.05213753506541252 0.0 -2.9920918941497803 0.35092705488204956 0.05222364515066147 0.0 -2.992948293685913 0.38837137818336487 0.05231795087456703 0.0 -2.9938082695007324 0.42595693469047546 0.052420537918806076 0.0 -2.99467134475708 0.46369585394859314 0.052531469613313675 0.0 -2.9955387115478516 0.5016006231307983 0.05265084654092789 0.0 -2.9964098930358887 0.5396837592124939 0.05277875438332558 0.0 -2.9972853660583496 0.5779582262039185 0.0529152974486351 0.0 -2.9981653690338135 0.6164369583129883 0.05306057631969452 0.0 -2.9990508556365967 0.6551335453987122 0.053214725106954575 0.0 -2.99994158744812 0.6940615773200989 0.05337785929441452 0.0 -3.000837802886963 0.7332348823547363 0.053550105541944504 0.0 -3.001739740371704 0.7726677656173706 0.05373160541057587 0.0 -3.002647876739502 0.8123748302459717 0.05392250791192055 0.0 -3.0035626888275146 0.852371096611023 0.05412297695875168 0.0 -3.0044848918914795 0.8926721811294556 0.05433318763971329 0.0 -3.0054144859313965 0.9332935810089111 0.054553307592868805 0.0 -3.0063509941101074 0.9742515683174133 0.05478351563215256 0.0 -3.007296323776245 1.0155631303787231 0.055024031549692154 0.0 -3.0082499980926514 1.0572453737258911 0.05527505278587341 0.0 -3.0092127323150635 1.0993160009384155 0.05553680285811424 0.0 -3.010183811187744 1.141793131828308 0.05580949783325195 0.0 -3.011164903640747 1.184696078300476 0.056093402206897736 0.0 -3.0121567249298096 1.2280445098876953 0.05638877674937248 0.0 -3.0131592750549316 1.2718586921691895 0.05669588968157768 0.0 -3.03961181640625 1.3272674083709717 0.057496216148138046 0.0 -3.0901741981506348 1.3948101997375488 0.05877246335148811 0.0 -3.1430394649505615 1.4654301404953003 0.06011591851711273 0.0 -3.1983871459960938 1.5393656492233276 0.06153174862265587 0.0 -6.466626167297363 3.210819959640503 0.12515705823898315 0.0 -6.388535976409912 3.2705211639404297 0.12441424280405045 0.0 -6.311354160308838 3.3295257091522217 0.12369872629642487 0.0 -6.235044956207275 3.3878650665283203 0.12300989776849747 0.0 -6.139796733856201 3.43450665473938 0.12195432931184769 0.0 -6.044631481170654 3.4794840812683105 0.1209043487906456 0.0 -5.951077938079834 3.523700714111328 0.11989026516675949 0.0 -5.867961406707764 3.572603702545166 0.11909137666225433 0.0 -5.806656837463379 3.633835554122925 0.1187446266412735 0.0 -5.654068946838379 3.6357994079589844 0.11652923375368118 0.0 -5.5070481300354 3.637691020965576 0.11441195011138916 0.0 -5.365254878997803 3.639516592025757 0.11238693445920944 0.0 -5.228372573852539 3.641278028488159 0.11044872552156448 0.0 -5.09611177444458 3.6429800987243652 0.10859236121177673 0.0 -4.968204975128174 3.6446263790130615 0.10681323707103729 0.0 -4.84440279006958 3.6462197303771973 0.10510708391666412 0.0 -4.724475860595703 3.6477630138397217 0.10346996039152145 0.0 -4.60821008682251 3.649259328842163 0.1018982082605362 0.0 -4.4954071044921875 3.6507110595703125 0.10038843005895615 0.0 -4.3858819007873535 3.65212082862854 0.09893746674060822 0.0 -4.27946138381958 3.6534905433654785 0.09754236787557602 0.0 -4.229487419128418 3.7016470432281494 0.09743288904428482 0.0 -4.130251884460449 3.7054152488708496 0.09618867933750153 0.0 -4.030900478363037 3.7066941261291504 0.09492868185043335 0.0 -3.934103488922119 3.707939863204956 0.09371523559093475 0.0 -3.839735507965088 3.709153890609741 0.09254620969295502 0.0 -3.7476794719696045 3.710338592529297 0.09141962975263596 0.0 -3.6578245162963867 3.7114951610565186 0.09033364057540894 0.0 -3.570066452026367 3.712625026702881 0.08928647637367249 0.0 -3.4843063354492188 3.713728427886963 0.08827648311853409 0.0 -3.426600933074951 3.7433736324310303 0.087973453104496 0.0 -3.3874285221099854 3.793140411376953 0.08815796673297882 0.0 -3.348083734512329 3.8431222438812256 0.08835658431053162 0.0 -3.3085567951202393 3.893338918685913 0.08856954425573349 0.0 -3.268832206726074 3.943805456161499 0.08879696577787399 0.0 -3.2288970947265625 3.9945390224456787 0.08903902769088745 0.0 -3.1962332725524902 4.055068016052246 0.08950585871934891 0.0 -3.197596788406372 4.160977840423584 0.0909692570567131 0.0 -3.199005603790283 4.270424842834473 0.09249549359083176 0.0 -3.2004618644714355 4.3836236000061035 0.09408825635910034 0.0 -3.2019705772399902 4.500808238983154 0.0957515686750412 0.0 -3.2035329341888428 4.622228622436523 0.09748972952365875 0.0 -3.205153465270996 4.748157978057861 0.09930742532014847 0.0 -3.2680394649505615 4.972008228302002 0.1031414046883583 0.0 -3.2698209285736084 5.1104631423950195 0.10517197102308273 0.0 -3.216674566268921 5.166168689727783 0.10549681633710861 0.0 -3.2122979164123535 5.303300857543945 0.10748282819986343 0.0 -3.1335768699645996 8.018192291259766 0.14923341572284698 0.0 -3.137575387954712 8.328914642333984 0.1542871743440628 0.0 -3.1418559551239014 8.66147518157959 0.1597202718257904 0.0 -3.1464483737945557 9.018363952636719 0.1655758023262024 0.0 -3.2516655921936035 9.701656341552734 0.17737382650375366 0.0 -0.24397896230220795 0.758756160736084 0.0138163510710001 0.0 -0.22803440690040588 0.7402666807174683 0.013427624478936195 0.0 -0.21295998990535736 0.7227855324745178 0.013062073849141598 0.0 -0.19868285953998566 0.7062298655509949 0.012717792764306068 0.0 -0.18513664603233337 0.6905207633972168 0.012392993085086346 0.0 -0.17226359248161316 0.6755934357643127 0.012086176313459873 0.0 -0.16001056134700775 0.6613844633102417 0.011795910075306892 0.0 -0.1483304500579834 0.6478395462036133 0.011520950123667717 0.0 -0.137180894613266 0.6349102258682251 0.011260186322033405 0.0 -0.12652337551116943 0.622551679611206 0.01101259607821703 0.0 -0.11632285267114639 0.6107227206230164 0.01077724527567625 0.0 -0.10654786229133606 0.5993877053260803 0.010553314350545406 0.0 -0.09716934710741043 0.5885120630264282 0.01034002099186182 0.0 -0.08854316174983978 0.5805709958076477 0.010180610232055187 0.0 -0.08126859366893768 0.5806646347045898 0.010163969360291958 0.0 -0.07401670515537262 0.5807580947875977 0.010148916393518448 0.0 -0.06678514182567596 0.580851137638092 0.010135432705283165 0.0 -0.059571683406829834 0.5809438824653625 0.010123510845005512 0.0 -0.05237410590052605 0.5810366272926331 0.010113147087395191 0.0 -0.04519015550613403 0.5811291337013245 0.010104326531291008 0.0 -0.038017638027668 0.5812212824821472 0.010097041726112366 0.0 -0.030854374170303345 0.5813133716583252 0.010091292671859264 0.0 -0.023698193952441216 0.5814056992530823 0.01008707657456398 0.0 -0.016546903178095818 0.5814976692199707 0.010084383189678192 0.0 -0.009398353286087513 0.5815896391868591 0.0100832125172019 0.0 -0.002250382676720619 0.5816816091537476 0.010083566419780254 0.0 --0.004899169318377972 0.581773579120636 0.010085443034768105 0.0 --0.012052464298903942 0.5818656086921692 0.0100888442248106 0.0 --0.019211675971746445 0.581957995891571 0.010093777440488338 0.0 --0.026378953829407692 0.5820500254631042 0.010100234299898148 0.0 --0.033556513488292694 0.5821424722671509 0.010108232498168945 0.0 --0.040746524930000305 0.5822350382804871 0.010117770172655582 0.0 --0.047951195389032364 0.5823276042938232 0.010128854773938656 0.0 --0.055172789841890335 0.5824206471443176 0.010141502134501934 0.0 --0.06241350620985031 0.582513689994812 0.010155712254345417 0.0 --0.06967567652463913 0.5826073288917542 0.010171506553888321 0.0 --0.07696153968572617 0.5827009677886963 0.01018888596445322 0.0 --0.08427347242832184 0.5827952027320862 0.010207871906459332 0.0 --0.09161379933357239 0.5828895568847656 0.010228474624454975 0.0 --0.09898494929075241 0.5829845666885376 0.010250714607536793 0.0 --0.10638931393623352 0.5830796957015991 0.01027460303157568 0.0 --0.11382941901683807 0.5831754803657532 0.010300164110958576 0.0 --0.12130776047706604 0.5832716822624207 0.010327416472136974 0.0 --0.12882694602012634 0.5833685994148254 0.010356384329497814 0.0 --0.13638953864574432 0.5834658145904541 0.010387084446847439 0.0 --0.14399826526641846 0.5835637450218201 0.010419546626508236 0.0 --0.1516558825969696 0.5836623311042786 0.01045379787683487 0.0 --0.15936513245105743 0.5837615132331848 0.010489861480891705 0.0 --0.16712898015975952 0.5838614702224731 0.010527773760259151 0.0 --0.17495033144950867 0.5839622020721436 0.010567561723291874 0.0 --0.18283219635486603 0.5840635895729065 0.010609258897602558 0.0 --0.1907777488231659 0.5841659307479858 0.010652904398739338 0.0 --0.19879010319709778 0.5842689275741577 0.010698528960347176 0.0 --0.20687267184257507 0.5843729972839355 0.010746179148554802 0.0 --0.215028777718544 0.5844780206680298 0.010795893147587776 0.0 --0.22326189279556274 0.5845838785171509 0.010847712866961956 0.0 --0.23157574236392975 0.5846909284591675 0.01090168859809637 0.0 --0.2399740219116211 0.58479905128479 0.010957867838442326 0.0 --0.24846051633358002 0.584908127784729 0.011016298085451126 0.0 --0.2570394277572632 0.5850186347961426 0.011077042669057846 0.0 --0.2657146453857422 0.5851301550865173 0.011140147224068642 0.0 --0.2744907736778259 0.5852432250976562 0.011205681599676609 0.0 --0.2833719849586487 0.5853574275970459 0.01127370074391365 0.0 --0.29236313700675964 0.5854732394218445 0.01134427823126316 0.0 --0.3014688789844513 0.5855903625488281 0.011417476460337639 0.0 --0.3106943368911743 0.5857090950012207 0.011493375524878502 0.0 --0.32004469633102417 0.585829496383667 0.011572049930691719 0.0 --0.32952532172203064 0.5859513878822327 0.011653576977550983 0.0 --0.3391420245170593 0.5860752463340759 0.011738050729036331 0.0 --0.34890061616897583 0.5862008333206177 0.011825555004179478 0.0 --0.3588073253631592 0.5863283276557922 0.011916187591850758 0.0 --0.3688685894012451 0.5864579081535339 0.01201004907488823 0.0 --0.3790910542011261 0.5865892767906189 0.012107240036129951 0.0 --0.3894820809364319 0.5867231488227844 0.012207881547510624 0.0 --0.40004876255989075 0.5868590474128723 0.012312079779803753 0.0 --0.4107992351055145 0.5869976282119751 0.012419971637427807 0.0 --0.42174121737480164 0.587138295173645 0.012531672604382038 0.0 --0.4328835606575012 0.5872816443443298 0.012647331692278385 0.0 --0.44423526525497437 0.5874277949333191 0.012767092324793339 0.0 --0.45580577850341797 0.5875767469406128 0.01289110817015171 0.0 --0.46760499477386475 0.5877284407615662 0.013019539415836334 0.0 --0.47964367270469666 0.587883472442627 0.013152566738426685 0.0 --0.49193260073661804 0.5880415439605713 0.013290364295244217 0.0 --0.5044838786125183 0.5882031917572021 0.013433135114610195 0.0 --0.5173096060752869 0.58836829662323 0.013581077568233013 0.0 --0.5304228663444519 0.5885369777679443 0.013734410516917706 0.0 --0.54383784532547 0.5887097120285034 0.0138933714479208 0.0 --0.5575688481330872 0.5888862609863281 0.014058196917176247 0.0 --0.5716319680213928 0.5890673398971558 0.014229160733520985 0.0 --0.5860435366630554 0.5892528891563416 0.014406537637114525 0.0 --0.6008208990097046 0.5894429087638855 0.014590617269277573 0.0 --0.6159834265708923 0.5896381139755249 0.014781730249524117 0.0 --0.6315506100654602 0.5898383855819702 0.014980202540755272 0.0 --0.647544264793396 0.590044379234314 0.015186410397291183 0.0 --0.6639865040779114 0.590255856513977 0.015400724485516548 0.0 --0.6809022426605225 0.5904735326766968 0.015623570419847965 0.0 --0.6983175873756409 0.5906978249549866 0.015855396166443825 0.0 --0.7162599563598633 0.5909286141395569 0.01609666459262371 0.0 --0.7347596287727356 0.591166615486145 0.016347896307706833 0.0 --0.7589805722236633 0.5954381227493286 0.01672271080315113 0.0 --0.7862485647201538 0.6013689041137695 0.017159366980195045 0.0 --0.814983069896698 0.6076185703277588 0.017622167244553566 0.0 --0.8453153967857361 0.6142159104347229 0.01811344176530838 0.0 --0.877392590045929 0.6211928129196167 0.018635790795087814 0.0 --0.9113803505897522 0.6285853385925293 0.019192149862647057 0.0 --0.9474648833274841 0.6364337205886841 0.019785819575190544 0.0 --0.9858598709106445 0.6447849273681641 0.020420588552951813 0.0 --1.0268054008483887 0.6536904573440552 0.021100707352161407 0.0 --1.0705796480178833 0.663211464881897 0.02183111198246479 0.0 --1.1175005435943604 0.6734168529510498 0.022617435082793236 0.0 --1.189410924911499 0.6969707012176514 0.023897677659988403 0.0 --1.318427324295044 0.7509595155715942 0.026302451267838478 0.0 --3.8772013187408447 1.0812515020370483 0.06977616995573044 0.0 --3.8791584968566895 0.9291545748710632 0.06914758682250977 0.0 --3.8804447650909424 0.8291823267936707 0.0687863677740097 0.0 --3.8810834884643555 0.7795720100402832 0.0686226636171341 0.0 --3.881718873977661 0.7301898002624512 0.0684700533747673 0.0 --3.8823516368865967 0.6810192465782166 0.06832841783761978 0.0 --3.8829822540283203 0.6320444941520691 0.06819765269756317 0.0 --3.8836100101470947 0.5832493305206299 0.06807763874530792 0.0 --3.8842358589172363 0.5346183180809021 0.06796829402446747 0.0 --3.884859800338745 0.48613595962524414 0.06786954402923584 0.0 --3.8854820728302 0.4377869963645935 0.06778129190206528 0.0 --3.8861026763916016 0.38955631852149963 0.0677034854888916 0.0 --3.8867223262786865 0.3414289951324463 0.06763606518507004 0.0 --3.887340545654297 0.2933901846408844 0.06757897138595581 0.0 --3.88795804977417 0.24542516469955444 0.06753216683864594 0.0 --3.8885743618011475 0.19751928746700287 0.06749560683965683 0.0 --3.8891899585723877 0.14965802431106567 0.0674692764878273 0.0 --3.889805793762207 0.10182689875364304 0.06745315343141556 0.0 --3.8904213905334473 0.05401139706373215 0.0674472227692604 0.0 --3.89103627204895 0.00619707815349102 0.06745146960020065 0.0 --3.89119815826416 -0.006197335664182901 0.20252513885498047 0.0 --3.8918142318725586 -0.054030731320381165 0.20257645845413208 0.0 --3.892430067062378 -0.10189559310674667 0.20265839993953705 0.0 --3.8930463790893555 -0.1498064249753952 0.20277103781700134 0.0 --3.8936638832092285 -0.19777782261371613 0.20291447639465332 0.0 --3.894282579421997 -0.24582439661026 0.20308883488178253 0.0 --3.894902229309082 -0.2939608693122864 0.20329420268535614 0.0 --3.8955228328704834 -0.3422020971775055 0.20353074371814728 0.0 --3.8961448669433594 -0.3905629813671112 0.20379865169525146 0.0 --3.8967692852020264 -0.43905875086784363 0.2040981650352478 0.0 --3.897395372390747 -0.4877046048641205 0.20442944765090942 0.0 --3.898023843765259 -0.5365160703659058 0.2047928124666214 0.0 --3.8986544609069824 -0.5855087637901306 0.20518852770328522 0.0 --3.899287223815918 -0.6346985101699829 0.20561684668064117 0.0 --3.89992356300354 -0.6841016411781311 0.2060782015323639 0.0 --3.900562047958374 -0.7337343692779541 0.20657284557819366 0.0 --3.9012041091918945 -0.7836135625839233 0.2071012556552887 0.0 --3.9018492698669434 -0.8337560892105103 0.20766380429267883 0.0 --3.9024980068206787 -0.8841794729232788 0.20826095342636108 0.0 --3.903151035308838 -0.9349013566970825 0.20889319479465485 0.0 --3.9038078784942627 -0.9859399199485779 0.2095610499382019 0.0 --3.904468536376953 -1.037313461303711 0.21026501059532166 0.0 --3.905135154724121 -1.0890415906906128 0.21100576221942902 0.0 --3.9058051109313965 -1.1411428451538086 0.2117837816476822 0.0 --3.9064810276031494 -1.1936380863189697 0.21259982883930206 0.0 --3.9071617126464844 -1.2465472221374512 0.21345451474189758 0.0 --3.907848358154297 -1.299891710281372 0.21434862911701202 0.0 --3.908540725708008 -1.3536931276321411 0.21528291702270508 0.0 --3.9092392921447754 -1.4079738855361938 0.2162581980228424 0.0 --3.909944534301758 -1.4627569913864136 0.21727532148361206 0.0 --3.910655975341797 -1.5180659294128418 0.21833515167236328 0.0 --3.9113752841949463 -1.5739259719848633 0.21943871676921844 0.0 --3.9121012687683105 -1.6303619146347046 0.22058695554733276 0.0 --3.9128353595733643 -1.6874003410339355 0.2217809557914734 0.0 --3.9135777950286865 -1.7450684309005737 0.22302183508872986 0.0 --3.9143283367156982 -1.8033941984176636 0.2243107408285141 0.0 --3.915088176727295 -1.8624072074890137 0.2256489098072052 0.0 --3.9158568382263184 -1.9221373796463013 0.22703763842582703 0.0 --3.9166347980499268 -1.9826164245605469 0.22847825288772583 0.0 --3.9174232482910156 -2.043877363204956 0.229972243309021 0.0 --3.918222427368164 -2.10595440864563 0.2315211296081543 0.0 --3.9190328121185303 -2.1688826084136963 0.2331264615058899 0.0 --3.919853448867798 -2.232699155807495 0.2347898632287979 0.0 --3.920687198638916 -2.297443151473999 0.23651321232318878 0.0 --3.92153263092041 -2.363154172897339 0.23829825222492218 0.0 --3.922391653060913 -2.429875135421753 0.24014705419540405 0.0 --3.9232635498046875 -2.4976494312286377 0.2420615404844284 0.0 --3.9241504669189453 -2.566524028778076 0.24404402077198029 0.0 --3.925051212310791 -2.6365461349487305 0.2460966557264328 0.0 --3.9259684085845947 -2.7077677249908447 0.2482219934463501 0.0 --3.926900863647461 -2.780240774154663 0.2504224479198456 0.0 --3.9278507232666016 -2.8540215492248535 0.2527008056640625 0.0 --3.9288177490234375 -2.929168462753296 0.2550598382949829 0.0 --3.9298031330108643 -3.0057435035705566 0.25750261545181274 0.0 --3.930807590484619 -3.083811044692993 0.2600322663784027 0.0 --3.931832790374756 -3.163440465927124 0.2626522183418274 0.0 --3.9328789710998535 -3.2447030544281006 0.26536598801612854 0.0 --3.933946371078491 -3.327674627304077 0.2681773006916046 0.0 --3.93503737449646 -3.4124362468719482 0.27109020948410034 0.0 --3.936152219772339 -3.499072313308716 0.2741089463233948 0.0 --3.93729305267334 -3.587674140930176 0.27723807096481323 0.0 --3.938459634780884 -3.678334951400757 0.2804822623729706 0.0 --3.939654588699341 -3.7711575031280518 0.2838466763496399 0.0 --3.94087815284729 -3.86624813079834 0.28733667731285095 0.0 --3.92692232131958 -3.948427438735962 0.28983545303344727 0.0 --3.8327369689941406 -3.9496395587921143 0.2864450216293335 0.0 --3.740715980529785 -3.9508235454559326 0.2831752598285675 0.0 --3.650758743286133 -3.95198130607605 0.2800211012363434 0.0 --3.562769889831543 -3.953113317489624 0.2769778072834015 0.0 --3.47666072845459 -3.9542219638824463 0.27404093742370605 0.0 --3.392345905303955 -3.9553072452545166 0.27120622992515564 0.0 --3.3097445964813232 -3.9563701152801514 0.2684696614742279 0.0 --3.2287819385528564 -3.957412004470825 0.2658275365829468 0.0 --2.1694228649139404 -3.9710452556610107 0.2355121523141861 0.0 --2.1069014072418213 -3.9718503952026367 0.23400649428367615 0.0 --2.0451645851135254 -3.972644567489624 0.2325548231601715 0.0 --1.9841798543930054 -3.9734292030334473 0.23115578293800354 0.0 --1.9239155054092407 -3.9742047786712646 0.22980795800685883 0.0 --1.864341378211975 -3.9749722480773926 0.22851012647151947 0.0 --1.805426836013794 -3.9757297039031982 0.22726091742515564 0.0 --1.7471445798873901 -3.976480007171631 0.22605930268764496 0.0 --1.6894663572311401 -3.977221727371216 0.22490407526493073 0.0 --1.6323665380477905 -3.977957248687744 0.22379428148269653 0.0 --1.575818657875061 -3.978684663772583 0.22272880375385284 0.0 --1.5197982788085938 -3.979405641555786 0.22170677781105042 0.0 --1.464281439781189 -3.9801201820373535 0.22072727978229523 0.0 --1.4092445373535156 -3.980827808380127 0.21978941559791565 0.0 --1.3546653985977173 -3.9815306663513184 0.21889245510101318 0.0 --1.3005216121673584 -3.9822275638580322 0.21803556382656097 0.0 --1.2467920780181885 -3.9829189777374268 0.21721802651882172 0.0 --1.193455696105957 -3.983604907989502 0.2164391279220581 0.0 --1.1404929161071777 -3.9842870235443115 0.21569833159446716 0.0 --1.0878833532333374 -3.984964370727539 0.21499492228031158 0.0 --1.0356078147888184 -3.9856371879577637 0.2143283486366272 0.0 --0.9836476445198059 -3.9863057136535645 0.21369805932044983 0.0 --0.9319844245910645 -3.9869704246520996 0.21310356259346008 0.0 --0.880600094795227 -3.9876315593719482 0.21254436671733856 0.0 --0.829477071762085 -3.9882895946502686 0.21202005445957184 0.0 --0.7785979509353638 -3.9889442920684814 0.2115301787853241 0.0 --0.7279458045959473 -3.989596366882324 0.21107438206672668 0.0 --0.6775038242340088 -3.9902455806732178 0.21065229177474976 0.0 --0.6272556781768799 -3.990892171859741 0.21026356518268585 0.0 --0.5771850347518921 -3.991536855697632 0.20990793406963348 0.0 --0.5272759795188904 -3.9921791553497314 0.20958510041236877 0.0 --0.4775126874446869 -3.992819309234619 0.20929479598999023 0.0 --0.42787957191467285 -3.9934580326080322 0.20903684198856354 0.0 --0.3783612847328186 -3.994096040725708 0.20881105959415436 0.0 --0.32894229888916016 -3.994732141494751 0.2086171954870224 0.0 --0.27960753440856934 -3.9953665733337402 0.2084551304578781 0.0 --0.23034195601940155 -3.9960005283355713 0.20832476019859314 0.0 --0.181130513548851 -3.996633768081665 0.20822599530220032 0.0 --0.13195830583572388 -3.9972667694091797 0.20815876126289368 0.0 --0.0828104168176651 -3.997898817062378 0.20812295377254486 0.0 --0.03367200866341591 -3.9985315799713135 0.20811863243579865 0.0 -0.015471778810024261 -3.99916410446167 0.20814573764801025 0.0 -0.06463579088449478 -3.9997971057891846 0.20820429921150208 0.0 -0.11383489519357681 -4.000429630279541 0.2082943320274353 0.0 -0.16308404505252838 -4.001064300537109 0.20841598510742188 0.0 -0.21239817142486572 -4.0016984939575195 0.2085692435503006 0.0 -0.2617923319339752 -4.002334117889404 0.208754301071167 0.0 -0.31128180027008057 -4.002971172332764 0.208971306681633 0.0 -0.36088165640830994 -4.003609657287598 0.20922036468982697 0.0 -0.4106074571609497 -4.004249572753906 0.209501713514328 0.0 -0.4604746699333191 -4.004891395568848 0.20981553196907043 0.0 -0.5104991793632507 -4.00553560256958 0.21016211807727814 0.0 -0.5606966614723206 -4.006181240081787 0.21054165065288544 0.0 -0.611083447933197 -4.006829261779785 0.210954487323761 0.0 -0.6616759300231934 -4.007480621337891 0.21140094101428986 0.0 -0.7124907970428467 -4.008134841918945 0.21188139915466309 0.0 -0.7635446190834045 -4.008791446685791 0.21239612996578217 0.0 -0.8148550987243652 -4.009451866149902 0.21294565498828888 0.0 -0.8664395809173584 -4.010116100311279 0.21353037655353546 0.0 -0.9183157682418823 -4.0107831954956055 0.21415069699287415 0.0 -0.9705024361610413 -4.011455535888672 0.21480722725391388 0.0 -1.0230180025100708 -4.012131690979004 0.21550044417381287 0.0 -1.0758813619613647 -4.012811660766602 0.2162308543920517 0.0 -1.1291124820709229 -4.013496398925781 0.2169991433620453 0.0 -1.1827315092086792 -4.014186859130859 0.21780593693256378 0.0 -1.2367585897445679 -4.014881610870361 0.2186518758535385 0.0 -1.2912155389785767 -4.01558256149292 0.21953772008419037 0.0 -1.3461236953735352 -4.016289234161377 0.22046419978141785 0.0 -1.4015058279037476 -4.017002105712891 0.2214321345090866 0.0 -1.457384705543518 -4.017721176147461 0.22244231402873993 0.0 -1.5137845277786255 -4.018447399139404 0.2234957069158554 0.0 -1.5707297325134277 -4.019180774688721 0.22459320724010468 0.0 -1.628245234489441 -4.019920349121094 0.22573573887348175 0.0 -1.686358094215393 -4.0206685066223145 0.22692444920539856 0.0 -1.745094895362854 -4.021423816680908 0.2281603366136551 0.0 -1.8044841289520264 -4.022188186645508 0.22944463789463043 0.0 -1.8645551204681396 -4.022961616516113 0.2307785600423813 0.0 -1.9253379106521606 -4.023744106292725 0.23216335475444794 0.0 -1.986863613128662 -4.0245361328125 0.23360033333301544 0.0 -2.0491654872894287 -4.025338172912598 0.235090970993042 0.0 -2.112276554107666 -4.026149749755859 0.2366366684436798 0.0 -2.1762332916259766 -4.026973247528076 0.2382390797138214 0.0 -2.241072177886963 -4.02780818939209 0.23989984393119812 0.0 -2.306830644607544 -4.028654098510742 0.24162063002586365 0.0 -2.373549699783325 -4.029512405395508 0.24340328574180603 0.0 -2.4412713050842285 -4.030384540557861 0.24524985253810883 0.0 -2.510038375854492 -4.031269550323486 0.24716219305992126 0.0 -2.5798966884613037 -4.032167911529541 0.24914251267910004 0.0 -2.6508946418762207 -4.033082008361816 0.2511930763721466 0.0 -2.7230823040008545 -4.034011363983154 0.2533162832260132 0.0 -2.7965118885040283 -4.034956932067871 0.25551465153694153 0.0 -2.871237277984619 -4.03591775894165 0.25779062509536743 0.0 -2.9473187923431396 -4.0368971824646 0.2601472735404968 0.0 -3.024815559387207 -4.0378947257995605 0.26258742809295654 0.0 -3.103792428970337 -4.038911819458008 0.2651142477989197 0.0 -3.1843152046203613 -4.039947509765625 0.2677308917045593 0.0 -3.266456365585327 -4.041004657745361 0.2704409956932068 0.0 -3.350290536880493 -4.042083740234375 0.27324825525283813 0.0 -3.435896396636963 -4.043185710906982 0.27615654468536377 0.0 -3.5233569145202637 -4.044311046600342 0.2791699767112732 0.0 -3.6127614974975586 -4.045461654663086 0.28229305148124695 0.0 -3.704202890396118 -4.046638488769531 0.2855303883552551 0.0 -3.7977805137634277 -4.0478434562683105 0.28888699412345886 0.0 -3.8935978412628174 -4.049075603485107 0.2923680543899536 0.0 -3.9917688369750977 -4.050339221954346 0.295979380607605 0.0 -4.092411041259766 -4.0516357421875 0.2997269034385681 0.0 -4.195649147033691 -4.052963733673096 0.30361688137054443 0.0 -4.301619529724121 -4.054327964782715 0.30765631794929504 0.0 -4.410463333129883 -4.055728435516357 0.311852365732193 0.0 -4.522334575653076 -4.057168483734131 0.31621289253234863 0.0 -4.637397289276123 -4.058650016784668 0.3207462430000305 0.0 -4.755823612213135 -4.060173511505127 0.3254612684249878 0.0 -4.877803802490234 -4.061744213104248 0.3303677439689636 0.0 -5.003536224365234 -4.063361644744873 0.33547574281692505 0.0 -5.133238315582275 -4.065031051635742 0.34079650044441223 0.0 -5.267141819000244 -4.0667548179626465 0.34634196758270264 0.0 -5.405494689941406 -4.068534851074219 0.35212481021881104 0.0 -5.548570156097412 -4.070376873016357 0.35815921425819397 0.0 -5.696656703948975 -4.072282314300537 0.36445993185043335 0.0 -5.850070953369141 -4.0742573738098145 0.37104347348213196 0.0 -6.009153842926025 -4.076304912567139 0.3779272735118866 0.0 -6.174275875091553 -4.078429698944092 0.38513055443763733 0.0 -6.345842361450195 -4.0806379318237305 0.3926743268966675 0.0 -2.9836435317993164 -0.01833416521549225 0.15529239177703857 0.0 -2.984482526779175 0.01833932101726532 0.15533606708049774 0.0 -2.9853222370147705 0.05503898486495018 0.1554032266139984 0.0 -2.9861626625061035 0.09177594631910324 0.15549394488334656 0.0 -2.987004041671753 0.12856139242649078 0.15560829639434814 0.0 -2.987847328186035 0.16540656983852386 0.15574637055397034 0.0 -2.988691806793213 0.20232272148132324 0.1559082269668579 0.0 -2.989537477493286 0.2393212467432022 0.15609398484230042 0.0 -2.990386724472046 0.27641376852989197 0.15630389750003815 0.0 -2.9912374019622803 0.3136117458343506 0.1565380096435547 0.0 -2.992090940475464 0.35092693567276 0.15679654479026794 0.0 -2.992947578430176 0.3883712887763977 0.15707969665527344 0.0 -2.993807554244995 0.4259568452835083 0.15738770365715027 0.0 -2.9946706295013428 0.4636957347393036 0.15772077441215515 0.0 -2.9955379962921143 0.5016005039215088 0.15807919204235077 0.0 -2.9964089393615723 0.5396835803985596 0.15846320986747742 0.0 -2.997284173965454 0.5779579281806946 0.15887314081192017 0.0 -2.998164653778076 0.616436779499054 0.15930937230587006 0.0 -2.9990499019622803 0.6551333665847778 0.15977217257022858 0.0 -2.9999406337738037 0.6940613389015198 0.16026195883750916 0.0 -3.0008366107940674 0.7332345843315125 0.16077910363674164 0.0 -3.0017385482788086 0.772667407989502 0.16132403910160065 0.0 -3.0026471614837646 0.8123745918273926 0.16189724206924438 0.0 -3.0035619735717773 0.8523709177970886 0.16249912977218628 0.0 -3.004483699798584 0.8926717638969421 0.1631302386522293 0.0 -3.005413055419922 0.9332932233810425 0.16379112005233765 0.0 -3.006349802017212 0.9742512106895447 0.16448231041431427 0.0 -3.0072948932647705 1.015562653541565 0.16520442068576813 0.0 -3.008248805999756 1.057244896888733 0.16595809161663055 0.0 -3.0092105865478516 1.0993152856826782 0.1667439341545105 0.0 -3.0101823806762695 1.14179265499115 0.16756270825862885 0.0 -3.0111641883850098 1.1846957206726074 0.1684151291847229 0.0 -3.012155771255493 1.2280441522598267 0.16930195689201355 0.0 -3.013158082962036 1.2718580961227417 0.17022402584552765 0.0 -3.0396106243133545 1.327266812324524 0.17262692749500275 0.0 -3.090172529220581 1.3948094844818115 0.1764587014913559 0.0 -3.143038511276245 1.465429663658142 0.1804923415184021 0.0 -3.1983864307403564 1.539365291595459 0.1847432553768158 0.0 -6.466622352600098 3.21081805229187 0.3757721185684204 0.0 -6.38853120803833 3.2705187797546387 0.37354183197021484 0.0 -6.311350345611572 3.329523801803589 0.371393620967865 0.0 -6.235040187835693 3.3878626823425293 0.3693253993988037 0.0 -6.139792442321777 3.4345040321350098 0.3661561608314514 0.0 -6.044627666473389 3.4794816970825195 0.3630037307739258 0.0 -5.95107364654541 3.523698329925537 0.35995903611183167 0.0 -5.867958068847656 3.572601556777954 0.35756048560142517 0.0 -5.8066534996032715 3.633833646774292 0.3565194010734558 0.0 -5.654065132141113 3.6357970237731934 0.34986788034439087 0.0 -5.507045745849609 3.6376895904541016 0.34351101517677307 0.0 -5.365251541137695 3.639514207839966 0.33743101358413696 0.0 -5.22836971282959 3.6412761211395264 0.3316117525100708 0.0 -5.096109390258789 3.6429781913757324 0.3260382115840912 0.0 -4.968202114105225 3.6446242332458496 0.32069653272628784 0.0 -4.844400405883789 3.6462178230285645 0.3155740201473236 0.0 -4.724473476409912 3.647761344909668 0.31065869331359863 0.0 -4.608207702636719 3.6492574214935303 0.305939644575119 0.0 -4.4954047203063965 3.6507091522216797 0.3014066815376282 0.0 -4.385879993438721 3.6521191596984863 0.2970503270626068 0.0 -4.279459476470947 3.6534886360168457 0.2928616404533386 0.0 -4.2294840812683105 3.7016441822052 0.29253289103507996 0.0 -4.130249500274658 3.7054128646850586 0.2887973189353943 0.0 -4.030898094177246 3.7066919803619385 0.2850143015384674 0.0 -3.934101104736328 3.707937479019165 0.28137102723121643 0.0 -3.839733600616455 3.7091519832611084 0.2778611481189728 0.0 -3.747677803039551 3.710336923599243 0.2744787335395813 0.0 -3.657823324203491 3.711493968963623 0.2712181806564331 0.0 -3.5700643062591553 3.712622880935669 0.2680741250514984 0.0 -3.484304428100586 3.713726758956909 0.265041708946228 0.0 -3.348081588745117 3.8431196212768555 0.26528218388557434 0.0 -3.308554172515869 3.893336057662964 0.26592153310775757 0.0 -3.2688300609588623 3.943802833557129 0.26660436391830444 0.0 -3.2288947105407715 3.9945363998413086 0.26733115315437317 0.0 -3.196229934692383 4.055063724517822 0.2687326669692993 0.0 -3.1975929737091064 4.160973072052002 0.2731263339519501 0.0 -3.1990013122558594 4.270419120788574 0.27770867943763733 0.0 -3.200458526611328 4.3836188316345215 0.2824908494949341 0.0 -3.2019665241241455 4.500802516937256 0.2874847650527954 0.0 -3.203529119491577 4.622223377227783 0.29270341992378235 0.0 -3.2051491737365723 4.748151779174805 0.2981608510017395 0.0 -3.2680346965789795 4.972001075744629 0.30967193841934204 0.0 -3.2698166370391846 5.110456466674805 0.3157685697078705 0.0 -3.2166733741760254 5.16616678237915 0.3167441785335541 0.0 -3.2122936248779297 5.303293228149414 0.3227066397666931 0.0 -0.24397842586040497 0.7587544918060303 0.04148220643401146 0.0 -0.2280339002609253 0.7402650117874146 0.040315091609954834 0.0 -0.21295960247516632 0.7227842211723328 0.03921758010983467 0.0 -0.1986825317144394 0.7062286734580994 0.03818391636013985 0.0 -0.18513637781143188 0.6905198097229004 0.03720874711871147 0.0 -0.17226330935955048 0.675592303276062 0.03628754988312721 0.0 -0.16001024842262268 0.6613831520080566 0.03541604429483414 0.0 -0.14833013713359833 0.6478381752967834 0.034590497612953186 0.0 -0.13718059659004211 0.6349088549613953 0.033807579427957535 0.0 -0.12652304768562317 0.6225500702857971 0.03306420147418976 0.0 -0.11632268875837326 0.6107218861579895 0.03235762566328049 0.0 -0.10654769837856293 0.5993867516517639 0.03168528899550438 0.0 -0.09716912358999252 0.5885106921195984 0.031044872477650642 0.0 -0.0885431244969368 0.5805707573890686 0.030566316097974777 0.0 -0.0812685489654541 0.5806642770767212 0.03051634691655636 0.0 -0.07401665300130844 0.580757737159729 0.03047114796936512 0.0 -0.06678509712219238 0.5808507204055786 0.030430663377046585 0.0 -0.05957164987921715 0.5809435248374939 0.03039487451314926 0.0 -0.052374064922332764 0.5810361504554749 0.030363749712705612 0.0 -0.04519011452794075 0.5811285376548767 0.0303372610360384 0.0 -0.03801761567592621 0.5812209844589233 0.030315404757857323 0.0 -0.030854357406497 0.5813130736351013 0.0302981436252594 0.0 -0.023698173463344574 0.5814052224159241 0.03028547577559948 0.0 -0.01654689572751522 0.5814973711967468 0.030277397483587265 0.0 -0.00939834862947464 0.5815892815589905 0.030273882672190666 0.0 -0.0022503812797367573 0.5816812515258789 0.030274944379925728 0.0 --0.004899166990071535 0.5817732810974121 0.0302805807441473 0.0 --0.012052460573613644 0.5818654298782349 0.03029080107808113 0.0 --0.01921166107058525 0.5819575190544128 0.030305596068501472 0.0 --0.026378944516181946 0.5820497870445251 0.030324993655085564 0.0 --0.033556487411260605 0.5821420550346375 0.030348995700478554 0.0 --0.040746498852968216 0.5822346806526184 0.030377639457583427 0.0 --0.047951165586709976 0.5823272466659546 0.030410919338464737 0.0 --0.05517274886369705 0.5824202299118042 0.03044888749718666 0.0 --0.06241348385810852 0.5825135111808777 0.03049156256020069 0.0 --0.06967563927173615 0.5826070308685303 0.030538976192474365 0.0 --0.07696148008108139 0.5827005505561829 0.030591148883104324 0.0 --0.08427339792251587 0.5827946662902832 0.03064815141260624 0.0 --0.0916137546300888 0.5828893184661865 0.030710021033883095 0.0 --0.09898487478494644 0.5829840898513794 0.03077678568661213 0.0 --0.10638925433158875 0.5830793976783752 0.030848514288663864 0.0 --0.11382933706045151 0.5831750631332397 0.03092525526881218 0.0 --0.12130773067474365 0.5832715034484863 0.03100709244608879 0.0 --0.12882685661315918 0.583368182182312 0.031094050034880638 0.0 --0.13638944923877716 0.5834654569625854 0.03118622675538063 0.0 --0.14399820566177368 0.583563506603241 0.031283698976039886 0.0 --0.15165580809116364 0.5836620926856995 0.03138653188943863 0.0 --0.15936505794525146 0.5837612152099609 0.03149481117725372 0.0 --0.16712884604930878 0.5838609933853149 0.03160862997174263 0.0 --0.1749502420425415 0.5839618444442749 0.031728096306324005 0.0 --0.18283207714557648 0.5840631723403931 0.03185328468680382 0.0 --0.19077759981155396 0.5841654539108276 0.031984321773052216 0.0 --0.19878995418548584 0.5842685103416443 0.03212130442261696 0.0 --0.20687244832515717 0.5843724608421326 0.03226436302065849 0.0 --0.21502859890460968 0.5844775438308716 0.032413631677627563 0.0 --0.22326168417930603 0.5845833420753479 0.03256920725107193 0.0 --0.2315755933523178 0.5846905708312988 0.032731276005506516 0.0 --0.23997379839420319 0.5847985148429871 0.03289994224905968 0.0 --0.2484603375196457 0.5849077105522156 0.033075377345085144 0.0 --0.2570391893386841 0.5850180983543396 0.03325774893164635 0.0 --0.26571449637413025 0.5851297974586487 0.03344722464680672 0.0 --0.27449050545692444 0.5852426290512085 0.03364397585391998 0.0 --0.28337183594703674 0.585357129573822 0.03384821116924286 0.0 --0.2923629581928253 0.5854728817939758 0.03406010940670967 0.0 --0.3014686107635498 0.5855898261070251 0.034279871731996536 0.0 --0.31069400906562805 0.585708498954773 0.03450774401426315 0.0 --0.3200443387031555 0.5858289003372192 0.03474395349621773 0.0 --0.3295249938964844 0.5859508514404297 0.03498873859643936 0.0 --0.33914175629615784 0.5860747694969177 0.035242367535829544 0.0 --0.34890028834342957 0.5862002968788147 0.035505086183547974 0.0 --0.35880693793296814 0.5863277316093445 0.035777200013399124 0.0 --0.3688682019710541 0.5864572525024414 0.03605900704860687 0.0 --0.37909072637557983 0.5865887999534607 0.03635082021355629 0.0 --0.38948163390159607 0.5867224335670471 0.03665297478437424 0.0 --0.4000483453273773 0.5868584513664246 0.03696582838892937 0.0 --0.4107987880706787 0.5869969129562378 0.037289757281541824 0.0 --0.4217407703399658 0.5871376395225525 0.03762513026595116 0.0 --0.43288302421569824 0.5872809290885925 0.037972379475831985 0.0 --0.44423481822013855 0.5874271988868713 0.038331955671310425 0.0 --0.455805242061615 0.5875760316848755 0.038704294711351395 0.0 --0.4676045775413513 0.587727963924408 0.03908991068601608 0.0 --0.4796431362628937 0.5878828763961792 0.03948930278420448 0.0 --0.49193206429481506 0.5880409479141235 0.039903029799461365 0.0 --0.504483163356781 0.5882024168968201 0.04033167287707329 0.0 --0.5173089504241943 0.5883675217628479 0.04077586159110069 0.0 --0.5304223299026489 0.5885363817214966 0.041236236691474915 0.0 --0.5438371896743774 0.5887089967727661 0.041713494807481766 0.0 --0.5575681328773499 0.5888855457305908 0.042208362370729446 0.0 --0.5716311931610107 0.5890665650367737 0.042721666395664215 0.0 --0.5860428214073181 0.5892521739006042 0.04325422644615173 0.0 --0.6008203625679016 0.5894423723220825 0.04380691796541214 0.0 --0.6159825921058655 0.5896373391151428 0.04438069835305214 0.0 --0.6315498948097229 0.5898377299308777 0.044976606965065 0.0 --0.6475432515144348 0.5900434255599976 0.04559570178389549 0.0 --0.6639857292175293 0.5902552008628845 0.046239178627729416 0.0 --0.6809014081954956 0.5904728174209595 0.04690824821591377 0.0 --0.6983165144920349 0.5906969308853149 0.0476042665541172 0.0 --0.7162589430809021 0.5909278392791748 0.04832865670323372 0.0 --0.7347587943077087 0.5911659598350525 0.04908296838402748 0.0 --0.7589793801307678 0.595437228679657 0.05020828917622566 0.0 --0.7862473130226135 0.6013679504394531 0.051519304513931274 0.0 --0.8149817585945129 0.6076176166534424 0.052908822894096375 0.0 --0.8453140258789062 0.6142148971557617 0.05438382178544998 0.0 --0.8773910999298096 0.6211917400360107 0.05595211684703827 0.0 --0.9113783240318298 0.6285840272903442 0.057622507214546204 0.0 --0.9474632740020752 0.6364326477050781 0.05940496549010277 0.0 --0.985857367515564 0.6447833180427551 0.061310749500989914 0.0 --1.026802897453308 0.653688907623291 0.06335274130105972 0.0 --1.0705769062042236 0.6632096767425537 0.0655456930398941 0.0 --1.1174979209899902 0.6734153032302856 0.06790656596422195 0.0 --1.1894049644470215 0.6969671249389648 0.07175017148256302 0.0 --1.3184176683425903 0.7509540915489197 0.07897007465362549 0.0 --3.863600254058838 2.138205051422119 0.22982902824878693 0.0 --3.8643877506256104 2.077019453048706 0.22834011912345886 0.0 --3.8651652336120605 2.0166122913360596 0.22690443694591522 0.0 --3.8659329414367676 1.9569509029388428 0.2255205363035202 0.0 --3.8666913509368896 1.8980040550231934 0.22418706119060516 0.0 --3.867441177368164 1.8397414684295654 0.22290274500846863 0.0 --3.868182897567749 1.7821341753005981 0.2216663658618927 0.0 --3.8689160346984863 1.7251536846160889 0.22047671675682068 0.0 --3.8696417808532715 1.6687731742858887 0.2193327397108078 0.0 --3.8703598976135254 1.6129662990570068 0.21823333203792572 0.0 --3.8710711002349854 1.557707667350769 0.21717755496501923 0.0 --3.8717753887176514 1.502972960472107 0.21616441011428833 0.0 --3.8724727630615234 1.4487383365631104 0.2151930183172226 0.0 --3.8731653690338135 1.3949812650680542 0.21426258981227875 0.0 --3.8738512992858887 1.3416787385940552 0.21337221562862396 0.0 --3.8745315074920654 1.2888094186782837 0.21252118051052094 0.0 --3.875206708908081 1.2363523244857788 0.21170876920223236 0.0 --3.8758764266967773 1.1842868328094482 0.21093425154685974 0.0 --3.876542091369629 1.1325932741165161 0.2101970613002777 0.0 --3.877202272415161 1.0812517404556274 0.20949646830558777 0.0 --3.877859115600586 1.030243992805481 0.2088320255279541 0.0 --3.878511428833008 0.9795510768890381 0.20820310711860657 0.0 --3.879160165786743 0.9291549324989319 0.20760923624038696 0.0 --3.879804849624634 0.8790378570556641 0.2070499062538147 0.0 --3.880446672439575 0.8291827440261841 0.20652471482753754 0.0 --3.881085157394409 0.7795723676681519 0.20603321492671967 0.0 --3.8817203044891357 0.7301900386810303 0.20557498931884766 0.0 --3.8823533058166504 0.6810195446014404 0.20514975488185883 0.0 --3.882983446121216 0.6320446729660034 0.20475710928440094 0.0 --3.8836116790771484 0.583249568939209 0.2043968141078949 0.0 --3.884237051010132 0.5346184968948364 0.20406849682331085 0.0 --3.8848612308502197 0.48613613843917847 0.20377199351787567 0.0 --3.8854830265045166 0.43778711557388306 0.20350702106952667 0.0 --3.886104106903076 0.3895564377307892 0.20327343046665192 0.0 --3.886723518371582 0.34142911434173584 0.2030710130929947 0.0 --3.8873417377471924 0.29339027404785156 0.20289959013462067 0.0 --3.8879587650299072 0.24542522430419922 0.2027590423822403 0.0 --3.888575792312622 0.19751936197280884 0.2026493102312088 0.0 --3.8891918659210205 0.14965809881687164 0.20257025957107544 0.0 --3.8898072242736816 0.10182693600654602 0.20252183079719543 0.0 --3.8904225826263428 0.05401141196489334 0.2025040239095688 0.0 --3.891037702560425 0.006197080481797457 0.20251677930355072 0.0 --3.8911995887756348 -0.006197338458150625 0.3380846083164215 0.0 --3.891815662384033 -0.054030753672122955 0.33817028999328613 0.0 --3.8924312591552734 -0.10189563035964966 0.33830705285072327 0.0 --3.89304780960083 -0.14980648458003998 0.3384951055049896 0.0 --3.8936655521392822 -0.1977778971195221 0.33873456716537476 0.0 --3.8942837715148926 -0.24582448601722717 0.339025616645813 0.0 --3.8949031829833984 -0.29396095871925354 0.33936840295791626 0.0 --3.8955237865448 -0.34220215678215027 0.3397632837295532 0.0 --3.896146535873413 -0.39056313037872314 0.34021055698394775 0.0 --3.896770715713501 -0.43905889987945557 0.34071052074432373 0.0 --3.8973965644836426 -0.4877047538757324 0.3412635624408722 0.0 --3.8980252742767334 -0.5365162491798401 0.34187015891075134 0.0 --3.898655414581299 -0.5855088829994202 0.3425306975841522 0.0 --3.8992884159088135 -0.6346986889839172 0.3432457149028778 0.0 --3.899923801422119 -0.6841017007827759 0.34401580691337585 0.0 --3.9005630016326904 -0.7337344884872437 0.3448415994644165 0.0 --3.901204824447632 -0.7836136817932129 0.3457236886024475 0.0 --3.9018499851226807 -0.8337562084197998 0.3466627597808838 0.0 --3.9024994373321533 -0.8841797113418579 0.3476596772670746 0.0 --3.9031519889831543 -0.9349015951156616 0.3487150967121124 0.0 --3.903809070587158 -0.985940158367157 0.3498299717903137 0.0 --3.904470205307007 -1.0373139381408691 0.3510051667690277 0.0 --3.9051358699798584 -1.089041829109192 0.3522416651248932 0.0 --3.905806064605713 -1.1411432027816772 0.35354045033454895 0.0 --3.906481981277466 -1.1936384439468384 0.3549027144908905 0.0 --3.907162666320801 -1.2465475797653198 0.3563295006752014 0.0 --3.9078495502471924 -1.2998921871185303 0.35782212018966675 0.0 --3.9085419178009033 -1.3536936044692993 0.359381765127182 0.0 --3.9092400074005127 -1.407974123954773 0.36100977659225464 0.0 --3.9099457263946533 -1.4627573490142822 0.3627077639102936 0.0 --3.9106574058532715 -1.5180665254592896 0.3644770085811615 0.0 --3.9113759994506836 -1.573926329612732 0.3663191795349121 0.0 --3.912102460861206 -1.6303625106811523 0.3682360351085663 0.0 --3.9128365516662598 -1.6874008178710938 0.37022921442985535 0.0 --3.913578510284424 -1.7450687885284424 0.3723006546497345 0.0 --3.914329767227173 -1.8033947944641113 0.3744523227214813 0.0 --3.9150891304016113 -1.8624076843261719 0.376686155796051 0.0 --3.915858030319214 -1.9221380949020386 0.37900444865226746 0.0 --3.9166364669799805 -1.9826172590255737 0.3814093768596649 0.0 --3.9174249172210693 -2.0438780784606934 0.3839033544063568 0.0 --3.9182238578796387 -2.105954885482788 0.3864889442920685 0.0 --3.9190335273742676 -2.1688830852508545 0.38916873931884766 0.0 --3.9198546409606934 -2.2326998710632324 0.39194560050964355 0.0 --3.9206881523132324 -2.2974436283111572 0.39482244849205017 0.0 --3.9215335845947266 -2.363154888153076 0.39780232310295105 0.0 --2.2969624996185303 -3.969407558441162 0.3984593451023102 0.0 --2.2327661514282227 -3.970233917236328 0.395757794380188 0.0 --2.1694247722625732 -3.971048593521118 0.39315155148506165 0.0 --2.106902837753296 -3.971853017807007 0.3906380236148834 0.0 --2.045166254043579 -3.9726481437683105 0.38821476697921753 0.0 --1.9841816425323486 -3.973432779312134 0.3858792781829834 0.0 --1.923917293548584 -3.974208354949951 0.38362929224967957 0.0 --1.8643425703048706 -3.9749746322631836 0.3814626634120941 0.0 --1.8054282665252686 -3.9757330417633057 0.3793773651123047 0.0 --1.7471458911895752 -3.976483106613159 0.3773714303970337 0.0 --1.6894677877426147 -3.9772250652313232 0.3754429817199707 0.0 --1.632367491722107 -3.977959632873535 0.37359026074409485 0.0 --1.575819969177246 -3.9786880016326904 0.37181171774864197 0.0 --1.5197994709014893 -3.9794085025787354 0.3701055645942688 0.0 --1.464282512664795 -3.9801230430603027 0.3684704303741455 0.0 --1.4092457294464111 -3.9808313846588135 0.3669048547744751 0.0 --1.3546663522720337 -3.9815335273742676 0.36540746688842773 0.0 --1.3005224466323853 -3.9822301864624023 0.36397698521614075 0.0 --1.2467930316925049 -3.982922077178955 0.3626122772693634 0.0 --1.193456768989563 -3.9836084842681885 0.3613120913505554 0.0 --1.1404937505722046 -3.98429012298584 0.3600753843784332 0.0 --1.0878840684890747 -3.984966993331909 0.35890111327171326 0.0 --1.0356084108352661 -3.9856395721435547 0.3577883541584015 0.0 --0.9836483597755432 -3.9863083362579346 0.3567362129688263 0.0 --0.9319850206375122 -3.9869730472564697 0.35574376583099365 0.0 --0.8806007504463196 -3.9876344203948975 0.35481032729148865 0.0 --0.8294776678085327 -3.988292694091797 0.3539350628852844 0.0 --0.7785984873771667 -3.9889471530914307 0.3531172573566437 0.0 --0.7279463410377502 -3.9895992279052734 0.3523564040660858 0.0 --0.6775043606758118 -3.990248680114746 0.35165178775787354 0.0 --0.6272559762001038 -3.990894317626953 0.3510027825832367 0.0 --0.5771853923797607 -3.991539239883423 0.3504091501235962 0.0 --0.5272762775421143 -3.9921813011169434 0.3498701751232147 0.0 --0.47751307487487793 -3.9928224086761475 0.34938567876815796 0.0 --0.42787986993789673 -3.9934608936309814 0.3489550054073334 0.0 --0.37836146354675293 -3.99409818649292 0.3485780358314514 0.0 --0.3289424479007721 -3.9947338104248047 0.34825438261032104 0.0 --0.27960771322250366 -3.9953689575195312 0.3479838967323303 0.0 --0.2303420901298523 -3.9960029125213623 0.34776628017425537 0.0 --0.18113064765930176 -3.996636390686035 0.34760141372680664 0.0 --0.13195838034152985 -3.9972689151763916 0.3474891483783722 0.0 --0.08281047642230988 -3.9979019165039062 0.34742945432662964 0.0 --0.0336720272898674 -3.9985337257385254 0.34742215275764465 0.0 -0.015471789985895157 -3.999166965484619 0.34746745228767395 0.0 -0.06463582813739777 -3.9997990131378174 0.3475651443004608 0.0 -0.11383496224880219 -4.000432014465332 0.34771546721458435 0.0 -0.16308413445949554 -4.001066207885742 0.3479185402393341 0.0 -0.21239830553531647 -4.001701354980469 0.34817442297935486 0.0 -0.26179248094558716 -4.002336025238037 0.3484833240509033 0.0 -0.3112819492816925 -4.002973556518555 0.34884557127952576 0.0 -0.36088189482688904 -4.003612041473389 0.3492613732814789 0.0 -0.4106076955795288 -4.004251956939697 0.3497309982776642 0.0 -0.46047496795654297 -4.004893779754639 0.3502548933029175 0.0 -0.5104994177818298 -4.005537509918213 0.3508334159851074 0.0 -0.5606970191001892 -4.006183624267578 0.3514670431613922 0.0 -0.6110838055610657 -4.006831645965576 0.3521561920642853 0.0 -0.661676287651062 -4.007482528686523 0.35290148854255676 0.0 -0.7124910354614258 -4.00813627243042 0.35370346903800964 0.0 -0.763545036315918 -4.008793354034424 0.35456278920173645 0.0 -0.8148555755615234 -4.009454250335693 0.3554801642894745 0.0 -0.8664401173591614 -4.0101189613342285 0.3564562499523163 0.0 -0.9183163046836853 -4.0107855796813965 0.35749176144599915 0.0 -0.9705029726028442 -4.011457443237305 0.35858774185180664 0.0 -1.0230183601379395 -4.0121331214904785 0.3597448766231537 0.0 -1.0758819580078125 -4.012813568115234 0.36096426844596863 0.0 -1.1291130781173706 -4.013498783111572 0.3622468113899231 0.0 -1.182732105255127 -4.01418924331665 0.3635936379432678 0.0 -1.2367594242095947 -4.0148844718933105 0.36500585079193115 0.0 -1.291216254234314 -4.015584945678711 0.3664845824241638 0.0 -1.3461246490478516 -4.016292095184326 0.36803123354911804 0.0 -1.4015065431594849 -4.017004489898682 0.36964699625968933 0.0 -1.457385540008545 -4.017723560333252 0.37133336067199707 0.0 -1.5137852430343628 -4.018449306488037 0.37309178709983826 0.0 -1.5707303285598755 -4.0191826820373535 0.3749238848686218 0.0 -1.6282460689544678 -4.019922256469727 0.37683120369911194 0.0 -1.6863588094711304 -4.020670413970947 0.37881553173065186 0.0 -1.74509596824646 -4.021426200866699 0.380878746509552 0.0 -1.8044854402542114 -4.022191047668457 0.3830227255821228 0.0 -1.8645563125610352 -4.022964000701904 0.38524946570396423 0.0 -1.925338864326477 -4.023746013641357 0.3875611126422882 0.0 -1.9868645668029785 -4.024538040161133 0.3899599313735962 0.0 -2.049166440963745 -4.0253400802612305 0.3924483060836792 0.0 -2.1122777462005615 -4.02615213394165 0.39502865076065063 0.0 -2.176234483718872 -4.026975154876709 0.397703617811203 0.0 -3.487544059753418 -0.36564624309539795 0.3046737015247345 0.0 -3.488100290298462 -0.32241949439048767 0.30435311794281006 0.0 -3.190000534057617 -0.2553688883781433 0.278047651052475 0.0 -3.1490800380706787 -0.21318037807941437 0.27423185110092163 0.0 -3.1092605590820312 -0.17212797701358795 0.2705595791339874 0.0 -3.070488214492798 -0.13215456902980804 0.2670242190361023 0.0 -3.032709836959839 -0.09320652484893799 0.2636193335056305 0.0 -2.995878219604492 -0.05523360148072243 0.26033902168273926 0.0 -2.9836416244506836 -0.018334154039621353 0.25923654437065125 0.0 -2.984480619430542 0.018339309841394424 0.25930944085121155 0.0 -2.9853196144104004 0.0550389364361763 0.2594214975833893 0.0 -2.9861600399017334 0.09177586436271667 0.25957295298576355 0.0 -2.9870011806488037 0.12856125831604004 0.25976380705833435 0.0 -2.9878435134887695 0.16540634632110596 0.2599942088127136 0.0 -2.9886882305145264 0.20232248306274414 0.26026442646980286 0.0 -2.9895341396331787 0.23932099342346191 0.2605745792388916 0.0 -2.990382432937622 0.2764133810997009 0.26092490553855896 0.0 -2.9912333488464355 0.31361132860183716 0.2613157331943512 0.0 -2.992086887359619 0.3509264886379242 0.2617473006248474 0.0 -2.9929428100585938 0.38837066292762756 0.2622199058532715 0.0 -2.993802547454834 0.425956130027771 0.2627340853214264 0.0 -2.99466609954834 0.4636950194835663 0.2632901072502136 0.0 -2.995532512664795 0.5015996098518372 0.2638883590698242 0.0 -2.996403455734253 0.5396826267242432 0.26452940702438354 0.0 -2.997278928756714 0.5779569745063782 0.2652137577533722 0.0 -2.998159170150757 0.616435706615448 0.26594194769859314 0.0 -2.999044179916382 0.6551321148872375 0.26671451330184937 0.0 -2.999933958053589 0.6940598487854004 0.2675320506095886 0.0 -3.0008301734924316 0.7332330346107483 0.2683953642845154 0.0 -3.0017318725585938 0.7726656794548035 0.2693049907684326 0.0 -3.0026400089263916 0.8123726844787598 0.27026182413101196 0.0 -3.0035548210144043 0.8523688912391663 0.2712666094303131 0.0 -3.004476308822632 0.8926695585250854 0.27232009172439575 0.0 -3.0054054260253906 0.9332907795906067 0.27342331409454346 0.0 -3.0063421726226807 0.9742487668991089 0.27457717061042786 0.0 -3.00728702545166 1.0155600309371948 0.27578258514404297 0.0 -3.008239984512329 1.0572417974472046 0.27704066038131714 0.0 -3.009202480316162 1.0993123054504395 0.2783525288105011 0.0 -3.010173797607422 1.141789436340332 0.2797192931175232 0.0 -3.011154890060425 1.184692144393921 0.2811422348022461 0.0 -3.012146234512329 1.228040337562561 0.28262263536453247 0.0 -3.013148307800293 1.271854043006897 0.28416183590888977 0.0 -3.039564371109009 1.3272466659545898 0.28816965222358704 0.0 -3.09012508392334 1.3947880268096924 0.2945660650730133 0.0 -3.1429882049560547 1.4654061794281006 0.3012993037700653 0.0 -3.198333501815796 1.5393399000167847 0.30839529633522034 0.0 -0.24398499727249146 0.7587749361991882 0.06925000995397568 0.0 -0.22804002463817596 0.7402849197387695 0.06730163842439651 0.0 -0.2129652351140976 0.7228032946586609 0.06546943634748459 0.0 -0.1986875832080841 0.7062466740608215 0.06374378502368927 0.0 -0.18514108657836914 0.6905373334884644 0.06211584061384201 0.0 -0.1722673773765564 0.675608217716217 0.06057789921760559 0.0 -0.16001422703266144 0.6613995432853699 0.05912309139966965 0.0 -0.1483338326215744 0.6478543281555176 0.05774494633078575 0.0 -0.13718397915363312 0.6349244713783264 0.05643793195486069 0.0 -0.12652604281902313 0.6225647926330566 0.05519689619541168 0.0 -0.11632535606622696 0.6107358336448669 0.05401730164885521 0.0 -0.10655005276203156 0.5994000434875488 0.05289487540721893 0.0 -0.09717122465372086 0.5885234475135803 0.05182574689388275 0.0 -0.0885440930724144 0.5805771350860596 0.05102631077170372 0.0 -0.08126945048570633 0.5806707143783569 0.05094289779663086 0.0 -0.07401745021343231 0.5807639360427856 0.05086743086576462 0.0 -0.06678584218025208 0.5808572173118591 0.05079986900091171 0.0 -0.05957229807972908 0.5809498429298401 0.05074010789394379 0.0 -0.05237462744116783 0.5810424089431763 0.05068814381957054 0.0 -0.04519060626626015 0.5811349153518677 0.050643935799598694 0.0 -0.03801802545785904 0.5812272429466248 0.05060743913054466 0.0 -0.03085467964410782 0.5813191533088684 0.050578609108924866 0.0 -0.023698419332504272 0.5814112424850464 0.0505574569106102 0.0 -0.01654706709086895 0.5815033912658691 0.05054397135972977 0.0 -0.00939844362437725 0.5815951824188232 0.05053809657692909 0.0 -0.0022504040971398354 0.5816872119903564 0.05053986608982086 0.0 --0.004899218212813139 0.5817793607711792 0.05054929107427597 0.0 --0.012052581645548344 0.5818712711334229 0.05056632682681084 0.0 --0.01921185478568077 0.5819634199142456 0.050591032952070236 0.0 --0.026379209011793137 0.5820556282997131 0.05062340945005417 0.0 --0.03355681523680687 0.5821477770805359 0.05066346749663353 0.0 --0.04074689745903015 0.5822403430938721 0.05071127787232399 0.0 --0.047951653599739075 0.5823331475257874 0.05076685547828674 0.0 --0.05517328158020973 0.5824258327484131 0.050830211490392685 0.0 --0.06241409480571747 0.5825191736221313 0.05090146139264107 0.0 --0.06967630982398987 0.5826125741004944 0.05098060145974159 0.0 --0.07696224004030228 0.5827063322067261 0.051067713648080826 0.0 --0.08427422493696213 0.5828003883361816 0.05116286501288414 0.0 --0.09161461144685745 0.5828947424888611 0.051266126334667206 0.0 --0.09898582100868225 0.5829896330833435 0.051377587020397186 0.0 --0.10639025270938873 0.5830848813056946 0.05149732157588005 0.0 --0.11383041739463806 0.5831806063652039 0.051625438034534454 0.0 --0.1213088110089302 0.5832767486572266 0.05176202207803726 0.0 --0.1288280189037323 0.5833734273910522 0.051907192915678024 0.0 --0.13639067113399506 0.5834707021713257 0.052061066031455994 0.0 --0.14399944245815277 0.5835685133934021 0.05222376063466072 0.0 --0.1516571342945099 0.5836671590805054 0.05239543691277504 0.0 --0.1593664586544037 0.5837663412094116 0.05257619172334671 0.0 --0.16713033616542816 0.5838662385940552 0.05276620015501976 0.0 --0.1749517023563385 0.5839667320251465 0.05296560749411583 0.0 --0.18283362686634064 0.5840681195259094 0.05317459627985954 0.0 --0.1907792091369629 0.584170401096344 0.05339334160089493 0.0 --0.19879163801670074 0.5842734575271606 0.05362201854586601 0.0 --0.20687425136566162 0.5843774676322937 0.05386084318161011 0.0 --0.21503035724163055 0.5844823122024536 0.05410999804735184 0.0 --0.22326356172561646 0.5845882296562195 0.0543697290122509 0.0 --0.23157744109630585 0.5846952199935913 0.054640255868434906 0.0 --0.2399757355451584 0.5848032236099243 0.054921820759773254 0.0 --0.24846237897872925 0.5849125385284424 0.05521470308303833 0.0 --0.25704121589660645 0.5850227475166321 0.05551912635564804 0.0 --0.26571667194366455 0.5851345658302307 0.05583544075489044 0.0 --0.27449271082878113 0.5852473974227905 0.056163884699344635 0.0 --0.28337404131889343 0.585361659526825 0.056504812091588974 0.0 --0.2923651933670044 0.585477352142334 0.05685853585600853 0.0 --0.30147096514701843 0.5855944156646729 0.057225409895181656 0.0 --0.31069648265838623 0.5857132077217102 0.05760582163929939 0.0 --0.3200467526912689 0.5858333110809326 0.0580001138150692 0.0 --0.32952752709388733 0.5859553217887878 0.05840874835848808 0.0 --0.33914414048194885 0.586078941822052 0.058832112699747086 0.0 --0.34890294075012207 0.5862047076225281 0.059270717203617096 0.0 --0.35880956053733826 0.5863320231437683 0.05972495302557945 0.0 --0.36887088418006897 0.5864615440368652 0.06019539386034012 0.0 --0.3790934979915619 0.5865930914878845 0.06068253517150879 0.0 --0.3894844353199005 0.5867266654968262 0.061186932027339935 0.0 --0.4000512659549713 0.5868626832962036 0.0617091991007328 0.0 --0.41080164909362793 0.5870010256767273 0.062249936163425446 0.0 --0.42174363136291504 0.5871416926383972 0.0628097876906395 0.0 --0.4328860640525818 0.587285041809082 0.06338948011398315 0.0 --0.44423776865005493 0.5874310731887817 0.06398971378803253 0.0 --0.45580828189849854 0.5875799655914307 0.0646112859249115 0.0 --0.4676074981689453 0.5877315998077393 0.06525498628616333 0.0 --0.4796462655067444 0.5878866910934448 0.06592173874378204 0.0 --0.49193528294563293 0.5880447626113892 0.06661239266395569 0.0 --0.5044865012168884 0.5882062315940857 0.06732795387506485 0.0 --0.5173121690750122 0.5883712768554688 0.0680694431066513 0.0 --0.530425488948822 0.5885398387908936 0.06883794814348221 0.0 --0.5438404083251953 0.5887125134468079 0.06963466107845306 0.0 --0.5575715899467468 0.5888891816139221 0.07046079635620117 0.0 --0.5716344714164734 0.5890699625015259 0.0713176429271698 0.0 --0.586046040058136 0.5892553925514221 0.07220665365457535 0.0 --0.600823700428009 0.5894456505775452 0.07312930375337601 0.0 --0.6159860491752625 0.5896406173706055 0.07408714294433594 0.0 --0.6315531730651855 0.5898407697677612 0.07508189976215363 0.0 --0.647546648979187 0.5900465846061707 0.07611539959907532 0.0 --0.6639891862869263 0.5902582406997681 0.07718957960605621 0.0 --0.680904746055603 0.5904757380485535 0.07830647379159927 0.0 --0.6983199715614319 0.5906998515129089 0.07946837693452835 0.0 --0.7162623405456543 0.5909306406974792 0.08067762106657028 0.0 --0.7347622513771057 0.5911687612533569 0.08193683624267578 0.0 --0.7589824199676514 0.5954395532608032 0.0838153287768364 0.0 --0.7862505912780762 0.6013704538345337 0.08600389957427979 0.0 --0.814984917640686 0.6076200008392334 0.08832345902919769 0.0 --0.8453172445297241 0.6142172813415527 0.09078574925661087 0.0 --0.8773940801620483 0.6211938858032227 0.09340374916791916 0.0 --0.9113810062408447 0.6285858154296875 0.09619217365980148 0.0 --0.9474655389785767 0.6364341378211975 0.09916767477989197 0.0 --0.9858598709106445 0.6447849273681641 0.10234909504652023 0.0 --1.0268054008483887 0.6536904573440552 0.10575789213180542 0.0 --1.0705785751342773 0.6632107496261597 0.1094186007976532 0.0 --1.117498755455017 0.6734157204627991 0.11335962265729904 0.0 --1.189400315284729 0.69696444272995 0.11977538466453552 0.0 --1.3184096813201904 0.750949501991272 0.13182754814624786 0.0 --3.863614797592163 2.1382131576538086 0.383665531873703 0.0 --3.864401340484619 2.077026605606079 0.38117995858192444 0.0 --3.8651788234710693 2.0166192054748535 0.37878331542015076 0.0 --3.865945816040039 1.956957459449768 0.37647300958633423 0.0 --3.8667049407958984 1.8980107307434082 0.37424707412719727 0.0 --3.8674538135528564 1.8397475481033325 0.3721030056476593 0.0 --3.868194818496704 1.782139778137207 0.3700389862060547 0.0 --3.8689281940460205 1.7251591682434082 0.36805304884910583 0.0 --3.8696532249450684 1.6687781810760498 0.36614328622817993 0.0 --3.870371103286743 1.6129709482192993 0.3643079698085785 0.0 --3.871081829071045 1.5577120780944824 0.3625454306602478 0.0 --3.871785879135132 1.5029770135879517 0.3608541190624237 0.0 --3.872483253479004 1.4487422704696655 0.3592325448989868 0.0 --3.8731749057769775 1.3949846029281616 0.35767924785614014 0.0 --3.8738608360290527 1.3416820764541626 0.3561929166316986 0.0 --3.8745408058166504 1.2888123989105225 0.3547722101211548 0.0 --3.875215768814087 1.236355185508728 0.35341596603393555 0.0 --3.875885486602783 1.184289574623108 0.3521230220794678 0.0 --3.8765501976013184 1.1325955390930176 0.3508923053741455 0.0 --3.8772106170654297 1.0812541246414185 0.34972280263900757 0.0 --3.877866744995117 1.0302460193634033 0.34861356019973755 0.0 --3.878519058227539 0.9795529842376709 0.34756365418434143 0.0 --3.879167318344116 0.9291567206382751 0.34657225012779236 0.0 --3.8798115253448486 0.8790394067764282 0.3456384837627411 0.0 --3.880453109741211 0.8291841149330139 0.3447617292404175 0.0 --3.881091594696045 0.7795736193656921 0.34394124150276184 0.0 --3.8817265033721924 0.7301912307739258 0.34317630529403687 0.0 --3.882359027862549 0.6810205578804016 0.3424663841724396 0.0 --3.8829894065856934 0.6320456266403198 0.341810941696167 0.0 --3.8836169242858887 0.5832503437995911 0.34120941162109375 0.0 --3.884242534637451 0.5346192121505737 0.34066134691238403 0.0 --3.8848659992218018 0.4861367344856262 0.3401663601398468 0.0 --3.8854880332946777 0.4377876818180084 0.33972403407096863 0.0 --3.8861083984375 0.389556884765625 0.33933404088020325 0.0 --3.886727809906006 0.3414295017719269 0.33899611234664917 0.0 --3.887345314025879 0.29339054226875305 0.33870989084243774 0.0 --3.887962579727173 0.24542546272277832 0.3384752869606018 0.0 --3.8885786533355713 0.19751951098442078 0.33829203248023987 0.0 --3.8891942501068115 0.149658203125 0.33816003799438477 0.0 --3.8898098468780518 0.10182700306177139 0.33807921409606934 0.0 --3.890424966812134 0.05401144549250603 0.33804944157600403 0.0 --3.891040086746216 0.006197084207087755 0.33807075023651123 0.0 -3.1900007724761963 -0.2553689181804657 0.3902083933353424 0.0 -3.1490793228149414 -0.2131803333759308 0.38485321402549744 0.0 -3.109259843826294 -0.17212793231010437 0.37969961762428284 0.0 -3.0704877376556396 -0.13215455412864685 0.3747381865978241 0.0 -3.0327095985412598 -0.0932065099477768 0.3699597716331482 0.0 -2.995877742767334 -0.05523359403014183 0.3653562664985657 0.0 -2.9836394786834717 -0.01833414100110531 0.36380884051322937 0.0 -2.98447847366333 0.01833929680287838 0.36391112208366394 0.0 -2.9853174686431885 0.05503889545798302 0.3640683889389038 0.0 -2.9869987964630127 0.12856116890907288 0.3645487427711487 0.0 -2.987842082977295 0.1654062718153 0.3648722171783447 0.0 -2.9886860847473145 0.2023223340511322 0.3652513325214386 0.0 -2.989532470703125 0.23932084441184998 0.3656866252422333 0.0 -2.9903807640075684 0.276413232088089 0.3661783039569855 0.0 -2.9912314414978027 0.31361111998558044 0.36672675609588623 0.0 -2.9920849800109863 0.3509262204170227 0.367332398891449 0.0 -2.99294114112854 0.38837045431137085 0.3679957091808319 0.0 -2.993800640106201 0.4259558618068695 0.368717223405838 0.0 -2.994663953781128 0.46369469165802 0.36949753761291504 0.0 -2.995530366897583 0.5015992522239685 0.3703371286392212 0.0 -2.996401786804199 0.5396823287010193 0.3712368309497833 0.0 -2.997277021408081 0.5779566168785095 0.3721972107887268 0.0 -2.998157024383545 0.6164352893829346 0.3732191026210785 0.0 -2.999041795730591 0.6551315784454346 0.37430328130722046 0.0 -2.999932289123535 0.694059431552887 0.3754507005214691 0.0 -3.0008280277252197 0.7332324981689453 0.37666216492652893 0.0 -3.001729965209961 0.77266526222229 0.37793880701065063 0.0 -3.0026378631591797 0.812372088432312 0.37928158044815063 0.0 -3.0035526752471924 0.8523682355880737 0.38069161772727966 0.0 -3.00447416305542 0.8926689624786377 0.3821701109409332 0.0 -3.0054032802581787 0.9332901835441589 0.3837183713912964 0.0 -3.0063395500183105 0.9742478728294373 0.38533756136894226 0.0 -3.007284641265869 1.015559196472168 0.3870292901992798 0.0 -3.008237838745117 1.0572410821914673 0.388794869184494 0.0 -3.00920033454895 1.0993114709854126 0.3906359076499939 0.0 -3.01017165184021 1.1417884826660156 0.39255401492118835 0.0 -3.011152982711792 1.184691309928894 0.39455097913742065 0.0 -3.0121443271636963 1.2280395030975342 0.39662855863571167 0.0 -3.0131466388702393 1.2718532085418701 0.3987886905670166 0.0 -0.24398548901081085 0.7587764859199524 0.09718474000692368 0.0 -0.22804057598114014 0.7402867078781128 0.0944504514336586 0.0 -0.21296575665473938 0.7228050827980042 0.09187915176153183 0.0 -0.19868791103363037 0.7062478065490723 0.08945732563734055 0.0 -0.1851413995027542 0.6905385255813599 0.08717268705368042 0.0 -0.1722678393125534 0.6756100654602051 0.08501444011926651 0.0 -0.16001442074775696 0.6614003777503967 0.08297266066074371 0.0 -0.14833399653434753 0.6478549838066101 0.08103856444358826 0.0 -0.1371840387582779 0.6349247694015503 0.07920427620410919 0.0 -0.12652623653411865 0.622565746307373 0.07746270298957825 0.0 -0.11632553488016129 0.6107367873191833 0.07580727338790894 0.0 -0.10655026137828827 0.5994011759757996 0.07423210144042969 0.0 -0.09717147797346115 0.5885249972343445 0.07273175567388535 0.0 -0.08854416012763977 0.580577552318573 0.07160969078540802 0.0 -0.08126949518918991 0.5806710124015808 0.07149261981248856 0.0 -0.07401750236749649 0.5807644128799438 0.07138672471046448 0.0 -0.06678586453199387 0.5808573961257935 0.07129187881946564 0.0 -0.059572335332632065 0.5809502005577087 0.07120802998542786 0.0 -0.05237464979290962 0.5810426473617554 0.07113509625196457 0.0 -0.04519062489271164 0.5811351537704468 0.07107304781675339 0.0 -0.038018036633729935 0.5812274217605591 0.07102182507514954 0.0 -0.030854707583785057 0.5813196897506714 0.07098140567541122 0.0 -0.023698441684246063 0.5814117789268494 0.07095172256231308 0.0 -0.016547072678804398 0.5815036296844482 0.07093276083469391 0.0 -0.009398449212312698 0.5815955400466919 0.07092452794313431 0.0 -0.002250405726954341 0.5816876292228699 0.07092702388763428 0.0 --0.004899219144135714 0.5817794799804688 0.07094021141529083 0.0 --0.012052585370838642 0.581871509552002 0.07096413522958755 0.0 --0.019211864098906517 0.5819637179374695 0.07099881768226624 0.0 --0.02637922205030918 0.582055926322937 0.07104425132274628 0.0 --0.03355684131383896 0.5821481943130493 0.07110048830509186 0.0 --0.04074692726135254 0.5822408199310303 0.07116758078336716 0.0 --0.04795167222619057 0.5823333859443665 0.07124555110931396 0.0 --0.05517331138253212 0.5824261903762817 0.07133448123931885 0.0 --0.06241411715745926 0.5825194120407104 0.07143445312976837 0.0 --0.06967633217573166 0.5826128125190735 0.07154551893472672 0.0 --0.07696226239204407 0.5827065110206604 0.07166776806116104 0.0 --0.08427425473928452 0.5828006267547607 0.07180130481719971 0.0 --0.09161464869976044 0.5828949809074402 0.07194621860980988 0.0 --0.09898588061332703 0.5829899907112122 0.07210266590118408 0.0 --0.10639029741287231 0.5830850601196289 0.07227068394422531 0.0 --0.11383046209812164 0.583180844783783 0.07245047390460968 0.0 --0.12130890041589737 0.58327716588974 0.07264218479394913 0.0 --0.12882809340953827 0.5833737254142761 0.07284589856863022 0.0 --0.1363907754421234 0.5834711790084839 0.07306186109781265 0.0 --0.14399954676628113 0.5835689306259155 0.07329017668962479 0.0 --0.15165719389915466 0.5836674571037292 0.07353108376264572 0.0 --0.15936653316020966 0.5837666392326355 0.07378476113080978 0.0 --0.1671304553747177 0.5838666558265686 0.07405143231153488 0.0 --0.17495185136795044 0.5839672684669495 0.07433129101991653 0.0 --0.18283377587795258 0.5840686559677124 0.07462458312511444 0.0 --0.19077934324741364 0.5841708183288574 0.0749315544962883 0.0 --0.19879180192947388 0.5842739343643188 0.0752524882555008 0.0 --0.20687440037727356 0.5843779444694519 0.07558764517307281 0.0 --0.2150304913520813 0.584482729434967 0.07593730092048645 0.0 --0.2232637107372284 0.5845886468887329 0.07630180567502975 0.0 --0.23157759010791779 0.58469557762146 0.07668145000934601 0.0 --0.2399759292602539 0.5848037004470825 0.07707661390304565 0.0 --0.2484624981880188 0.5849127769470215 0.07748761028051376 0.0 --0.25704142451286316 0.5850231647491455 0.07791485637426376 0.0 --0.2657168209552765 0.5851348638534546 0.07835875451564789 0.0 --0.27449285984039307 0.5852476954460144 0.07881968468427658 0.0 --0.283374160528183 0.585361897945404 0.07929812371730804 0.0 --0.29236531257629395 0.5854775905609131 0.07979454100131989 0.0 --0.30147117376327515 0.5855948328971863 0.0803094357252121 0.0 --0.31069663166999817 0.5857135057449341 0.08084327727556229 0.0 --0.3200470507144928 0.5858338475227356 0.08139665424823761 0.0 --0.32952776551246643 0.5859557390213013 0.08197011798620224 0.0 --0.3391444683074951 0.586079478263855 0.08256427943706512 0.0 --0.34890303015708923 0.5862048864364624 0.08317975699901581 0.0 --0.3588097393512726 0.5863323211669922 0.0838172435760498 0.0 --0.3688710629940033 0.5864618420600891 0.08447745442390442 0.0 --0.37909364700317383 0.5865932703018188 0.08516108989715576 0.0 --0.3894847333431244 0.5867271423339844 0.08586899191141129 0.0 --0.4000515043735504 0.5868630409240723 0.08660191297531128 0.0 --0.41080179810523987 0.5870012640953064 0.08736075460910797 0.0 --0.4217439293861389 0.5871420502662659 0.08814647048711777 0.0 --0.43288639187812805 0.5872854590415955 0.08896000683307648 0.0 --0.4442381262779236 0.5874315500259399 0.08980238437652588 0.0 --0.4558086395263672 0.5875803828239441 0.09067468345165253 0.0 --0.46760785579681396 0.5877320766448975 0.09157805144786835 0.0 --0.47964659333229065 0.5878871083259583 0.09251374751329422 0.0 --0.4919355809688568 0.5880451202392578 0.09348299354314804 0.0 --0.5044867396354675 0.5882065296173096 0.09448719024658203 0.0 --0.5173124670982361 0.5883715748786926 0.09552779048681259 0.0 --0.5304258465766907 0.588540256023407 0.09660632163286209 0.0 --0.5438408851623535 0.5887129902839661 0.09772443026304245 0.0 --0.5575719475746155 0.5888895392417908 0.09888380020856857 0.0 --0.5716350674629211 0.5890705585479736 0.10008633136749268 0.0 --0.5860464572906494 0.5892558097839355 0.10133392363786697 0.0 --0.6008241772651672 0.5894460678100586 0.10262876003980637 0.0 --0.6159864068031311 0.5896409749984741 0.10397296398878098 0.0 --0.6315538287162781 0.589841365814209 0.10536903142929077 0.0 --0.64754718542099 0.5900470614433289 0.10681942105293274 0.0 --0.6639896631240845 0.5902586579322815 0.10832689702510834 0.0 --0.6809054017066956 0.5904762744903564 0.10989435762166977 0.0 --0.6983204483985901 0.5907002687454224 0.11152493208646774 0.0 --0.716262936592102 0.5909311175346375 0.11322199553251266 0.0 --0.7347627878189087 0.5911691784858704 0.11498913913965225 0.0 --0.7589833736419678 0.5954403281211853 0.11762546747922897 0.0 --0.7862511873245239 0.6013709306716919 0.12069681286811829 0.0 --0.8149856328964233 0.6076205372810364 0.12395208328962326 0.0 --0.8453179597854614 0.6142177581787109 0.12740761041641235 0.0 --0.8773947954177856 0.6211943626403809 0.13108167052268982 0.0 --0.9113821983337402 0.6285866498947144 0.1349949836730957 0.0 --0.9474665522575378 0.6364348530769348 0.13917073607444763 0.0 --0.9858607649803162 0.6447855234146118 0.14363548159599304 0.0 --1.0268064737319946 0.6536911129951477 0.1484193652868271 0.0 --1.0705803632736206 0.6632118225097656 0.15355685353279114 0.0 --1.1175003051757812 0.6734166741371155 0.15908759832382202 0.0 --1.1894035339355469 0.696966290473938 0.16809162497520447 0.0 --1.3184125423431396 0.7509511113166809 0.18500542640686035 0.0 -0.24398618936538696 0.7587786316871643 0.12535694241523743 0.0 -0.22804100811481476 0.7402880787849426 0.12182990461587906 0.0 -0.21296624839305878 0.7228067517280579 0.11851329356431961 0.0 -0.19868825376033783 0.7062489986419678 0.11538933962583542 0.0 -0.18514184653759003 0.6905401945114136 0.1124425157904625 0.0 -0.17226815223693848 0.6756112575531006 0.10965856909751892 0.0 -0.16001464426517487 0.6614012718200684 0.10702485591173172 0.0 -0.14833438396453857 0.6478567719459534 0.10453025251626968 0.0 -0.13718438148498535 0.6349263191223145 0.10216420143842697 0.0 -0.12652646005153656 0.622566819190979 0.0999177098274231 0.0 -0.11632578074932098 0.6107380986213684 0.0977824330329895 0.0 -0.10655044764280319 0.5994022488594055 0.09575061500072479 0.0 -0.09717155247926712 0.5885254144668579 0.09381525218486786 0.0 -0.08854421973228455 0.5805779099464417 0.09236791729927063 0.0 -0.08126954734325409 0.5806713700294495 0.09221690893173218 0.0 -0.07401755452156067 0.5807647705078125 0.09208031743764877 0.0 -0.06678590923547745 0.5808578133583069 0.09195798635482788 0.0 -0.05957237631082535 0.5809506177902222 0.09184983372688293 0.0 -0.05237468332052231 0.581043004989624 0.09175574034452438 0.0 -0.04519065096974373 0.5811354517936707 0.09167569875717163 0.0 -0.03801807016134262 0.5812278389930725 0.0916096493601799 0.0 -0.03085472621023655 0.58132004737854 0.09155749529600143 0.0 -0.02369845099747181 0.5814120173454285 0.09151919186115265 0.0 -0.016547083854675293 0.5815039873123169 0.09149475395679474 0.0 -0.009398456662893295 0.5815959572792053 0.09148414433002472 0.0 -0.002250406425446272 0.5816878080368042 0.0914873257279396 0.0 --0.004899223335087299 0.581779956817627 0.09150438010692596 0.0 --0.012052596546709538 0.5818719863891602 0.09153524041175842 0.0 --0.019211871549487114 0.5819639563560486 0.09157993644475937 0.0 --0.026379233226180077 0.5820561647415161 0.09163854271173477 0.0 --0.03355685994029045 0.582148551940918 0.09171109646558762 0.0 --0.04074694961309433 0.5822411179542542 0.09179764240980148 0.0 --0.04795170575380325 0.5823338031768799 0.09189822524785995 0.0 --0.055173344910144806 0.5824265480041504 0.092012919485569 0.0 --0.06241416186094284 0.5825198292732239 0.09214188903570175 0.0 --0.06967638432979584 0.5826132297515869 0.09228515625 0.0 --0.07696232944726944 0.5827069878578186 0.09244284778833389 0.0 --0.0842742919921875 0.5828008651733398 0.09261506050825119 0.0 --0.091614730656147 0.5828955173492432 0.0928020253777504 0.0 --0.09898592531681061 0.582990288734436 0.0930037721991539 0.0 --0.10639037936925888 0.5830855965614319 0.0932205319404602 0.0 --0.11383054405450821 0.5831812024116516 0.09345243126153946 0.0 --0.12130895256996155 0.5832774639129639 0.09369968622922897 0.0 --0.12882818281650543 0.5833741426467896 0.09396247565746307 0.0 --0.1363908350467682 0.583471417427063 0.09424101561307907 0.0 --0.1439996212720871 0.5835692286491394 0.09453553706407547 0.0 --0.15165728330612183 0.5836677551269531 0.09484627097845078 0.0 --0.15936662256717682 0.5837669372558594 0.09517348557710648 0.0 --0.16713055968284607 0.5838669538497925 0.09551745653152466 0.0 --0.1749519258737564 0.5839675068855286 0.09587842971086502 0.0 --0.18283383548259735 0.5840688347816467 0.09625672549009323 0.0 --0.1907794177532196 0.5841710567474365 0.09665269404649734 0.0 --0.19879190623760223 0.5842742323875427 0.09706667810678482 0.0 --0.20687447488307953 0.5843781232833862 0.09749896824359894 0.0 --0.21503065526485443 0.5844831466674805 0.09795001894235611 0.0 --0.22326387465000153 0.5845890641212463 0.09842018783092499 0.0 --0.23157772421836853 0.5846959352493286 0.0989098772406578 0.0 --0.23997603356838226 0.5848039388656616 0.09941956400871277 0.0 --0.24846266210079193 0.5849131941795349 0.09994972497224808 0.0 --0.2570416033267975 0.5850235819816589 0.10050082951784134 0.0 --0.2657169699668884 0.585135281085968 0.10107339918613434 0.0 --0.2744930386543274 0.5852480530738831 0.10166794061660767 0.0 --0.2833743989467621 0.585362434387207 0.10228510200977325 0.0 --0.29236552119255066 0.5854780077934265 0.10292540490627289 0.0 --0.3014713525772095 0.5855951905250549 0.10358952730894089 0.0 --0.3106968402862549 0.5857138633728027 0.10427813231945038 0.0 --0.3200472593307495 0.5858342051506042 0.10499192774295807 0.0 --0.32952794432640076 0.5859560966491699 0.10573161393404007 0.0 --0.3391447067260742 0.5860798954963684 0.10649802535772324 0.0 --0.3489033579826355 0.5862054824829102 0.10729194432497025 0.0 --0.35881009697914124 0.5863329172134399 0.10811422765254974 0.0 --0.36887142062187195 0.5864623785018921 0.10896581411361694 0.0 --0.3790939152240753 0.5865936875343323 0.10984760522842407 0.0 --0.3894849419593811 0.5867274403572083 0.11076068878173828 0.0 --0.4000517427921295 0.5868633985519409 0.11170608550310135 0.0 --0.41080212593078613 0.5870017409324646 0.11268492788076401 0.0 --0.4217442572116852 0.5871425271034241 0.11369839310646057 0.0 --0.43288663029670715 0.5872858166694641 0.11474773287773132 0.0 --0.4442383944988251 0.5874319076538086 0.1158342957496643 0.0 --0.4558088481426239 0.587580680847168 0.11695945262908936 0.0 --0.467608243227005 0.5877325534820557 0.11812472343444824 0.0 --0.47964680194854736 0.5878873467445374 0.11933161318302155 0.0 --0.49193599820137024 0.588045597076416 0.12058187276124954 0.0 --0.5044872760772705 0.5882071852684021 0.12187720835208893 0.0 --0.5173128843307495 0.588371992111206 0.12321941554546356 0.0 --0.5304262638092041 0.5885407328605652 0.12461058795452118 0.0 --0.5438411831855774 0.5887133479118347 0.12605279684066772 0.0 --0.5575724244117737 0.588890016078949 0.12754826247692108 0.0 --0.5716354250907898 0.5890709161758423 0.12909936904907227 0.0 --0.5860470533370972 0.5892564058303833 0.13070866465568542 0.0 --0.6008245944976807 0.5894465446472168 0.13237881660461426 0.0 --0.6159870624542236 0.5896416306495667 0.13411271572113037 0.0 --0.631554365158081 0.589841902256012 0.13591346144676208 0.0 --0.647547721862793 0.5900475382804871 0.13778427243232727 0.0 --0.6639901995658875 0.5902591347694397 0.13972873985767365 0.0 --0.6809059977531433 0.5904768109321594 0.14175057411193848 0.0 --0.6983211636543274 0.5907008647918701 0.14385384321212769 0.0 --0.7162637710571289 0.5909318327903748 0.1460428684949875 0.0 --0.7347635626792908 0.5911697745323181 0.14832226932048798 0.0 --0.7589842081069946 0.5954409837722778 0.15172281861305237 0.0 --0.7862517833709717 0.6013714075088501 0.1556844264268875 0.0 --0.8149864077568054 0.6076210737228394 0.15988336503505707 0.0 --0.8453192114830017 0.6142187118530273 0.16434067487716675 0.0 --0.8773958086967468 0.6211950778961182 0.1690797358751297 0.0 --0.9113827347755432 0.6285870671272278 0.17412734031677246 0.0 --0.9474676847457886 0.6364355683326721 0.17951366305351257 0.0 --0.9858614206314087 0.6447859406471252 0.18527255952358246 0.0 --1.0268073081970215 0.6536917090415955 0.19144321978092194 0.0 --1.0705814361572266 0.6632124781608582 0.1980699896812439 0.0 --1.117501974105835 0.6734176278114319 0.2052040994167328 0.0 --1.189406156539917 0.6969678997993469 0.21681839227676392 0.0 --1.3184162378311157 0.750953197479248 0.2386353313922882 0.0 -0.24398669600486755 0.7587801814079285 0.15383818745613098 0.0 -0.22804145514965057 0.7402895092964172 0.14950978755950928 0.0 -0.21296653151512146 0.7228077054023743 0.14543955028057098 0.0 -0.19868877530097961 0.7062508463859558 0.14160601794719696 0.0 -0.18514226377010345 0.6905417442321777 0.1379896104335785 0.0 -0.17226846516132355 0.6756125092506409 0.1345731019973755 0.0 -0.16001494228839874 0.6614025831222534 0.13134102523326874 0.0 -0.14833465218544006 0.6478579044342041 0.12827961146831512 0.0 -0.1371847540140152 0.6349280476570129 0.12537610530853271 0.0 -0.12652677297592163 0.6225683689117432 0.12261918932199478 0.0 -0.11632595211267471 0.61073899269104 0.11999865621328354 0.0 -0.10655049234628677 0.5994024872779846 0.11750508099794388 0.0 -0.09717181324958801 0.5885270237922668 0.11513026803731918 0.0 -0.08854424953460693 0.5805781483650208 0.11335382610559464 0.0 -0.08126960694789886 0.5806717872619629 0.11316855996847153 0.0 -0.07401757687330246 0.5807649493217468 0.11300088465213776 0.0 -0.06678593158721924 0.5808579921722412 0.11285075545310974 0.0 -0.05957239866256714 0.5809508562088013 0.11271803826093674 0.0 -0.05237472802400589 0.581043541431427 0.11260262876749039 0.0 -0.045190680772066116 0.5811358690261841 0.11250437796115875 0.0 -0.03801808878779411 0.5812281370162964 0.11242330819368362 0.0 -0.030854739248752594 0.5813202857971191 0.11235928535461426 0.0 -0.0236984696239233 0.5814124345779419 0.11231233179569244 0.0 -0.016547096893191338 0.5815044045448303 0.11228232830762863 0.0 -0.009398460388183594 0.5815962553024292 0.11226927489042282 0.0 -0.0022504085209220648 0.5816883444786072 0.11227323114871979 0.0 --0.0048992265947163105 0.5817803740501404 0.11229413747787476 0.0 --0.012052602134644985 0.581872284412384 0.11233198642730713 0.0 --0.019211886450648308 0.581964373588562 0.11238686740398407 0.0 --0.02637924998998642 0.5820565223693848 0.11245877295732498 0.0 --0.03355688229203224 0.5821489691734314 0.11254781484603882 0.0 --0.040746960788965225 0.5822412371635437 0.11265397071838379 0.0 --0.047951724380254745 0.582334041595459 0.11277743428945541 0.0 --0.055173393338918686 0.5824270248413086 0.11291824281215668 0.0 --0.062414202839136124 0.5825202465057373 0.11307648569345474 0.0 --0.06967642158269882 0.5826135873794556 0.11325228214263916 0.0 --0.07696236670017242 0.5827072262763977 0.11344578862190247 0.0 --0.08427436649799347 0.582801342010498 0.11365717649459839 0.0 --0.09161476045846939 0.5828956961631775 0.11388656497001648 0.0 --0.09898596256971359 0.5829905271530151 0.11413415521383286 0.0 --0.10639043152332306 0.583085834980011 0.11440016329288483 0.0 --0.11383061110973358 0.5831815600395203 0.11468476802110672 0.0 --0.12130900472402573 0.583277702331543 0.11498818546533585 0.0 --0.1288282573223114 0.5833745002746582 0.11531069874763489 0.0 --0.13639089465141296 0.5834716558456421 0.11565250158309937 0.0 --0.14399974048137665 0.5835697054862976 0.11601397395133972 0.0 --0.15165738761425018 0.5836681723594666 0.11639530211687088 0.0 --0.15936672687530518 0.583767294883728 0.11679685115814209 0.0 --0.16713066399097443 0.5838673114776611 0.117218978703022 0.0 --0.17495207488536835 0.5839679837226868 0.1176619827747345 0.0 --0.1828339844942093 0.5840693116188049 0.11812622845172882 0.0 --0.19077952206134796 0.5841713547706604 0.1186121255159378 0.0 --0.19879205524921417 0.5842747092247009 0.11912018805742264 0.0 --0.2068745642900467 0.5843784213066101 0.11965066194534302 0.0 --0.21503080427646637 0.5844835638999939 0.12020422518253326 0.0 --0.22326397895812988 0.5845893621444702 0.12078117579221725 0.0 --0.23157790303230286 0.584696352481842 0.12138216197490692 0.0 --0.2399761974811554 0.584804356098175 0.12200764566659927 0.0 --0.24846288561820984 0.5849136710166931 0.12265828251838684 0.0 --0.25704169273376465 0.585023820400238 0.12333453446626663 0.0 --0.265717089176178 0.5851355195045471 0.12403719872236252 0.0 --0.2744932472705841 0.5852485299110413 0.12476686388254166 0.0 --0.28337445855140686 0.5853625535964966 0.12552417814731598 0.0 --0.292365700006485 0.5854784250259399 0.12631000578403473 0.0 --0.3014715015888214 0.5855954885482788 0.12712499499320984 0.0 --0.3106969892978668 0.5857141017913818 0.12797005474567413 0.0 --0.32004740834236145 0.5858344435691833 0.12884600460529327 0.0 --0.32952821254730225 0.5859565734863281 0.12975379824638367 0.0 --0.3391449451446533 0.5860803127288818 0.13069432973861694 0.0 --0.3489035665988922 0.5862058401107788 0.13166861236095428 0.0 --0.35881027579307556 0.5863332152366638 0.13267771899700165 0.0 --0.3688715696334839 0.5864626169204712 0.13372276723384857 0.0 --0.3790942132472992 0.5865941643714905 0.13480493426322937 0.0 --0.3894851803779602 0.5867277979850769 0.13592545688152313 0.0 --0.40005210041999817 0.5868639349937439 0.1370856761932373 0.0 --0.41080242395401 0.587002158164978 0.13828688859939575 0.0 --0.42174458503723145 0.5871430039405823 0.13953062891960144 0.0 --0.43288689851760864 0.5872861742973328 0.14081835746765137 0.0 --0.44423869252204895 0.587432324886322 0.14215180277824402 0.0 --0.45580926537513733 0.5875811576843262 0.14353260397911072 0.0 --0.4676031470298767 0.5877261757850647 0.1449609249830246 0.0 --0.47964155673980713 0.5878809094429016 0.1464419960975647 0.0 --0.4919305741786957 0.5880391597747803 0.14797629415988922 0.0 --0.5044816732406616 0.5882006287574768 0.14956587553024292 0.0 --0.5173072218894958 0.5883655548095703 0.15121304988861084 0.0 --0.5304205417633057 0.588534414768219 0.15292030572891235 0.0 --0.5438351631164551 0.5887068510055542 0.15469011664390564 0.0 --0.5575664639472961 0.5888836979866028 0.1565253883600235 0.0 --0.5716291666030884 0.5890644788742065 0.1584288328886032 0.0 --0.586040735244751 0.5892500877380371 0.160403773188591 0.0 --0.6008181571960449 0.5894402265548706 0.16245336830615997 0.0 --0.6159802675247192 0.5896350741386414 0.16458113491535187 0.0 --0.6315473914146423 0.5898353457450867 0.16679096221923828 0.0 --0.6475408673286438 0.5900412797927856 0.16908687353134155 0.0 --0.6639829277992249 0.590252697467804 0.17147304117679596 0.0 --0.6808985471725464 0.5904703140258789 0.17395423352718353 0.0 --0.6983135342597961 0.5906943678855896 0.17653530836105347 0.0 --0.7162559032440186 0.5909253358840942 0.17922165989875793 0.0 --0.7347556948661804 0.5911634564399719 0.1820189356803894 0.0 --0.7589738368988037 0.5954328775405884 0.18619149923324585 0.0 --0.7862419486045837 0.6013638377189636 0.1910533457994461 0.0 --0.8149760365486145 0.6076133847236633 0.19620616734027863 0.0 --0.8453078269958496 0.6142103672027588 0.20167595148086548 0.0 --0.8773844242095947 0.6211870312690735 0.20749174058437347 0.0 --0.9113712906837463 0.6285791397094727 0.21368615329265594 0.0 --0.947455108165741 0.6364271640777588 0.2202960103750229 0.0 --0.9858490824699402 0.6447778940200806 0.22736340761184692 0.0 --1.026794195175171 0.6536833047866821 0.23493586480617523 0.0 --1.0705674886703491 0.6632038950920105 0.24306809902191162 0.0 --1.1174874305725098 0.6734089255332947 0.25182291865348816 0.0 --1.1893770694732666 0.6969508528709412 0.26607272028923035 0.0 --1.318382740020752 0.7509341239929199 0.2928455173969269 0.0 -0.24397826194763184 0.7587539553642273 0.18269672989845276 0.0 -0.228033646941185 0.7402641773223877 0.17755642533302307 0.0 -0.2129596322774887 0.7227842807769775 0.1727229505777359 0.0 -0.19868209958076477 0.70622718334198 0.16817009449005127 0.0 -0.18513624370098114 0.6905192732810974 0.16387546062469482 0.0 -0.172263041138649 0.675591230392456 0.15981818735599518 0.0 -0.16001002490520477 0.6613821983337402 0.15597990155220032 0.0 -0.1483299732208252 0.6478374600410461 0.15234406292438507 0.0 -0.13718046247959137 0.6349081993103027 0.14889593422412872 0.0 -0.1265230029821396 0.622549831867218 0.14562204480171204 0.0 -0.11632248759269714 0.6107208132743835 0.14250990748405457 0.0 -0.10654757171869278 0.5993860363960266 0.1395488679409027 0.0 -0.09716904908418655 0.588510274887085 0.1367284059524536 0.0 -0.08854284137487411 0.5805689096450806 0.13462041318416595 0.0 -0.0812683030962944 0.5806624889373779 0.1344003528356552 0.0 -0.07401642203330994 0.580755889415741 0.1342012882232666 0.0 -0.06678488850593567 0.5808489322662354 0.13402298092842102 0.0 -0.059571485966444016 0.580941915512085 0.13386540114879608 0.0 -0.05237390100955963 0.5810343623161316 0.1337282806634903 0.0 -0.0451899878680706 0.5811269283294678 0.13361166417598724 0.0 -0.038017500191926956 0.5812191367149353 0.1335153579711914 0.0 -0.030854273587465286 0.5813115239143372 0.13343939185142517 0.0 -0.0236981064081192 0.5814034938812256 0.13338357210159302 0.0 -0.01654684729874134 0.5814956426620483 0.1333479881286621 0.0 -0.009398317895829678 0.5815874338150024 0.13333247601985931 0.0 -0.002250374061986804 0.5816794633865356 0.13333715498447418 0.0 --0.004899151157587767 0.5817713737487793 0.13336196541786194 0.0 --0.012052422389388084 0.5818635821342468 0.13340698182582855 0.0 --0.019211603328585625 0.5819557905197144 0.13347217440605164 0.0 --0.02637885883450508 0.5820478796958923 0.13355757296085358 0.0 --0.033556386828422546 0.582140326499939 0.1336633265018463 0.0 --0.04074636846780777 0.5822327733039856 0.13378943502902985 0.0 --0.047951024025678635 0.5823255181312561 0.1339360475540161 0.0 --0.055172573775053024 0.5824183821678162 0.13410323858261108 0.0 --0.0624132864177227 0.5825116634368896 0.13429118692874908 0.0 --0.06967540085315704 0.5826050043106079 0.13449996709823608 0.0 --0.07696127146482468 0.5826990008354187 0.13472986221313477 0.0 --0.08427315950393677 0.5827929973602295 0.13498087227344513 0.0 --0.09161344915628433 0.5828873515129089 0.13525329530239105 0.0 --0.09898455440998077 0.5829821825027466 0.13554735481739044 0.0 --0.10638889670372009 0.5830774307250977 0.13586324453353882 0.0 --0.11382898688316345 0.5831732153892517 0.13620127737522125 0.0 --0.12130732834339142 0.5832695960998535 0.13656166195869446 0.0 --0.12882645428180695 0.583366334438324 0.13694466650485992 0.0 --0.13638898730278015 0.5834634900093079 0.13735060393810272 0.0 --0.14399772882461548 0.5835615992546082 0.13777990639209747 0.0 --0.15165527164936066 0.5836600065231323 0.1382327675819397 0.0 --0.15936455130577087 0.5837593674659729 0.13870969414710999 0.0 --0.16712833940982819 0.5838592052459717 0.13921098411083221 0.0 --0.17494963109493256 0.5839598178863525 0.1397370994091034 0.0 --0.18283145129680634 0.5840612053871155 0.14028845727443695 0.0 --0.1907769739627838 0.5841635465621948 0.14086559414863586 0.0 --0.1987893283367157 0.5842666625976562 0.14146891236305237 0.0 --0.20687179267406464 0.5843705534934998 0.14209896326065063 0.0 --0.2150278389453888 0.5844755172729492 0.14275631308555603 0.0 --0.2232610136270523 0.5845815539360046 0.1434415876865387 0.0 --0.23157477378845215 0.5846884846687317 0.14415529370307922 0.0 --0.2399730086326599 0.5847965478897095 0.1448981612920761 0.0 --0.24845950305461884 0.584905743598938 0.1456708163022995 0.0 --0.25703832507133484 0.585016131401062 0.14647403359413147 0.0 --0.26571354269981384 0.5851276516914368 0.14730846881866455 0.0 --0.27448952198028564 0.5852405428886414 0.14817501604557037 0.0 --0.2833707630634308 0.5853549242019653 0.1490744799375534 0.0 --0.29236188530921936 0.5854707360267639 0.15000773966312408 0.0 --0.3014675974845886 0.5855878591537476 0.15097565948963165 0.0 --0.3106929063796997 0.5857064127922058 0.1519792228937149 0.0 --0.32004329562187195 0.5858269333839417 0.15301957726478577 0.0 --0.32952380180358887 0.5859487652778625 0.15409761667251587 0.0 --0.33914047479629517 0.586072564125061 0.15521462261676788 0.0 --0.3488990068435669 0.5861981511116028 0.15637171268463135 0.0 --0.3588056266307831 0.5863255858421326 0.15757015347480774 0.0 --0.36886686086654663 0.5864551663398743 0.1588113009929657 0.0 --0.3790893256664276 0.586586594581604 0.16009649634361267 0.0 --0.3894801437854767 0.5867202281951904 0.16142722964286804 0.0 --0.4000469148159027 0.5868563055992126 0.16280512511730194 0.0 --0.410797119140625 0.5869945883750916 0.16423171758651733 0.0 --0.4217391908168793 0.5871354937553406 0.16570882499217987 0.0 --0.43288135528564453 0.5872786641120911 0.16723814606666565 0.0 --0.44423291087150574 0.587424635887146 0.16882172226905823 0.0 --0.45580339431762695 0.5875736474990845 0.17046162486076355 0.0 --0.4676026701927185 0.5877255797386169 0.17215994000434875 0.0 --0.4796411991119385 0.5878804922103882 0.1739189624786377 0.0 --0.49192991852760315 0.5880383849143982 0.1757410317659378 0.0 --0.5044810771942139 0.5881999731063843 0.17762890458106995 0.0 --0.5173065662384033 0.588364839553833 0.17958512902259827 0.0 --0.5304200649261475 0.5885338187217712 0.1816127598285675 0.0 --0.5438348650932312 0.5887064337730408 0.18371468782424927 0.0 --0.5575657486915588 0.5888829827308655 0.1858942061662674 0.0 --0.5716285705566406 0.589063823223114 0.18815483152866364 0.0 --0.5860400199890137 0.5892493724822998 0.19050030410289764 0.0 --0.6008173227310181 0.5894393920898438 0.19293442368507385 0.0 --0.615979790687561 0.5896346569061279 0.19546155631542206 0.0 --0.6315467953681946 0.5898348093032837 0.1980859786272049 0.0 --0.647540271282196 0.5900407433509827 0.2008126676082611 0.0 --0.6639823913574219 0.5902522206306458 0.20364658534526825 0.0 --0.680898129940033 0.5904699563980103 0.2065933346748352 0.0 --0.6983129978179932 0.5906939506530762 0.2096586972475052 0.0 --0.7162553668022156 0.590924859046936 0.21284906566143036 0.0 --0.7347549200057983 0.5911628603935242 0.21617116034030914 0.0 --0.7589729428291321 0.5954321026802063 0.22112657129764557 0.0 --0.7862405180931091 0.6013627648353577 0.22690051794052124 0.0 --0.8149745464324951 0.6076122522354126 0.2330201417207718 0.0 --0.8453063368797302 0.6142093539237976 0.2395162433385849 0.0 --0.8773828744888306 0.6211858987808228 0.24642322957515717 0.0 --0.9113694429397583 0.6285778284072876 0.2537798285484314 0.0 --0.9474536776542664 0.6364262104034424 0.26163002848625183 0.0 --0.9858468770980835 0.644776463508606 0.27002328634262085 0.0 --1.0267918109893799 0.6536818146705627 0.27901652455329895 0.0 --1.0705652236938477 0.6632025241851807 0.28867465257644653 0.0 --1.1174849271774292 0.6734073758125305 0.29907211661338806 0.0 --1.1893702745437622 0.6969467997550964 0.3159944713115692 0.0 --1.3183752298355103 0.7509298920631409 0.34779053926467896 0.0 -0.24397853016853333 0.7587547898292542 0.21202339231967926 0.0 -0.2280336618423462 0.7402642369270325 0.20605777204036713 0.0 -0.2129596322774887 0.7227842807769775 0.2004484087228775 0.0 -0.19868215918540955 0.7062273621559143 0.1951647847890854 0.0 -0.18513618409633636 0.6905190944671631 0.19018065929412842 0.0 -0.17226308584213257 0.6755914092063904 0.18547222018241882 0.0 -0.16001014411449432 0.6613827347755432 0.1810179054737091 0.0 -0.14833012223243713 0.6478381156921387 0.1767984926700592 0.0 -0.13718056678771973 0.6349086761474609 0.172796830534935 0.0 -0.12652303278446198 0.6225499510765076 0.16899728775024414 0.0 -0.11632263660430908 0.6107215881347656 0.16538578271865845 0.0 -0.10654748231172562 0.5993855595588684 0.16194909811019897 0.0 -0.09716905653476715 0.588510274887085 0.15867604315280914 0.0 -0.08854278922080994 0.5805685520172119 0.15622955560684204 0.0 -0.08126824349164963 0.5806621313095093 0.15597417950630188 0.0 -0.07401637732982635 0.5807555913925171 0.15574316680431366 0.0 -0.06678486615419388 0.5808486938476562 0.15553627908229828 0.0 -0.05957143008708954 0.580941379070282 0.15535330772399902 0.0 -0.05237388238310814 0.5810341238975525 0.1551942676305771 0.0 -0.04518995061516762 0.5811264514923096 0.1550588607788086 0.0 -0.03801747411489487 0.5812187790870667 0.15494713187217712 0.0 -0.030854254961013794 0.5813111662864685 0.15485896170139313 0.0 -0.02369808591902256 0.5814030766487122 0.15479415655136108 0.0 -0.016546834260225296 0.5814952254295349 0.15475288033485413 0.0 -0.009398315101861954 0.5815872550010681 0.15473493933677673 0.0 -0.002250372665002942 0.5816790461540222 0.1547403186559677 0.0 --0.004899149760603905 0.581771194934845 0.154769167304039 0.0 --0.012052415870130062 0.581863284111023 0.15482138097286224 0.0 --0.01921158842742443 0.5819553136825562 0.15489698946475983 0.0 --0.026378843933343887 0.5820475816726685 0.1549961268901825 0.0 --0.03355636075139046 0.5821398496627808 0.15511880815029144 0.0 --0.04074634984135628 0.5822325348854065 0.1552652269601822 0.0 --0.04795099422335625 0.5823251008987427 0.15543532371520996 0.0 --0.05517255514860153 0.5824182033538818 0.15562941133975983 0.0 --0.062413256615400314 0.5825113654136658 0.15584751963615417 0.0 --0.06967537105083466 0.5826047658920288 0.15608982741832733 0.0 --0.0769612044095993 0.5826984643936157 0.15635652840137482 0.0 --0.0842730924487114 0.5827925205230713 0.15664786100387573 0.0 --0.09161340445280075 0.5828871130943298 0.15696407854557037 0.0 --0.098984494805336 0.5829818248748779 0.1573053002357483 0.0 --0.1063888743519783 0.5830773115158081 0.1576719582080841 0.0 --0.11382891982793808 0.5831729173660278 0.15806418657302856 0.0 --0.12130721658468246 0.5832690596580505 0.1584823727607727 0.0 --0.12882636487483978 0.5833659768104553 0.15892690420150757 0.0 --0.13638891279697418 0.583463191986084 0.15939801931381226 0.0 --0.14399763941764832 0.5835612416267395 0.15989620983600616 0.0 --0.1516551673412323 0.5836596488952637 0.16042175889015198 0.0 --0.15936443209648132 0.5837589502334595 0.16097523272037506 0.0 --0.16712823510169983 0.583858847618103 0.16155700385570526 0.0 --0.1749495416879654 0.5839595198631287 0.16216757893562317 0.0 --0.18283134698867798 0.5840608477592468 0.162807434797287 0.0 --0.19077685475349426 0.5841631889343262 0.16347719728946686 0.0 --0.19878916442394257 0.584266185760498 0.16417734324932098 0.0 --0.20687167346477509 0.5843702554702759 0.16490857303142548 0.0 --0.21502773463726044 0.5844752192497253 0.1656714528799057 0.0 --0.2232607901096344 0.5845810174942017 0.16646665334701538 0.0 --0.2315746545791626 0.584688127040863 0.16729499399662018 0.0 --0.23997284471988678 0.5847961902618408 0.16815708577632904 0.0 --0.2484593540430069 0.5849053859710693 0.16905377805233002 0.0 --0.2570381760597229 0.5850157737731934 0.16998590528964996 0.0 --0.26571333408355713 0.5851272344589233 0.17095428705215454 0.0 --0.2744893729686737 0.5852402448654175 0.17195995151996613 0.0 --0.28337058424949646 0.5853545665740967 0.17300379276275635 0.0 --0.29236164689064026 0.5854702591896057 0.1740868091583252 0.0 --0.30146726965904236 0.5855872631072998 0.17521007359027863 0.0 --0.3106927275657654 0.5857061147689819 0.17637480795383453 0.0 --0.3200429677963257 0.5858263373374939 0.17758207023143768 0.0 --0.32952359318733215 0.5859483480453491 0.1788332164287567 0.0 --0.33914026618003845 0.5860722064971924 0.1801295429468155 0.0 --0.3488987386226654 0.5861976742744446 0.18147233128547668 0.0 --0.3588053584098816 0.5863251686096191 0.18286314606666565 0.0 --0.36886659264564514 0.5864547491073608 0.18430353701114655 0.0 --0.37908902764320374 0.5865861773490906 0.18579500913619995 0.0 --0.38947993516921997 0.5867199301719666 0.1873393952846527 0.0 --0.40004658699035645 0.5868558287620544 0.1889384239912033 0.0 --0.41079673171043396 0.5869939923286438 0.19059397280216217 0.0 --0.42173874378204346 0.587134838104248 0.19230815768241882 0.0 --0.43288111686706543 0.5872783064842224 0.1940830647945404 0.0 --0.4442327320575714 0.5874244570732117 0.1959208846092224 0.0 --0.45580294728279114 0.5875730514526367 0.1978238970041275 0.0 --0.4676022231578827 0.5877249836921692 0.19979484379291534 0.0 --0.4796407222747803 0.5878798961639404 0.2018362134695053 0.0 --0.49192970991134644 0.5880380868911743 0.20395086705684662 0.0 --0.5044807195663452 0.5881995558738708 0.20614172518253326 0.0 --0.5173061490058899 0.5883643627166748 0.20841191709041595 0.0 --0.530419647693634 0.5885334014892578 0.2107650488615036 0.0 --0.543834388256073 0.5887059569358826 0.21320435404777527 0.0 --0.5575652718544006 0.5888825058937073 0.21573373675346375 0.0 --0.5716280937194824 0.5890634059906006 0.21835723519325256 0.0 --0.5860394239425659 0.589248776435852 0.22107915580272675 0.0 --0.6008168458938599 0.5894389152526855 0.2239040583372116 0.0 --0.6159792542457581 0.589634120464325 0.22683680057525635 0.0 --0.631546139717102 0.5898342132568359 0.22988247871398926 0.0 --0.647539496421814 0.5900400876998901 0.23304682970046997 0.0 --0.6639819145202637 0.5902517437934875 0.23633570969104767 0.0 --0.8149730563163757 0.6076111793518066 0.2704240083694458 0.0 --0.8453049659729004 0.6142083406448364 0.27796289324760437 0.0 --0.8773812055587769 0.621184766292572 0.2859785258769989 0.0 --0.9113677740097046 0.6285766959190369 0.294515997171402 0.0 --0.9474517703056335 0.6364248991012573 0.3036262094974518 0.0 --0.9858450293540955 0.6447752118110657 0.31336677074432373 0.0 --1.0267897844314575 0.6536805033683777 0.323803573846817 0.0 --1.0705628395080566 0.6632009744644165 0.33501186966896057 0.0 --1.1174821853637695 0.6734057664871216 0.3470782935619354 0.0 --1.189361333847046 0.696941614151001 0.36671510338783264 0.0 diff --git a/open_place_recognition/src/dataset_from_rosbag_node.py b/open_place_recognition/src/dataset_from_rosbag_node.py index 5f49f4c..b8a6e24 100755 --- a/open_place_recognition/src/dataset_from_rosbag_node.py +++ b/open_place_recognition/src/dataset_from_rosbag_node.py @@ -2,313 +2,476 @@ import rclpy from rclpy.node import Node -from rclpy.time import Time +from rclpy.serialization import deserialize_message -# Messages we’ll be subscribing to: -from sensor_msgs.msg import Image, LaserScan # or PointCloud2 -from geometry_msgs.msg import PoseStamped +import rosbag2_py -# For writing images: -import os import cv2 import numpy as np - -import math -import struct - -def euler_to_quaternion(roll, pitch, yaw): +from cv_bridge import CvBridge +from sensor_msgs.msg import CompressedImage, PointCloud2 +from sensor_msgs.point_cloud2 import read_points + +import matplotlib +import matplotlib.pyplot as plt + +from pathlib import Path +from pandas import DataFrame +from typing import Dict, List, Tuple, Union +from tqdm import tqdm + +matplotlib.use("Agg") + +############################################################################### +# Helper functions (preprocessing) +############################################################################### +def closest_values_indices(in_array: np.ndarray, from_array: np.ndarray) -> np.ndarray: + """For each element in the first array find the closest value from the second array.""" + closest_idxs = np.zeros(len(in_array), dtype=np.int64) + for i, a_val in enumerate(in_array): + abs_diffs = np.abs(from_array - a_val) + closest_idxs[i] = np.argmin(abs_diffs) + return closest_idxs + + +def filter_timestamps( + pose_ts: np.ndarray, + front_ts: np.ndarray, + back_ts: np.ndarray, + lidar_ts: np.ndarray, + max_diff: int = 10000, +) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: + """ + Filter timestamps. For each pose_ts, find the closest front_ts, back_ts, lidar_ts + that differ by less than `max_diff`. Return the filtered indices. + """ + filtered_pose_idxs = [] + filtered_front_idxs = [] + filtered_back_idxs = [] + filtered_lidar_idxs = [] + + for i, ts in enumerate(pose_ts): + front_idx = closest_values_indices(np.array([ts]), front_ts)[0] + back_idx = closest_values_indices(np.array([ts]), back_ts)[0] + lidar_idx = closest_values_indices(np.array([ts]), lidar_ts)[0] + + if ( + abs(ts - front_ts[front_idx]) <= max_diff + and abs(ts - back_ts[back_idx]) <= max_diff + and abs(ts - lidar_ts[lidar_idx]) <= max_diff + ): + filtered_pose_idxs.append(i) + filtered_front_idxs.append(front_idx) + filtered_back_idxs.append(back_idx) + filtered_lidar_idxs.append(lidar_idx) + + return ( + np.array(filtered_pose_idxs), + np.array(filtered_front_idxs), + np.array(filtered_back_idxs), + np.array(filtered_lidar_idxs), + ) + + +def filter_by_distance_indices(utm_points: np.ndarray, distance: float = 5.0) -> np.ndarray: + """ + Filter points so that each point is ~ `distance` meters away from the previous one. + """ + filtered_points = np.array([0], dtype=int) # start with index 0 + for i in range(1, utm_points.shape[0]): + # distance from current to last filtered + right_dist = np.linalg.norm(utm_points[i] - utm_points[filtered_points[-1]]) + if right_dist >= distance: + left_dist = np.linalg.norm(utm_points[i - 1] - utm_points[filtered_points[-1]]) + if abs(right_dist - distance) < abs(left_dist - distance): + filtered_points = np.append(filtered_points, i) + else: + filtered_points = np.append(filtered_points, i - 1) + return filtered_points + + +def plot_track_map(utms: np.ndarray) -> np.ndarray: + """ + Plot a 2D track (X-Y) and return it as a BGR image (for saving via OpenCV). + """ + x, y = utms[:, 0], utms[:, 1] + x_min, x_max = np.min(x) - 2, np.max(x) + 2 + y_min, y_max = np.min(y) - 2, np.max(y) + 2 + fig, ax = plt.subplots(dpi=200) + ax.scatter(x, y, s=0.5) + ax.set_xlabel("x") + ax.set_xlim(x_min, x_max) + ax.set_ylabel("y") + ax.set_ylim(y_min, y_max) + ax.set_aspect("equal", adjustable="box") + fig.canvas.draw() + + # Convert canvas to image + img = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8) + img = img.reshape(fig.canvas.get_width_height()[::-1] + (3,)) + plt.close(fig) + + # convert from RGB to BGR + img_bgr = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + return img_bgr + + +############################################################################### +# Helper functions (reading + unpacking) +############################################################################### +def merge_dicts(dict1: Dict[str, List[int]], dict2: Dict[str, List[int]]) -> Dict[str, List[int]]: + """Merge two dicts of lists, appending values of matching keys.""" + for k in dict2: + dict1[k] += dict2[k] + return dict1 + + +def read_ros2_bag_messages( + bag_file_path: Path, + wanted_topics: List[str], + max_count: int = -1, +): + """ + Reads messages from a ROS 2 bag using rosbag2_py. + Yields tuples: (topic_name, message, time_ns). + """ + # Create storage and converter options to open the bag + storage_options = rosbag2_py.StorageOptions(uri=str(bag_file_path), storage_id="sqlite3") + converter_options = rosbag2_py.ConverterOptions( + input_serialization_format="cdr", + output_serialization_format="cdr", + ) + + reader = rosbag2_py.SequentialReader() + reader.open(storage_options, converter_options) + + # Map topic name -> type so we can deserialize messages properly + type_map = {} + for topic_metadata in reader.get_all_topics_and_types(): + if topic_metadata.name in wanted_topics: + type_map[topic_metadata.name] = topic_metadata.type + + count = 0 + while reader.has_next(): + (topic, raw_data, t) = reader.read_next() + if topic not in wanted_topics: + continue + # If the topic is known, we can figure out how to deserialize + if type_map[topic] == "sensor_msgs/msg/CompressedImage": + msg = deserialize_message(raw_data, CompressedImage) + elif type_map[topic] == "sensor_msgs/msg/PointCloud2": + msg = deserialize_message(raw_data, PointCloud2) + else: + # For other types: geometry_msgs/msg/TransformStamped, etc. + # This is a minimal example, add more if needed + msg = deserialize_message(raw_data, PointCloud2) # or appropriate type + count += 1 + yield (topic, msg, t) + if max_count > 0 and count >= max_count: + break + + +def list_images_and_points_ros2( + bag_file_path: Union[str, Path], + front_cam_topic: str, + back_cam_topic: str, + lidar_topic: str, +) -> Dict[str, List[int]]: """ - Convert Euler angles (roll, pitch, yaw) to quaternion (qx, qy, qz, qw). - Assuming roll = x-rotation, pitch = y-rotation, yaw = z-rotation. + Return timestamps for images and LiDAR from a ROS 2 bag file. """ - cy = math.cos(yaw * 0.5) - sy = math.sin(yaw * 0.5) - cp = math.cos(pitch * 0.5) - sp = math.sin(pitch * 0.5) - cr = math.cos(roll * 0.5) - sr = math.sin(roll * 0.5) - - qw = cr * cp * cy + sr * sp * sy - qx = sr * cp * cy - cr * sp * sy - qy = cr * sp * cy + sr * cp * sy - qz = cr * cp * sy - sr * sp * cy - return (qx, qy, qz, qw) - -class DatasetCreateNode(Node): + bag_file_path = Path(bag_file_path) + out_dict = {"front_cam": [], "back_cam": [], "lidar": []} + wanted_topics = [front_cam_topic, back_cam_topic, lidar_topic] + + for topic, msg, t_ns in tqdm( + read_ros2_bag_messages(bag_file_path, wanted_topics), + desc=f"Listing {bag_file_path.name}", + leave=False, + ): + if topic == front_cam_topic: + out_dict["front_cam"].append(t_ns) + elif topic == back_cam_topic: + out_dict["back_cam"].append(t_ns) + elif topic == lidar_topic: + out_dict["lidar"].append(t_ns) + + return out_dict + + +def export_from_bag_ros2( + bag_file_path: Union[str, Path], + output_dir: Union[str, Path], + timestamps_dict: Dict[str, np.ndarray], + front_cam_topic: str, + back_cam_topic: str, + lidar_topic: str, +): """ - This node subscribes to front camera, back camera, lidar, and pose topics - and builds a dataset in a specified output directory. - - The user can configure the following ROS parameters: - - front_camera_topic (default: /camera_front/image_raw) - - back_camera_topic (default: /camera_back/image_raw) - - lidar_topic (default: /scan) - - pose_topic (default: /robot_pose) - - output_path (default: ~/.ros/opr_dataset) - - track_name (default: 00_my_map) - - For each message received, the node: - - Decodes images and writes them to disk. - - Buffers topic timestamps and relevant data in memory. - - On shutdown, writes out a CSV describing all data. - - NOTE: This example is not time-synchronizing the topics. - Each message will appear in the CSV under its own stamp entry. + Extract images (PNG) and LiDAR points (BIN) from a ROS 2 bag file. """ + bag_file_path = Path(bag_file_path) + output_dir = Path(output_dir) + output_dir.mkdir(parents=True, exist_ok=True) + + front_cam_dir = output_dir / "front_cam" + front_cam_dir.mkdir(exist_ok=True) + back_cam_dir = output_dir / "back_cam" + back_cam_dir.mkdir(exist_ok=True) + lidar_dir = output_dir / "lidar" + lidar_dir.mkdir(exist_ok=True) + + bridge = CvBridge() + + # Turn them into sets for quick membership tests + front_cam_set = set(timestamps_dict["front_cam"].tolist()) + back_cam_set = set(timestamps_dict["back_cam"].tolist()) + lidar_set = set(timestamps_dict["lidar"].tolist()) + + wanted_topics = [front_cam_topic, back_cam_topic, lidar_topic] + + for topic, msg, t_ns in tqdm( + read_ros2_bag_messages(bag_file_path, wanted_topics), + desc=f"Exporting {bag_file_path.name}", + leave=False, + ): + if topic == front_cam_topic: + if t_ns in front_cam_set: + # msg is sensor_msgs/CompressedImage + cv_image = bridge.compressed_imgmsg_to_cv2(msg, desired_encoding="bgr8") + cv2.imwrite(str(front_cam_dir / f"{t_ns}.png"), cv_image) + elif topic == back_cam_topic: + if t_ns in back_cam_set: + cv_image = bridge.compressed_imgmsg_to_cv2(msg, desired_encoding="bgr8") + cv2.imwrite(str(back_cam_dir / f"{t_ns}.png"), cv_image) + elif topic == lidar_topic: + if t_ns in lidar_set: + # msg is sensor_msgs/PointCloud2 + points_arr = np.array(list(read_points(msg)), dtype=np.float32) + # scale intensity from [0..255] to [0..1], if needed + points_arr[:, 3] /= 255.0 + points_file_path = lidar_dir / f"{t_ns}.bin" + points_arr[:, :4].tofile(points_file_path) + + +def read_trajectory_bag_ros2(filepath: Path, trajectory_topic: str) -> DataFrame: + """ + Reads a trajectory from a ROS 2 bag file, if it’s stored as e.g. geometry_msgs/TransformStamped. + """ + # We assume the topic is geometry_msgs/msg/TransformStamped + # If your transform is a different type, adjust accordingly. + from geometry_msgs.msg import TransformStamped + + data = { + "timestamp": [], "tx": [], "ty": [], "tz": [], + "qx": [], "qy": [], "qz": [], "qw": [] + } + wanted_topics = [trajectory_topic] + + for topic, msg, t_ns in read_ros2_bag_messages(filepath, wanted_topics): + # deserialize as TransformStamped + # (adjust if your bag actually uses a different type) + trans_msg = deserialize_message(msg.serialize(), TransformStamped) + data["timestamp"].append(t_ns) + data["tx"].append(trans_msg.transform.translation.x) + data["ty"].append(trans_msg.transform.translation.y) + data["tz"].append(trans_msg.transform.translation.z) + data["qx"].append(trans_msg.transform.rotation.x) + data["qy"].append(trans_msg.transform.rotation.y) + data["qz"].append(trans_msg.transform.rotation.z) + data["qw"].append(trans_msg.transform.rotation.w) + + return DataFrame(data=data) + + +def read_trajectory_tum(filepath: Path) -> DataFrame: + """ + Reads a trajectory from a TUM file: + """ + data = {"timestamp": [], "tx": [], "ty": [], "tz": [], "qx": [], "qy": [], "qz": [], "qw": []} + with open(filepath, "r") as f: + for line in f: + vals = line.strip().split() + if len(vals) < 8: + continue + ts_float = float(vals[0]) + timestamp = int(ts_float * 1e9) # float secs -> nanosecs + + tx, ty, tz = [float(x) for x in vals[1:4]] + qx, qy, qz, qw = [float(x) for x in vals[4:8]] + data["timestamp"].append(timestamp) + data["tx"].append(tx) + data["ty"].append(ty) + data["tz"].append(tz) + data["qx"].append(qx) + data["qy"].append(qy) + data["qz"].append(qz) + data["qw"].append(qw) + return DataFrame(data=data) + + +############################################################################### +# Main Node +############################################################################### +class BagConverterNode(Node): def __init__(self): - super().__init__('dataset_create_node') - - # Declare parameters - self.declare_parameter('front_camera_topic', '/camera_front/image_raw') - self.declare_parameter('back_camera_topic', '/camera_back/image_raw') - self.declare_parameter('lidar_topic', '/scan') - self.declare_parameter('pose_topic', '/robot_pose') - self.declare_parameter('output_path', '~/.ros/opr_dataset') - self.declare_parameter('track_name', '00_my_map') - - # Retrieve parameter values - self.front_cam_topic = self.get_parameter('front_camera_topic').value - self.back_cam_topic = self.get_parameter('back_camera_topic').value - self.lidar_topic = self.get_parameter('lidar_topic').value - self.pose_topic = self.get_parameter('pose_topic').value - self.output_path = os.path.expanduser(self.get_parameter('output_path').value) - self.track_name = self.get_parameter('track_name').value - - # Prepare output directories - self.images_dir = os.path.join(self.output_path, "images") - os.makedirs(self.images_dir, exist_ok=True) - self.csv_path = os.path.join(self.output_path, "tracker.csv") - - # Data storage: dictionary keyed by stamp (float) - # We store a subdict with e.g.: - # { 'front_cam_ts': stamp_if_front_camera, - # 'back_cam_ts': stamp_if_back_camera, - # 'lidar_ts': stamp_if_lidar, - # 'pose_stamp': stamp_if_pose, - # 'x': ..., - # 'y': ..., - # 'z': ..., - # 'qx': ..., - # 'qy': ..., - # 'qz': ..., - # 'qw': ... } - # - # In practice, you may want more sophisticated time alignment or - # separate dictionaries for each topic, etc. - self.data = {} - - # Subscriptions - self.sub_front_cam = self.create_subscription( - Image, - self.front_cam_topic, - self.front_camera_callback, - 10 - ) - self.sub_back_cam = self.create_subscription( - Image, - self.back_cam_topic, - self.back_camera_callback, - 10 + super().__init__("bag_converter_node") + + # Declare ROS 2 parameters so we can override them in a launch file. + self.declare_parameter("input_dir", "/path/to/input_dir") + self.declare_parameter("trajectory_file", "/path/to/trajectory.db3") # e.g. a ROS 2 bag + self.declare_parameter("out_dir", "/path/to/output_dir") + self.declare_parameter("distance_threshold", 5.0) + self.declare_parameter("max_diff", 60000000) # 60 ms in nanoseconds + + # Topics to read from the bags + self.declare_parameter("front_cam_topic", "/zed_node/left/image_rect_color/compressed") + self.declare_parameter("back_cam_topic", "/realsense_back/color/image_raw/compressed") + self.declare_parameter("lidar_topic", "/velodyne_points") + # If your trajectory is published as geometry_msgs/TransformStamped on this topic: + self.declare_parameter("trajectory_topic", "/global_trajectory_0") + + # Fetch parameter values + input_dir = Path(self.get_parameter("input_dir").value) + trajectory_file = Path(self.get_parameter("trajectory_file").value) + out_dir = Path(self.get_parameter("out_dir").value) + distance_threshold = float(self.get_parameter("distance_threshold").value) + max_diff = int(self.get_parameter("max_diff").value) + + front_cam_topic = self.get_parameter("front_cam_topic").value + back_cam_topic = self.get_parameter("back_cam_topic").value + lidar_topic = self.get_parameter("lidar_topic").value + trajectory_topic = self.get_parameter("trajectory_topic").value + + # Run the core logic + self.run_conversion( + input_dir, + trajectory_file, + out_dir, + distance_threshold, + max_diff, + front_cam_topic, + back_cam_topic, + lidar_topic, + trajectory_topic, ) - self.sub_lidar = self.create_subscription( - LaserScan, - self.lidar_topic, - self.lidar_callback, - 10 + + def run_conversion( + self, + input_dir: Path, + trajectory_file: Path, + out_dir: Path, + dist_threshold: float, + max_diff_ns: int, + front_cam_topic: str, + back_cam_topic: str, + lidar_topic: str, + trajectory_topic: str, + ): + # Find all ROS 2 bag files in the input directory. By default, ros2 bag creates a folder + # (e.g. "my_bag") containing a "metadata.yaml" and .db3 files. + # You might want to gather all `.db3` or all subfolders. Adjust logic as needed. + bag_files_list = sorted( + f for f in input_dir.iterdir() + if f.is_file() and f.suffix in [".db3", ".mcap"] ) - self.sub_pose = self.create_subscription( - PoseStamped, - self.pose_callback, - 10 + + if not bag_files_list: + self.get_logger().error(f"No ROS 2 bag files found in {input_dir}") + return + + # Merge timestamps found in the bag files + timestamps_dict = {"front_cam": [], "back_cam": [], "lidar": []} + for bag_file_path in tqdm(bag_files_list, desc="Reading timestamps", position=0): + sub_dict = list_images_and_points_ros2( + bag_file_path, + front_cam_topic, + back_cam_topic, + lidar_topic, + ) + timestamps_dict = merge_dicts(timestamps_dict, sub_dict) + + # Convert all to NumPy + timestamps_dict = {k: np.array(v) for k, v in timestamps_dict.items()} + + # Read the trajectory from either a TUM file or a ROS 2 bag + if trajectory_file.suffix in [".db3", ".mcap"]: + # assume ROS 2 bag file with geometry_msgs/TransformStamped + poses_df = read_trajectory_bag_ros2(trajectory_file, trajectory_topic) + elif trajectory_file.suffix in [".tum", ".txt"]: + poses_df = read_trajectory_tum(trajectory_file) + else: + self.get_logger().error(f"Unsupported trajectory file: {trajectory_file}") + return + + # Filter timestamps + filtered_indices = filter_timestamps( + pose_ts=poses_df["timestamp"].to_numpy(), + front_ts=timestamps_dict["front_cam"], + back_ts=timestamps_dict["back_cam"], + lidar_ts=timestamps_dict["lidar"], + max_diff=max_diff_ns, ) - self.get_logger().info("DatasetCreateNode started. Listening to topics:") - self.get_logger().info(f" front_camera_topic: {self.front_cam_topic}") - self.get_logger().info(f" back_camera_topic: {self.back_cam_topic}") - self.get_logger().info(f" lidar_topic: {self.lidar_topic}") - self.get_logger().info(f" pose_topic: {self.pose_topic}") - self.get_logger().info(f"Writing results to: {self.output_path}") - - def _to_float_stamp(self, stamp_msg): - """ - Convert a builtin_interfaces.msg.Time or ROS2 stamp to a float of seconds. - """ - return float(stamp_msg.sec) + 1e-9 * float(stamp_msg.nanosec) - - def _ensure_entry(self, t: float): - """ - Ensure our data dictionary has an entry for this time. - Returns the subdict for that time. - """ - if t not in self.data: - self.data[t] = { - "front_cam_ts": 0, - "back_cam_ts": 0, - "lidar_ts": 0, - # We'll store the pose separately: - "pose_ts": 0, - "tx": 0.0, - "ty": 0.0, - "tz": 0.0, - "qx": 0.0, - "qy": 0.0, - "qz": 0.0, - "qw": 1.0 - } - return self.data[t] - - def front_camera_callback(self, msg: Image): - """ - Front camera image callback. - Write out the image to file, store timestamp in our dictionary. - """ - stamp_float = self._to_float_stamp(msg.header.stamp) - entry = self._ensure_entry(stamp_float) - - # Mark that we have a front camera image at this time - entry["front_cam_ts"] = stamp_float - - # Decode the image if it's something like raw or compressed: - # We'll assume it's an 8UC3 (BGR) or 8UC1 for demonstration. - # The encoding can vary (e.g. 'bgr8', 'rgb8', 'mono8', etc.). - # We demonstrate a simple approach with OpenCV. - try: - # Convert ROS Image (raw bytes) to a NumPy array - dtype = np.uint8 - channels = 3 - if msg.encoding == 'mono8': - channels = 1 - # Construct a 2D array from the raw data - img_np = np.frombuffer(msg.data, dtype=dtype).reshape(msg.height, msg.width, channels) - - # If needed to convert from RGB->BGR or vice versa - # depending on the encoding. Here we assume it's already BGR. - # If it was 'rgb8', you might do: img_np = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR) - - # Write to disk - out_name = f"front_{stamp_float:.6f}.png" - out_path = os.path.join(self.images_dir, out_name) - cv2.imwrite(out_path, img_np) - except Exception as e: - self.get_logger().warn(f"Front camera image decode failed at stamp {stamp_float}: {e}") - - def back_camera_callback(self, msg: Image): - """ - Back camera image callback. - """ - stamp_float = self._to_float_stamp(msg.header.stamp) - entry = self._ensure_entry(stamp_float) - entry["back_cam_ts"] = stamp_float - - try: - dtype = np.uint8 - channels = 3 - if msg.encoding == 'mono8': - channels = 1 - img_np = np.frombuffer(msg.data, dtype=dtype).reshape(msg.height, msg.width, channels) - - out_name = f"back_{stamp_float:.6f}.png" - out_path = os.path.join(self.images_dir, out_name) - cv2.imwrite(out_path, img_np) - except Exception as e: - self.get_logger().warn(f"Back camera image decode failed at stamp {stamp_float}: {e}") - - def lidar_callback(self, msg: LaserScan): - """ - Example LIDAR callback. We only store the timestamp here. - If needed, you could also dump the data (ranges, intensities) to disk. - """ - stamp_float = self._to_float_stamp(msg.header.stamp) - entry = self._ensure_entry(stamp_float) - entry["lidar_ts"] = stamp_float - # If you want to save the entire scan, you might do so here. - # E.g., out_name = f"lidar_{stamp_float:.6f}.txt" or .csv - # For demonstration, we only store the timestamp in memory. - - def pose_callback(self, msg: PoseStamped): - """ - Pose callback. We'll store the pose in our dictionary. - """ - stamp_float = self._to_float_stamp(msg.header.stamp) - entry = self._ensure_entry(stamp_float) - entry["pose_ts"] = stamp_float - - # Extract position - px = msg.pose.position.x - py = msg.pose.position.y - pz = msg.pose.position.z - - # Extract orientation - qx = msg.pose.orientation.x - qy = msg.pose.orientation.y - qz = msg.pose.orientation.z - qw = msg.pose.orientation.w - - entry["tx"] = px - entry["ty"] = py - entry["tz"] = pz - entry["qx"] = qx - entry["qy"] = qy - entry["qz"] = qz - entry["qw"] = qw - - def write_csv(self): - """ - Write out a CSV of all the data we've collected. - """ - self.get_logger().info(f"Writing CSV to: {self.csv_path}") - - with open(self.csv_path, 'w') as f: - f.write("track,floor,timestamp,front_cam_ts,back_cam_ts,lidar_ts,tx,ty,tz,qx,qy,qz,qw\n") - - # We do not have a 'floor' concept in this example, so let's store '0' or something static. - floor_id = 0 - - # Sort all entries by the earliest stamp - sorted_stamps = sorted(self.data.keys()) - for t in sorted_stamps: - row = self.data[t] - # We'll store 't' as the primary timestamp - # front_cam_ts, back_cam_ts, etc. are in row - front_cam_ts = row["front_cam_ts"] - back_cam_ts = row["back_cam_ts"] - lidar_ts = row["lidar_ts"] - tx = row["tx"] - ty = row["ty"] - tz = row["tz"] - qx = row["qx"] - qy = row["qy"] - qz = row["qz"] - qw = row["qw"] - - csv_line = ( - f"{self.track_name},{floor_id},{t:.6f}," - f"{front_cam_ts:.6f},{back_cam_ts:.6f},{lidar_ts:.6f}," - f"{tx:.6f},{ty:.6f},{tz:.6f}," - f"{qx:.6f},{qy:.6f},{qz:.6f},{qw:.6f}\n" - ) - f.write(csv_line) - - def destroy_node(self): - """ - Override destroy_node to write out the CSV before shutting down. - """ - self.write_csv() - super().destroy_node() + # Apply the filter + poses_df = poses_df.iloc[filtered_indices[0]] + timestamps_dict["front_cam"] = timestamps_dict["front_cam"][filtered_indices[1]] + timestamps_dict["back_cam"] = timestamps_dict["back_cam"][filtered_indices[2]] + timestamps_dict["lidar"] = timestamps_dict["lidar"][filtered_indices[3]] + + # Filter by distance + distance_filtered_indices = filter_by_distance_indices( + poses_df[["tx", "ty", "tz"]].to_numpy(), distance=dist_threshold + ) + poses_df = poses_df.iloc[distance_filtered_indices] + timestamps_dict["front_cam"] = timestamps_dict["front_cam"][distance_filtered_indices] + timestamps_dict["back_cam"] = timestamps_dict["back_cam"][distance_filtered_indices] + timestamps_dict["lidar"] = timestamps_dict["lidar"][distance_filtered_indices] + + # Plot the final track map + track_map_img = plot_track_map(poses_df[["tx", "ty"]].to_numpy()) + + # Create output directory + if out_dir.exists(): + self.get_logger().warn(f"Output directory already exists: {out_dir}") + else: + self.get_logger().info(f"Creating output directory: {out_dir}") + out_dir.mkdir(parents=True, exist_ok=True) + + # Save the track map + cv2.imwrite(str(out_dir / "track_map.png"), track_map_img) + + # Save final CSV + out_df = poses_df.copy() + out_df["front_cam_ts"] = timestamps_dict["front_cam"] + out_df["back_cam_ts"] = timestamps_dict["back_cam"] + out_df["lidar_ts"] = timestamps_dict["lidar"] + out_df = out_df[ + ["timestamp", "front_cam_ts", "back_cam_ts", "lidar_ts", "tx", "ty", "tz", "qx", "qy", "qz", "qw"] + ] + out_df.to_csv(out_dir / "track.csv", index=False) + + # Extract images + LiDAR from each bag + for bag_file_path in tqdm(bag_files_list, desc="Exporting data", position=0): + export_from_bag_ros2( + bag_file_path, + out_dir, + timestamps_dict, + front_cam_topic, + back_cam_topic, + lidar_topic, + ) + + self.get_logger().info("Dataset conversion is complete.") def main(args=None): rclpy.init(args=args) - node = DatasetCreateNode() - - try: - rclpy.spin(node) - except KeyboardInterrupt: - pass - finally: - node.destroy_node() - rclpy.shutdown() + node = BagConverterNode() + # For one-shot execution, just destroy after finishing + node.destroy_node() + rclpy.shutdown() -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/open_place_recognition/src/dataset_publisher_node.py b/open_place_recognition/src/dataset_publisher_node.py index 476e7de..978c4f5 100755 --- a/open_place_recognition/src/dataset_publisher_node.py +++ b/open_place_recognition/src/dataset_publisher_node.py @@ -24,22 +24,22 @@ def __init__(self): super().__init__('database_publisher') # Declare parameters - self.declare_parameter('dataset_dir', '', ParameterDescriptor(description="Path to the dataset directory.")) - self.declare_parameter('enable_front_camera', True, ParameterDescriptor(description="Enable front camera publishing.")) - self.declare_parameter('enable_back_camera', True, ParameterDescriptor(description="Enable back camera publishing.")) - self.declare_parameter('enable_lidar', True, ParameterDescriptor(description="Enable lidar publishing.")) - self.declare_parameter('enable_global_ref', True, ParameterDescriptor(description="Enable global reference subscription.")) - self.declare_parameter('global_ref_topic', '/global_ref', ParameterDescriptor(description="Global reference topic.")) - self.declare_parameter('reserve', False, ParameterDescriptor(description="Reserved for future use.")) + self.declare_parameter('dataset_dir', '', ParameterDescriptor(description="Path to the dataset directory.")) + self.declare_parameter('enable_front_camera', True, ParameterDescriptor(description="Enable front camera publishing.")) + self.declare_parameter('enable_back_camera', True, ParameterDescriptor(description="Enable back camera publishing.")) + self.declare_parameter('enable_lidar', True, ParameterDescriptor(description="Enable lidar publishing.")) + self.declare_parameter('enable_global_ref', True, ParameterDescriptor(description="Enable global reference subscription.")) + self.declare_parameter('global_ref_topic', '/global_ref', ParameterDescriptor(description="Global reference topic.")) + self.declare_parameter('reserve', False, ParameterDescriptor(description="Reserved for future use.")) # Declare topic parameters - self.declare_parameter('front_cam_topic', '/zed_node/left/image_rect_color/compressed') - self.declare_parameter('front_cam_mask_topic', '/zed_node/left/semantic_segmentation') - self.declare_parameter('front_cam_info_topic', '/zed_node/left/image_rect_color/camera_info') - self.declare_parameter('back_cam_topic', '/realsense_back/color/image_raw/compressed') - self.declare_parameter('back_cam_mask_topic', '/realsense_back/semantic_segmentation') - self.declare_parameter('back_cam_info_topic', '/realsense_back/color/image_raw/camera_info') - self.declare_parameter('lidar_topic', '/velodyne_points') + self.declare_parameter('front_cam_topic', '/zed_node/left/image_rect_color/compressed') + self.declare_parameter('front_cam_mask_topic', '/zed_node/left/semantic_segmentation') + self.declare_parameter('front_cam_info_topic', '/zed_node/left/image_rect_color/camera_info') + self.declare_parameter('back_cam_topic', '/realsense_back/color/image_raw/compressed') + self.declare_parameter('back_cam_mask_topic', '/realsense_back/semantic_segmentation') + self.declare_parameter('back_cam_info_topic', '/realsense_back/color/image_raw/camera_info') + self.declare_parameter('lidar_topic', '/velodyne_points') # Declare TF frame parameters self.declare_parameter('tf_parent_frame', 'base_link') diff --git a/open_place_recognition/src/dataset_train_node.py b/open_place_recognition/src/dataset_train_node.py index ac4577f..1c523fa 100755 --- a/open_place_recognition/src/dataset_train_node.py +++ b/open_place_recognition/src/dataset_train_node.py @@ -1,58 +1,230 @@ #!/usr/bin/env python3 -import rclpy -from rclpy.node import Node import os import sys -from ament_index_python.packages import get_package_share_directory import time +import rclpy +from rclpy.node import Node +from ament_index_python.packages import get_package_share_directory + +import torch +import numpy as np +import faiss +from torch.utils.data import DataLoader +from tqdm import tqdm +from hydra.utils import instantiate +from omegaconf import OmegaConf + +from opr.datasets.itlp import ITLPCampus + class DatasetTrainNode(Node): def __init__(self): super().__init__('dataset_train_node') - # Get parameters - self.declare_parameter('dataset_path', 'datasets') - self.declare_parameter('map_name', 'default_map') + # + # --------------------------- + # Declare ROS 2 Parameters + # --------------------------- + # + # General dataset paths + self.declare_parameter('dataset_path', '') self.declare_parameter('output_path', '~/.ros/opr_dataset') - - dataset_path = self.get_parameter('dataset_path').value - map_name = self.get_parameter('map_name').value + + # MinkLoc3D / descriptor extraction parameters + self.declare_parameter('batch_size', 64) + self.declare_parameter('num_workers', 4) + self.declare_parameter('device', 'cuda') + self.declare_parameter('model_config_path', 'configs/model/place_recognition/minkloc3d.yaml') + self.declare_parameter('weights_path', 'weights/place_recognition/minkloc3d_nclt.pth') + + # Additional dataset options + self.declare_parameter('mink_quantization_size', 0.5) + self.declare_parameter('load_semantics', False) + self.declare_parameter('load_text_descriptions', False) + self.declare_parameter('load_text_labels', False) + self.declare_parameter('load_aruco_labels', False) + self.declare_parameter('indoor', False) + + # + # --------------------------- + # Fetch Parameter Values + # --------------------------- + # + dataset_path = os.path.expanduser(self.get_parameter('dataset_path').value) output_path = os.path.expanduser(self.get_parameter('output_path').value) - # Get package share directory and build paths for datasets - package_dir = get_package_share_directory('orca_opr') - dataset_dir = os.path.join(package_dir, dataset_path) - - # Check that required folders exist - if not os.path.exists(dataset_dir): - self.get_logger().error(f"Datasets directory {dataset_dir} does not exist. Please create it and try again.") + # MinkLoc3D / descriptor extraction parameters + dataset_path = os.path.expanduser(self.get_parameter('dataset_path').value) + batch_size = int(self.get_parameter('batch_size').value) + num_workers = int(self.get_parameter('num_workers').value) + device = self.get_parameter('device').value + model_config_path = self.get_parameter('model_config_path').value + weights_path = self.get_parameter('weights_path').value + + # Additional dataset options + mink_quantization_size = float(self.get_parameter('mink_quantization_size').value) + load_semantics = bool(self.get_parameter('load_semantics').value) + load_text_descriptions = bool(self.get_parameter('load_text_descriptions').value) + load_text_labels = bool(self.get_parameter('load_text_labels').value) + load_aruco_labels = bool(self.get_parameter('load_aruco_labels').value) + indoor = bool(self.get_parameter('indoor').value) + + # + # --------------------------- + # Check and prepare directories + # --------------------------- + # + if not os.path.exists(dataset_path): + self.get_logger().error( + f"Datasets directory {dataset_path} does not exist. Please create it and try again." + ) sys.exit(1) + if not os.path.exists(output_path): - self.get_logger().error(f"Output directory {output_path} does not exist. Please create it and try again.") + self.get_logger().error( + f"Output directory {output_path} does not exist. Please create it and try again." + ) sys.exit(1) - if not self.run_torch_training(dataset_dir, output_path, map_name): - self.get_logger().error(f"Error during training {map_name}") + # + # --------------------------- + # Run the descriptor-extraction (or "train") function + # --------------------------- + # + status_ok = self.run_descriptor_extraction( + dataset_path=dataset_path, + batch_size=batch_size, + num_workers=num_workers, + device=device, + model_config_path=model_config_path, + weights_path=weights_path, + output_path=output_path, + mink_quantization_size=mink_quantization_size, + load_semantics=load_semantics, + load_text_descriptions=load_text_descriptions, + load_text_labels=load_text_labels, + load_aruco_labels=load_aruco_labels, + indoor=indoor + ) + + if not status_ok: + self.get_logger().error("Error during descriptor extraction.") sys.exit(1) + else: + self.get_logger().info("Descriptor extraction completed successfully.") - def run_torch_training(self, dataset_path: str, output_path: str, map_name: str): + def run_descriptor_extraction( + self, + dataset_path: str, + batch_size: int, + num_workers: int, + device: str, + model_config_path: str, + weights_path: str, + output_path: str, + mink_quantization_size: float, + load_semantics: bool, + load_text_descriptions: bool, + load_text_labels: bool, + load_aruco_labels: bool, + indoor: bool + ): """ - Loads dataset from dataset_path and performs training for map_name. + Load dataset, run the MinkLoc3D model to extract descriptors, and build a FAISS index. """ - print(f"[TRAINER] Starting training on dataset: {dataset_path} for map: {map_name}") - time.sleep(3) # Simulate training time + try: + # + # 1. Prepare the dataset + # + self.get_logger().info(f"Loading dataset from: {dataset_path}") + db_dataset = ITLPCampus( + dataset_root=dataset_path, + sensors=["lidar"], # or parameterize if you want + mink_quantization_size=mink_quantization_size, + load_semantics=load_semantics, + load_text_descriptions=load_text_descriptions, + load_text_labels=load_text_labels, + load_aruco_labels=load_aruco_labels, + indoor=indoor, + ) + + self.get_logger().info(f"Dataset size: {len(db_dataset)}") + + db_dataloader = DataLoader( + db_dataset, + batch_size=batch_size, + shuffle=False, + num_workers=num_workers, + collate_fn=db_dataset.collate_fn, + ) + + # + # 2. Load the MinkLoc3D model + # + self.get_logger().info(f"Loading MinkLoc3D config from: {model_config_path}") + model_config = OmegaConf.load(model_config_path) + model = instantiate(model_config) + + self.get_logger().info(f"Loading MinkLoc3D weights from: {weights_path}") + model.load_state_dict(torch.load(weights_path)) + model = model.to(device) + model.eval() + + # + # 3. Extract descriptors + # + descriptors_list = [] + self.get_logger().info("Extracting descriptors...") + with torch.no_grad(): + for batch in tqdm(db_dataloader, desc="Descriptor Extraction", leave=True): + # Move input tensors to the correct device + batch = {k: v.to(device) for k, v in batch.items()} + # Forward pass + output = model(batch) + final_descriptor = output["final_descriptor"] # MinkLoc3D's key + descriptors_list.append(final_descriptor.detach().cpu().numpy()) + + descriptors = np.concatenate(descriptors_list, axis=0) + self.get_logger().info(f"Descriptors shape: {descriptors.shape}") + + # + # 4. Build a FAISS index + # + index_dim = descriptors.shape[1] + index = faiss.IndexFlatL2(index_dim) + index.add(descriptors) + self.get_logger().info(f"FAISS index trained: {index.is_trained}, total vectors: {index.ntotal}") + + # + # 5. Write the index to disk + # + faiss_index_path = os.path.join(output_path, "index.faiss") + faiss.write_index(index, faiss_index_path) + self.get_logger().info(f"FAISS index saved to: {faiss_index_path}") + + # + # 6. List directory contents (optional logging) + # + dirs = [d for d in os.listdir(dataset_path) + if os.path.isdir(os.path.join(dataset_path, d))] + files = [f for f in os.listdir(dataset_path) + if os.path.isfile(os.path.join(dataset_path, f))] + + self.get_logger().info("Directory structure in dataset root:") + for item in sorted(dirs): + self.get_logger().info(f" {item}/") + for item in sorted(files): + self.get_logger().info(f" {item}") - # Simulate training by creating a dummy .pt file in the output_path folder - dummy_model_file = os.path.join(output_path, f"{map_name}.pt") - with open(dummy_model_file, 'w') as f: - f.write("dummy model weights") + return True - self.get_logger().info(f"Dummy model file created at: {dummy_model_file}") - print(f"[TRAINER] Finished training for map: {map_name} using dataset: {dataset_path}") - return True + except Exception as e: + self.get_logger().error(f"Exception in run_descriptor_extraction: {e}") + return False def main(args=None): rclpy.init(args=args) node = DatasetTrainNode() + # Spin once and exit (this node does a one-shot operation) rclpy.spin_once(node, timeout_sec=1) node.destroy_node() rclpy.shutdown() diff --git a/open_place_recognition/src/localization_node.py b/open_place_recognition/src/localization_node.py index 10824ae..de63c84 100755 --- a/open_place_recognition/src/localization_node.py +++ b/open_place_recognition/src/localization_node.py @@ -57,19 +57,20 @@ def __init__(self): # Declare required parameters directly in __init__ self.declare_parameter("image_front_topic", "", ParameterDescriptor(description="Front camera image topic.")) - self.declare_parameter("image_back_topic", "", ParameterDescriptor(description="Back camera image topic.")) - self.declare_parameter("mask_front_topic", "", ParameterDescriptor(description="Front semantic segmentation mask topic.")) - self.declare_parameter("mask_back_topic", "", ParameterDescriptor(description="Back semantic segmentation mask topic.")) - self.declare_parameter("lidar_topic", "", ParameterDescriptor(description="Lidar pointcloud topic.")) - self.declare_parameter("pipeline_cfg", "", ParameterDescriptor(description="Path to the pipeline configuration file.")) + self.declare_parameter("image_back_topic", "", ParameterDescriptor(description="Back camera image topic.")) + self.declare_parameter("mask_front_topic", "", ParameterDescriptor(description="Front semantic segmentation mask topic.")) + self.declare_parameter("mask_back_topic", "", ParameterDescriptor(description="Back semantic segmentation mask topic.")) + self.declare_parameter("lidar_topic", "", ParameterDescriptor(description="Lidar pointcloud topic.")) + self.declare_parameter("dataset_dir", "", ParameterDescriptor(description="dataset directory.")) + self.declare_parameter("pipeline_cfg", "", ParameterDescriptor(description="Path to the pipeline configuration file.")) self.declare_parameter("exclude_dynamic_classes", False, ParameterDescriptor(description="Exclude dynamic objects from the input data.")) - self.declare_parameter("image_resize", [], ParameterDescriptor(description="Image resize dimensions.")) + self.declare_parameter("image_resize", rclpy.Parameter.Type.INTEGER_ARRAY, ParameterDescriptor(description="Image resize dimensions.")) # New parameters for enabling/disabling sensors and global reference. self.declare_parameter("enable_front_camera", True, ParameterDescriptor(description="Enable front camera.")) - self.declare_parameter("enable_back_camera", True, ParameterDescriptor(description="Enable back camera.")) - self.declare_parameter("enable_lidar", True, ParameterDescriptor(description="Enable lidar sensor.")) - self.declare_parameter("enable_global_reference", True, ParameterDescriptor(description="Enable global reference system subscription.")) - self.declare_parameter("global_ref_topic", "", ParameterDescriptor(description="Global reference topic (e.g. GPS/Barometer, WGS84).")) + self.declare_parameter("enable_back_camera", True, ParameterDescriptor(description="Enable back camera.")) + self.declare_parameter("enable_lidar", True, ParameterDescriptor(description="Enable lidar sensor.")) + self.declare_parameter("enable_global_ref", True, ParameterDescriptor(description="Enable global reference system subscription.")) + self.declare_parameter("global_ref_topic", "", ParameterDescriptor(description="Global reference topic (e.g. GPS/Barometer, WGS84).")) # Retrieve parameters from the parameter server. self.image_front_topic = self.get_parameter("image_front_topic").get_parameter_value().string_value @@ -77,6 +78,7 @@ def __init__(self): self.mask_front_topic = self.get_parameter("mask_front_topic").get_parameter_value().string_value self.mask_back_topic = self.get_parameter("mask_back_topic").get_parameter_value().string_value self.lidar_topic = self.get_parameter("lidar_topic").get_parameter_value().string_value + self.dataset_dir = self.get_parameter("dataset_dir").get_parameter_value().string_value self.pipeline_cfg = self.get_parameter("pipeline_cfg").get_parameter_value().string_value self.exclude_dynamic_classes = self.get_parameter("exclude_dynamic_classes").get_parameter_value().bool_value self.image_resize = self.get_parameter("image_resize").get_parameter_value().integer_array_value @@ -84,7 +86,7 @@ def __init__(self): self.enable_front_camera = self.get_parameter("enable_front_camera").get_parameter_value().bool_value self.enable_back_camera = self.get_parameter("enable_back_camera").get_parameter_value().bool_value self.enable_lidar = self.get_parameter("enable_lidar").get_parameter_value().bool_value - self.enable_global_reference = self.get_parameter("enable_global_reference").get_parameter_value().bool_value + self.enable_global_ref = self.get_parameter("enable_global_ref").get_parameter_value().bool_value self.global_ref_topic = self.get_parameter("global_ref_topic").get_parameter_value().string_value # Initialize cv_bridge for converting ROS image messages to OpenCV format. @@ -137,12 +139,12 @@ def __init__(self): self.get_logger().error("No sensors enabled; cannot create synchronizer.") # Create publishers for pose and database match index. - self.db_match_pose_pub = self.create_publisher(PoseStamped, "/place_recognition/pose", 10) - self.idx_pub = self.create_publisher(DatabaseMatchIndex, "/place_recognition/db_idx", 10) + self.db_match_pose_pub = self.create_publisher(PoseStamped, "/place_recognition/pose", 10) + self.idx_pub = self.create_publisher(DatabaseMatchIndex, "/place_recognition/db_idx", 10) self.estimated_pose_pub = self.create_publisher(PoseStamped, "/localization/pose", 10) # If enabled, create a subscriber for the global reference system. - if self.enable_global_reference: + if self.enable_global_ref: from sensor_msgs.msg import NavSatFix self.global_ref_sub = self.create_subscription(NavSatFix, self.global_ref_topic, self.global_ref_callback, 10) else: @@ -150,9 +152,24 @@ def __init__(self): self.global_ref = None # Instantiate the localization pipeline from configuration. + if not os.path.exists(self.pipeline_cfg): + exit(1) cfg = OmegaConf.load(self.pipeline_cfg) - cfg.database_dir = os.path.abspath(os.path.join(os.path.expanduser('~'), cfg.database_dir)) - cfg.model_weights_path = os.path.abspath(os.path.join(os.path.expanduser('~'), cfg.model_weights_path)) + + if not os.path.exists(self.dataset_dir): + exit(1) + + # Check out the open_place_recognition/configs/pipelines/localization_pipeline.yaml + print("This node is not fully developed") + exit(1) + model_weights_path = os.path.join(os.path.expanduser("~"), "OpenPlaceRecognition", cfg.model_weights_path) + if not os.path.exists(self.dataset_dir): + exit(1) + self.get_logger().error(f"dataset_dir does not exist: {self.dataset_dir}") + self.get_logger().error(f"model_weights_path does not exist: {model_weights_path}") + cfg.database_dir = self.dataset_dir + cfg.model_weights_path = model_weights_path + self.pipeline = instantiate(cfg) diff --git a/open_place_recognition/src/place_recognition_node.py b/open_place_recognition/src/place_recognition_node.py index eb19f3e..f85d234 100755 --- a/open_place_recognition/src/place_recognition_node.py +++ b/open_place_recognition/src/place_recognition_node.py @@ -44,35 +44,37 @@ def __init__(self): super().__init__("place_recognition") # Declare required parameters directly in __init__ self.declare_parameter("image_front_topic", "", ParameterDescriptor(description="Front camera image topic.")) - self.declare_parameter("image_back_topic", "", ParameterDescriptor(description="Back camera image topic.")) - self.declare_parameter("mask_front_topic", "", ParameterDescriptor(description="Front semantic segmentation mask topic.")) - self.declare_parameter("mask_back_topic", "", ParameterDescriptor(description="Back semantic segmentation mask topic.")) - self.declare_parameter("lidar_topic", "", ParameterDescriptor(description="Lidar pointcloud topic.")) - self.declare_parameter("pipeline_cfg", "", ParameterDescriptor(description="Path to the pipeline configuration file.")) - self.declare_parameter("image_resize", [], ParameterDescriptor(description="Image resize dimensions.")) + self.declare_parameter("image_back_topic", "", ParameterDescriptor(description="Back camera image topic.")) + self.declare_parameter("mask_front_topic", "", ParameterDescriptor(description="Front semantic segmentation mask topic.")) + self.declare_parameter("mask_back_topic", "", ParameterDescriptor(description="Back semantic segmentation mask topic.")) + self.declare_parameter("lidar_topic", "", ParameterDescriptor(description="Lidar pointcloud topic.")) + self.declare_parameter("dataset_dir", "", ParameterDescriptor(description="dataset directory.")) + self.declare_parameter("pipeline_cfg", "", ParameterDescriptor(description="Path to the pipeline configuration file.")) + self.declare_parameter("image_resize", rclpy.Parameter.Type.INTEGER_ARRAY, ParameterDescriptor(description="Image resize dimensions.")) self.declare_parameter("enable_front_camera", True, ParameterDescriptor(description="Enable front camera.")) - self.declare_parameter("enable_back_camera", True, ParameterDescriptor(description="Enable back camera.")) - self.declare_parameter("enable_lidar", True, ParameterDescriptor(description="Enable lidar sensor.")) - self.declare_parameter("global_ref_topic", "", ParameterDescriptor(description="Global reference system topic (e.g. GPS/Barometer, WGS84).")) - self.declare_parameter("enable_global_ref", True, ParameterDescriptor(description="Enable global reference subscription.")) - self.declare_parameter("reserve", False, ParameterDescriptor(description="Reserve variable for future use.")) + self.declare_parameter("enable_back_camera", True, ParameterDescriptor(description="Enable back camera.")) + self.declare_parameter("enable_lidar", True, ParameterDescriptor(description="Enable lidar sensor.")) + self.declare_parameter("global_ref_topic", "", ParameterDescriptor(description="Global reference system topic (e.g. GPS/Barometer, WGS84).")) + self.declare_parameter("enable_global_ref", True, ParameterDescriptor(description="Enable global reference subscription.")) + self.declare_parameter("reserve", False, ParameterDescriptor(description="Reserve variable for future use.")) # Retrieve topics and configuration from parameters. - image_front_topic = self.get_parameter("image_front_topic").get_parameter_value().string_value - image_back_topic = self.get_parameter("image_back_topic").get_parameter_value().string_value - mask_front_topic = self.get_parameter("mask_front_topic").get_parameter_value().string_value - mask_back_topic = self.get_parameter("mask_back_topic").get_parameter_value().string_value - lidar_topic = self.get_parameter("lidar_topic").get_parameter_value().string_value - pipeline_cfg = self.get_parameter("pipeline_cfg").get_parameter_value().string_value - image_resize = self.get_parameter("image_resize").get_parameter_value().integer_array_value + image_front_topic = self.get_parameter("image_front_topic").get_parameter_value().string_value + image_back_topic = self.get_parameter("image_back_topic").get_parameter_value().string_value + mask_front_topic = self.get_parameter("mask_front_topic").get_parameter_value().string_value + mask_back_topic = self.get_parameter("mask_back_topic").get_parameter_value().string_value + lidar_topic = self.get_parameter("lidar_topic").get_parameter_value().string_value + dataset_dir = self.get_parameter("dataset_dir").get_parameter_value().string_value + pipeline_cfg = self.get_parameter("pipeline_cfg").get_parameter_value().string_value + image_resize = self.get_parameter("image_resize").get_parameter_value().integer_array_value # Retrieve sensor enable/disable parameters and global reference topic. self.enable_front_camera = self.get_parameter("enable_front_camera").get_parameter_value().bool_value self.enable_back_camera = self.get_parameter("enable_back_camera").get_parameter_value().bool_value - self.enable_lidar = self.get_parameter("enable_lidar").get_parameter_value().bool_value - self.enable_global_ref = self.get_parameter("enable_global_ref").get_parameter_value().bool_value - self.global_ref_topic = self.get_parameter("global_ref_topic").get_parameter_value().string_value - self.reserve = self.get_parameter("reserve").get_parameter_value().bool_value + self.enable_lidar = self.get_parameter("enable_lidar").get_parameter_value().bool_value + self.enable_global_ref = self.get_parameter("enable_global_ref").get_parameter_value().bool_value + self.global_ref_topic = self.get_parameter("global_ref_topic").get_parameter_value().string_value + self.reserve = self.get_parameter("reserve").get_parameter_value().bool_value # Initialize CvBridge for image conversions. self.cv_bridge = CvBridge() @@ -133,19 +135,29 @@ def __init__(self): self.global_ref = None # Instantiate the place recognition pipeline from configuration. - pipeline_config = OmegaConf.load(pipeline_cfg) - self.pr_pipe = instantiate(pipeline_config) + cfg = OmegaConf.load(pipeline_cfg) + if not os.path.exists(dataset_dir): + self.get_logger().error(f"dataset_dir does not exist: {dataset_dir}") + exit(1) + model_weights_path = os.path.join(os.path.expanduser("~"), "OpenPlaceRecognition", cfg.model_weights_path) + if not os.path.exists(dataset_dir): + self.get_logger().error(f"model_weights_path does not exist: {model_weights_path}") + exit(1) + cfg.database_dir = dataset_dir + cfg.model_weights_path = model_weights_path + + self.pipeline = instantiate(cfg) # Check for Scene Object Context (SOC) module support. - if self.pr_pipe.model.soc_module is not None: + if self.pipeline.model.soc_module is not None: self.load_soc = True self.get_logger().info("self.load_soc is set to True.") sensors_cfg = OmegaConf.load(os.path.join(get_package_share_directory("open_place_recognition"), "configs/sensors/husky.yaml")) - anno_cfg = OmegaConf.load(os.path.join(get_package_share_directory("open_place_recognition"), "configs/anno/oneformer.yaml")) + anno_cfg = OmegaConf.load(os.path.join(get_package_share_directory("open_place_recognition"), "configs/anno/oneformer.yaml")) self.front_cam_proj = Projector(sensors_cfg.front_cam, sensors_cfg.lidar) self.back_cam_proj = Projector(sensors_cfg.back_cam, sensors_cfg.lidar) self.max_distance_soc = 50.0 - self.top_k_soc = self.pr_pipe.model.soc_module.num_objects + self.top_k_soc = self.pipeline.model.soc_module.num_objects self.special_classes = anno_cfg.special_classes self.soc_coords_type = "euclidean" else: @@ -231,16 +243,14 @@ def _get_soc(self, mask_front: np.ndarray, mask_back: np.ndarray, lidar_scan: np A PyTorch tensor representing packed objects. """ coords_front, _, in_image_front = self.front_cam_proj(lidar_scan) - coords_back, _, in_image_back = self.back_cam_proj(lidar_scan) + coords_back, _, in_image_back = self.back_cam_proj(lidar_scan) point_labels = np.zeros(len(lidar_scan), dtype=np.uint8) point_labels[in_image_front] = get_points_labels_by_mask(coords_front, mask_front) - point_labels[in_image_back] = get_points_labels_by_mask(coords_back, mask_back) + point_labels[in_image_back] = get_points_labels_by_mask(coords_back, mask_back) instances_front = semantic_mask_to_instances(mask_front, area_threshold=10, labels_whitelist=self.special_classes) - instances_back = semantic_mask_to_instances(mask_back, area_threshold=10, labels_whitelist=self.special_classes) - objects_front = instance_masks_to_objects(instances_front, coords_front, - point_labels[in_image_front], lidar_scan[in_image_front]) - objects_back = instance_masks_to_objects(instances_back, coords_back, - point_labels[in_image_back], lidar_scan[in_image_back]) + instances_back = semantic_mask_to_instances(mask_back, area_threshold=10, labels_whitelist=self.special_classes) + objects_front = instance_masks_to_objects(instances_front, coords_front, point_labels[in_image_front], lidar_scan[in_image_front]) + objects_back = instance_masks_to_objects(instances_back, coords_back, point_labels[in_image_back], lidar_scan[in_image_back]) objects = {**objects_front, **objects_back} packed_objects = pack_objects(objects, self.top_k_soc, self.max_distance_soc, self.special_classes) @@ -319,15 +329,15 @@ def listener_callback(self, *msgs) -> None: mapping = self.subscriber_mapping front_image_msg = msgs[mapping["front_image"]] if "front_image" in mapping else None - front_mask_msg = msgs[mapping["front_mask"]] if "front_mask" in mapping else None - back_image_msg = msgs[mapping["back_image"]] if "back_image" in mapping else None - back_mask_msg = msgs[mapping["back_mask"]] if "back_mask" in mapping else None - lidar_msg = msgs[mapping["lidar"]] if "lidar" in mapping else None + front_mask_msg = msgs[mapping["front_mask"]] if "front_mask" in mapping else None + back_image_msg = msgs[mapping["back_image"]] if "back_image" in mapping else None + back_mask_msg = msgs[mapping["back_mask"]] if "back_mask" in mapping else None + lidar_msg = msgs[mapping["lidar"]] if "lidar" in mapping else None front_image = self.cv_bridge.compressed_imgmsg_to_cv2(front_image_msg) if front_image_msg is not None else None - back_image = self.cv_bridge.compressed_imgmsg_to_cv2(back_image_msg) if back_image_msg is not None else None - front_mask = self.cv_bridge.imgmsg_to_cv2(front_mask_msg) if front_mask_msg is not None else None - back_mask = self.cv_bridge.imgmsg_to_cv2(back_mask_msg) if back_mask_msg is not None else None + back_image = self.cv_bridge.compressed_imgmsg_to_cv2(back_image_msg) if back_image_msg is not None else None + front_mask = self.cv_bridge.imgmsg_to_cv2(front_mask_msg) if front_mask_msg is not None else None + back_mask = self.cv_bridge.imgmsg_to_cv2(back_mask_msg) if back_mask_msg is not None else None if lidar_msg is not None: points = read_points(lidar_msg, field_names=("x", "y", "z")) @@ -341,7 +351,7 @@ def listener_callback(self, *msgs) -> None: pointcloud=pointcloud ) - output = self.pr_pipe.infer(input_data) + output = self.pipeline.infer(input_data) t_taken = self.get_clock().now() - t_start self.get_logger().info(f"Place recognition inference took: {t_taken.nanoseconds / 1e6} ms.") diff --git a/open_place_recognition/src/test_opr_odom_node.py b/open_place_recognition/src/test_opr_odom_node.py deleted file mode 100755 index ceb1c93..0000000 --- a/open_place_recognition/src/test_opr_odom_node.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 -import rclpy -from rclpy.node import Node -import os -import sys -from ament_index_python.packages import get_package_share_directory - -class ModelOPRNode(Node): - def __init__(self): - super().__init__('model_opr_node') - # Get parameter (only map_name is needed) - self.declare_parameter('map_name', 'default_map') - map_name = self.get_parameter('map_name').value - - # Get package share directory and build the weights path - package_dir = get_package_share_directory('orca_opr') - weights_path = os.path.join(package_dir, 'weights') - - if not os.path.exists(weights_path): - self.get_logger().error(f"Weights directory {weights_path} does not exist. Please create it and try again.") - sys.exit(1) - - dummy_model_file = os.path.join(weights_path, f"{map_name}.pt") - if not os.path.exists(dummy_model_file): - self.get_logger().error(f"Model file {dummy_model_file} does not exist. Please run the training node first.") - sys.exit(1) - else: - self.get_logger().info(f"Model file {dummy_model_file} found. Loading model...") - # Simulate model loading (in future, actual torch code will be used) - self.get_logger().info("Model loaded successfully.") - -def main(args=None): - rclpy.init(args=args) - node = ModelOPRNode() - rclpy.spin_once(node, timeout_sec=1) - node.destroy_node() - rclpy.shutdown() - -if __name__ == '__main__': - main() From 5667e1a7818c40cb5f9d8ea1f9b68cced220f43a Mon Sep 17 00:00:00 2001 From: TPODAvia Date: Tue, 1 Apr 2025 11:15:28 +0300 Subject: [PATCH 3/5] Add qos for all topics --- .../launch/dataset_publisher.launch.py | 33 +++- .../launch/localization.launch.py | 35 ++++- .../launch/place_recognition.launch.py | 69 ++++++-- .../src/dataset_publisher_node.py | 69 ++++++-- .../src/localization_node.py | 104 ++++++++++-- .../src/place_recognition_node.py | 148 ++++++++++++++---- 6 files changed, 372 insertions(+), 86 deletions(-) diff --git a/open_place_recognition/launch/dataset_publisher.launch.py b/open_place_recognition/launch/dataset_publisher.launch.py index 8688f85..cfbd344 100644 --- a/open_place_recognition/launch/dataset_publisher.launch.py +++ b/open_place_recognition/launch/dataset_publisher.launch.py @@ -102,6 +102,28 @@ def generate_launch_description(): description='Lidar TF frame' ) + # New QoS arguments (separate for front camera, back camera, lidar, global ref) + qos_front_cam_arg = DeclareLaunchArgument( + 'qos_front_cam', + default_value='2', + description='QoS for front camera (0=SystemDefault,1=BestEffort,2=Reliable)' + ) + qos_back_cam_arg = DeclareLaunchArgument( + 'qos_back_cam', + default_value='2', + description='QoS for back camera (0=SystemDefault,1=BestEffort,2=Reliable)' + ) + qos_lidar_arg = DeclareLaunchArgument( + 'qos_lidar', + default_value='2', + description='QoS for lidar (0=SystemDefault,1=BestEffort,2=Reliable)' + ) + qos_global_ref_arg = DeclareLaunchArgument( + 'qos_global_ref', + default_value='2', + description='QoS for global ref subscription (0=SystemDefault,1=BestEffort,2=Reliable)' + ) + # Use LaunchConfiguration substitutions to pass these values as parameters params = { "dataset_dir": LaunchConfiguration('dataset_dir'), @@ -123,7 +145,12 @@ def generate_launch_description(): "tf_parent_frame": LaunchConfiguration('tf_parent_frame'), "front_cam_frame": LaunchConfiguration('front_cam_frame'), "back_cam_frame": LaunchConfiguration('back_cam_frame'), - "lidar_frame": LaunchConfiguration('lidar_frame') + "lidar_frame": LaunchConfiguration('lidar_frame'), + # QoS + "qos_front_cam": LaunchConfiguration('qos_front_cam'), + "qos_back_cam": LaunchConfiguration('qos_back_cam'), + "qos_lidar": LaunchConfiguration('qos_lidar'), + "qos_global_ref": LaunchConfiguration('qos_global_ref'), } return LaunchDescription([ @@ -146,6 +173,10 @@ def generate_launch_description(): front_cam_frame_arg, back_cam_frame_arg, lidar_frame_arg, + qos_front_cam_arg, + qos_back_cam_arg, + qos_lidar_arg, + qos_global_ref_arg, # Launch the node with the parameters Node( package='open_place_recognition', diff --git a/open_place_recognition/launch/localization.launch.py b/open_place_recognition/launch/localization.launch.py index f7abab4..2958a6f 100644 --- a/open_place_recognition/launch/localization.launch.py +++ b/open_place_recognition/launch/localization.launch.py @@ -11,9 +11,33 @@ def generate_launch_description(): get_package_share_directory('open_place_recognition'), 'configs/pipelines' ) + qos_front_camera_arg = DeclareLaunchArgument( + 'qos_front_camera', + default_value='2', + description='QoS for front camera (0=SystemDefault,1=BestEffort,2=Reliable)' + ) + qos_back_camera_arg = DeclareLaunchArgument( + 'qos_back_camera', + default_value='2', + description='QoS for back camera (0=SystemDefault,1=BestEffort,2=Reliable)' + ) + qos_lidar_arg = DeclareLaunchArgument( + 'qos_lidar', + default_value='2', + description='QoS for lidar (0=SystemDefault,1=BestEffort,2=Reliable)' + ) + qos_global_ref_arg = DeclareLaunchArgument( + 'qos_global_ref', + default_value='2', + description='QoS for global reference subscription (0=SystemDefault,1=BestEffort,2=Reliable)' + ) # Declare launch arguments for configurable parameters launch_args = [ + qos_front_camera_arg, + qos_back_camera_arg, + qos_lidar_arg, + qos_global_ref_arg, # Topics for images and masks DeclareLaunchArgument( 'image_front_topic', @@ -97,6 +121,10 @@ def generate_launch_description(): ] params = { + "qos_front_camera": LaunchConfiguration("qos_front_camera"), + "qos_back_camera": LaunchConfiguration("qos_back_camera"), + "qos_lidar": LaunchConfiguration("qos_lidar"), + "qos_global_ref": LaunchConfiguration("qos_global_ref"), "image_front_topic": LaunchConfiguration("image_front_topic"), "image_back_topic": LaunchConfiguration("image_back_topic"), "mask_front_topic": LaunchConfiguration("mask_front_topic"), @@ -114,13 +142,6 @@ def generate_launch_description(): "reserve": LaunchConfiguration("reserve"), } - # If a sensor is disabled, the node code should (with proper checks) skip creating the Subscriber. - # For example, if enable_lidar is false, you may have your node check if lidar_topic is empty. - # Here we assume that the node code will interpret a disabled sensor if its topic string is empty. - # One way to do that is to pass an empty string when the sensor is disabled. - # This can be achieved by a remapping or by using a conditional in your node code. - # In this launch file we simply pass the value from LaunchConfiguration. - localization_node = Node( package='open_place_recognition', executable='localization_node.py', diff --git a/open_place_recognition/launch/place_recognition.launch.py b/open_place_recognition/launch/place_recognition.launch.py index 258c71e..09f99f4 100644 --- a/open_place_recognition/launch/place_recognition.launch.py +++ b/open_place_recognition/launch/place_recognition.launch.py @@ -12,8 +12,38 @@ def generate_launch_description(): 'configs/pipelines/place_recognition' ) - # Declare launch arguments for configurable parameters + # ---------------------------------------------------------------------- + # New QoS arguments for front camera, back camera, lidar, global ref: + # ---------------------------------------------------------------------- + qos_front_camera_arg = DeclareLaunchArgument( + 'qos_front_camera', + default_value='2', + description='QoS for front camera (0=SystemDefault,1=BestEffort,2=Reliable)' + ) + qos_back_camera_arg = DeclareLaunchArgument( + 'qos_back_camera', + default_value='2', + description='QoS for back camera (0=SystemDefault,1=BestEffort,2=Reliable)' + ) + qos_lidar_arg = DeclareLaunchArgument( + 'qos_lidar', + default_value='2', + description='QoS for lidar (0=SystemDefault,1=BestEffort,2=Reliable)' + ) + qos_global_ref_arg = DeclareLaunchArgument( + 'qos_global_ref', + default_value='2', + description='QoS for global reference subscription (0=SystemDefault,1=BestEffort,2=Reliable)' + ) + + # ---------------------------------------------------------------------- + # Declare launch arguments for configurable parameters (original code): + # ---------------------------------------------------------------------- launch_arguments = [ + qos_front_camera_arg, + qos_back_camera_arg, + qos_lidar_arg, + qos_global_ref_arg, DeclareLaunchArgument( 'image_front_topic', default_value='/zed_node/left/image_rect_color/compressed', @@ -87,22 +117,29 @@ def generate_launch_description(): ) ] - # Use LaunchConfiguration substitutions for all parameters + # ---------------------------------------------------------------------- + # Use LaunchConfiguration substitutions for all parameters (original code): + # ---------------------------------------------------------------------- node_parameters = { - "image_front_topic": LaunchConfiguration("image_front_topic"), - "image_back_topic": LaunchConfiguration("image_back_topic"), - "mask_front_topic": LaunchConfiguration("mask_front_topic"), - "mask_back_topic": LaunchConfiguration("mask_back_topic"), - "lidar_topic": LaunchConfiguration("lidar_topic"), - "dataset_dir": LaunchConfiguration("dataset_dir"), - "pipeline_cfg": LaunchConfiguration("pipeline_cfg"), - "image_resize": LaunchConfiguration("image_resize"), - "enable_front_camera": LaunchConfiguration("enable_front_camera"), - "enable_back_camera": LaunchConfiguration("enable_back_camera"), - "enable_lidar": LaunchConfiguration("enable_lidar"), - "enable_global_ref": LaunchConfiguration("enable_global_ref"), - "global_ref_topic": LaunchConfiguration("global_ref_topic"), - "reserve": LaunchConfiguration("reserve"), + "qos_front_camera": LaunchConfiguration("qos_front_camera"), + "qos_back_camera": LaunchConfiguration("qos_back_camera"), + "qos_lidar": LaunchConfiguration("qos_lidar"), + "qos_global_ref": LaunchConfiguration("qos_global_ref"), + + "image_front_topic": LaunchConfiguration("image_front_topic"), + "image_back_topic": LaunchConfiguration("image_back_topic"), + "mask_front_topic": LaunchConfiguration("mask_front_topic"), + "mask_back_topic": LaunchConfiguration("mask_back_topic"), + "lidar_topic": LaunchConfiguration("lidar_topic"), + "dataset_dir": LaunchConfiguration("dataset_dir"), + "pipeline_cfg": LaunchConfiguration("pipeline_cfg"), + "image_resize": LaunchConfiguration("image_resize"), + "enable_front_camera": LaunchConfiguration("enable_front_camera"), + "enable_back_camera": LaunchConfiguration("enable_back_camera"), + "enable_lidar": LaunchConfiguration("enable_lidar"), + "enable_global_ref": LaunchConfiguration("enable_global_ref"), + "global_ref_topic": LaunchConfiguration("global_ref_topic"), + "reserve": LaunchConfiguration("reserve"), } # Create the Node action with parameters from LaunchConfiguration diff --git a/open_place_recognition/src/dataset_publisher_node.py b/open_place_recognition/src/dataset_publisher_node.py index 978c4f5..76c5d0c 100755 --- a/open_place_recognition/src/dataset_publisher_node.py +++ b/open_place_recognition/src/dataset_publisher_node.py @@ -19,6 +19,9 @@ from geometry_msgs.msg import TransformStamped from ament_index_python.packages import get_package_share_directory +# Import QoS-related classes +from rclpy.qos import QoSProfile, QoSReliabilityPolicy + class DatabasePublisherNode(Node): def __init__(self): super().__init__('database_publisher') @@ -47,6 +50,12 @@ def __init__(self): self.declare_parameter('back_cam_frame', 'realsense_back') self.declare_parameter('lidar_frame', 'velodyne') + # Declare QoS parameters + self.declare_parameter('qos_front_cam', 2, ParameterDescriptor(description="QoS for front camera (0=SystemDefault,1=BestEffort,2=Reliable)")) + self.declare_parameter('qos_back_cam', 2, ParameterDescriptor(description="QoS for back camera (0=SystemDefault,1=BestEffort,2=Reliable)")) + self.declare_parameter('qos_lidar', 2, ParameterDescriptor(description="QoS for lidar (0=SystemDefault,1=BestEffort,2=Reliable)")) + self.declare_parameter('qos_global_ref',2, ParameterDescriptor(description="QoS for global ref subscription (0=SystemDefault,1=BestEffort,2=Reliable)")) + # Retrieve parameters self.dataset_dir = self.get_parameter('dataset_dir').get_parameter_value().string_value if not self.dataset_dir: @@ -74,23 +83,39 @@ def __init__(self): self.back_cam_frame = self.get_parameter('back_cam_frame').get_parameter_value().string_value self.lidar_frame = self.get_parameter('lidar_frame').get_parameter_value().string_value + # QoS parameter values + self.qos_front_cam_value = self.get_parameter('qos_front_cam').get_parameter_value().integer_value + self.qos_back_cam_value = self.get_parameter('qos_back_cam').get_parameter_value().integer_value + self.qos_lidar_value = self.get_parameter('qos_lidar').get_parameter_value().integer_value + self.qos_global_ref_value = self.get_parameter('qos_global_ref').get_parameter_value().integer_value + + # Create QoS profiles for each + self.qos_front_cam_profile = self._create_qos_profile(self.qos_front_cam_value) + self.qos_back_cam_profile = self._create_qos_profile(self.qos_back_cam_value) + self.qos_lidar_profile = self._create_qos_profile(self.qos_lidar_value) + self.qos_global_ref_profile = self._create_qos_profile(self.qos_global_ref_value, depth=10) # subscription with depth=10 + # Create publishers using the parameterized topics if self.enable_front_camera: - self.pub_front_cam = self.create_publisher(CompressedImage, self.front_cam_topic, 1) - self.pub_front_cam_mask = self.create_publisher(Image, self.front_cam_mask_topic, 1) - self.pub_front_cam_info = self.create_publisher(CameraInfo, self.front_cam_info_topic, 1) + self.pub_front_cam = self.create_publisher(CompressedImage, self.front_cam_topic, self.qos_front_cam_profile) + self.pub_front_cam_mask = self.create_publisher(Image, self.front_cam_mask_topic, self.qos_front_cam_profile) + self.pub_front_cam_info = self.create_publisher(CameraInfo, self.front_cam_info_topic, self.qos_front_cam_profile) else: - self.pub_front_cam = self.pub_front_cam_mask = self.pub_front_cam_info = None + self.pub_front_cam = None + self.pub_front_cam_mask = None + self.pub_front_cam_info = None if self.enable_back_camera: - self.pub_back_cam = self.create_publisher(CompressedImage, self.back_cam_topic, 1) - self.pub_back_cam_mask = self.create_publisher(Image, self.back_cam_mask_topic, 1) - self.pub_back_cam_info = self.create_publisher(CameraInfo, self.back_cam_info_topic, 1) + self.pub_back_cam = self.create_publisher(CompressedImage, self.back_cam_topic, self.qos_back_cam_profile) + self.pub_back_cam_mask = self.create_publisher(Image, self.back_cam_mask_topic, self.qos_back_cam_profile) + self.pub_back_cam_info = self.create_publisher(CameraInfo, self.back_cam_info_topic, self.qos_back_cam_profile) else: - self.pub_back_cam = self.pub_back_cam_mask = self.pub_back_cam_info = None + self.pub_back_cam = None + self.pub_back_cam_mask = None + self.pub_back_cam_info = None if self.enable_lidar: - self.pub_lidar = self.create_publisher(PointCloud2, self.lidar_topic, 1) + self.pub_lidar = self.create_publisher(PointCloud2, self.lidar_topic, self.qos_lidar_profile) else: self.pub_lidar = None @@ -99,7 +124,12 @@ def __init__(self): # Global reference subscription (if enabled) if self.enable_global_ref: - self.global_ref_sub = self.create_subscription(NavSatFix, self.global_ref_topic, self.global_ref_callback, 10) + self.global_ref_sub = self.create_subscription( + NavSatFix, + self.global_ref_topic, + self.global_ref_callback, + self.qos_global_ref_profile + ) else: self.global_ref_sub = None self.global_ref = None @@ -126,6 +156,19 @@ def __init__(self): self.get_logger().info("DatabasePublisherNode initialized.") + def _create_qos_profile(self, qos_value, depth=1): + """ + Create a QoSProfile based on integer (0=SystemDefault,1=BestEffort,2=Reliable). + """ + qos_profile = QoSProfile(depth=depth) + if qos_value == 0: + qos_profile.reliability = QoSReliabilityPolicy.SYSTEM_DEFAULT + elif qos_value == 1: + qos_profile.reliability = QoSReliabilityPolicy.BEST_EFFORT + else: + qos_profile.reliability = QoSReliabilityPolicy.RELIABLE + return qos_profile + def global_ref_callback(self, msg): self.global_ref = msg @@ -234,6 +277,9 @@ def publish_sensor_config(self): except Exception as e: self.get_logger().error(f"Error publishing lidar config: {e}") + def global_ref_callback(self, msg): + self.global_ref = msg + def publish_one_row(self, i): self.publish_sensor_config() floor_num = int(self.track_df['floor'][i]) @@ -304,11 +350,10 @@ def read_image_as_compressed(self, image_path, frame_id='camera'): return None def read_image_as_uncompressed(self, image_path, frame_id='camera'): - if not os.path.exists(image_path): self.get_logger().error(f"Mask image not found: {image_path}") return None - + img = cv2.imread(image_path, cv2.IMREAD_UNCHANGED) if img is None: self.get_logger().error(f"Failed to read image {image_path}") diff --git a/open_place_recognition/src/localization_node.py b/open_place_recognition/src/localization_node.py index de63c84..58a5a87 100755 --- a/open_place_recognition/src/localization_node.py +++ b/open_place_recognition/src/localization_node.py @@ -26,6 +26,9 @@ from albumentations.pytorch import ToTensorV2 from ament_index_python.packages import get_package_share_directory +# Import QoS classes for separate QoS handling +from rclpy.qos import QoSProfile, QoSReliabilityPolicy + # Importing required modules from our package from opr.pipelines.localization import ArucoLocalizationPipeline from opr_interfaces.msg import DatabaseMatchIndex @@ -56,15 +59,21 @@ def __init__(self): super().__init__("localization") # Declare required parameters directly in __init__ + self.declare_parameter("qos_front_camera", 2, ParameterDescriptor(description="QoS for front camera")) + self.declare_parameter("qos_back_camera", 2, ParameterDescriptor(description="QoS for back camera")) + self.declare_parameter("qos_lidar", 2, ParameterDescriptor(description="QoS for lidar")) + self.declare_parameter("qos_global_ref", 2, ParameterDescriptor(description="QoS for global reference subscription")) + # Declare other parameters self.declare_parameter("image_front_topic", "", ParameterDescriptor(description="Front camera image topic.")) self.declare_parameter("image_back_topic", "", ParameterDescriptor(description="Back camera image topic.")) self.declare_parameter("mask_front_topic", "", ParameterDescriptor(description="Front semantic segmentation mask topic.")) self.declare_parameter("mask_back_topic", "", ParameterDescriptor(description="Back semantic segmentation mask topic.")) self.declare_parameter("lidar_topic", "", ParameterDescriptor(description="Lidar pointcloud topic.")) - self.declare_parameter("dataset_dir", "", ParameterDescriptor(description="dataset directory.")) + self.declare_parameter("dataset_dir", "", ParameterDescriptor(description="dataset directory.")) self.declare_parameter("pipeline_cfg", "", ParameterDescriptor(description="Path to the pipeline configuration file.")) self.declare_parameter("exclude_dynamic_classes", False, ParameterDescriptor(description="Exclude dynamic objects from the input data.")) self.declare_parameter("image_resize", rclpy.Parameter.Type.INTEGER_ARRAY, ParameterDescriptor(description="Image resize dimensions.")) + # New parameters for enabling/disabling sensors and global reference. self.declare_parameter("enable_front_camera", True, ParameterDescriptor(description="Enable front camera.")) self.declare_parameter("enable_back_camera", True, ParameterDescriptor(description="Enable back camera.")) @@ -72,7 +81,13 @@ def __init__(self): self.declare_parameter("enable_global_ref", True, ParameterDescriptor(description="Enable global reference system subscription.")) self.declare_parameter("global_ref_topic", "", ParameterDescriptor(description="Global reference topic (e.g. GPS/Barometer, WGS84).")) - # Retrieve parameters from the parameter server. + # Retrieve QoS parameter values + self.qos_front_camera_value = self.get_parameter("qos_front_camera").get_parameter_value().integer_value + self.qos_back_camera_value = self.get_parameter("qos_back_camera").get_parameter_value().integer_value + self.qos_lidar_value = self.get_parameter("qos_lidar").get_parameter_value().integer_value + self.qos_global_ref_value = self.get_parameter("qos_global_ref").get_parameter_value().integer_value + + # Retrieve other parameters self.image_front_topic = self.get_parameter("image_front_topic").get_parameter_value().string_value self.image_back_topic = self.get_parameter("image_back_topic").get_parameter_value().string_value self.mask_front_topic = self.get_parameter("mask_front_topic").get_parameter_value().string_value @@ -92,33 +107,73 @@ def __init__(self): # Initialize cv_bridge for converting ROS image messages to OpenCV format. self.cv_bridge = CvBridge() - # Build a list of subscribers conditionally based on enabled sensors. + # Create QoS profiles + self.qos_front_cam_profile = self._create_qos_profile(self.qos_front_camera_value) + self.qos_back_cam_profile = self._create_qos_profile(self.qos_back_camera_value) + self.qos_lidar_profile = self._create_qos_profile(self.qos_lidar_value) + self.qos_global_ref_profile = self._create_qos_profile(self.qos_global_ref_value, depth=10) + + # Build a list of subscribers conditionally based on enabled sensors, + # each with its own QoS profile. subscribers = [] mapping = {} # Will map sensor name to its index in the synchronizer arguments. + if self.enable_front_camera: - self.image_front_sub = Subscriber(self, CompressedImage, self.image_front_topic) + # Subscriber for front camera image + self.image_front_sub = Subscriber( + self, + CompressedImage, + self.image_front_topic, + qos_profile=self.qos_front_cam_profile + ) subscribers.append(self.image_front_sub) mapping['front_image'] = len(subscribers) - 1 - self.mask_front_sub = Subscriber(self, Image, self.mask_front_topic) + + # Subscriber for front camera mask + self.mask_front_sub = Subscriber( + self, + Image, + self.mask_front_topic, + qos_profile=self.qos_front_cam_profile + ) subscribers.append(self.mask_front_sub) mapping['front_mask'] = len(subscribers) - 1 else: self.image_front_sub = None - self.mask_front_sub = None + self.mask_front_sub = None if self.enable_back_camera: - self.image_back_sub = Subscriber(self, CompressedImage, self.image_back_topic) + # Subscriber for back camera image + self.image_back_sub = Subscriber( + self, + CompressedImage, + self.image_back_topic, + qos_profile=self.qos_back_cam_profile + ) subscribers.append(self.image_back_sub) mapping['back_image'] = len(subscribers) - 1 - self.mask_back_sub = Subscriber(self, Image, self.mask_back_topic) + + # Subscriber for back camera mask + self.mask_back_sub = Subscriber( + self, + Image, + self.mask_back_topic, + qos_profile=self.qos_back_cam_profile + ) subscribers.append(self.mask_back_sub) mapping['back_mask'] = len(subscribers) - 1 else: self.image_back_sub = None - self.mask_back_sub = None + self.mask_back_sub = None if self.enable_lidar: - self.lidar_sub = Subscriber(self, PointCloud2, self.lidar_topic) + # Subscriber for LiDAR + self.lidar_sub = Subscriber( + self, + PointCloud2, + self.lidar_topic, + qos_profile=self.qos_lidar_profile + ) subscribers.append(self.lidar_sub) mapping['lidar'] = len(subscribers) - 1 else: @@ -138,15 +193,20 @@ def __init__(self): else: self.get_logger().error("No sensors enabled; cannot create synchronizer.") - # Create publishers for pose and database match index. + # Create publishers for pose and database match index (use default QoS or 10). self.db_match_pose_pub = self.create_publisher(PoseStamped, "/place_recognition/pose", 10) self.idx_pub = self.create_publisher(DatabaseMatchIndex, "/place_recognition/db_idx", 10) self.estimated_pose_pub = self.create_publisher(PoseStamped, "/localization/pose", 10) - # If enabled, create a subscriber for the global reference system. + # If enabled, create a subscriber for the global reference system with its QoS. if self.enable_global_ref: from sensor_msgs.msg import NavSatFix - self.global_ref_sub = self.create_subscription(NavSatFix, self.global_ref_topic, self.global_ref_callback, 10) + self.global_ref_sub = self.create_subscription( + NavSatFix, + self.global_ref_topic, + self.global_ref_callback, + self.qos_global_ref_profile + ) else: self.global_ref_sub = None self.global_ref = None @@ -169,7 +229,7 @@ def __init__(self): self.get_logger().error(f"model_weights_path does not exist: {model_weights_path}") cfg.database_dir = self.dataset_dir cfg.model_weights_path = model_weights_path - + # ---------------------------------- self.pipeline = instantiate(cfg) @@ -204,7 +264,7 @@ def __init__(self): [ 0.01509615, -0.99976457, -0.01558544, 0.04632156], [ 0.00871086, 0.01571812, -0.99983852, -0.13278588], [ 0.9998481, 0.01495794, 0.0089461, -0.06092749], - [ 0., 0., 0., 1. ] + [ 0., 0., 0., 1. ] ]) self.lidar2back = np.array([ [-1.50409674e-02, 9.99886421e-01, 9.55906151e-04, 1.82703304e-02], @@ -227,6 +287,19 @@ def __init__(self): self.get_logger().info(f"Initialized {self.__class__.__name__} node.") + def _create_qos_profile(self, qos_value: int, depth=1) -> QoSProfile: + """ + Create a QoSProfile based on integer (0=SystemDefault,1=BestEffort,2=Reliable). + """ + qos_profile = QoSProfile(depth=depth) + if qos_value == 0: + qos_profile.reliability = QoSReliabilityPolicy.SYSTEM_DEFAULT + elif qos_value == 1: + qos_profile.reliability = QoSReliabilityPolicy.BEST_EFFORT + else: + qos_profile.reliability = QoSReliabilityPolicy.RELIABLE + return qos_profile + def global_ref_callback(self, msg) -> None: """Callback to update the global reference message.""" self.global_ref = msg @@ -513,7 +586,6 @@ def listener_callback(self, *msgs) -> None: self.idx_pub.publish(idx_msg) self.get_logger().info(f"Published database index message: {idx_msg.index}") - def main(args=None): """Main function to initialize and spin the localization node.""" rclpy.init(args=args) diff --git a/open_place_recognition/src/place_recognition_node.py b/open_place_recognition/src/place_recognition_node.py index f85d234..a2172f9 100755 --- a/open_place_recognition/src/place_recognition_node.py +++ b/open_place_recognition/src/place_recognition_node.py @@ -25,6 +25,9 @@ from torch import Tensor from ament_index_python.packages import get_package_share_directory +# QoS imports +from rclpy.qos import QoSProfile, QoSReliabilityPolicy + # Import custom message and processing functions from opr_interfaces.msg import DatabaseMatchIndex from opr.datasets.augmentations import DefaultImageTransform, DefaultSemanticTransform @@ -42,13 +45,24 @@ class PlaceRecognitionNode(Node): def __init__(self): super().__init__("place_recognition") - # Declare required parameters directly in __init__ + + # ---------------------------------------------------------------------- + # New QoS Parameters (separate for front camera, back camera, lidar, global ref): + # ---------------------------------------------------------------------- + self.declare_parameter("qos_front_camera", 2, ParameterDescriptor(description="QoS for front camera (0=SystemDefault,1=BestEffort,2=Reliable)")) + self.declare_parameter("qos_back_camera", 2, ParameterDescriptor(description="QoS for back camera (0=SystemDefault,1=BestEffort,2=Reliable)")) + self.declare_parameter("qos_lidar", 2, ParameterDescriptor(description="QoS for lidar (0=SystemDefault,1=BestEffort,2=Reliable)")) + self.declare_parameter("qos_global_ref", 2, ParameterDescriptor(description="QoS for global ref subscription (0=SystemDefault,1=BestEffort,2=Reliable)")) + + # ---------------------------------------------------------------------- + # Declare required parameters directly in __init__ (original code): + # ---------------------------------------------------------------------- self.declare_parameter("image_front_topic", "", ParameterDescriptor(description="Front camera image topic.")) self.declare_parameter("image_back_topic", "", ParameterDescriptor(description="Back camera image topic.")) self.declare_parameter("mask_front_topic", "", ParameterDescriptor(description="Front semantic segmentation mask topic.")) self.declare_parameter("mask_back_topic", "", ParameterDescriptor(description="Back semantic segmentation mask topic.")) self.declare_parameter("lidar_topic", "", ParameterDescriptor(description="Lidar pointcloud topic.")) - self.declare_parameter("dataset_dir", "", ParameterDescriptor(description="dataset directory.")) + self.declare_parameter("dataset_dir", "", ParameterDescriptor(description="dataset directory.")) self.declare_parameter("pipeline_cfg", "", ParameterDescriptor(description="Path to the pipeline configuration file.")) self.declare_parameter("image_resize", rclpy.Parameter.Type.INTEGER_ARRAY, ParameterDescriptor(description="Image resize dimensions.")) self.declare_parameter("enable_front_camera", True, ParameterDescriptor(description="Enable front camera.")) @@ -58,56 +72,99 @@ def __init__(self): self.declare_parameter("enable_global_ref", True, ParameterDescriptor(description="Enable global reference subscription.")) self.declare_parameter("reserve", False, ParameterDescriptor(description="Reserve variable for future use.")) - # Retrieve topics and configuration from parameters. - image_front_topic = self.get_parameter("image_front_topic").get_parameter_value().string_value - image_back_topic = self.get_parameter("image_back_topic").get_parameter_value().string_value - mask_front_topic = self.get_parameter("mask_front_topic").get_parameter_value().string_value - mask_back_topic = self.get_parameter("mask_back_topic").get_parameter_value().string_value - lidar_topic = self.get_parameter("lidar_topic").get_parameter_value().string_value - dataset_dir = self.get_parameter("dataset_dir").get_parameter_value().string_value - pipeline_cfg = self.get_parameter("pipeline_cfg").get_parameter_value().string_value - image_resize = self.get_parameter("image_resize").get_parameter_value().integer_array_value - - # Retrieve sensor enable/disable parameters and global reference topic. + # ---------------------------------------------------------------------- + # Retrieve QoS parameter values + # ---------------------------------------------------------------------- + self.qos_front_cam_val = self.get_parameter("qos_front_camera").get_parameter_value().integer_value + self.qos_back_cam_val = self.get_parameter("qos_back_camera").get_parameter_value().integer_value + self.qos_lidar_val = self.get_parameter("qos_lidar").get_parameter_value().integer_value + self.qos_global_ref_val= self.get_parameter("qos_global_ref").get_parameter_value().integer_value + + # Create QoS profiles using the helper method below + self.qos_front_cam_profile = self._create_qos_profile(self.qos_front_cam_val) + self.qos_back_cam_profile = self._create_qos_profile(self.qos_back_cam_val) + self.qos_lidar_profile = self._create_qos_profile(self.qos_lidar_val) + self.qos_global_ref_profile = self._create_qos_profile(self.qos_global_ref_val, depth=10) + + # ---------------------------------------------------------------------- + # Retrieve other parameters (original code) + # ---------------------------------------------------------------------- + image_front_topic = self.get_parameter("image_front_topic").get_parameter_value().string_value + image_back_topic = self.get_parameter("image_back_topic").get_parameter_value().string_value + mask_front_topic = self.get_parameter("mask_front_topic").get_parameter_value().string_value + mask_back_topic = self.get_parameter("mask_back_topic").get_parameter_value().string_value + lidar_topic = self.get_parameter("lidar_topic").get_parameter_value().string_value + dataset_dir = self.get_parameter("dataset_dir").get_parameter_value().string_value + pipeline_cfg = self.get_parameter("pipeline_cfg").get_parameter_value().string_value + image_resize = self.get_parameter("image_resize").get_parameter_value().integer_array_value + self.enable_front_camera = self.get_parameter("enable_front_camera").get_parameter_value().bool_value - self.enable_back_camera = self.get_parameter("enable_back_camera").get_parameter_value().bool_value - self.enable_lidar = self.get_parameter("enable_lidar").get_parameter_value().bool_value - self.enable_global_ref = self.get_parameter("enable_global_ref").get_parameter_value().bool_value - self.global_ref_topic = self.get_parameter("global_ref_topic").get_parameter_value().string_value - self.reserve = self.get_parameter("reserve").get_parameter_value().bool_value + self.enable_back_camera = self.get_parameter("enable_back_camera").get_parameter_value().bool_value + self.enable_lidar = self.get_parameter("enable_lidar").get_parameter_value().bool_value + self.enable_global_ref = self.get_parameter("enable_global_ref").get_parameter_value().bool_value + self.global_ref_topic = self.get_parameter("global_ref_topic").get_parameter_value().string_value + self.reserve = self.get_parameter("reserve").get_parameter_value().bool_value # Initialize CvBridge for image conversions. self.cv_bridge = CvBridge() - # Create subscribers and map sensor names to synchronizer indices. + # ---------------------------------------------------------------------- + # Create subscribers with their respective QoS profiles + # ---------------------------------------------------------------------- subscribers = [] mapping = {} + if self.enable_front_camera: - self.image_front_sub = Subscriber(self, CompressedImage, image_front_topic) + self.image_front_sub = Subscriber( + self, + CompressedImage, + image_front_topic, + qos_profile=self.qos_front_cam_profile + ) subscribers.append(self.image_front_sub) mapping["front_image"] = len(subscribers) - 1 - self.mask_front_sub = Subscriber(self, Image, mask_front_topic) + self.mask_front_sub = Subscriber( + self, + Image, + mask_front_topic, + qos_profile=self.qos_front_cam_profile + ) subscribers.append(self.mask_front_sub) mapping["front_mask"] = len(subscribers) - 1 else: self.image_front_sub = None - self.mask_front_sub = None + self.mask_front_sub = None if self.enable_back_camera: - self.image_back_sub = Subscriber(self, CompressedImage, image_back_topic) + self.image_back_sub = Subscriber( + self, + CompressedImage, + image_back_topic, + qos_profile=self.qos_back_cam_profile + ) subscribers.append(self.image_back_sub) mapping["back_image"] = len(subscribers) - 1 - self.mask_back_sub = Subscriber(self, Image, mask_back_topic) + self.mask_back_sub = Subscriber( + self, + Image, + mask_back_topic, + qos_profile=self.qos_back_cam_profile + ) subscribers.append(self.mask_back_sub) mapping["back_mask"] = len(subscribers) - 1 else: self.image_back_sub = None - self.mask_back_sub = None + self.mask_back_sub = None if self.enable_lidar: - self.lidar_sub = Subscriber(self, PointCloud2, lidar_topic) + self.lidar_sub = Subscriber( + self, + PointCloud2, + lidar_topic, + qos_profile=self.qos_lidar_profile + ) subscribers.append(self.lidar_sub) mapping["lidar"] = len(subscribers) - 1 else: @@ -125,16 +182,25 @@ def __init__(self): # Create publishers for pose and database match index. self.pose_pub = self.create_publisher(PoseStamped, "/place_recognition/pose", 10) - self.idx_pub = self.create_publisher(DatabaseMatchIndex, "/place_recognition/db_idx", 10) + self.idx_pub = self.create_publisher(DatabaseMatchIndex, "/place_recognition/db_idx", 10) - # Subscribe to global reference system messages if enabled. + # ---------------------------------------------------------------------- + # Global reference subscription (with QoS) if enabled + # ---------------------------------------------------------------------- if self.enable_global_ref: - self.global_ref_sub = self.create_subscription(NavSatFix, self.global_ref_topic, self.global_ref_callback, 10) + self.global_ref_sub = self.create_subscription( + NavSatFix, + self.global_ref_topic, + self.global_ref_callback, + self.qos_global_ref_profile + ) else: self.global_ref_sub = None self.global_ref = None - # Instantiate the place recognition pipeline from configuration. + # ---------------------------------------------------------------------- + # Instantiate the place recognition pipeline from configuration (original code) + # ---------------------------------------------------------------------- cfg = OmegaConf.load(pipeline_cfg) if not os.path.exists(dataset_dir): self.get_logger().error(f"dataset_dir does not exist: {dataset_dir}") @@ -165,10 +231,26 @@ def __init__(self): # Set up image and mask transformations. self.image_transform = DefaultImageTransform(train=False, resize=image_resize) - self.mask_transform = DefaultSemanticTransform(train=False, resize=image_resize) + self.mask_transform = DefaultSemanticTransform(train=False, resize=image_resize) self.get_logger().info(f"Initialized {self.__class__.__name__} node.") + # -------------------------------------------------------------------------- + # Helper function to create QoSProfile from integer + # -------------------------------------------------------------------------- + def _create_qos_profile(self, qos_value, depth=1) -> QoSProfile: + """ + Create a QoSProfile based on integer (0=SystemDefault,1=BestEffort,2=Reliable). + """ + profile = QoSProfile(depth=depth) + if qos_value == 0: + profile.reliability = QoSReliabilityPolicy.SYSTEM_DEFAULT + elif qos_value == 1: + profile.reliability = QoSReliabilityPolicy.BEST_EFFORT + else: + profile.reliability = QoSReliabilityPolicy.RELIABLE + return profile + def global_ref_callback(self, msg: NavSatFix) -> None: """Callback to update the global reference system message.""" self.global_ref = msg @@ -357,13 +439,12 @@ def listener_callback(self, *msgs) -> None: timestamp = lidar_msg.header.stamp if lidar_msg is not None else self.get_clock().now().to_msg() pose_msg = self._create_pose_msg(output["pose"], timestamp) - idx_msg = self._create_idx_msg(int(output["idx"]), timestamp) + idx_msg = self._create_idx_msg(int(output["idx"]), timestamp) self.pose_pub.publish(pose_msg) self.get_logger().info(f"Published pose message: {pose_msg.pose}") self.idx_pub.publish(idx_msg) self.get_logger().info(f"Published database index message: {idx_msg.index}") - def main(args=None): """Main entry point for the Place Recognition node.""" rclpy.init(args=args) @@ -372,6 +453,5 @@ def main(args=None): pr_node.destroy_node() rclpy.shutdown() - if __name__ == '__main__': main() From b0dfab784a232421adfd1e082a787c996b3a4a13 Mon Sep 17 00:00:00 2001 From: TPODAvia Date: Fri, 4 Apr 2025 13:46:02 +0300 Subject: [PATCH 4/5] Update README.md --- README.md | 236 ++++++++---------- TODO.md | 5 + open_place_recognition/CMakeLists.txt | 2 +- ...n.launch.py => dataset_indexing.launch.py} | 4 +- ...train_node.py => dataset_indexing_node.py} | 6 +- 5 files changed, 112 insertions(+), 141 deletions(-) create mode 100644 TODO.md rename open_place_recognition/launch/{dataset_train.launch.py => dataset_indexing.launch.py} (96%) rename open_place_recognition/src/{dataset_train_node.py => dataset_indexing_node.py} (98%) diff --git a/README.md b/README.md index 81947d2..ccabbfc 100644 --- a/README.md +++ b/README.md @@ -1,187 +1,153 @@ # OpenPlaceRecognition-ROS2 -Note: This project is the revisions for the Open PLace Recognition project for ROS2 Humble -# Installation +The OpenPlaceRecognition ROS2 wrapper is intended for: -## Prerequisites +- 🔌 **Easy integration** of multimodal localization into robots and autonomous systems based on ROS2. +- 🚘 **Application in existing robotic platforms and autopilots** running ROS2. +- ⚙️ **Rapid deployment** of neural network-based global localization methods into real-world ROS2 projects. -- [OpenPlaceRecognition](https://github.com/OPR-Project/OpenPlaceRecognition) recommended environment: - - Ubuntu 22.04 - - Python 3.10 - - CUDA 12.1.1 - - cuDNN 8 - - PyTorch 2.1.2 - - torhvision 0.16.2 - - MinkowskiEngine - - faiss -- ROS2 Humble +# Requirements -It is highly recommended to use the provided Dockerfile to build the environment. -The scripts to build, run and enter the container are provided in the [docker/](./docker) directory. -You can use the following commands: +#### Hardware -create a folder to store: +- **CPU**: 6 or more physical cores +- **RAM**: at least 8 GB +- **GPU**: NVIDIA RTX 2060 or higher (to ensure adequate performance) +- **Video memory**: at least 4 GB +- **Storage**: SSD recommended for faster loading of data and models -cd ~/Downloads -mkdir OpenPlaceRecognition -cd OpenPlaceRecognition -git clone Datasets -git clone OpenPlaceRecognition +#### Software +- **Operating System**: + - Any OS with support for Docker and CUDA >= 11.1. + *Ubuntu 20.04 or later is recommended.* -To use [OpenPlaceRecognition](https://github.com/OPR-Project/OpenPlaceRecognition) library in the container, you need to install it first. +- **Dependencies** (if not using Docker): + - Python >= 3.10 + - CUDA Toolkit >= 11.1 + - cuDNN >= 7.5 + - [OpenPlaceRecognition](https://github.com/OPR-Project/OpenPlaceRecognition) + - [ROS2 Humble](https://docs.ros.org/en/humble/Installation.html) + - Docker -```bash -# 1. build the image -export OPR_PATH=$HOME/Downloads/OpenPlaceRecognition/OpenPlaceRecognition -export DATASETS_DIR=$HOME/Downloads/OpenPlaceRecognition/Datasets -export DISPLAY=:0 -bash docker/build_x86_64.sh - -# 2. start the container and mount the data directory -bash docker/start_x86_64.sh +# Installation -# 3. enter the container -bash docker/into.sh -``` +Firstly retreave all dependencies for this project -Run the following command inside the container: ```bash -pip install -e ~/OpenPlaceRecognition -pip install -e ~/OpenPlaceRecognition/third_party/GeoTransformer -pip install -e ~/OpenPlaceRecognition/third_party/HRegNet -pip install -e ~/OpenPlaceRecognition/third_party/PointMamba -``` +# Step 1: Clone the main repository with submodules +cd ~ +git clone --recursive https://github.com/OPR-Project/OpenPlaceRecognition -# Running nodes +# Step 2: Clone the ITLP-Campus-Outdoor dataset +git clone https://huggingface.co/datasets/OPR-Project/ITLP-Campus-Outdoor ~/Datasets/ITLP-Campus-Outdoor -## Build the workspace +# Step 3: Create required directories for pretrained weights +mkdir -p ~/OpenPlaceRecognition/weights/place_recognition +mkdir -p ~/OpenPlaceRecognition/weights/registration -Inside `ros2_ws/` directory, run the following command: +# Step 4: Download pretrained weights +wget https://huggingface.co/OPR-Project/PlaceRecognition-NCLT/resolve/main/minkloc3d_nclt.pth \ + -O ~/OpenPlaceRecognition/weights/place_recognition/minkloc3d_nclt.pth -```bash -cd ~/ros2_ws/ -colcon build --symlink-install +wget https://huggingface.co/OPR-Project/Registration-KITTI/resolve/main/geotransformer_kitti.pth \ + -O ~/OpenPlaceRecognition/weights/registration/geotransformer_kitti.pth + +# Step 5: Export environment variables +export OPR_PATH=$HOME/OpenPlaceRecognition +export DATASETS_DIR=$HOME/Datasets +export DISPLAY=:0 ``` -## Run the nodes +### Quick Start with Docker -Open the new terminal and run: +It is highly recommended to use the provided Dockerfile to build the complete environment. The Docker scripts are located in the `docker/` directory. For now, we only support x86_64 architecture. The aarch64 version will be released soon. ```bash -source ~/ros2_ws/install/setup.bash -``` +# 0. Clone the repository +git clone https://github.com/OPR-Project/OpenPlaceRecognition-ROS2.git +cd OpenPlaceRecognition-ROS2 -Run the place recognition node using launch file: +# 1. Build the Docker image +bash docker/build_x86_64.sh -```bash -ros2 launch open_place_recognition database_publisher.launch.py -``` +# 2. Start the container with the data directory mounted +bash docker/start_x86_64.sh -```bash -ros2 launch open_place_recognition place_recognition.launch.py +# 3. Enter the container +bash docker/into.sh ``` -Run the visualizer node using launch file: +Inside the container, install the additional Python dependencies: ```bash -ros2 launch open_place_recognition visualizer.launch.py +pip install -e ~/OpenPlaceRecognition +pip install -e ~/OpenPlaceRecognition/third_party/GeoTransformer +pip install -e ~/OpenPlaceRecognition/third_party/HRegNet +pip install -e ~/OpenPlaceRecognition/third_party/PointMamba ``` +### Build the ROS2 Workspace -## Package Overview - -The package includes three main nodes: - -1. **Dataset Creation Node (`dataset_create_node.py`)** - - Creates a dataset for a given map. - - Accepts parameters: - - `dataset_path`: Directory path to store or access the dataset. - - `map_name`: Name of the map for which the dataset is generated. - -2. **Dataset Training Node (`dataset_train_node.py`)** - - Simulates training on the created dataset using Torch. - - Accepts parameters: - - `dataset_path`: Directory path where the dataset is stored. - - `map_name`: Name of the map used for training. - -3. **Model Operation Node (`model_opr_node.py`)** - - Simulates reading a trained model and performing operations with it. - - Accepts parameters: - - `trained_model_path`: Directory path of the trained model. - - `map_name`: Name of the map used during training. - - -## Package Structure - -``` -open_place_recognition/ -├── launch/ -│ ├── dataset_create.launch.py -│ ├── dataset_train.launch.py -│ └── opr_odometry.launch.py -├── src/ -│ ├── dataset_create_node.py -│ ├── dataset_train_node.py -│ └── opr_odom_node.py -├── package.xml -└── README.md +```bash +cd ~/ros2_ws/ +colcon build --symlink-install +source ~/ros2_ws/install/setup.bash ``` -## Building the Package - -1. **Clone the repository into your ROS2 workspace's `src` directory:** +## Launch Files and Usage - ```bash - cd ~/ros2_ws/src - git clone open_place_recognition - ``` +The project provides a variety of launch files to support testing, visualization, and deployment. Each launch file is configurable via command-line arguments to adapt to different sensor setups and dataset paths. -2. **Build the workspace using `colcon`:** +- **Dataset Conversion from Bag Files:** + Convert ROS2 bag files into a standardized OPR dataset format for further processing. + ```bash + ros2 launch open_place_recognition dataset_from_bag.launch.py + ``` - ```bash - cd ~/ros2_ws - colcon build --packages-select open_place_recognition - ``` +- **Dataset Conversion from RTAB-Map:** + Convert RTAB-Map datasets to the compatible format required by the OPR pipeline. + ```bash + ros2 launch open_place_recognition dataset_from_rtabmap.launch.py + ``` -3. **Source your workspace:** +- **Dataset Publisher:** + Publish sensor streams (cameras, LiDAR, etc.) for dataset creation or real-time monitoring. + ```bash + ros2 launch open_place_recognition dataset_publisher.launch.py + ``` - ```bash - source install/setup.bash - ``` +- **Dataset Indexing:** + Index your dataset features to prepare for efficient retrieval and subsequent training. + ```bash + ros2 launch open_place_recognition dataset_indexing.launch.py + ``` -## Running the Nodes +- **Place Recognition:** + This node performs a simple database search using the current sensor inputs (e.g. images, LiDAR) to identify the closest matching location in the pre-built database. + ```bash + ros2 launch open_place_recognition place_recognition.launch.py + ``` -After building the package, you can launch the nodes using the provided launch files. +- **Localization:** + This pipeline extends place recognition by adding position matching algorithms, improving accuracy and robustness for real-world deployment. + ```bash + ros2 launch open_place_recognition localization.launch.py + ``` -### 1. Create Dataset -```bash -ros2 launch open_place_recognition dataset_create.launch.py -``` +## Additional Tools -This command starts the Dataset Creation Node using the parameters provided in the launch file (e.g., dataset path and map name). - -### 2. Train Dataset +For further analysis and visualization, you can run Jupyter Lab from within the container: ```bash -ros2 launch open_place_recognition dataset_train.launch.py -``` - -This command starts the Dataset Training Node, which simulates training on the dataset created in the previous step. - -### 3. Operate on Trained Model - -```bash -ros2 launch open_place_recognition opr.launch.py +export PATH=$PATH:$HOME/.local/bin +cd ~/OpenPlaceRecognition/notebooks +jupyter lab --ip=0.0.0.0 --port=8888 --allow-root ``` -This command starts the Model Operation Node, which simulates reading the trained model and performing operations on it. - -export PATH=$PATH:$HOME/.local/bin -docker_opr_ros2@rover2:~/OpenPlaceRecognition/notebooks$ jupyter lab --ip=0.0.0.0 --port=8888 --allow-root ## License -[Apache 2.0 license](./LICENSE) \ No newline at end of file +This project is licensed under the [Apache 2.0 License](./LICENSE). \ No newline at end of file diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..def4ec0 --- /dev/null +++ b/TODO.md @@ -0,0 +1,5 @@ +- Fix place_recognition node +- Fix localization node +- Add gps/barometer for better global localization +- Test rtabmap and rosbag convertions +- Add docker supports for aarch64(Jetson based PC) \ No newline at end of file diff --git a/open_place_recognition/CMakeLists.txt b/open_place_recognition/CMakeLists.txt index 5fc8046..c2d8c8c 100644 --- a/open_place_recognition/CMakeLists.txt +++ b/open_place_recognition/CMakeLists.txt @@ -23,7 +23,7 @@ install(PROGRAMS src/dataset_from_rosbag_node.py src/dataset_from_rtabmap_node.py src/dataset_publisher_node.py - src/dataset_train_node.py + src/dataset_indexing_node.py src/localization_node.py src/place_recognition_node.py # src/test_depth_estimation_node.py diff --git a/open_place_recognition/launch/dataset_train.launch.py b/open_place_recognition/launch/dataset_indexing.launch.py similarity index 96% rename from open_place_recognition/launch/dataset_train.launch.py rename to open_place_recognition/launch/dataset_indexing.launch.py index 5175ffb..aa142fe 100644 --- a/open_place_recognition/launch/dataset_train.launch.py +++ b/open_place_recognition/launch/dataset_indexing.launch.py @@ -54,8 +54,8 @@ def generate_launch_description(): Node( package='open_place_recognition', - executable='dataset_train_node.py', - name='dataset_train_node', + executable='dataset_indexing_node.py', + name='dataset_indexing_node', output='screen', parameters=[{ 'dataset_path': LaunchConfiguration('dataset_path'), diff --git a/open_place_recognition/src/dataset_train_node.py b/open_place_recognition/src/dataset_indexing_node.py similarity index 98% rename from open_place_recognition/src/dataset_train_node.py rename to open_place_recognition/src/dataset_indexing_node.py index 1c523fa..8a1f6d6 100755 --- a/open_place_recognition/src/dataset_train_node.py +++ b/open_place_recognition/src/dataset_indexing_node.py @@ -17,9 +17,9 @@ from opr.datasets.itlp import ITLPCampus -class DatasetTrainNode(Node): +class DatasetIndexingNode(Node): def __init__(self): - super().__init__('dataset_train_node') + super().__init__('dataset_indexing_node') # # --------------------------- # Declare ROS 2 Parameters @@ -223,7 +223,7 @@ def run_descriptor_extraction( def main(args=None): rclpy.init(args=args) - node = DatasetTrainNode() + node = DatasetIndexingNode() # Spin once and exit (this node does a one-shot operation) rclpy.spin_once(node, timeout_sec=1) node.destroy_node() From a5af59110d40e9e34912026044b902433115995f Mon Sep 17 00:00:00 2001 From: TPODAvia Date: Mon, 28 Apr 2025 13:14:04 +0300 Subject: [PATCH 5/5] Enable sudo inside the docker --- docker/Dockerfile.x86_64 | 12 +++++++++--- .../pipelines/topological_localization_pipeline.yaml | 0 2 files changed, 9 insertions(+), 3 deletions(-) rename {src/open_place_recognition => open_place_recognition}/configs/pipelines/topological_localization_pipeline.yaml (100%) diff --git a/docker/Dockerfile.x86_64 b/docker/Dockerfile.x86_64 index 16b36c9..e7a16ef 100644 --- a/docker/Dockerfile.x86_64 +++ b/docker/Dockerfile.x86_64 @@ -21,16 +21,19 @@ RUN apt-get install -y software-properties-common && add-apt-repository universe curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg && \ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | tee /etc/apt/sources.list.d/ros2.list > /dev/null -# Install ROS2 +# Install ROS2 and common tools RUN apt-get update && apt-get upgrade -y && apt-get install -y \ + sudo \ + wget \ + git \ nano \ + curl \ ros-humble-desktop \ ros-dev-tools \ ros-humble-image-transport-plugins && \ rosdep init && rosdep update # Copy local ROS2 packages into the workspace source directory. -# These folders (open_place_recognition and opr_interfaces) are assumed to be in the repository (build context). RUN mkdir -p /ros2_ws/src # Run additional setup steps from the external OPR folder. @@ -44,7 +47,9 @@ ENV USER=docker_opr_ros2 ARG UID=1000 ARG GID=1000 ARG PW=user -RUN useradd -m ${USER} --uid=${UID} && echo "${USER}:${PW}" | chpasswd && adduser ${USER} sudo +RUN useradd -m ${USER} --uid=${UID} && echo "${USER}:${PW}" | chpasswd && \ + usermod -aG sudo ${USER} && echo "${USER} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + WORKDIR /home/${USER} # Create directories for mounting volumes. @@ -53,6 +58,7 @@ RUN mkdir OpenPlaceRecognition && chown -R ${UID}:${GID} /home/${USER} USER ${UID}:${GID} +# Source ROS2 on startup RUN echo "source /opt/ros/humble/setup.bash" >> /home/${USER}/.bashrc # Install pip requirements from the external folder. diff --git a/src/open_place_recognition/configs/pipelines/topological_localization_pipeline.yaml b/open_place_recognition/configs/pipelines/topological_localization_pipeline.yaml similarity index 100% rename from src/open_place_recognition/configs/pipelines/topological_localization_pipeline.yaml rename to open_place_recognition/configs/pipelines/topological_localization_pipeline.yaml