add some code

This commit is contained in:
2025-09-05 13:25:11 +08:00
parent 9ff0a99e7a
commit 3cf1229a85
8911 changed files with 2535396 additions and 0 deletions

View File

@@ -0,0 +1 @@
619639efc18cfa361a9e423739b9b0ffc14991effc6c027f955c2f2c3bf1754b

View File

@@ -0,0 +1,60 @@
.config
*.o
*.pyc
# gtags
GTAGS
GRTAGS
GPATH
# emacs
.dir-locals.el
# emacs temp file suffixes
*~
.#*
\#*#
# eclipse setting
.settings
# MacOS directory files
.DS_Store
# Example project files
examples/**/sdkconfig
examples/**/sdkconfig.old
examples/**/build
examples/**/dependencies.lock
exmaples/**/managed_components
# Test app files
test_app/build
test_app/sdkconfig
test_app/sdkconfig.old
test_app/dependencies.lock
# Doc build artifacts
docs/_build/
docs/doxygen-warning-log.txt
docs/sphinx-warning-log.txt
docs/sphinx-warning-log-sanitized.txt
docs/xml/
docs/xml_in/
docs/man/
docs/doxygen_sqlite3.db
TEST_LOGS
# gcov coverage reports
*.gcda
*.gcno
coverage.info
coverage_report/
# VS Code Settings
.vscode/
# incorrect build locations
build/

View File

@@ -0,0 +1,19 @@
repos:
- repo: https://github.com/espressif/astyle_py
rev: v1.0.5
hooks:
- id: astyle_py
args: ['--style=otbs', '--attach-namespaces', '--attach-classes', '--indent=spaces=4', '--convert-tabs', '--align-pointer=name', '--align-reference=name', '--keep-one-line-statements', '--pad-header', '--pad-oper']
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
- id: trailing-whitespace
types_or: [c, c++]
- id: end-of-file-fixer
types_or: [c, c++]
- id: check-merge-conflict
- id: mixed-line-ending
types_or: [c, c++]
args: ['--fix=lf']
description: Forces to replace line ending by the UNIX 'lf' character

View File

@@ -0,0 +1,153 @@
# Esp-dsp Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [1.6.0] 2025-04-16
### Added
- IIR filter for stereo data processing
- Add DCT-IV and DST-IV
### Changed
- Improvements for FFT2R and FFT4R for esp32 and esp32s3
- Update 3D graphics applications for M5Stack Core S3 board
- Bugfix for SNR calculation: free array in case of error
- Bugfix for determinant calculation in mat.cpp
- Bugfix esp32s3 sub/mul s8/s16
- Bugfix - definition in fft4_fc32 for esp32p4
- Bugfix for IIR esp32p4
### Removed
## [1.5.2] 2024-08-16
### Changed
- Add esp32p4 chip to chip list into main readme
### Added
- CI test build for Clang
### Removed
## [1.5.1] 2024-08-2
### Added
- Added support for esp32p4 chip
## [1.4.14] 2024-07-31
### Added
- 2D convolution added
## [1.4.13] 2024-05-08
### Added
- ci: add tests for IDF release 5.3
## [1.4.12] 2024-03-21
### Added
- ci: add pre-commit hooks
### Changed
- dock: list of supported targets updated
## [1.4.11] 2024-02-21
### Added
- Fixed point functions mul/add/sub for esp32 and esp32s3
## [1.4.10] 2023-11-30
### Added
- Demo application for ESP32-S3-BOX-Lite Board
## [1.4.9] 2023-11-09
### Added
- New methods for Mat class to support sub-matrix operations
## [1.4.8] 2023-10-16
### Added
- Audio amplifier application for the esp32-LyraT board
## [1.4.7] 2023-07-13
### Changed
- Demo applications added to the component manager as examples
## [1.4.6] 2023-07-11
### Added
- FIR f32 decimation filter optimized for esp32s3
### Changed
- In dsps_fird_init_f32() function the parameter start_pos removed
- In dsps_fird_f32() function the coefficients order changed to backward order
## [1.4.5] 2023-07-11
### Added
- Application for Azure IoT board
- Add Esp32-LyraT board application
## [1.4.4] 2023-07-03
### Changed
- Update documentation build
## [1.4.1] 2023-06-30
### Fixed
- Add Bi-Quad for esp32s3 into common CMakeLists.txt
## [1.4.0] 2023-03-29
### Added
- Complex signal generator dsps_cplx_gen()
- FIR f32 filter optimized for esp32s3
- Memcpy and Memset optimized for esp32s3
### Fixed
- Fix in tests to pass
- Minimum coeffcient length for fird_s16
- Include malloc.h into dsps_fft4r_fc32_ansi.c
- Fix for calculation length for dsps_corr_f32_axxx
### Changed
### Removed
## [1.3.0] 2023-03-10
### Added
- Fixed point FIR filter with decimation
- Update tag to 1.2.1 for component manager
- Extend dsp_power_of_two() to 32-bit value
### Fixed
- add various links to idf_component.yml, exclude unnecessary files
- cmake: update component CMakeLists.txt file syntax to IDF v4.x+
- docs: move instructions for contributors into CONTRIBUTING.md
- docs: update README.md to use IDF component manager for installation
- drop IDF v4.0 and v4.1 support, add a CI build with IDF release/v5.0
- examples: remove GNU Make instructions from README files
- examples: allow examples to be installed from the component manager
- Fix for fft_cplx2reC_f32 function
- Wno-format-fix related errors
- Wrong path for extra component directory
### Changed
### Removed
## [1.2.0] 2022-09-22

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,222 @@
set(srcs "modules/common/misc/dsps_pwroftwo.cpp"
"modules/common/misc/aes3_tie_log.c"
"modules/dotprod/float/dsps_dotprod_f32_ae32.S"
"modules/dotprod/float/dsps_dotprod_f32_m_ae32.S"
"modules/dotprod/float/dsps_dotprode_f32_ae32.S"
"modules/dotprod/float/dsps_dotprode_f32_m_ae32.S"
"modules/dotprod/float/dsps_dotprod_f32_ansi.c"
"modules/dotprod/float/dsps_dotprode_f32_ansi.c"
"modules/dotprod/float/dsps_dotprod_f32_aes3.S"
"modules/dotprod/float/dsps_dotprod_f32_arp4.S"
"modules/dotprod/float/dsps_dotprode_f32_arp4.S"
"modules/dotprod/fixed/dsps_dotprod_s16_ae32.S"
"modules/dotprod/fixed/dsps_dotprod_s16_m_ae32.S"
"modules/dotprod/fixed/dsps_dotprod_s16_ansi.c"
"modules/dotprod/fixed/dsps_dotprod_s16_arp4.S"
"modules/dotprod/float/dspi_dotprod_f32_ansi.c"
"modules/dotprod/float/dspi_dotprod_off_f32_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_s16_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_u16_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_s8_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_u8_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_off_s16_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_off_u16_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_off_s8_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_off_u8_ansi.c"
"modules/dotprod/fixed/dspi_dotprod_s16_aes3.S"
"modules/dotprod/fixed/dspi_dotprod_u16_aes3.S"
"modules/dotprod/fixed/dspi_dotprod_off_s16_aes3.S"
"modules/dotprod/fixed/dspi_dotprod_off_u16_aes3.S"
"modules/dotprod/fixed/dspi_dotprod_s8_aes3.S"
"modules/dotprod/fixed/dspi_dotprod_u8_aes3.S"
"modules/dotprod/fixed/dspi_dotprod_off_u8_aes3.S"
"modules/dotprod/fixed/dspi_dotprod_off_s8_aes3.S"
"modules/dotprod/fixed/dspi_dotprod_s16_arp4.S"
"modules/dotprod/fixed/dspi_dotprod_s8_arp4.S"
"modules/dotprod/fixed/dspi_dotprod_u16_arp4.S"
"modules/dotprod/fixed/dspi_dotprod_u8_arp4.S"
"modules/dotprod/fixed/dspi_dotprod_off_s16_arp4.S"
"modules/dotprod/fixed/dspi_dotprod_off_u16_arp4.S"
"modules/dotprod/fixed/dspi_dotprod_off_s8_arp4.S"
"modules/dotprod/fixed/dspi_dotprod_off_u8_arp4.S"
"modules/matrix/mul/float/dspm_mult_3x3x1_f32_ae32.S"
"modules/matrix/mul/float/dspm_mult_3x3x3_f32_ae32.S"
"modules/matrix/mul/float/dspm_mult_4x4x1_f32_ae32.S"
"modules/matrix/mul/float/dspm_mult_4x4x4_f32_ae32.S"
"modules/matrix/mul/float/dspm_mult_f32_ae32.S"
"modules/matrix/mul/float/dspm_mult_f32_aes3.S"
"modules/matrix/mul/float/dspm_mult_f32_ansi.c"
"modules/matrix/mul/float/dspm_mult_f32_arp4.S"
"modules/matrix/mul/float/dspm_mult_ex_f32_ansi.c"
"modules/matrix/mul/float/dspm_mult_ex_f32_ae32.S"
"modules/matrix/mul/float/dspm_mult_ex_f32_arp4.S"
"modules/matrix/mul/float/dspm_mult_ex_f32_aes3.S"
"modules/matrix/mul/fixed/dspm_mult_s16_ae32.S"
"modules/matrix/mul/fixed/dspm_mult_s16_m_ae32_vector.S"
"modules/matrix/mul/fixed/dspm_mult_s16_m_ae32.S"
"modules/matrix/mul/fixed/dspm_mult_s16_ansi.c"
"modules/matrix/mul/fixed/dspm_mult_s16_aes3.S"
"modules/matrix/mul/fixed/dspm_mult_s16_arp4.S"
"modules/matrix/add/float/dspm_add_f32_ansi.c"
"modules/matrix/add/float/dspm_add_f32_ae32.S"
"modules/matrix/addc/float/dspm_addc_f32_ansi.c"
"modules/matrix/addc/float/dspm_addc_f32_ae32.S"
"modules/matrix/mulc/float/dspm_mulc_f32_ansi.c"
"modules/matrix/mulc/float/dspm_mulc_f32_ae32.S"
"modules/matrix/sub/float/dspm_sub_f32_ansi.c"
"modules/matrix/sub/float/dspm_sub_f32_ae32.S"
"modules/matrix/mat/mat.cpp"
"modules/math/mulc/float/dsps_mulc_f32_ansi.c"
"modules/math/addc/float/dsps_addc_f32_ansi.c"
"modules/math/mulc/fixed/dsps_mulc_s16_ansi.c"
"modules/math/mulc/fixed/dsps_mulc_s16_ae32.S"
"modules/math/add/float/dsps_add_f32_ansi.c"
"modules/math/add/fixed/dsps_add_s16_ansi.c"
"modules/math/add/fixed/dsps_add_s16_ae32.S"
"modules/math/add/fixed/dsps_add_s16_aes3.S"
"modules/math/add/fixed/dsps_add_s8_ansi.c"
"modules/math/add/fixed/dsps_add_s8_aes3.S"
"modules/math/sub/float/dsps_sub_f32_ansi.c"
"modules/math/sub/fixed/dsps_sub_s16_ansi.c"
"modules/math/sub/fixed/dsps_sub_s16_ae32.S"
"modules/math/sub/fixed/dsps_sub_s16_aes3.S"
"modules/math/sub/fixed/dsps_sub_s8_ansi.c"
"modules/math/sub/fixed/dsps_sub_s8_aes3.S"
"modules/math/mul/float/dsps_mul_f32_ansi.c"
"modules/math/mul/fixed/dsps_mul_s16_ansi.c"
"modules/math/mul/fixed/dsps_mul_s16_ae32.S"
"modules/math/mul/fixed/dsps_mul_s16_aes3.S"
"modules/math/mul/fixed/dsps_mul_s8_ansi.c"
"modules/math/mul/fixed/dsps_mul_s8_aes3.S"
"modules/math/mulc/float/dsps_mulc_f32_ae32.S"
"modules/math/addc/float/dsps_addc_f32_ae32.S"
"modules/math/add/float/dsps_add_f32_ae32.S"
"modules/math/sub/float/dsps_sub_f32_ae32.S"
"modules/math/mul/float/dsps_mul_f32_ae32.S"
"modules/math/sqrt/float/dsps_sqrt_f32_ansi.c"
"modules/fft/float/dsps_fft2r_fc32_ae32_.S"
"modules/fft/float/dsps_fft2r_fc32_aes3_.S"
"modules/fft/float/dsps_fft2r_fc32_arp4.S"
"modules/fft/float/dsps_fft2r_fc32_ansi.c"
"modules/fft/float/dsps_fft2r_fc32_ae32.c"
"modules/fft/float/dsps_bit_rev_lookup_fc32_aes3.S"
"modules/fft/float/dsps_fft4r_fc32_ansi.c"
"modules/fft/float/dsps_fft4r_fc32_ae32.c"
"modules/fft/float/dsps_fft4r_fc32_ae32_.S"
"modules/fft/float/dsps_fft4r_fc32_aes3_.S"
"modules/fft/float/dsps_fft4r_fc32_arp4.S"
"modules/fft/float/dsps_fft2r_bitrev_tables_fc32.c"
"modules/fft/float/dsps_fft4r_bitrev_tables_fc32.c"
"modules/fft/fixed/dsps_fft2r_sc16_ae32.S"
"modules/fft/fixed/dsps_fft2r_sc16_ansi.c"
"modules/fft/fixed/dsps_fft2r_sc16_aes3.S"
"modules/fft/fixed/dsps_fft2r_sc16_arp4.S"
"modules/dct/float/dsps_dct_f32.c"
"modules/dct/float/dsps_dctiv_f32.c"
"modules/dct/float/dsps_dstiv_f32.c"
"modules/support/snr/float/dsps_snr_f32.cpp"
"modules/support/sfdr/float/dsps_sfdr_f32.cpp"
"modules/support/misc/dsps_d_gen.c"
"modules/support/misc/dsps_h_gen.c"
"modules/support/misc/dsps_tone_gen.c"
"modules/support/cplx_gen/dsps_cplx_gen.c"
"modules/support/cplx_gen/dsps_cplx_gen.S"
"modules/support/cplx_gen/dsps_cplx_gen_init.c"
"modules/support/mem/esp32s3/dsps_memset_aes3.S"
"modules/support/mem/esp32s3/dsps_memcpy_aes3.S"
"modules/support/view/dsps_view.cpp"
"modules/windows/hann/float/dsps_wind_hann_f32.c"
"modules/windows/blackman/float/dsps_wind_blackman_f32.c"
"modules/windows/blackman_harris/float/dsps_wind_blackman_harris_f32.c"
"modules/windows/blackman_nuttall/float/dsps_wind_blackman_nuttall_f32.c"
"modules/windows/nuttall/float/dsps_wind_nuttall_f32.c"
"modules/windows/flat_top/float/dsps_wind_flat_top_f32.c"
"modules/conv/float/dsps_conv_f32_ansi.c"
"modules/conv/float/dspi_conv_f32_ansi.c"
"modules/conv/float/dsps_conv_f32_ae32.S"
"modules/conv/float/dsps_corr_f32_ansi.c"
"modules/conv/float/dsps_corr_f32_ae32.S"
"modules/conv/float/dsps_ccorr_f32_ansi.c"
"modules/conv/float/dsps_ccorr_f32_ae32.S"
"modules/iir/biquad/dsps_biquad_f32_ae32.S"
"modules/iir/biquad/dsps_biquad_sf32_ae32.S"
"modules/iir/biquad/dsps_biquad_f32_aes3.S"
"modules/iir/biquad/dsps_biquad_f32_arp4.S"
"modules/iir/biquad/dsps_biquad_sf32_arp4.S"
"modules/iir/biquad/dsps_biquad_f32_ansi.c"
"modules/iir/biquad/dsps_biquad_sf32_ansi.c"
"modules/iir/biquad/dsps_biquad_gen_f32.c"
"modules/fir/float/dsps_fir_f32_ae32.S"
"modules/fir/float/dsps_fir_f32_aes3.S"
"modules/fir/float/dsps_fird_f32_ae32.S"
"modules/fir/float/dsps_fird_f32_aes3.S"
"modules/fir/float/dsps_fird_f32_arp4.S"
"modules/fir/float/dsps_fir_f32_ansi.c"
"modules/fir/float/dsps_fir_init_f32.c"
"modules/fir/float/dsps_fird_f32_ansi.c"
"modules/fir/float/dsps_fird_init_f32.c"
"modules/fir/fixed/dsps_fird_init_s16.c"
"modules/fir/fixed/dsps_fird_s16_ansi.c"
"modules/fir/fixed/dsps_fird_s16_ae32.S"
"modules/fir/fixed/dsps_fir_s16_m_ae32.S"
"modules/fir/fixed/dsps_fird_s16_aes3.S"
"modules/fir/fixed/dsps_fird_s16_arp4.S"
# EKF files
"modules/kalman/ekf/common/ekf.cpp"
"modules/kalman/ekf_imu13states/ekf_imu13states.cpp"
)
set(include_dirs "modules/dotprod/include"
"modules/support/include"
"modules/support/mem/include"
"modules/windows/include"
"modules/windows/hann/include"
"modules/windows/blackman/include"
"modules/windows/blackman_harris/include"
"modules/windows/blackman_nuttall/include"
"modules/windows/nuttall/include"
"modules/windows/flat_top/include"
"modules/iir/include"
"modules/fir/include"
"modules/math/include"
"modules/math/add/include"
"modules/math/sub/include"
"modules/math/mul/include"
"modules/math/addc/include"
"modules/math/mulc/include"
"modules/math/sqrt/include"
"modules/matrix/mul/include"
"modules/matrix/add/include"
"modules/matrix/addc/include"
"modules/matrix/mulc/include"
"modules/matrix/sub/include"
"modules/matrix/include"
"modules/fft/include"
"modules/dct/include"
"modules/conv/include"
"modules/common/include"
"modules/matrix/mul/test/include"
# EKF files
"modules/kalman/ekf/include"
"modules/kalman/ekf_imu13states/include"
)
set(priv_include_dirs "modules/dotprod/float"
"modules/dotprod/fixed")
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${include_dirs}
PRIV_INCLUDE_DIRS ${priv_include_dirs})

View File

@@ -0,0 +1,70 @@
# Contributing
Contributions to ESP-DSP project in the form of pull requests, bug reports, and feature requests are welcome!
This document covers various topics related to contributions to the ESP-DSP projects. Please read it if you plan to submit a PR!
## CLA
We require accepting the contributor's license agreement for all pull requests. When opening a pull request the first time you will be prompted to sign the CLA by the [CLA Assistant](https://cla-assistant.io/) service.
## Large-scale Changes
If you'd like to propose a change to the existing APIs or a large-scale refactoring of the implementation, we recommend opening an issue first to discuss this.
## Pre-commit hooks
ESP-DSP project uses [pre-commit hooks](https://pre-commit.com/) to perform code formatting and other checks when you run `git commit`.
To install pre-commit hooks, run `pip install pre-commit && pre-commit install`.
## Updating the Benchmarks Table
The benchmarks table [esp-dsp-benchmarks.rst](docs/esp-dsp-benchmarks.rst) contains benchmarks for ESP32 and ESP32-S3 CPUs. The benchmarks are collected with compiler optimizations for speed (-Os) and for size (-O2). This table may need to be updated if you have changed the implementations of some of the functions.
To build this table:
- Build the test application in the `test_app` directory.
- Run "DSP Benchmarks data" test and copy the output into the CSV file [docs/esp_bm_results.csv](docs/esp_bm_results.csv).
- Run the [docs/build_bm_table.py](docs/build_bm_table.py) script to update the benchmarks table [esp-dsp-benchmarks.rst](docs/esp-dsp-benchmarks.rst).
If you have added new functions, modify the [benchmarks test](test/test_dsp.c) to call these new functions.
## Supported IDF Versions
The component is expected to be usable with multiple supported IDF versions. You can find the list in the [CI workflow file](.gitlab-ci.yml).
Note that for compatibility reasons, the component has to support the legacy GNU Make build system which was present up until ESP-IDF v5.0. Remember to add or update `component.mk` and `Makefile` files when adding or changing examples. GNU Make support can be removed from ESP-DSP when IDF v4.4 maintenance period expires.
## Releasing a new version
Maintainers should follow the steps below to release a new version of ESP-DSP component. Assuming the new version is `vX.Y.Z`:
1. Ensure you are on the latest `master` branch, then create a new branch:
```bash
git checkout master
git pull --ff-only origin master
git checkout -b update_version_vX.Y.Z
```
1. Update the version in [idf_component.yml](idf_component.yml):
```yml
version: "X.Y.Z"
```
1. Commit the changes:
```bash
git add idf_component.yml
git commit -s -m "version: update to vX.Y.Z"
```
1. Create the new tag:
```bash
git tag -s -a -m "vX.Y.Z" vX.Y.Z
```
1. Push the tag and the branch to the internal repository:
```bash
git push origin update_version_vX.Y.Z
git push origin vX.Y.Z
```
1. Create the merge request, get it reviewed and merged.
1. CI will automatically push the tag to Github and will upload the new version to the IDF Component Registry.
1. Go to https://github.com/espressif/esp-dsp/releases and create a release from the tag vX.Y.Z.
1. Write the release notes and publish the release.

View File

@@ -0,0 +1,61 @@
menu "DSP Library"
config DSP_OPTIMIZATIONS_SUPPORTED
bool
default y
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4
choice DSP_OPTIMIZATION
bool "DSP Optimization"
default DSP_OPTIMIZED if DSP_OPTIMIZATIONS_SUPPORTED
default DSP_ANSI
help
An ANSI C version could be used for verification and debug purpose,
or for chips where an optimized version is not available.
config DSP_ANSI
bool "ANSI C"
config DSP_OPTIMIZED
bool "Optimized"
depends on DSP_OPTIMIZATIONS_SUPPORTED
endchoice
config DSP_OPTIMIZATION
int
default 0 if DSP_ANSI
default 1 if DSP_OPTIMIZED
choice DSP_MAX_FFT_SIZE
bool "Maximum FFT length"
default DSP_MAX_FFT_SIZE_4096
help
This is default FFT size for internal usage.
config DSP_MAX_FFT_SIZE_512
bool "512"
config DSP_MAX_FFT_SIZE_1024
bool "1024"
config DSP_MAX_FFT_SIZE_2048
bool "2048"
config DSP_MAX_FFT_SIZE_4096
bool "4096"
config DSP_MAX_FFT_SIZE_8192
bool "8192"
config DSP_MAX_FFT_SIZE_16384
bool "16384"
config DSP_MAX_FFT_SIZE_32768
bool "32768"
endchoice
config DSP_MAX_FFT_SIZE
int
default 512 if DSP_MAX_FFT_SIZE_512
default 1024 if DSP_MAX_FFT_SIZE_1024
default 2048 if DSP_MAX_FFT_SIZE_2048
default 4096 if DSP_MAX_FFT_SIZE_4096
default 8192 if DSP_MAX_FFT_SIZE_8192
default 16384 if DSP_MAX_FFT_SIZE_16384
default 32768 if DSP_MAX_FFT_SIZE_32768
endmenu

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@@ -0,0 +1,82 @@
[![Component Registry](https://components.espressif.com/components/espressif/esp-dsp/badge.svg)](https://components.espressif.com/components/espressif/esp-dsp)
# Espressif DSP Library
ESP-DSP is the official DSP library for all Espressif chips. The library contains optimized functions for [ESP32](https://espressif.com/en/products/hardware/esp32/overview), [ESP32-S3](https://espressif.com/en/products/hardware/esp32s3/overview) and [ESP32P4](https://www.espressif.com/en/products/socs/esp32-p4) chips.
## Overview
ESP-DSP is intended to be used as an [ESP-IDF](https://github.com/espressif/esp-idf) component. For the introduction to ESP-IDF, refer to the [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/).
The ESP-DSP library includes implementations of the following functions:
- Matrix multiplication: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#matrix-operations-apis)
- Dot product: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#dot-product), [example](https://github.com/espressif/esp-dsp/tree/master/examples/dotprod)
- FFT: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#fft), [example](https://github.com/espressif/esp-dsp/tree/master/examples/fft)
- IIR: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#iir), [example](https://github.com/espressif/esp-dsp/tree/master/examples/iir)
- FIR: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#fir)
- Vector math operations: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#math)
- Kalman filter: [reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html#kalman)
Many of the library functions are written in assembly and are optimized for the CPU configuration used in the ESP32. In addition to the optimized implementations, reference implementations written in ANSI C are provided.
Function implementations are provided for single precision floating point (32-bit float), and 16-bit signed integers.
## Documentation
- [ESP-DSP Overview](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-library.html)
- [ESP-DSP API Reference](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-apis.html)
- [ESP-DSP Benchmarks](https://docs.espressif.com/projects/esp-dsp/en/latest/esp-dsp-benchmarks.html)
Documentation found in the above links is automatically generated from the contents of this repository. If you find that some information is missing or incomplete, please report an issue.
## Installation and Usage
The ESP-DSP library is a component for the [ESP-IDF build system](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html).
The recommended way to use the component is to install it from the [IDF Component Registry](https://components.espressif.com/components/espressif/esp-dsp).
### Adding ESP-DSP component to an existing project
In the project directory, run:
```bash
idf.py add-dependency "espressif/esp-dsp"
```
This will add the esp-dsp component as a dependency to the `main` component of your project. You can also add it by editing the `idf_component.yml` file manually.
### Downloading ESP-DSP examples
You can download the example projects from the IDF Component Registry website or use the `idf.py create-project-from-example` command. For example:
```bash
idf.py create-project-from-example "espressif/esp-dsp:basic_math"
```
Please refer to the [IDF Component Registry](https://components.espressif.com/components/espressif/esp-dsp) for the download links and the instructions.
You can also use Git to clone this repository and find all the examples in the `examples/` subdirectory. For the list of the examples, please see [README.md](examples/README.md) in the examples directory.
### Building and running ESP-DSP examples
Build, flash and monitor as this is usually done for ESP-IDF projects:
```bash
idf.py -p PORT flash monitor
```
where `PORT` is the UART port name of your development board, such as `/dev/ttyUSB0` or `COM1`.
Note that you need to set up ESP-IDF before building the project. Refer to the [ESP-IDF Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) if you don't have the environment set up yet.
## Reporting Issues
If you have found an issue in ESP-DSP, or wish to submit an enhancement request, please use the [Issues](https://github.com/espressif/esp-dsp/issues) section on Github.
For general questions related to this library, please use the [esp32.com forum](https://esp32.com/).
## Contributing to ESP-DSP
Please check [CONTRIBUTING.md](CONTRIBUTING.md) if you'd like to contribute to ESP-DSP.
## Copyrights and License
All original source code in this repository is Copyright (C) 2018-2023 Espressif Systems. This source code is licensed under the Apache License 2.0 as described in the file LICENSE.

View File

@@ -0,0 +1,20 @@
# ESP-DSP Applications
This directory contains a range of applications for ESP-DSP library.
These applications are intended to demonstrate part of ESP-DSP functionality (e.g. initialization, execution) and to provide examples of fully working projects built using ESP-DSP component
See the [README.md](../README.md) file in the upper level directory for more information about ESP-DSP.
# Applications Layout
The applications are grouped into subdirectories by category. Each category directory contains one or more projects:
* [ESP32-Azure IoT kit](./azure_board_apps/README.md) applications
* [3d graphics](./azure_board_apps/apps/3d_graphics/README.md) application
* [Kalman filter](./azure_board_apps/apps/kalman_filter/README.md) application
* [LyraT Board](./lyrat_board_app/README.md) application
* [ESP32-S3-BOX-Lite](./spectrum_box_lite/README.md) application

View File

@@ -0,0 +1,5 @@
**/build/
**/sdkconfig
**/sdkconfig.old
**/dependencies.lock
**/managed_components/**

View File

@@ -0,0 +1,29 @@
# ESP-DSP ESP32-Azure IoT kit demo applications
The demo applications are developed for ESP32-Azure IoT kit development board and are demonstrating usage of matrices with ESP-DPS Mat class, Kalman filter and basic
3D projection with matrices
### [3D Graphics demo](apps/3d_graphics)
* a simple rotation of a selected 3D objects is shown on the display
* demonstrating usage the Mat class, matrices and operations with matrices
<div align="center">
<img src= "apps/3d_graphics/3d_graphics.gif">
</div>
### [Kalman filter demo](apps/kalman_filter/)
* a selected 3D object is following movements of the development board with IMU sensors
* the sensors outputs are processed by the Kalman filter
* demonstrating usage the Mat class, matrices, operations with matrices and Kalman filter
<div align="center">
<img src= "apps/kalman_filter/kalman_filter.gif">
</div>
### [3D graphics](graphics/img_to_3d_matrix/example/)
Simple 3D graphics is used in the both demos, to display the 3D on the monochromatic display. The Graphics is using transformation matrices to rotate, scale and translate (move) 3D objects, to show the matrix calculation capabilities of the ESP-DSP repository.
## Used components
* [ESP-DSP](https://github.com/espressif/esp-dsp): matrices, Mat class, Kalman filter
* [ESP-BSP](https://github.com/espressif/esp-bsp): ESP32-Azure IoT kit

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

View File

@@ -0,0 +1,8 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
add_compile_options("-Wno-format")
project(esp-dsp-azure-board-app-3d-graphics)

View File

@@ -0,0 +1,27 @@
# ESP-DSP ESP32-Azure IoT kit 3d graphics demo application
The demo is developed for [ESP32-Azure IoT kit](https://github.com/espressif/esp-bsp/tree/master/esp32_azure_iot_kit) development board and is demonstrating the usage of matrices with `ESP-DSP` `Mat` class, Kalman filter and basic 3D graphics.
The 3D Graphics demo displays a 2D graphics, converted to 3D as a 3D rotating object, on the development board's display. Button press changes the rotation direction of the 3D object. Run the menuconfig using the following command:
idf.py mencuonfig
In the menuconfig's menu item `Demo user configuration` select which 3D object to display. It's either a 3D cube, or ESP logo, or a user-defined graphics. Getting the user-defined graphics is described in an [example](../../graphics/img_to_3d_matrix/example/)
## Running the demo
To start the demo, run the following command:
idf.py build flash monitor
The expected output is the following:
I (570) 3D image demo: Selected 3D image - ESP Logo
I (570) 3D image demo: Showing ESP text
I (6730) 3D image demo: Showing 3D image
Note, that the first line `Selected 3D image` from the expected output depends on the user's Kconfing menu selection
<div align="center">
<img src= "applications/azure_board_apps/apps/3d_graphics/3d_graphics.gif">
</div>

View File

@@ -0,0 +1,240 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "esp_log.h"
#include "ssd1306.h"
#include "bsp/esp-bsp.h"
#include "esp_dsp.h"
#include "cube_matrix.h"
#include "esp_logo.h"
#include "esp_text.h"
#include "graphics_support.h"
#include "image_to_3d_matrix.h"
static ssd1306_handle_t ssd1306_dev = NULL;
static bool button_pressed = true;
dspm::Mat perspective_matrix(MATRIX_SIZE, MATRIX_SIZE);
extern "C" void app_main();
/**
* @brief Initialize 3d image structure
*
* Assigns a 3d image to be displayed to the 3d image structure based on the Kconfig menu result.
* The Kconfig menu is operated by a user
*
* @param image: 3d image structure
*/
static void init_3d_matrix_struct(image_3d_matrix_t *image)
{
#ifdef CONFIG_3D_OBJECT_ESP_LOGO
image->matrix = image_3d_matrix_esp_logo;
image->matrix_len = ((sizeof(image_3d_matrix_esp_logo)) / sizeof(float)) / MATRIX_SIZE;
ESP_LOGI("3D image demo", "Selected 3D image - ESP Logo");
#elif CONFIG_3D_OBJECT_CUSTOM
image->matrix = image_to_3d_matrix_custom;
image->matrix_len = ((sizeof(image_to_3d_matrix_custom)) / sizeof(float)) / MATRIX_SIZE;
ESP_LOGI("3D image demo", "Selected 3D image - User's custom image");
#elif CONFIG_3D_OBJECT_CUBE
image->matrix = cube_vectors_3d;
image->matrix_len = ((sizeof(cube_vectors_3d)) / sizeof(float)) / MATRIX_SIZE;
ESP_LOGI("3D image demo", "Selected 3D image - 3D cube");
#endif
}
/**
* @brief Initialize display
*/
static void app_ssd1306_init(void)
{
ssd1306_dev = ssd1306_create((i2c_port_t)BSP_I2C_NUM, SSD1306_I2C_ADDRESS);
ssd1306_clear_screen(ssd1306_dev, 0x00);
ssd1306_refresh_gram(ssd1306_dev);
}
/**
* @brief Display a 3d image
*
* If the object is the 3d cube, connect the projected cube points by lines and display the lines
* For any other 3d object lit pixels on the display from provided XY coordinates
*
* @param projected_image: 3d matrix from Mat class after projection
*/
static void display_3d_image(dspm::Mat projected_image)
{
ssd1306_clear_screen(ssd1306_dev, 0);
if (OBJECT_3D_CUBE) {
// For the 3D cube, only the 6 points of the cube are transformed
// Cube edges, connecting transformed 3D cube points are connected with lines here
for (uint8_t cube_point = 0; cube_point < CUBE_EDGES; cube_point++) {
ssd1306_draw_line(ssd1306_dev,
(int16_t)projected_image(cube_dict_line_begin[cube_point], 0),
(int16_t)projected_image(cube_dict_line_begin[cube_point], 1),
(int16_t)projected_image(cube_dict_line_end[cube_point], 0),
(int16_t)projected_image(cube_dict_line_end[cube_point], 1));
}
} else {
// Every other 3D image is drawn here pixel by pixel
for (uint32_t pixel = 0; pixel < projected_image.rows; pixel++ ) {
ssd1306_fill_point(ssd1306_dev, projected_image(pixel, 0), projected_image(pixel, 1), 1);
}
}
ssd1306_refresh_gram(ssd1306_dev);
}
/**
* @brief Display ESPRESSIF text
*
* To demonstrate usage of the translation and scaling matrices
*/
static void dispaly_esp_text(void)
{
image_3d_matrix_t esp_text;
esp_text.matrix = image_3d_array_esp_text;
esp_text.matrix_len = ((sizeof(image_3d_array_esp_text)) / sizeof(float)) / MATRIX_SIZE;
int16_t shift_x = -SSD1606_X_CENTER;
dspm::Mat T = dspm::Mat::eye(MATRIX_SIZE); // Transformation matrix
dspm::Mat transformed_image(esp_text.matrix_len, MATRIX_SIZE); // 3D image matrix after transformation
dspm::Mat matrix_3d((float *)esp_text.matrix[0], esp_text.matrix_len, MATRIX_SIZE);
ESP_LOGI("3D image demo", "Showing ESP text");
for (int i = 0; i < 52; i++) {
update_translation_matrix(T, true, (float)shift_x, (float)SSD1606_Y_CENTER, 0);
transformed_image = matrix_3d * T;
ssd1306_clear_screen(ssd1306_dev, 0);
for (uint32_t point = 0; point < transformed_image.rows; point++ ) {
ssd1306_fill_point(ssd1306_dev, transformed_image(point, 0), transformed_image(point, 1), 1);
}
ssd1306_refresh_gram(ssd1306_dev);
vTaskDelay(50 / portTICK_PERIOD_MS);
shift_x += 5;
}
ssd1306_clear_screen(ssd1306_dev, 0);
ssd1306_draw_bitmap(ssd1306_dev, 0, 24, &image_bmp_array_esp_text[0], 128, 24);
ssd1306_refresh_gram(ssd1306_dev);
update_translation_matrix(T, true, (float)SSD1606_X_CENTER, (float)SSD1606_Y_CENTER, 0);
vTaskDelay(100 / portTICK_PERIOD_MS);
float scale = 1;
for (int i = 0; i < 20; i++) {
update_scaling_matrix(T, false, scale, scale, 1);
transformed_image = matrix_3d * T;
ssd1306_clear_screen(ssd1306_dev, 0);
for (uint32_t point = 0; point < transformed_image.rows; point++ ) {
ssd1306_fill_point(ssd1306_dev, transformed_image(point, 0), transformed_image(point, 1), 1);
}
ssd1306_refresh_gram(ssd1306_dev);
vTaskDelay(50 / portTICK_PERIOD_MS);
if (i < 10) {
scale -= 0.05;
} else {
scale += 0.05;
}
}
}
/**
* @brief RTOS task to draw a 3d image.
*
* Updates 3d matrices, prepares the final 3d matrix to be displayed on the display
*
* @param arg: pointer to RTOS task arguments, 3d image structure in this case
*/
static void draw_3d_image_task(void *arg)
{
float rot_y = 0, rot_x = 0;
const float angle_increment = 4;
image_3d_matrix_t *image = (image_3d_matrix_t *)arg;
dspm::Mat T = dspm::Mat::eye(MATRIX_SIZE); // Transformation matrix
dspm::Mat transformed_image(image->matrix_len, MATRIX_SIZE); // 3D image matrix after transformation
dspm::Mat projected_image(image->matrix_len, MATRIX_SIZE); // 3D image matrix after projection
dspm::Mat matrix_3d((float *)image->matrix[0], image->matrix_len, MATRIX_SIZE);
if (OBJECT_3D_CUBE) {
rot_x = 45;
}
while (1) {
if (button_pressed) {
rot_y += angle_increment;
if (rot_y >= 360) {
rot_y -= 360;
}
} else {
rot_y -= angle_increment;
if (rot_y <= 0) {
rot_y += 360;
}
}
// Apply rotation in all the axes to the transformation matrix
update_rotation_matrix(T, rot_x, rot_y, 0);
// Apply translation to the transformation matrix
update_translation_matrix(T, true, ((float)SSD1606_X_CENTER), ((float)SSD1606_Y_CENTER), 0);
// explanation for the matrix multiplication is for the 3D cube scenario, applies for all of the objects
// where matrix rows for the transformed image and the projected image are set according to the specific 3d object
// matrix mul cube_matirx(8x4) * transformation_matrix(4x4) = transformed_cube(8x4)
transformed_image = matrix_3d * T;
// matrix mul transformed_cube(8x4) * perspective_matrix(4x4) = projected_cube(8x4)
projected_image = transformed_image * perspective_matrix;
display_3d_image(projected_image);
vTaskDelay(20 / portTICK_PERIOD_MS);
}
}
void app_main(void)
{
static bool button_prev_val = false;
image_3d_matrix_t image;
ekf_imu13states *ekf13 = new ekf_imu13states();
ekf13->Init();
// Init all board components
bsp_i2c_init();
app_ssd1306_init(); // display init
bsp_leds_init(); // LEDs init
bsp_i2c_set_clk_speed(I2C_CLK_600KHZ); // Set I2C to 600kHz
init_perspective_matrix(perspective_matrix);
init_3d_matrix_struct(&image);
dispaly_esp_text();
vTaskDelay(1000 / portTICK_PERIOD_MS);
xTaskCreate(draw_3d_image_task, "draw_3d_image", 2048, &image, 4, NULL);
ESP_LOGI("3D image demo", "Showing 3D image");
while (1) {
if (bsp_button_get()) {
button_pressed = !button_pressed;
}
if (button_prev_val != button_pressed) {
button_prev_val = button_pressed;
if (button_pressed) {
bsp_led_set(BSP_LED_AZURE, true);
} else {
bsp_led_set(BSP_LED_AZURE, false);
}
}
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}

View File

@@ -0,0 +1,8 @@
idf_component_register(SRCS "3d_graphics_demo.cpp"
"../../../graphics/3d_matrix/3d_matrix_data/esp_logo.c"
"../../../graphics/3d_matrix/3d_matrix_data/esp_text.c"
"../../../graphics/3d_matrix/3d_matrix_data/image_to_3d_matrix.c"
"../../../graphics/3d_matrix/3d_matrix_src/graphics_support.cpp"
INCLUDE_DIRS "."
"../../../graphics/3d_matrix/3d_matrix_data"
"../../../graphics/3d_matrix/3d_matrix_src")

View File

@@ -0,0 +1,19 @@
menu "Demo user configuration"
choice
prompt "Select 3D object"
config 3D_OBJECT_CUBE
bool "3D cube"
help
3D graphics to be displayed is cube
config 3D_OBJECT_ESP_LOGO
bool "3D ESP Logo"
help
3D graphics to be displayed is ESP Logo
config 3D_OBJECT_CUSTOM
bool "User-defined graphics"
help
3D graphics to be displayed is a user-defined graphics
endchoice
endmenu

View File

@@ -0,0 +1,8 @@
## IDF Component Manager Manifest File
description: ESP-DSP azure board application 3d graphics
dependencies:
espressif/esp32_azure_iot_kit: "*"
espressif/esp-dsp:
version: "*"
override_path: "../../../../../../esp-dsp"

View File

@@ -0,0 +1,8 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
add_compile_options("-Wno-format")
project(esp-dsp-azure-board-app-kalman-filter)

View File

@@ -0,0 +1,59 @@
# ESP-DSP ESP32-Azure IoT kit Kalman filter demo application
The demo is developed for [ESP32-Azure IoT kit](https://github.com/espressif/esp-bsp/tree/master/esp32_azure_iot_kit) development board and is demonstrating the usage of matrices with `ESP-DSP` `Mat` class, Kalman filter and basic 3D graphics.
The Kalman filter demo displays a 2D graphics, converted to 3D as a 3D object, on the development board's display. The 3D object follows the movements of the development board, where the Kalman filter is used for processing the output signals of the IMU sensors accommodated on the development board. The 3D object rotation is calculated by the Kalman filter class methods. All 3 IMU sensors present on the dev board (accelerometer, gyroscope and magnetometer) are used for sensing the development board's position.
If the board is inactive (no, or very low rotation is detected) for a set period of time, the demo enters an "Idle" state, in which a 3D rotating object is displayed. Once a certain set level of the board's rotation is detected, the demo enters a normal, "Active", state.
For the project settings, run the menuconfig using the following command:
idf.py mencuonfig
In the menuconfig's menu item `Demo user configuration` select which 3D object to display. It's either 3D cube, or ESP logo, or a user-defined graphics. Getting the user-defined 3D object is described in the [3D Graphics demo](../3d_graphics)
## Kalman filter
#### Calibration
The filter must be calibrated before the first run, which takes several minutes. But the calibration process before each run can be omitted by calibrating the filter once, saving Kalman's filter state vectors to the NVS, and loading those vectors back into the Kalman filter before the run. In addition, every 5 minutes a current state vectors are saved into the flash memory.
## Running the demo
To start the demo, run the following command:
idf.py build flash monitor
The expected output is the following:
I (589) Kalman filter demo: Selected 3D image - 3D cube
I (590) Kalman filter demo: Filter state vectors present in the NVS
I (592) Kalman filter demo: Loading state vectors into the filter structure
I (604) Kalman filter demo: State vectors loaded from the NVS
I (606) Barometer: disabled
I (619) Board status: board put to active mode
I (95780) Board status: board put to idle mode
I (300619) Kalman filter demo: State vectors saved to NVS
Note, that the first line `Selected 3D image` from the expected output depends on the user's Kconfing menu selection
To start the demo and run the initial Kalman filter calibration, one must erase the flash memory, to remove the previously stored Kalman filter's state vectors. To do so, run the following command:
idf.py erase_flash build flash monitor
The expected output is the following:
I (592) Kalman filter demo: Selected 3D image - 3D cube
I (595) Kalman filter demo: Filter state vectors not present in the NVS
I (595) Kalman filter demo: Starting Kalman filter calibration loop
I (100699) Kalman filter demo: Exiting Kalman filter calibration loop
I (100894) Kalman filter demo: Estimated gyroscope bias error [deg/sec]: -0.020715 -0.000431 -0.022452
I (100900) Kalman filter demo: State vectors saved to the NVS
I (100900) Barometer: disabled
I (100911) Board status: board put to active mode
I (196072) Board status: board put to idle mode
I (400912) Kalman filter demo: State vectors saved to NVS
<div align="center">
<img src= "applications/azure_board_apps/apps/kalman_filter/kalman_filter.gif">
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

View File

@@ -0,0 +1,7 @@
idf_component_register(SRCS "kalman_filter_demo.cpp"
"../../../graphics/3d_matrix/3d_matrix_data/esp_logo.c"
"../../../graphics/3d_matrix/3d_matrix_data/image_to_3d_matrix.c"
"../../../graphics/3d_matrix/3d_matrix_src/graphics_support.cpp"
INCLUDE_DIRS "."
"../../../graphics/3d_matrix/3d_matrix_data"
"../../../graphics/3d_matrix/3d_matrix_src")

View File

@@ -0,0 +1,19 @@
menu "Demo user configuration"
choice
prompt "Select 3D object"
config 3D_OBJECT_CUBE
bool "3D cube"
help
3D graphics to be displayed is cube
config 3D_OBJECT_ESP_LOGO
bool "3D ESP Logo"
help
3D graphics to be displayed is ESP Logo
config 3D_OBJECT_CUSTOM
bool "User-defined graphics"
help
3D graphics to be displayed is a user-defined graphics
endchoice
endmenu

View File

@@ -0,0 +1,8 @@
## IDF Component Manager Manifest File
description: ESP-DSP azure board application Kalman filter
dependencies:
espressif/esp32_azure_iot_kit: "*"
espressif/esp-dsp:
version: "*"
override_path: "../../../../../../esp-dsp"

View File

@@ -0,0 +1,608 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <malloc.h>
#include "mpu6050.h"
#include "ssd1306.h"
#include "mag3110.h"
#include "fbm320.h"
#include "bsp/esp-bsp.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "esp_idf_version.h" // for backward compatibility of esp-timer
#include "nvs.h"
#include "nvs_flash.h"
#include "graphics_support.h"
#include "cube_matrix.h"
#include "esp_dsp.h"
#include "ekf_imu13states.h"
#include "esp_logo.h"
#include "image_to_3d_matrix.h"
#define STORAGE_NAMESPACE "kalman_filter"
#define USE_BAROMETER 0
static ssd1306_handle_t ssd1306_dev = NULL;
static mpu6050_handle_t mpu6050_dev = NULL;
static mag3110_handle_t mag3110_dev = NULL;
static fbm320_handle_t fbm320_dev = NULL;
static bool kalman_filter_calibrated = false;
static bool board_inactive = true;
dspm::Mat perspective_matrix(MATRIX_SIZE, MATRIX_SIZE);
extern "C" void app_main();
/**
* @brief Initialize magnetometer
*/
static void app_mag3110_init(void)
{
esp_err_t ret;
mag3110_dev = mag3110_create((i2c_port_t)BSP_I2C_NUM);
mag3110_start_raw(mag3110_dev, MAG3110_DR_OS_80_16);
assert(ESP_OK == ret);
}
/**
* @brief Initialize display
*/
static void app_ssd1306_init(void)
{
ssd1306_dev = ssd1306_create((i2c_port_t)BSP_I2C_NUM, SSD1306_I2C_ADDRESS);
ssd1306_clear_screen(ssd1306_dev, 0x00);
ssd1306_refresh_gram(ssd1306_dev);
}
/**
* @brief Initialize accelerometer and gyroscope
*/
static void mpu6050_init(void)
{
esp_err_t ret;
mpu6050_dev = mpu6050_create((i2c_port_t)BSP_I2C_NUM, MPU6050_I2C_ADDRESS);
ret = mpu6050_config(mpu6050_dev, ACCE_FS_8G, GYRO_FS_2000DPS);
assert(ESP_OK == ret);
ret = mpu6050_wake_up(mpu6050_dev);
assert(ESP_OK == ret);
}
/**
* @brief Initialize pressure sensor
*/
static void app_fbm320_init(void)
{
esp_err_t ret;
fbm320_dev = fbm320_create((i2c_port_t)BSP_I2C_NUM, FBM320_I2C_ADDRESS_1);
ret = fbm320_init(fbm320_dev);
assert(ESP_OK == ret);
}
/**
* @brief Initialize NVS flash memory
*/
static void init_nvs_flash_memory(void)
{
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
// NVS partition was truncated and needs to be erased
// Retry nvs_flash_init
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK( err );
}
/**
* @brief Initialize 3d image structure
*
* Assigns a 3d image to be displayed to the 3d image structure based on the Kconfig menu result.
* The Kconfig menu is operated by a user
*
* @param image: pointer to 3d image structure
* @param ekf13: kalman filter object
*/
static void init_3d_matrix_struct(image_3d_matrix_kalman_t *image, ekf_imu13states *ekf13)
{
#ifdef CONFIG_3D_OBJECT_ESP_LOGO
image->matrix = image_3d_matrix_esp_logo;
image->matrix_len = ((sizeof(image_3d_matrix_esp_logo)) / sizeof(float)) / MATRIX_SIZE;
ESP_LOGI("Kalman filter demo", "Selected 3D image - ESP Logo");
#elif CONFIG_3D_OBJECT_CUSTOM
image->matrix = image_to_3d_matrix_custom;
image->matrix_len = ((sizeof(image_to_3d_matrix_custom)) / sizeof(float)) / MATRIX_SIZE;
ESP_LOGI("Kalman filter demo", "Selected 3D image - User's custom image");
#elif CONFIG_3D_OBJECT_CUBE
image->matrix = cube_vectors_3d;
image->matrix_len = ((sizeof(cube_vectors_3d)) / sizeof(float)) / MATRIX_SIZE;
ESP_LOGI("Kalman filter demo", "Selected 3D image - 3D cube");
#endif
image->ekf13 = ekf13;
}
/**
* @brief Display a 3d image
*
* If the object is the 3d cube, connect the projected cube points by lines and display the lines
* For any other 3d object lit pixels on the display from provided XY coordinates
*
* @param projected_image: 3d matrix from Mat class after projection
*/
static void display_3d_image(dspm::Mat projected_image)
{
ssd1306_clear_screen(ssd1306_dev, 0);
if (OBJECT_3D_CUBE) {
// For the 3D cube, only the 6 points of the cube are transformed
// Cube edges, connecting transformed 3D cube points are connected with lines here
for (uint8_t cube_point = 0; cube_point < CUBE_EDGES; cube_point++) {
ssd1306_draw_line(ssd1306_dev,
(int16_t)projected_image(cube_dict_line_begin[cube_point], 0),
(int16_t)projected_image(cube_dict_line_begin[cube_point], 1),
(int16_t)projected_image(cube_dict_line_end[cube_point], 0),
(int16_t)projected_image(cube_dict_line_end[cube_point], 1));
}
} else {
// Every other 3D image is drawn here pixel by pixel
for (uint32_t pixel = 0; pixel < projected_image.rows; pixel++ ) {
ssd1306_fill_point(ssd1306_dev, projected_image(pixel, 0), projected_image(pixel, 1), 1);
}
}
ssd1306_refresh_gram(ssd1306_dev);
}
/**
* @brief Draw a 3d image
*
* Updates 3d matrices and prepares the final 3d matrix to be displayed on the display.
* Board inactivity check - decides which board mode to display (active or inactive), based on the board movements.
*
* @param ekf13: kalman filter object
* @param transformed_image: 3d matrix holding a 3d image after transformation
* @param projected_image: 3d matrix holding a 3d image after projection
* @param matrix_3d: 3d matrix holding the original 3d image, without any transformation
*/
static void draw_3d_image(ekf_imu13states *ekf13, dspm::Mat &transformed_image, dspm::Mat &projected_image, dspm::Mat &matrix_3d)
{
static const float movement_treshold = 0.0001; // threshold to decide between Idle and Active state of the board
static float inactive_rotation = 0; // rotation angle (in degrees) for Idle state
static unsigned int inactivity_count = 0;
static const unsigned int inactivity_count_treshold = 75;
static unsigned int inactivity_check = 0; // activity of the board is being checked once in N calls of the function
static float prev_state_arr[3] = {0, 0, 0}; // holds the previous state of the Euler angles, to compare the diff
dspm::Mat T = dspm::Mat::eye(MATRIX_SIZE); // Transformation matrix
dspm::Mat R1 = ekf::quat2rotm(ekf13->X.data); // matrix(3x1) that holds x, y, z rotation data
dspm::Mat eul_angles = ekf::rotm2eul(R1);
// check if the board is active or not every N calls of the function
if (!(inactivity_check++ % 10)) {
dspm::Mat prev_state_mat(prev_state_arr, 3, 1);
dspm::Mat diff = eul_angles - prev_state_mat;
prev_state_mat = eul_angles;
float max_diff = fabs(diff(0, 0) * diff(1, 0) * diff(2, 0));
// wake-up the board if the current board movement crosses the threshold
if (board_inactive && (max_diff > movement_treshold)) {
board_inactive = false;
ESP_LOGI("Board status", "board put to active mode");
}
// if the board is awake, and the current movement of the board is lower than the threshold - the board is
// being moved with - run the inactivity_counter
// after some time (if the movement of the board has been lower than the threshold) put the board to idle mode
else if (!board_inactive && (max_diff < movement_treshold)) {
if (inactivity_count > inactivity_count_treshold) {
board_inactive = true;
inactivity_count = 0;
ESP_LOGI("Board status", "board put to idle mode");
update_perspective_matrix(perspective_matrix, 90);
}
inactivity_count++;
}
// if the board is awake and the current movement of the board is higher than the threshold clear the inactivity_counter
else if (!board_inactive && (max_diff >= movement_treshold)) {
inactivity_count = 0;
}
}
if (board_inactive) {
// board idle state - display a rotating cube
update_rotation_matrix(T, inactive_rotation += 3.0, 10.0, 10.0);
} else {
// board active state - 3D object follows movements of the board
eul_angles(2, 0) = -eul_angles(2, 0);
dspm::Mat R = ekf::eul2rotm(eul_angles.data);
// Enlarge rotation matrix from 3x3 to 4x4
// Copy rotation matrix R(3x3) to transformation matrix T_m(4x4)
for (int row = 0; row < R.rows; row++) {
for (int col = 0; col < R.cols; col++) {
T(row, col) = R(row, col);
}
}
}
// explanation for the matrix multiplication is for the 3D cube scenario, applies for all of the objects
// where matrix rows for the transformed image and the projected image are set according to the specific 3d object
// matrix mul cube_matirx(8x4) * transformation_matrix(4x4) = transformed_cube(8x4)
transformed_image = matrix_3d * T;
// matrix mul transformed_cube(8x4) * perspective_matrix(4x4) = projected_cube(8x4)
projected_image = transformed_image * perspective_matrix;
display_3d_image(projected_image);
}
/**
* @brief Kalman filter RTOS task (or ESP timer callback)
*
* Takes IMU sensors measurements to be processed by the Kalman filter
* Function is used as:
* RTOS task - during normal Kalman filter operation
* ESP Timer callback function - during Kalman filter calibration process
*
* @param arg: pointer to RTOS task arguments, 3d image structure in this case
*/
static void kalman_filter_task(void *arg)
{
mpu6050_acce_value_t acce_sample;
mpu6050_gyro_value_t gyro_sample;
mag3110_result_t mag_sample;
image_3d_matrix_kalman_t *kalman_filter_args = (image_3d_matrix_kalman_t *)arg;
ekf_imu13states *ekf13 = kalman_filter_args->ekf13;
dspm::Mat transformed_image(kalman_filter_args->matrix_len, MATRIX_SIZE); // 3D image matrix after transformation
dspm::Mat projected_image(kalman_filter_args->matrix_len, MATRIX_SIZE); // 3D image matrix after projection
dspm::Mat matrix_3d((float *)kalman_filter_args->matrix[0], kalman_filter_args->matrix_len, MATRIX_SIZE);
// Covariance matrix for Kalman filter, set specifically for this development board IMU sensors
float R_m[10] = {0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.000001, 0.000001, 0.000001, 0.000001};
update_perspective_matrix(perspective_matrix, 90);
while (1) {
// dt calculation
static float prev_time = 0;
const float current_time = dsp_get_cpu_cycle_count();
float dt = 0;
// Crystal count difference conversion to Dt time constant
if (current_time > prev_time) {
dt = current_time - prev_time;
dt = dt / 240000000.0;
}
prev_time = current_time;
// Get all the sensors values
mpu6050_get_acce(mpu6050_dev, &acce_sample);
mpu6050_get_gyro(mpu6050_dev, &gyro_sample);
mag3110_get_magnetic_induction(mag3110_dev, &mag_sample);
// Make arrays from the sensors values
float gyro_input_arr[3] = {gyro_sample.gyro_x, gyro_sample.gyro_y, gyro_sample.gyro_z};
float accel_input_arr[3] = {acce_sample.acce_x, acce_sample.acce_y, acce_sample.acce_z};
float mag_input_arr[3] = {(float)mag_sample.x, (float)mag_sample.y, (float)mag_sample.z};
// Accel and Mag data to Mat class
dspm::Mat gyro_input_mat(gyro_input_arr, 3, 1);
dspm::Mat accel_input_mat(accel_input_arr, 3, 1);
dspm::Mat mag_input_mat(mag_input_arr, 3, 1);
// Normalize vectors
dspm::Mat accel_norm = accel_input_mat / accel_input_mat.norm();
dspm::Mat magn_norm = mag_input_mat / mag_input_mat.norm();
gyro_input_mat *= DEG_TO_RAD;
ekf13->Process(gyro_input_mat.data, dt);
ekf13->UpdateRefMeasurementMagn(accel_norm.data, magn_norm.data, R_m);
if (kalman_filter_calibrated) {
// Use the function as RTOS task for the filter calculation
draw_3d_image(ekf13, transformed_image, projected_image, matrix_3d);
vTaskDelay(20 / portTICK_PERIOD_MS);
} else {
// Use the function as a callback for kalman_filter_calibration_timer
break;
}
}
}
/**
* @brief Kalman filter calibration procedure
*
* The Kalman filter must be calibrated before the very first run. The state of the Kalman filter is saved
* into NVS after the calibration.
* The calibration is run, only if no Kalman filter state is saved in the NVS. Which occurs after erasing
* the flash memory. Power cycling the board does not remove the Kalman filter state from the NVS.
*
* @param image: pointer to 3d image structure
*/
static void kalman_filter_calibration(image_3d_matrix_kalman_t *image)
{
ekf_imu13states *ekf13 = image->ekf13;
esp_err_t ret;
nvs_handle_t nvs_handle_kalman;
size_t state_vectors_size = 13 * 14;
float *state_vectors = (float *)malloc(state_vectors_size * sizeof(float));
ret = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &nvs_handle_kalman);
if (ret != ESP_OK) {
ESP_LOGE("NVS error", "(%s) opening NVS!\n", esp_err_to_name(ret));
assert(ESP_OK == ret);
}
// Read previously saved blob, if available
size_t required_size = 0; // value will default to 0, if not set yet in NVS
ret = nvs_get_blob(nvs_handle_kalman, "state_vectors", NULL, &required_size);
if (ret != ESP_OK && ret != ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGE("NVS error", "(%s) reading data from NVS!\n", esp_err_to_name(ret));
assert(ESP_OK == ret);
}
if (required_size > 0) {
ESP_LOGI("Kalman filter demo", "Filter state vectors present in the NVS");
ESP_LOGI("Kalman filter demo", "Loading state vectors into the filter structure");
size_t state_vectors_size_addr = state_vectors_size * sizeof(float);
ret = nvs_get_blob(nvs_handle_kalman, "state_vectors", state_vectors, &state_vectors_size_addr);
if (ret != ESP_OK) {
ESP_LOGE("NVS error", "(%s) reading data from NVS!\n", esp_err_to_name(ret));
assert(ESP_OK == ret);
}
for (int i = 0; i < state_vectors_size; i++) {
if (i < state_vectors_size - 13) {
ekf13->P.data[i] = state_vectors[i];
} else {
ekf13->X.data[i - (state_vectors_size - 13)] = state_vectors[i];
}
}
ESP_LOGI("Kalman filter demo", "State vectors loaded from the NVS");
nvs_close(nvs_handle_kalman);
} else {
ESP_LOGI("Kalman filter demo", "Filter state vectors not present in the NVS");
const float kalman_timer_period_us = 100000;
// ESP timer for the Kalman filter calibration
const esp_timer_create_args_t kalman_calibration_timer_config = {
.callback = kalman_filter_task,
.arg = image,
.dispatch_method = ESP_TIMER_TASK,
.name = "kalman_filter_calibration_timer",
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0)
.skip_unhandled_events = true,
#endif
};
esp_timer_handle_t kalman_calibration_timer = NULL;
ret = esp_timer_create(&kalman_calibration_timer_config, &kalman_calibration_timer);
assert(ESP_OK == ret);
ssd1306_clear_screen(ssd1306_dev, 0x00);
ESP_LOGI("Kalman filter demo", "Starting Kalman filter calibration loop");
ssd1306_clear_screen(ssd1306_dev, 0x00);
ssd1306_draw_string(ssd1306_dev, 0, 16, (const uint8_t *)"Kalman filter", 16, 1);
ssd1306_draw_string(ssd1306_dev, 0, 32, (const uint8_t *)"calibration", 16, 1);
ssd1306_refresh_gram(ssd1306_dev);
ret = esp_timer_start_periodic(kalman_calibration_timer, kalman_timer_period_us);
assert(ESP_OK == ret);
vTaskDelay(100000 / portTICK_PERIOD_MS);
ret = esp_timer_stop(kalman_calibration_timer);
assert(ESP_OK == ret);
ret = esp_timer_delete(kalman_calibration_timer);
assert(ESP_OK == ret);
ESP_LOGI("Kalman filter demo", "Exiting Kalman filter calibration loop");
ssd1306_draw_string(ssd1306_dev, 0, 48, (const uint8_t *)"Done!", 16, 1);
ssd1306_refresh_gram(ssd1306_dev);
vTaskDelay(100 / portTICK_PERIOD_MS);
dspm::Mat estimated_error(&ekf13->X.data[4], 3, 1);
ESP_LOGI("Kalman filter demo", "Estimated gyroscope bias error [deg/sec]: %.6f\t%.6f\t%.6f",
estimated_error.data[0], estimated_error.data[1], estimated_error.data[2]);
for (int i = 0; i < state_vectors_size; i++) {
if (i < state_vectors_size - 13) {
state_vectors[i] = ekf13->P.data[i];
} else {
state_vectors[i] = ekf13->X.data[i - (state_vectors_size - 13)];
}
}
ret = nvs_set_blob(nvs_handle_kalman, "state_vectors", state_vectors, state_vectors_size * sizeof(float));
assert(ESP_OK == ret);
ret = nvs_commit(nvs_handle_kalman);
assert(ESP_OK == ret);
nvs_close(nvs_handle_kalman);
ESP_LOGI("Kalman filter demo", "State vectors saved to the NVS");
}
// Set the initial state of the X vector
ekf13->X(0, 0) = 1;
ekf13->X(0, 1) = 0;
ekf13->X(0, 2) = 0;
ekf13->X(0, 3) = 0;
free(state_vectors);
kalman_filter_calibrated = true;
}
/**
* @brief RTOS task to periodically save the filter state
*
* The Kalman filter state is periodically saved into the NVS, each 5 min. So a recent Kalman filter state
* could be loaded into the Kalman filter object after a power cycle.
*
* @param arg: pointer to RTOS task arguments, Kalman filter object in this case
*/
static void save_state_vectors_task(void *arg)
{
esp_err_t ret;
size_t state_vectors_size = 13 * 14;
nvs_handle_t nvs_handle_kalman;
ekf_imu13states *ekf13 = (ekf_imu13states *)arg;
vTaskDelay((60000 * 5) / portTICK_PERIOD_MS); // 5min
while (1) {
float *state_vectors = (float *)malloc(state_vectors_size * sizeof(float));
ret = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &nvs_handle_kalman);
if (ret != ESP_OK) {
ESP_LOGE("NVS error", "(%s) opening NVS!\n", esp_err_to_name(ret));
assert(ESP_OK == ret);
}
for (int i = 0; i < state_vectors_size; i++) {
if (i < state_vectors_size - 13) {
state_vectors[i] = ekf13->P.data[i];
} else {
state_vectors[i] = ekf13->X.data[i - (state_vectors_size - 13)];
}
}
ret = nvs_set_blob(nvs_handle_kalman, "state_vectors", state_vectors, state_vectors_size * sizeof(float));
if (ret != ESP_OK && ret != ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGE("NVS error", "(%s) writing data to NVS!\n", esp_err_to_name(ret));
assert(ESP_OK == ret);
}
ret = nvs_commit(nvs_handle_kalman);
if (ret != ESP_OK && ret != ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGE("NVS error", "(%s) commiting data to NVS!\n", esp_err_to_name(ret));
assert(ESP_OK == ret);
}
nvs_close(nvs_handle_kalman);
ESP_LOGI("Kalman filter demo", "State vectors saved to NVS");
free(state_vectors);
vTaskDelay((60000 * 5) / portTICK_PERIOD_MS); // Save the State vectors each 5 min
}
}
/**
* @brief ROTS task to read a pressure
*
* Pressure is measured periodically to better average out a stable value of pressure
*
* @param arg: pointer to RTOS task arguments, pointer to the pressure variable in this case
*/
static void get_pressure_task(void *arg)
{
int32_t real_p, real_t;
float *pressure_ptr = (float *)arg;
float pressure_global = *pressure_ptr;
int call_count = 0;
int call_count1 = 0;
float pressure_initial = pressure_global;
float last_pressure = pressure_global;
float baro_image = pressure_global;
bool changed = false;
while (1) {
if (ESP_OK == fbm320_get_data(fbm320_dev, FBM320_MEAS_PRESS_OSR_4096, &real_t, &real_p)) {
pressure_global = (0.999 * pressure_global) + (0.001 * ((float)real_p) / 1000.0);
call_count1++;
}
if (board_inactive) {
pressure_initial = pressure_global;
last_pressure = pressure_global;
baro_image = pressure_global;
} else {
call_count++;
if (fabs(pressure_global - last_pressure) > 0.0005) { // cahnge more than 0.5 Pa
last_pressure = pressure_global;
baro_image = (0.9 * baro_image) + (0.1 * last_pressure);
changed = true;
}
if ((!(call_count % 10)) && changed) {
float fov = 90 + (1000.0 * ((float)(pressure_initial - baro_image)));
update_perspective_matrix(perspective_matrix, fov);
changed = false;
}
}
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
/**
* @brief read the initial value of pressure
*/
float get_initial_pressure(void)
{
float pressure;
int32_t real_p, real_t;
int averagning_loop_count = 500;
ESP_LOGI("Barometer", "Averagining initial barometer pressure");
ssd1306_clear_screen(ssd1306_dev, 0x00);
ssd1306_draw_string(ssd1306_dev, 0, 16, (const uint8_t *)"Barometer", 16, 1);
ssd1306_draw_string(ssd1306_dev, 0, 32, (const uint8_t *)"averaging", 16, 1);
ssd1306_refresh_gram(ssd1306_dev);
// take the first pressure measurement
while (1) {
if (ESP_OK == fbm320_get_data(fbm320_dev, FBM320_MEAS_PRESS_OSR_4096, &real_t, &real_p)) {
pressure = ((float)real_p) / 1000.0; // pressure in kPa
break;
}
}
// average first N measurements
while (averagning_loop_count--) {
if (ESP_OK == fbm320_get_data(fbm320_dev, FBM320_MEAS_PRESS_OSR_4096, &real_t, &real_p)) {
pressure = (0.999 * pressure) + (0.001 * ((float)real_p) / 1000.0);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
ESP_LOGI("Barometer", "Initial value set");
ssd1306_draw_string(ssd1306_dev, 0, 48, (const uint8_t *)"Done!", 16, 1);
ssd1306_refresh_gram(ssd1306_dev);
return (pressure);
}
void app_main(void)
{
image_3d_matrix_kalman_t image;
ekf_imu13states *ekf13 = new ekf_imu13states();
ekf13->Init();
// Init all board components
bsp_i2c_init();
app_ssd1306_init(); // display init
mpu6050_init(); // gyro, acc init
app_mag3110_init(); // magnetometer init
app_fbm320_init(); // barometer init
bsp_leds_init(); // LEDs init
init_nvs_flash_memory(); // Non-Volatile Storage
init_perspective_matrix(perspective_matrix);
init_3d_matrix_struct(&image, ekf13);
kalman_filter_calibration(&image);
// Use a barometer for measuring the altitude
if (USE_BAROMETER) {
float init_pressure = get_initial_pressure();
xTaskCreate(get_pressure_task, "get_pressure_task", 2048 * 4, &init_pressure, 4, NULL);
} else {
ESP_LOGI("Barometer", "disabled");
}
xTaskCreate(kalman_filter_task, "kalman_filter_task", 2048 * 4, &image, 5, NULL);
xTaskCreate(save_state_vectors_task, "save_state_vectors", 2048, ekf13, 6, NULL);
while (1) {
vTaskDelay(10000 / portTICK_PERIOD_MS);
}
}

View File

@@ -0,0 +1,3 @@
img_to_3d_matrix/converted_image/**
img_to_3d_matrix/example/*.c
img_to_3d_matrix/example/*.h

View File

@@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "graphics_support.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define CUBE_POINTS 8
#define CUBE_EDGES 12
#define CUBE_SIDE (SSD1606_Y_CENTER / 2)
// X Y Z coordinates of the cube centered to (0, 0, 0)
const float cube_vectors_3d[CUBE_POINTS][MATRIX_SIZE] =
// X Y Z W
{ {-CUBE_SIDE, -CUBE_SIDE, -CUBE_SIDE, 1}, // -1, -1, -1
{-CUBE_SIDE, -CUBE_SIDE, CUBE_SIDE, 1}, // -1, -1, 1
{-CUBE_SIDE, CUBE_SIDE, -CUBE_SIDE, 1}, // -1, 1, -1
{-CUBE_SIDE, CUBE_SIDE, CUBE_SIDE, 1}, // -1, 1, 1
{ CUBE_SIDE, -CUBE_SIDE, -CUBE_SIDE, 1}, // 1, -1, -1
{ CUBE_SIDE, -CUBE_SIDE, CUBE_SIDE, 1}, // 1, -1, 1
{ CUBE_SIDE, CUBE_SIDE, -CUBE_SIDE, 1}, // 1, 1, -1
{ CUBE_SIDE, CUBE_SIDE, CUBE_SIDE, 1} // 1, 1, 1
};
// Dictionary for 3d cube edges displaying
// Cube edges cube_vectors_3d[3] <-> cube_vectors_3d[1]
// cube_vectors_3d[3] <-> cube_vectors_3d[7]
// cube_vectors_3d[5] <-> cube_vectors_3d[7]
// cube_vectors_3d[5] <-> cube_vectors_3d[1]....
const uint8_t cube_dict_line_begin[CUBE_EDGES] = {3, 3, 5, 5, 2, 2, 4, 4, 3, 7, 1, 5};
const uint8_t cube_dict_line_end[CUBE_EDGES] = {1, 7, 7, 1, 0, 6, 6, 0, 2, 6, 0, 4};
#ifdef CONFIG_3D_OBJECT_CUBE
#define OBJECT_3D_CUBE 1
#else
#define OBJECT_3D_CUBE 0
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,290 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_logo.h"
#ifdef CONFIG_3D_OBJECT_ESP_LOGO
const uint8_t image_bmp_array_esp_logo[512] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00,
0x00, 0x00, 0x0f, 0xc0, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x0c, 0x1f, 0xfc, 0x07, 0xfe, 0x00, 0x00,
0x00, 0x0c, 0x3f, 0xff, 0x03, 0xff, 0x00, 0x00, 0x00, 0x18, 0x7f, 0xff, 0xc0, 0xff, 0xc0, 0x00,
0x00, 0x38, 0x7f, 0xff, 0xf0, 0x7f, 0xe0, 0x00, 0x00, 0x70, 0x7f, 0xff, 0xf8, 0x3f, 0xe0, 0x00,
0x00, 0x60, 0x7f, 0xff, 0xfe, 0x0f, 0xf0, 0x00, 0x00, 0xe0, 0x01, 0xff, 0xff, 0x07, 0xf8, 0x00,
0x00, 0xc0, 0x00, 0x3f, 0xff, 0x83, 0xfc, 0x00, 0x01, 0xc0, 0x00, 0x07, 0xff, 0xe1, 0xfc, 0x00,
0x01, 0x81, 0xfc, 0x01, 0xff, 0xf0, 0xfe, 0x00, 0x01, 0x87, 0xff, 0xc0, 0x7f, 0xf8, 0xfe, 0x00,
0x03, 0x0f, 0xff, 0xf0, 0x3f, 0xf8, 0x7e, 0x00, 0x03, 0x1f, 0xff, 0xfc, 0x1f, 0xfc, 0x3f, 0x00,
0x03, 0x1f, 0xff, 0xff, 0x07, 0xfe, 0x1f, 0x00, 0x03, 0x3f, 0xff, 0xff, 0x83, 0xff, 0x1f, 0x00,
0x06, 0x3f, 0xff, 0xff, 0xc1, 0xff, 0x0f, 0x00, 0x06, 0x3f, 0xff, 0xff, 0xe0, 0xff, 0x8f, 0x80,
0x06, 0x7f, 0x83, 0xff, 0xf0, 0xff, 0xc7, 0x80, 0x06, 0x7f, 0x80, 0x7f, 0xf8, 0x7f, 0xc7, 0x80,
0x06, 0x7f, 0xc0, 0x1f, 0xfc, 0x3f, 0xe3, 0x80, 0x06, 0x3f, 0xfc, 0x0f, 0xfe, 0x3f, 0xe3, 0x80,
0x06, 0x3f, 0xff, 0x07, 0xff, 0x1f, 0xf1, 0x80, 0x06, 0x3f, 0xff, 0xc3, 0xff, 0x0f, 0xf0, 0x00,
0x06, 0x1f, 0xff, 0xe1, 0xff, 0x8f, 0xf0, 0x00, 0x07, 0x0f, 0xff, 0xf0, 0xff, 0x8f, 0xf8, 0x00,
0x03, 0x07, 0xff, 0xf8, 0x7f, 0xc7, 0xf8, 0x00, 0x03, 0x01, 0xff, 0xfc, 0x3f, 0xc7, 0xf8, 0x00,
0x03, 0x00, 0x3f, 0xfe, 0x3f, 0xc7, 0xf8, 0x00, 0x01, 0x80, 0x07, 0xfe, 0x1f, 0xe3, 0xfc, 0x00,
0x01, 0x80, 0x03, 0xff, 0x1f, 0xe3, 0xfc, 0x00, 0x01, 0xc0, 0x01, 0xff, 0x1f, 0xe3, 0xfc, 0x00,
0x00, 0xc0, 0x78, 0xff, 0x0f, 0xe3, 0xfc, 0x00, 0x00, 0xe0, 0xfc, 0x7f, 0x8f, 0xf1, 0xf8, 0x00,
0x00, 0x61, 0xfc, 0x7f, 0x8f, 0xf1, 0xf0, 0x00, 0x00, 0x71, 0xfc, 0x7f, 0x8f, 0xf1, 0xf0, 0x00,
0x00, 0x39, 0xfc, 0x7f, 0x8f, 0xf1, 0xe0, 0x00, 0x00, 0x19, 0xfc, 0x7f, 0x8f, 0xf0, 0x00, 0x00,
0x00, 0x1c, 0xf8, 0x7f, 0x8f, 0xf0, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x7f, 0x8f, 0xf0, 0x10, 0x00,
0x00, 0x07, 0x00, 0x7f, 0x8f, 0xf0, 0x38, 0x00, 0x00, 0x03, 0xc0, 0xff, 0x0f, 0xe0, 0x70, 0x00,
0x00, 0x01, 0xe0, 0x7f, 0x0f, 0xc0, 0xe0, 0x00, 0x00, 0x00, 0x78, 0x1f, 0x00, 0x03, 0xc0, 0x00,
0x00, 0x00, 0x3e, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x7e, 0x00, 0x00,
0x00, 0x00, 0x03, 0xfc, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x07, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const float image_3d_matrix_esp_logo[1427][4] = {
{-2.0, -25.0, 0, 1}, {-1.0, -25.0, 0, 1}, {0.0, -25.0, 0, 1}, {1.0, -25.0, 0, 1}, {2.0, -25.0, 0, 1}, {3.0, -25.0, 0, 1},
{4.0, -25.0, 0, 1}, {5.0, -25.0, 0, 1}, {6.0, -25.0, 0, 1}, {-2.0, -24.0, 0, 1}, {-1.0, -24.0, 0, 1}, {0.0, -24.0, 0, 1},
{1.0, -24.0, 0, 1}, {2.0, -24.0, 0, 1}, {3.0, -24.0, 0, 1}, {4.0, -24.0, 0, 1}, {5.0, -24.0, 0, 1}, {6.0, -24.0, 0, 1},
{7.0, -24.0, 0, 1}, {8.0, -24.0, 0, 1}, {9.0, -24.0, 0, 1}, {1.0, -23.0, 0, 1}, {2.0, -23.0, 0, 1}, {3.0, -23.0, 0, 1},
{4.0, -23.0, 0, 1}, {5.0, -23.0, 0, 1}, {6.0, -23.0, 0, 1}, {7.0, -23.0, 0, 1}, {8.0, -23.0, 0, 1}, {9.0, -23.0, 0, 1},
{10.0, -23.0, 0, 1}, {11.0, -23.0, 0, 1}, {-12.0, -22.0, 0, 1}, {-11.0, -22.0, 0, 1}, {-10.0, -22.0, 0, 1}, {-9.0, -22.0, 0, 1},
{-8.0, -22.0, 0, 1}, {-7.0, -22.0, 0, 1}, {3.0, -22.0, 0, 1}, {4.0, -22.0, 0, 1}, {5.0, -22.0, 0, 1}, {6.0, -22.0, 0, 1},
{7.0, -22.0, 0, 1}, {8.0, -22.0, 0, 1}, {9.0, -22.0, 0, 1}, {10.0, -22.0, 0, 1}, {11.0, -22.0, 0, 1}, {12.0, -22.0, 0, 1},
{13.0, -22.0, 0, 1}, {-20.0, -21.0, 0, 1}, {-19.0, -21.0, 0, 1}, {-13.0, -21.0, 0, 1}, {-12.0, -21.0, 0, 1}, {-11.0, -21.0, 0, 1},
{-10.0, -21.0, 0, 1}, {-9.0, -21.0, 0, 1}, {-8.0, -21.0, 0, 1}, {-7.0, -21.0, 0, 1}, {-6.0, -21.0, 0, 1}, {-5.0, -21.0, 0, 1},
{-4.0, -21.0, 0, 1}, {-3.0, -21.0, 0, 1}, {5.0, -21.0, 0, 1}, {6.0, -21.0, 0, 1}, {7.0, -21.0, 0, 1}, {8.0, -21.0, 0, 1},
{9.0, -21.0, 0, 1}, {10.0, -21.0, 0, 1}, {11.0, -21.0, 0, 1}, {12.0, -21.0, 0, 1}, {13.0, -21.0, 0, 1}, {14.0, -21.0, 0, 1},
{-20.0, -20.0, 0, 1}, {-19.0, -20.0, 0, 1}, {-14.0, -20.0, 0, 1}, {-13.0, -20.0, 0, 1}, {-12.0, -20.0, 0, 1}, {-11.0, -20.0, 0, 1},
{-10.0, -20.0, 0, 1}, {-9.0, -20.0, 0, 1}, {-8.0, -20.0, 0, 1}, {-7.0, -20.0, 0, 1}, {-6.0, -20.0, 0, 1}, {-5.0, -20.0, 0, 1},
{-4.0, -20.0, 0, 1}, {-3.0, -20.0, 0, 1}, {-2.0, -20.0, 0, 1}, {-1.0, -20.0, 0, 1}, {6.0, -20.0, 0, 1}, {7.0, -20.0, 0, 1},
{8.0, -20.0, 0, 1}, {9.0, -20.0, 0, 1}, {10.0, -20.0, 0, 1}, {11.0, -20.0, 0, 1}, {12.0, -20.0, 0, 1}, {13.0, -20.0, 0, 1},
{14.0, -20.0, 0, 1}, {15.0, -20.0, 0, 1}, {-21.0, -19.0, 0, 1}, {-20.0, -19.0, 0, 1}, {-15.0, -19.0, 0, 1}, {-14.0, -19.0, 0, 1},
{-13.0, -19.0, 0, 1}, {-12.0, -19.0, 0, 1}, {-11.0, -19.0, 0, 1}, {-10.0, -19.0, 0, 1}, {-9.0, -19.0, 0, 1}, {-8.0, -19.0, 0, 1},
{-7.0, -19.0, 0, 1}, {-6.0, -19.0, 0, 1}, {-5.0, -19.0, 0, 1}, {-4.0, -19.0, 0, 1}, {-3.0, -19.0, 0, 1}, {-2.0, -19.0, 0, 1},
{-1.0, -19.0, 0, 1}, {0.0, -19.0, 0, 1}, {1.0, -19.0, 0, 1}, {8.0, -19.0, 0, 1}, {9.0, -19.0, 0, 1}, {10.0, -19.0, 0, 1},
{11.0, -19.0, 0, 1}, {12.0, -19.0, 0, 1}, {13.0, -19.0, 0, 1}, {14.0, -19.0, 0, 1}, {15.0, -19.0, 0, 1}, {16.0, -19.0, 0, 1},
{17.0, -19.0, 0, 1}, {-22.0, -18.0, 0, 1}, {-21.0, -18.0, 0, 1}, {-20.0, -18.0, 0, 1}, {-15.0, -18.0, 0, 1}, {-14.0, -18.0, 0, 1},
{-13.0, -18.0, 0, 1}, {-12.0, -18.0, 0, 1}, {-11.0, -18.0, 0, 1}, {-10.0, -18.0, 0, 1}, {-9.0, -18.0, 0, 1}, {-8.0, -18.0, 0, 1},
{-7.0, -18.0, 0, 1}, {-6.0, -18.0, 0, 1}, {-5.0, -18.0, 0, 1}, {-4.0, -18.0, 0, 1}, {-3.0, -18.0, 0, 1}, {-2.0, -18.0, 0, 1},
{-1.0, -18.0, 0, 1}, {0.0, -18.0, 0, 1}, {1.0, -18.0, 0, 1}, {2.0, -18.0, 0, 1}, {3.0, -18.0, 0, 1}, {9.0, -18.0, 0, 1},
{10.0, -18.0, 0, 1}, {11.0, -18.0, 0, 1}, {12.0, -18.0, 0, 1}, {13.0, -18.0, 0, 1}, {14.0, -18.0, 0, 1}, {15.0, -18.0, 0, 1},
{16.0, -18.0, 0, 1}, {17.0, -18.0, 0, 1}, {18.0, -18.0, 0, 1}, {-23.0, -17.0, 0, 1}, {-22.0, -17.0, 0, 1}, {-21.0, -17.0, 0, 1},
{-15.0, -17.0, 0, 1}, {-14.0, -17.0, 0, 1}, {-13.0, -17.0, 0, 1}, {-12.0, -17.0, 0, 1}, {-11.0, -17.0, 0, 1}, {-10.0, -17.0, 0, 1},
{-9.0, -17.0, 0, 1}, {-8.0, -17.0, 0, 1}, {-7.0, -17.0, 0, 1}, {-6.0, -17.0, 0, 1}, {-5.0, -17.0, 0, 1}, {-4.0, -17.0, 0, 1},
{-3.0, -17.0, 0, 1}, {-2.0, -17.0, 0, 1}, {-1.0, -17.0, 0, 1}, {0.0, -17.0, 0, 1}, {1.0, -17.0, 0, 1}, {2.0, -17.0, 0, 1},
{3.0, -17.0, 0, 1}, {4.0, -17.0, 0, 1}, {10.0, -17.0, 0, 1}, {11.0, -17.0, 0, 1}, {12.0, -17.0, 0, 1}, {13.0, -17.0, 0, 1},
{14.0, -17.0, 0, 1}, {15.0, -17.0, 0, 1}, {16.0, -17.0, 0, 1}, {17.0, -17.0, 0, 1}, {18.0, -17.0, 0, 1}, {-23.0, -16.0, 0, 1},
{-22.0, -16.0, 0, 1}, {-15.0, -16.0, 0, 1}, {-14.0, -16.0, 0, 1}, {-13.0, -16.0, 0, 1}, {-12.0, -16.0, 0, 1}, {-11.0, -16.0, 0, 1},
{-10.0, -16.0, 0, 1}, {-9.0, -16.0, 0, 1}, {-8.0, -16.0, 0, 1}, {-7.0, -16.0, 0, 1}, {-6.0, -16.0, 0, 1}, {-5.0, -16.0, 0, 1},
{-4.0, -16.0, 0, 1}, {-3.0, -16.0, 0, 1}, {-2.0, -16.0, 0, 1}, {-1.0, -16.0, 0, 1}, {0.0, -16.0, 0, 1}, {1.0, -16.0, 0, 1},
{2.0, -16.0, 0, 1}, {3.0, -16.0, 0, 1}, {4.0, -16.0, 0, 1}, {5.0, -16.0, 0, 1}, {6.0, -16.0, 0, 1}, {12.0, -16.0, 0, 1},
{13.0, -16.0, 0, 1}, {14.0, -16.0, 0, 1}, {15.0, -16.0, 0, 1}, {16.0, -16.0, 0, 1}, {17.0, -16.0, 0, 1}, {18.0, -16.0, 0, 1},
{19.0, -16.0, 0, 1}, {-24.0, -15.0, 0, 1}, {-23.0, -15.0, 0, 1}, {-22.0, -15.0, 0, 1}, {-9.0, -15.0, 0, 1}, {-8.0, -15.0, 0, 1},
{-7.0, -15.0, 0, 1}, {-6.0, -15.0, 0, 1}, {-5.0, -15.0, 0, 1}, {-4.0, -15.0, 0, 1}, {-3.0, -15.0, 0, 1}, {-2.0, -15.0, 0, 1},
{-1.0, -15.0, 0, 1}, {0.0, -15.0, 0, 1}, {1.0, -15.0, 0, 1}, {2.0, -15.0, 0, 1}, {3.0, -15.0, 0, 1}, {4.0, -15.0, 0, 1},
{5.0, -15.0, 0, 1}, {6.0, -15.0, 0, 1}, {7.0, -15.0, 0, 1}, {13.0, -15.0, 0, 1}, {14.0, -15.0, 0, 1}, {15.0, -15.0, 0, 1},
{16.0, -15.0, 0, 1}, {17.0, -15.0, 0, 1}, {18.0, -15.0, 0, 1}, {19.0, -15.0, 0, 1}, {20.0, -15.0, 0, 1}, {-24.0, -14.0, 0, 1},
{-23.0, -14.0, 0, 1}, {-6.0, -14.0, 0, 1}, {-5.0, -14.0, 0, 1}, {-4.0, -14.0, 0, 1}, {-3.0, -14.0, 0, 1}, {-2.0, -14.0, 0, 1},
{-1.0, -14.0, 0, 1}, {0.0, -14.0, 0, 1}, {1.0, -14.0, 0, 1}, {2.0, -14.0, 0, 1}, {3.0, -14.0, 0, 1}, {4.0, -14.0, 0, 1},
{5.0, -14.0, 0, 1}, {6.0, -14.0, 0, 1}, {7.0, -14.0, 0, 1}, {8.0, -14.0, 0, 1}, {14.0, -14.0, 0, 1}, {15.0, -14.0, 0, 1},
{16.0, -14.0, 0, 1}, {17.0, -14.0, 0, 1}, {18.0, -14.0, 0, 1}, {19.0, -14.0, 0, 1}, {20.0, -14.0, 0, 1}, {21.0, -14.0, 0, 1},
{-25.0, -13.0, 0, 1}, {-24.0, -13.0, 0, 1}, {-23.0, -13.0, 0, 1}, {-3.0, -13.0, 0, 1}, {-2.0, -13.0, 0, 1}, {-1.0, -13.0, 0, 1},
{0.0, -13.0, 0, 1}, {1.0, -13.0, 0, 1}, {2.0, -13.0, 0, 1}, {3.0, -13.0, 0, 1}, {4.0, -13.0, 0, 1}, {5.0, -13.0, 0, 1},
{6.0, -13.0, 0, 1}, {7.0, -13.0, 0, 1}, {8.0, -13.0, 0, 1}, {9.0, -13.0, 0, 1}, {10.0, -13.0, 0, 1}, {15.0, -13.0, 0, 1},
{16.0, -13.0, 0, 1}, {17.0, -13.0, 0, 1}, {18.0, -13.0, 0, 1}, {19.0, -13.0, 0, 1}, {20.0, -13.0, 0, 1}, {21.0, -13.0, 0, 1},
{-25.0, -12.0, 0, 1}, {-24.0, -12.0, 0, 1}, {-17.0, -12.0, 0, 1}, {-16.0, -12.0, 0, 1}, {-15.0, -12.0, 0, 1}, {-14.0, -12.0, 0, 1},
{-13.0, -12.0, 0, 1}, {-12.0, -12.0, 0, 1}, {-11.0, -12.0, 0, 1}, {-1.0, -12.0, 0, 1}, {0.0, -12.0, 0, 1}, {1.0, -12.0, 0, 1},
{2.0, -12.0, 0, 1}, {3.0, -12.0, 0, 1}, {4.0, -12.0, 0, 1}, {5.0, -12.0, 0, 1}, {6.0, -12.0, 0, 1}, {7.0, -12.0, 0, 1},
{8.0, -12.0, 0, 1}, {9.0, -12.0, 0, 1}, {10.0, -12.0, 0, 1}, {11.0, -12.0, 0, 1}, {16.0, -12.0, 0, 1}, {17.0, -12.0, 0, 1},
{18.0, -12.0, 0, 1}, {19.0, -12.0, 0, 1}, {20.0, -12.0, 0, 1}, {21.0, -12.0, 0, 1}, {22.0, -12.0, 0, 1}, {-25.0, -11.0, 0, 1},
{-24.0, -11.0, 0, 1}, {-19.0, -11.0, 0, 1}, {-18.0, -11.0, 0, 1}, {-17.0, -11.0, 0, 1}, {-16.0, -11.0, 0, 1}, {-15.0, -11.0, 0, 1},
{-14.0, -11.0, 0, 1}, {-13.0, -11.0, 0, 1}, {-12.0, -11.0, 0, 1}, {-11.0, -11.0, 0, 1}, {-10.0, -11.0, 0, 1}, {-9.0, -11.0, 0, 1},
{-8.0, -11.0, 0, 1}, {-7.0, -11.0, 0, 1}, {1.0, -11.0, 0, 1}, {2.0, -11.0, 0, 1}, {3.0, -11.0, 0, 1}, {4.0, -11.0, 0, 1},
{5.0, -11.0, 0, 1}, {6.0, -11.0, 0, 1}, {7.0, -11.0, 0, 1}, {8.0, -11.0, 0, 1}, {9.0, -11.0, 0, 1}, {10.0, -11.0, 0, 1},
{11.0, -11.0, 0, 1}, {12.0, -11.0, 0, 1}, {16.0, -11.0, 0, 1}, {17.0, -11.0, 0, 1}, {18.0, -11.0, 0, 1}, {19.0, -11.0, 0, 1},
{20.0, -11.0, 0, 1}, {21.0, -11.0, 0, 1}, {22.0, -11.0, 0, 1}, {-26.0, -10.0, 0, 1}, {-25.0, -10.0, 0, 1}, {-20.0, -10.0, 0, 1},
{-19.0, -10.0, 0, 1}, {-18.0, -10.0, 0, 1}, {-17.0, -10.0, 0, 1}, {-16.0, -10.0, 0, 1}, {-15.0, -10.0, 0, 1}, {-14.0, -10.0, 0, 1},
{-13.0, -10.0, 0, 1}, {-12.0, -10.0, 0, 1}, {-11.0, -10.0, 0, 1}, {-10.0, -10.0, 0, 1}, {-9.0, -10.0, 0, 1}, {-8.0, -10.0, 0, 1},
{-7.0, -10.0, 0, 1}, {-6.0, -10.0, 0, 1}, {-5.0, -10.0, 0, 1}, {2.0, -10.0, 0, 1}, {3.0, -10.0, 0, 1}, {4.0, -10.0, 0, 1},
{5.0, -10.0, 0, 1}, {6.0, -10.0, 0, 1}, {7.0, -10.0, 0, 1}, {8.0, -10.0, 0, 1}, {9.0, -10.0, 0, 1}, {10.0, -10.0, 0, 1},
{11.0, -10.0, 0, 1}, {12.0, -10.0, 0, 1}, {17.0, -10.0, 0, 1}, {18.0, -10.0, 0, 1}, {19.0, -10.0, 0, 1}, {20.0, -10.0, 0, 1},
{21.0, -10.0, 0, 1}, {22.0, -10.0, 0, 1}, {-26.0, -9.0, 0, 1}, {-25.0, -9.0, 0, 1}, {-21.0, -9.0, 0, 1}, {-20.0, -9.0, 0, 1},
{-19.0, -9.0, 0, 1}, {-18.0, -9.0, 0, 1}, {-17.0, -9.0, 0, 1}, {-16.0, -9.0, 0, 1}, {-15.0, -9.0, 0, 1}, {-14.0, -9.0, 0, 1},
{-13.0, -9.0, 0, 1}, {-12.0, -9.0, 0, 1}, {-11.0, -9.0, 0, 1}, {-10.0, -9.0, 0, 1}, {-9.0, -9.0, 0, 1}, {-8.0, -9.0, 0, 1},
{-7.0, -9.0, 0, 1}, {-6.0, -9.0, 0, 1}, {-5.0, -9.0, 0, 1}, {-4.0, -9.0, 0, 1}, {-3.0, -9.0, 0, 1}, {3.0, -9.0, 0, 1},
{4.0, -9.0, 0, 1}, {5.0, -9.0, 0, 1}, {6.0, -9.0, 0, 1}, {7.0, -9.0, 0, 1}, {8.0, -9.0, 0, 1}, {9.0, -9.0, 0, 1},
{10.0, -9.0, 0, 1}, {11.0, -9.0, 0, 1}, {12.0, -9.0, 0, 1}, {13.0, -9.0, 0, 1}, {18.0, -9.0, 0, 1}, {19.0, -9.0, 0, 1},
{20.0, -9.0, 0, 1}, {21.0, -9.0, 0, 1}, {22.0, -9.0, 0, 1}, {23.0, -9.0, 0, 1}, {-26.0, -8.0, 0, 1}, {-25.0, -8.0, 0, 1},
{-21.0, -8.0, 0, 1}, {-20.0, -8.0, 0, 1}, {-19.0, -8.0, 0, 1}, {-18.0, -8.0, 0, 1}, {-17.0, -8.0, 0, 1}, {-16.0, -8.0, 0, 1},
{-15.0, -8.0, 0, 1}, {-14.0, -8.0, 0, 1}, {-13.0, -8.0, 0, 1}, {-12.0, -8.0, 0, 1}, {-11.0, -8.0, 0, 1}, {-10.0, -8.0, 0, 1},
{-9.0, -8.0, 0, 1}, {-8.0, -8.0, 0, 1}, {-7.0, -8.0, 0, 1}, {-6.0, -8.0, 0, 1}, {-5.0, -8.0, 0, 1}, {-4.0, -8.0, 0, 1},
{-3.0, -8.0, 0, 1}, {-2.0, -8.0, 0, 1}, {-1.0, -8.0, 0, 1}, {5.0, -8.0, 0, 1}, {6.0, -8.0, 0, 1}, {7.0, -8.0, 0, 1},
{8.0, -8.0, 0, 1}, {9.0, -8.0, 0, 1}, {10.0, -8.0, 0, 1}, {11.0, -8.0, 0, 1}, {12.0, -8.0, 0, 1}, {13.0, -8.0, 0, 1},
{14.0, -8.0, 0, 1}, {19.0, -8.0, 0, 1}, {20.0, -8.0, 0, 1}, {21.0, -8.0, 0, 1}, {22.0, -8.0, 0, 1}, {23.0, -8.0, 0, 1},
{-26.0, -7.0, 0, 1}, {-25.0, -7.0, 0, 1}, {-22.0, -7.0, 0, 1}, {-21.0, -7.0, 0, 1}, {-20.0, -7.0, 0, 1}, {-19.0, -7.0, 0, 1},
{-18.0, -7.0, 0, 1}, {-17.0, -7.0, 0, 1}, {-16.0, -7.0, 0, 1}, {-15.0, -7.0, 0, 1}, {-14.0, -7.0, 0, 1}, {-13.0, -7.0, 0, 1},
{-12.0, -7.0, 0, 1}, {-11.0, -7.0, 0, 1}, {-10.0, -7.0, 0, 1}, {-9.0, -7.0, 0, 1}, {-8.0, -7.0, 0, 1}, {-7.0, -7.0, 0, 1},
{-6.0, -7.0, 0, 1}, {-5.0, -7.0, 0, 1}, {-4.0, -7.0, 0, 1}, {-3.0, -7.0, 0, 1}, {-2.0, -7.0, 0, 1}, {-1.0, -7.0, 0, 1},
{0.0, -7.0, 0, 1}, {6.0, -7.0, 0, 1}, {7.0, -7.0, 0, 1}, {8.0, -7.0, 0, 1}, {9.0, -7.0, 0, 1}, {10.0, -7.0, 0, 1},
{11.0, -7.0, 0, 1}, {12.0, -7.0, 0, 1}, {13.0, -7.0, 0, 1}, {14.0, -7.0, 0, 1}, {15.0, -7.0, 0, 1}, {19.0, -7.0, 0, 1},
{20.0, -7.0, 0, 1}, {21.0, -7.0, 0, 1}, {22.0, -7.0, 0, 1}, {23.0, -7.0, 0, 1}, {-27.0, -6.0, 0, 1}, {-26.0, -6.0, 0, 1},
{-22.0, -6.0, 0, 1}, {-21.0, -6.0, 0, 1}, {-20.0, -6.0, 0, 1}, {-19.0, -6.0, 0, 1}, {-18.0, -6.0, 0, 1}, {-17.0, -6.0, 0, 1},
{-16.0, -6.0, 0, 1}, {-15.0, -6.0, 0, 1}, {-14.0, -6.0, 0, 1}, {-13.0, -6.0, 0, 1}, {-12.0, -6.0, 0, 1}, {-11.0, -6.0, 0, 1},
{-10.0, -6.0, 0, 1}, {-9.0, -6.0, 0, 1}, {-8.0, -6.0, 0, 1}, {-7.0, -6.0, 0, 1}, {-6.0, -6.0, 0, 1}, {-5.0, -6.0, 0, 1},
{-4.0, -6.0, 0, 1}, {-3.0, -6.0, 0, 1}, {-2.0, -6.0, 0, 1}, {-1.0, -6.0, 0, 1}, {0.0, -6.0, 0, 1}, {1.0, -6.0, 0, 1},
{7.0, -6.0, 0, 1}, {8.0, -6.0, 0, 1}, {9.0, -6.0, 0, 1}, {10.0, -6.0, 0, 1}, {11.0, -6.0, 0, 1}, {12.0, -6.0, 0, 1},
{13.0, -6.0, 0, 1}, {14.0, -6.0, 0, 1}, {15.0, -6.0, 0, 1}, {20.0, -6.0, 0, 1}, {21.0, -6.0, 0, 1}, {22.0, -6.0, 0, 1},
{23.0, -6.0, 0, 1}, {-27.0, -5.0, 0, 1}, {-26.0, -5.0, 0, 1}, {-22.0, -5.0, 0, 1}, {-21.0, -5.0, 0, 1}, {-20.0, -5.0, 0, 1},
{-19.0, -5.0, 0, 1}, {-18.0, -5.0, 0, 1}, {-17.0, -5.0, 0, 1}, {-16.0, -5.0, 0, 1}, {-15.0, -5.0, 0, 1}, {-14.0, -5.0, 0, 1},
{-13.0, -5.0, 0, 1}, {-12.0, -5.0, 0, 1}, {-11.0, -5.0, 0, 1}, {-10.0, -5.0, 0, 1}, {-9.0, -5.0, 0, 1}, {-8.0, -5.0, 0, 1},
{-7.0, -5.0, 0, 1}, {-6.0, -5.0, 0, 1}, {-5.0, -5.0, 0, 1}, {-4.0, -5.0, 0, 1}, {-3.0, -5.0, 0, 1}, {-2.0, -5.0, 0, 1},
{-1.0, -5.0, 0, 1}, {0.0, -5.0, 0, 1}, {1.0, -5.0, 0, 1}, {2.0, -5.0, 0, 1}, {8.0, -5.0, 0, 1}, {9.0, -5.0, 0, 1},
{10.0, -5.0, 0, 1}, {11.0, -5.0, 0, 1}, {12.0, -5.0, 0, 1}, {13.0, -5.0, 0, 1}, {14.0, -5.0, 0, 1}, {15.0, -5.0, 0, 1},
{16.0, -5.0, 0, 1}, {20.0, -5.0, 0, 1}, {21.0, -5.0, 0, 1}, {22.0, -5.0, 0, 1}, {23.0, -5.0, 0, 1}, {24.0, -5.0, 0, 1},
{-27.0, -4.0, 0, 1}, {-26.0, -4.0, 0, 1}, {-23.0, -4.0, 0, 1}, {-22.0, -4.0, 0, 1}, {-21.0, -4.0, 0, 1}, {-20.0, -4.0, 0, 1},
{-19.0, -4.0, 0, 1}, {-18.0, -4.0, 0, 1}, {-17.0, -4.0, 0, 1}, {-16.0, -4.0, 0, 1}, {-10.0, -4.0, 0, 1}, {-9.0, -4.0, 0, 1},
{-8.0, -4.0, 0, 1}, {-7.0, -4.0, 0, 1}, {-6.0, -4.0, 0, 1}, {-5.0, -4.0, 0, 1}, {-4.0, -4.0, 0, 1}, {-3.0, -4.0, 0, 1},
{-2.0, -4.0, 0, 1}, {-1.0, -4.0, 0, 1}, {0.0, -4.0, 0, 1}, {1.0, -4.0, 0, 1}, {2.0, -4.0, 0, 1}, {3.0, -4.0, 0, 1},
{8.0, -4.0, 0, 1}, {9.0, -4.0, 0, 1}, {10.0, -4.0, 0, 1}, {11.0, -4.0, 0, 1}, {12.0, -4.0, 0, 1}, {13.0, -4.0, 0, 1},
{14.0, -4.0, 0, 1}, {15.0, -4.0, 0, 1}, {16.0, -4.0, 0, 1}, {17.0, -4.0, 0, 1}, {21.0, -4.0, 0, 1}, {22.0, -4.0, 0, 1},
{23.0, -4.0, 0, 1}, {24.0, -4.0, 0, 1}, {-27.0, -3.0, 0, 1}, {-26.0, -3.0, 0, 1}, {-23.0, -3.0, 0, 1}, {-22.0, -3.0, 0, 1},
{-21.0, -3.0, 0, 1}, {-20.0, -3.0, 0, 1}, {-19.0, -3.0, 0, 1}, {-18.0, -3.0, 0, 1}, {-17.0, -3.0, 0, 1}, {-16.0, -3.0, 0, 1},
{-7.0, -3.0, 0, 1}, {-6.0, -3.0, 0, 1}, {-5.0, -3.0, 0, 1}, {-4.0, -3.0, 0, 1}, {-3.0, -3.0, 0, 1}, {-2.0, -3.0, 0, 1},
{-1.0, -3.0, 0, 1}, {0.0, -3.0, 0, 1}, {1.0, -3.0, 0, 1}, {2.0, -3.0, 0, 1}, {3.0, -3.0, 0, 1}, {4.0, -3.0, 0, 1},
{9.0, -3.0, 0, 1}, {10.0, -3.0, 0, 1}, {11.0, -3.0, 0, 1}, {12.0, -3.0, 0, 1}, {13.0, -3.0, 0, 1}, {14.0, -3.0, 0, 1},
{15.0, -3.0, 0, 1}, {16.0, -3.0, 0, 1}, {17.0, -3.0, 0, 1}, {21.0, -3.0, 0, 1}, {22.0, -3.0, 0, 1}, {23.0, -3.0, 0, 1},
{24.0, -3.0, 0, 1}, {-27.0, -2.0, 0, 1}, {-26.0, -2.0, 0, 1}, {-23.0, -2.0, 0, 1}, {-22.0, -2.0, 0, 1}, {-21.0, -2.0, 0, 1},
{-20.0, -2.0, 0, 1}, {-19.0, -2.0, 0, 1}, {-18.0, -2.0, 0, 1}, {-17.0, -2.0, 0, 1}, {-16.0, -2.0, 0, 1}, {-15.0, -2.0, 0, 1},
{-5.0, -2.0, 0, 1}, {-4.0, -2.0, 0, 1}, {-3.0, -2.0, 0, 1}, {-2.0, -2.0, 0, 1}, {-1.0, -2.0, 0, 1}, {0.0, -2.0, 0, 1},
{1.0, -2.0, 0, 1}, {2.0, -2.0, 0, 1}, {3.0, -2.0, 0, 1}, {4.0, -2.0, 0, 1}, {5.0, -2.0, 0, 1}, {10.0, -2.0, 0, 1},
{11.0, -2.0, 0, 1}, {12.0, -2.0, 0, 1}, {13.0, -2.0, 0, 1}, {14.0, -2.0, 0, 1}, {15.0, -2.0, 0, 1}, {16.0, -2.0, 0, 1},
{17.0, -2.0, 0, 1}, {18.0, -2.0, 0, 1}, {22.0, -2.0, 0, 1}, {23.0, -2.0, 0, 1}, {24.0, -2.0, 0, 1}, {-27.0, -1.0, 0, 1},
{-26.0, -1.0, 0, 1}, {-22.0, -1.0, 0, 1}, {-21.0, -1.0, 0, 1}, {-20.0, -1.0, 0, 1}, {-19.0, -1.0, 0, 1}, {-18.0, -1.0, 0, 1},
{-17.0, -1.0, 0, 1}, {-16.0, -1.0, 0, 1}, {-15.0, -1.0, 0, 1}, {-14.0, -1.0, 0, 1}, {-13.0, -1.0, 0, 1}, {-12.0, -1.0, 0, 1},
{-11.0, -1.0, 0, 1}, {-4.0, -1.0, 0, 1}, {-3.0, -1.0, 0, 1}, {-2.0, -1.0, 0, 1}, {-1.0, -1.0, 0, 1}, {0.0, -1.0, 0, 1},
{1.0, -1.0, 0, 1}, {2.0, -1.0, 0, 1}, {3.0, -1.0, 0, 1}, {4.0, -1.0, 0, 1}, {5.0, -1.0, 0, 1}, {6.0, -1.0, 0, 1},
{10.0, -1.0, 0, 1}, {11.0, -1.0, 0, 1}, {12.0, -1.0, 0, 1}, {13.0, -1.0, 0, 1}, {14.0, -1.0, 0, 1}, {15.0, -1.0, 0, 1},
{16.0, -1.0, 0, 1}, {17.0, -1.0, 0, 1}, {18.0, -1.0, 0, 1}, {22.0, -1.0, 0, 1}, {23.0, -1.0, 0, 1}, {24.0, -1.0, 0, 1},
{-27.0, 0.0, 0, 1}, {-26.0, 0.0, 0, 1}, {-22.0, 0.0, 0, 1}, {-21.0, 0.0, 0, 1}, {-20.0, 0.0, 0, 1}, {-19.0, 0.0, 0, 1},
{-18.0, 0.0, 0, 1}, {-17.0, 0.0, 0, 1}, {-16.0, 0.0, 0, 1}, {-15.0, 0.0, 0, 1}, {-14.0, 0.0, 0, 1}, {-13.0, 0.0, 0, 1},
{-12.0, 0.0, 0, 1}, {-11.0, 0.0, 0, 1}, {-10.0, 0.0, 0, 1}, {-9.0, 0.0, 0, 1}, {-3.0, 0.0, 0, 1}, {-2.0, 0.0, 0, 1},
{-1.0, 0.0, 0, 1}, {0.0, 0.0, 0, 1}, {1.0, 0.0, 0, 1}, {2.0, 0.0, 0, 1}, {3.0, 0.0, 0, 1}, {4.0, 0.0, 0, 1},
{5.0, 0.0, 0, 1}, {6.0, 0.0, 0, 1}, {7.0, 0.0, 0, 1}, {11.0, 0.0, 0, 1}, {12.0, 0.0, 0, 1}, {13.0, 0.0, 0, 1},
{14.0, 0.0, 0, 1}, {15.0, 0.0, 0, 1}, {16.0, 0.0, 0, 1}, {17.0, 0.0, 0, 1}, {18.0, 0.0, 0, 1}, {19.0, 0.0, 0, 1},
{23.0, 0.0, 0, 1}, {24.0, 0.0, 0, 1}, {-27.0, 1.0, 0, 1}, {-26.0, 1.0, 0, 1}, {-22.0, 1.0, 0, 1}, {-21.0, 1.0, 0, 1},
{-20.0, 1.0, 0, 1}, {-19.0, 1.0, 0, 1}, {-18.0, 1.0, 0, 1}, {-17.0, 1.0, 0, 1}, {-16.0, 1.0, 0, 1}, {-15.0, 1.0, 0, 1},
{-14.0, 1.0, 0, 1}, {-13.0, 1.0, 0, 1}, {-12.0, 1.0, 0, 1}, {-11.0, 1.0, 0, 1}, {-10.0, 1.0, 0, 1}, {-9.0, 1.0, 0, 1},
{-8.0, 1.0, 0, 1}, {-7.0, 1.0, 0, 1}, {-2.0, 1.0, 0, 1}, {-1.0, 1.0, 0, 1}, {0.0, 1.0, 0, 1}, {1.0, 1.0, 0, 1},
{2.0, 1.0, 0, 1}, {3.0, 1.0, 0, 1}, {4.0, 1.0, 0, 1}, {5.0, 1.0, 0, 1}, {6.0, 1.0, 0, 1}, {7.0, 1.0, 0, 1},
{12.0, 1.0, 0, 1}, {13.0, 1.0, 0, 1}, {14.0, 1.0, 0, 1}, {15.0, 1.0, 0, 1}, {16.0, 1.0, 0, 1}, {17.0, 1.0, 0, 1},
{18.0, 1.0, 0, 1}, {19.0, 1.0, 0, 1}, {-27.0, 2.0, 0, 1}, {-26.0, 2.0, 0, 1}, {-21.0, 2.0, 0, 1}, {-20.0, 2.0, 0, 1},
{-19.0, 2.0, 0, 1}, {-18.0, 2.0, 0, 1}, {-17.0, 2.0, 0, 1}, {-16.0, 2.0, 0, 1}, {-15.0, 2.0, 0, 1}, {-14.0, 2.0, 0, 1},
{-13.0, 2.0, 0, 1}, {-12.0, 2.0, 0, 1}, {-11.0, 2.0, 0, 1}, {-10.0, 2.0, 0, 1}, {-9.0, 2.0, 0, 1}, {-8.0, 2.0, 0, 1},
{-7.0, 2.0, 0, 1}, {-6.0, 2.0, 0, 1}, {-1.0, 2.0, 0, 1}, {0.0, 2.0, 0, 1}, {1.0, 2.0, 0, 1}, {2.0, 2.0, 0, 1},
{3.0, 2.0, 0, 1}, {4.0, 2.0, 0, 1}, {5.0, 2.0, 0, 1}, {6.0, 2.0, 0, 1}, {7.0, 2.0, 0, 1}, {8.0, 2.0, 0, 1},
{12.0, 2.0, 0, 1}, {13.0, 2.0, 0, 1}, {14.0, 2.0, 0, 1}, {15.0, 2.0, 0, 1}, {16.0, 2.0, 0, 1}, {17.0, 2.0, 0, 1},
{18.0, 2.0, 0, 1}, {19.0, 2.0, 0, 1}, {-27.0, 3.0, 0, 1}, {-26.0, 3.0, 0, 1}, {-25.0, 3.0, 0, 1}, {-20.0, 3.0, 0, 1},
{-19.0, 3.0, 0, 1}, {-18.0, 3.0, 0, 1}, {-17.0, 3.0, 0, 1}, {-16.0, 3.0, 0, 1}, {-15.0, 3.0, 0, 1}, {-14.0, 3.0, 0, 1},
{-13.0, 3.0, 0, 1}, {-12.0, 3.0, 0, 1}, {-11.0, 3.0, 0, 1}, {-10.0, 3.0, 0, 1}, {-9.0, 3.0, 0, 1}, {-8.0, 3.0, 0, 1},
{-7.0, 3.0, 0, 1}, {-6.0, 3.0, 0, 1}, {-5.0, 3.0, 0, 1}, {0.0, 3.0, 0, 1}, {1.0, 3.0, 0, 1}, {2.0, 3.0, 0, 1},
{3.0, 3.0, 0, 1}, {4.0, 3.0, 0, 1}, {5.0, 3.0, 0, 1}, {6.0, 3.0, 0, 1}, {7.0, 3.0, 0, 1}, {8.0, 3.0, 0, 1},
{12.0, 3.0, 0, 1}, {13.0, 3.0, 0, 1}, {14.0, 3.0, 0, 1}, {15.0, 3.0, 0, 1}, {16.0, 3.0, 0, 1}, {17.0, 3.0, 0, 1},
{18.0, 3.0, 0, 1}, {19.0, 3.0, 0, 1}, {20.0, 3.0, 0, 1}, {-26.0, 4.0, 0, 1}, {-25.0, 4.0, 0, 1}, {-19.0, 4.0, 0, 1},
{-18.0, 4.0, 0, 1}, {-17.0, 4.0, 0, 1}, {-16.0, 4.0, 0, 1}, {-15.0, 4.0, 0, 1}, {-14.0, 4.0, 0, 1}, {-13.0, 4.0, 0, 1},
{-12.0, 4.0, 0, 1}, {-11.0, 4.0, 0, 1}, {-10.0, 4.0, 0, 1}, {-9.0, 4.0, 0, 1}, {-8.0, 4.0, 0, 1}, {-7.0, 4.0, 0, 1},
{-6.0, 4.0, 0, 1}, {-5.0, 4.0, 0, 1}, {-4.0, 4.0, 0, 1}, {1.0, 4.0, 0, 1}, {2.0, 4.0, 0, 1}, {3.0, 4.0, 0, 1},
{4.0, 4.0, 0, 1}, {5.0, 4.0, 0, 1}, {6.0, 4.0, 0, 1}, {7.0, 4.0, 0, 1}, {8.0, 4.0, 0, 1}, {9.0, 4.0, 0, 1},
{13.0, 4.0, 0, 1}, {14.0, 4.0, 0, 1}, {15.0, 4.0, 0, 1}, {16.0, 4.0, 0, 1}, {17.0, 4.0, 0, 1}, {18.0, 4.0, 0, 1},
{19.0, 4.0, 0, 1}, {20.0, 4.0, 0, 1}, {-26.0, 5.0, 0, 1}, {-25.0, 5.0, 0, 1}, {-17.0, 5.0, 0, 1}, {-16.0, 5.0, 0, 1},
{-15.0, 5.0, 0, 1}, {-14.0, 5.0, 0, 1}, {-13.0, 5.0, 0, 1}, {-12.0, 5.0, 0, 1}, {-11.0, 5.0, 0, 1}, {-10.0, 5.0, 0, 1},
{-9.0, 5.0, 0, 1}, {-8.0, 5.0, 0, 1}, {-7.0, 5.0, 0, 1}, {-6.0, 5.0, 0, 1}, {-5.0, 5.0, 0, 1}, {-4.0, 5.0, 0, 1},
{-3.0, 5.0, 0, 1}, {2.0, 5.0, 0, 1}, {3.0, 5.0, 0, 1}, {4.0, 5.0, 0, 1}, {5.0, 5.0, 0, 1}, {6.0, 5.0, 0, 1},
{7.0, 5.0, 0, 1}, {8.0, 5.0, 0, 1}, {9.0, 5.0, 0, 1}, {13.0, 5.0, 0, 1}, {14.0, 5.0, 0, 1}, {15.0, 5.0, 0, 1},
{16.0, 5.0, 0, 1}, {17.0, 5.0, 0, 1}, {18.0, 5.0, 0, 1}, {19.0, 5.0, 0, 1}, {20.0, 5.0, 0, 1}, {-26.0, 6.0, 0, 1},
{-25.0, 6.0, 0, 1}, {-14.0, 6.0, 0, 1}, {-13.0, 6.0, 0, 1}, {-12.0, 6.0, 0, 1}, {-11.0, 6.0, 0, 1}, {-10.0, 6.0, 0, 1},
{-9.0, 6.0, 0, 1}, {-8.0, 6.0, 0, 1}, {-7.0, 6.0, 0, 1}, {-6.0, 6.0, 0, 1}, {-5.0, 6.0, 0, 1}, {-4.0, 6.0, 0, 1},
{-3.0, 6.0, 0, 1}, {-2.0, 6.0, 0, 1}, {2.0, 6.0, 0, 1}, {3.0, 6.0, 0, 1}, {4.0, 6.0, 0, 1}, {5.0, 6.0, 0, 1},
{6.0, 6.0, 0, 1}, {7.0, 6.0, 0, 1}, {8.0, 6.0, 0, 1}, {9.0, 6.0, 0, 1}, {13.0, 6.0, 0, 1}, {14.0, 6.0, 0, 1},
{15.0, 6.0, 0, 1}, {16.0, 6.0, 0, 1}, {17.0, 6.0, 0, 1}, {18.0, 6.0, 0, 1}, {19.0, 6.0, 0, 1}, {20.0, 6.0, 0, 1},
{-25.0, 7.0, 0, 1}, {-24.0, 7.0, 0, 1}, {-11.0, 7.0, 0, 1}, {-10.0, 7.0, 0, 1}, {-9.0, 7.0, 0, 1}, {-8.0, 7.0, 0, 1},
{-7.0, 7.0, 0, 1}, {-6.0, 7.0, 0, 1}, {-5.0, 7.0, 0, 1}, {-4.0, 7.0, 0, 1}, {-3.0, 7.0, 0, 1}, {-2.0, 7.0, 0, 1},
{3.0, 7.0, 0, 1}, {4.0, 7.0, 0, 1}, {5.0, 7.0, 0, 1}, {6.0, 7.0, 0, 1}, {7.0, 7.0, 0, 1}, {8.0, 7.0, 0, 1},
{9.0, 7.0, 0, 1}, {10.0, 7.0, 0, 1}, {14.0, 7.0, 0, 1}, {15.0, 7.0, 0, 1}, {16.0, 7.0, 0, 1}, {17.0, 7.0, 0, 1},
{18.0, 7.0, 0, 1}, {19.0, 7.0, 0, 1}, {20.0, 7.0, 0, 1}, {21.0, 7.0, 0, 1}, {-25.0, 8.0, 0, 1}, {-24.0, 8.0, 0, 1},
{-10.0, 8.0, 0, 1}, {-9.0, 8.0, 0, 1}, {-8.0, 8.0, 0, 1}, {-7.0, 8.0, 0, 1}, {-6.0, 8.0, 0, 1}, {-5.0, 8.0, 0, 1},
{-4.0, 8.0, 0, 1}, {-3.0, 8.0, 0, 1}, {-2.0, 8.0, 0, 1}, {-1.0, 8.0, 0, 1}, {3.0, 8.0, 0, 1}, {4.0, 8.0, 0, 1},
{5.0, 8.0, 0, 1}, {6.0, 8.0, 0, 1}, {7.0, 8.0, 0, 1}, {8.0, 8.0, 0, 1}, {9.0, 8.0, 0, 1}, {10.0, 8.0, 0, 1},
{14.0, 8.0, 0, 1}, {15.0, 8.0, 0, 1}, {16.0, 8.0, 0, 1}, {17.0, 8.0, 0, 1}, {18.0, 8.0, 0, 1}, {19.0, 8.0, 0, 1},
{20.0, 8.0, 0, 1}, {21.0, 8.0, 0, 1}, {-25.0, 9.0, 0, 1}, {-24.0, 9.0, 0, 1}, {-23.0, 9.0, 0, 1}, {-9.0, 9.0, 0, 1},
{-8.0, 9.0, 0, 1}, {-7.0, 9.0, 0, 1}, {-6.0, 9.0, 0, 1}, {-5.0, 9.0, 0, 1}, {-4.0, 9.0, 0, 1}, {-3.0, 9.0, 0, 1},
{-2.0, 9.0, 0, 1}, {-1.0, 9.0, 0, 1}, {3.0, 9.0, 0, 1}, {4.0, 9.0, 0, 1}, {5.0, 9.0, 0, 1}, {6.0, 9.0, 0, 1},
{7.0, 9.0, 0, 1}, {8.0, 9.0, 0, 1}, {9.0, 9.0, 0, 1}, {10.0, 9.0, 0, 1}, {14.0, 9.0, 0, 1}, {15.0, 9.0, 0, 1},
{16.0, 9.0, 0, 1}, {17.0, 9.0, 0, 1}, {18.0, 9.0, 0, 1}, {19.0, 9.0, 0, 1}, {20.0, 9.0, 0, 1}, {21.0, 9.0, 0, 1},
{-24.0, 10.0, 0, 1}, {-23.0, 10.0, 0, 1}, {-15.0, 10.0, 0, 1}, {-14.0, 10.0, 0, 1}, {-13.0, 10.0, 0, 1}, {-12.0, 10.0, 0, 1},
{-8.0, 10.0, 0, 1}, {-7.0, 10.0, 0, 1}, {-6.0, 10.0, 0, 1}, {-5.0, 10.0, 0, 1}, {-4.0, 10.0, 0, 1}, {-3.0, 10.0, 0, 1},
{-2.0, 10.0, 0, 1}, {-1.0, 10.0, 0, 1}, {4.0, 10.0, 0, 1}, {5.0, 10.0, 0, 1}, {6.0, 10.0, 0, 1}, {7.0, 10.0, 0, 1},
{8.0, 10.0, 0, 1}, {9.0, 10.0, 0, 1}, {10.0, 10.0, 0, 1}, {14.0, 10.0, 0, 1}, {15.0, 10.0, 0, 1}, {16.0, 10.0, 0, 1},
{17.0, 10.0, 0, 1}, {18.0, 10.0, 0, 1}, {19.0, 10.0, 0, 1}, {20.0, 10.0, 0, 1}, {21.0, 10.0, 0, 1}, {-24.0, 11.0, 0, 1},
{-23.0, 11.0, 0, 1}, {-22.0, 11.0, 0, 1}, {-16.0, 11.0, 0, 1}, {-15.0, 11.0, 0, 1}, {-14.0, 11.0, 0, 1}, {-13.0, 11.0, 0, 1},
{-12.0, 11.0, 0, 1}, {-11.0, 11.0, 0, 1}, {-7.0, 11.0, 0, 1}, {-6.0, 11.0, 0, 1}, {-5.0, 11.0, 0, 1}, {-4.0, 11.0, 0, 1},
{-3.0, 11.0, 0, 1}, {-2.0, 11.0, 0, 1}, {-1.0, 11.0, 0, 1}, {0.0, 11.0, 0, 1}, {4.0, 11.0, 0, 1}, {5.0, 11.0, 0, 1},
{6.0, 11.0, 0, 1}, {7.0, 11.0, 0, 1}, {8.0, 11.0, 0, 1}, {9.0, 11.0, 0, 1}, {10.0, 11.0, 0, 1}, {11.0, 11.0, 0, 1},
{15.0, 11.0, 0, 1}, {16.0, 11.0, 0, 1}, {17.0, 11.0, 0, 1}, {18.0, 11.0, 0, 1}, {19.0, 11.0, 0, 1}, {20.0, 11.0, 0, 1},
{-23.0, 12.0, 0, 1}, {-22.0, 12.0, 0, 1}, {-17.0, 12.0, 0, 1}, {-16.0, 12.0, 0, 1}, {-15.0, 12.0, 0, 1}, {-14.0, 12.0, 0, 1},
{-13.0, 12.0, 0, 1}, {-12.0, 12.0, 0, 1}, {-11.0, 12.0, 0, 1}, {-7.0, 12.0, 0, 1}, {-6.0, 12.0, 0, 1}, {-5.0, 12.0, 0, 1},
{-4.0, 12.0, 0, 1}, {-3.0, 12.0, 0, 1}, {-2.0, 12.0, 0, 1}, {-1.0, 12.0, 0, 1}, {0.0, 12.0, 0, 1}, {4.0, 12.0, 0, 1},
{5.0, 12.0, 0, 1}, {6.0, 12.0, 0, 1}, {7.0, 12.0, 0, 1}, {8.0, 12.0, 0, 1}, {9.0, 12.0, 0, 1}, {10.0, 12.0, 0, 1},
{11.0, 12.0, 0, 1}, {15.0, 12.0, 0, 1}, {16.0, 12.0, 0, 1}, {17.0, 12.0, 0, 1}, {18.0, 12.0, 0, 1}, {19.0, 12.0, 0, 1},
{-23.0, 13.0, 0, 1}, {-22.0, 13.0, 0, 1}, {-21.0, 13.0, 0, 1}, {-17.0, 13.0, 0, 1}, {-16.0, 13.0, 0, 1}, {-15.0, 13.0, 0, 1},
{-14.0, 13.0, 0, 1}, {-13.0, 13.0, 0, 1}, {-12.0, 13.0, 0, 1}, {-11.0, 13.0, 0, 1}, {-7.0, 13.0, 0, 1}, {-6.0, 13.0, 0, 1},
{-5.0, 13.0, 0, 1}, {-4.0, 13.0, 0, 1}, {-3.0, 13.0, 0, 1}, {-2.0, 13.0, 0, 1}, {-1.0, 13.0, 0, 1}, {0.0, 13.0, 0, 1},
{4.0, 13.0, 0, 1}, {5.0, 13.0, 0, 1}, {6.0, 13.0, 0, 1}, {7.0, 13.0, 0, 1}, {8.0, 13.0, 0, 1}, {9.0, 13.0, 0, 1},
{10.0, 13.0, 0, 1}, {11.0, 13.0, 0, 1}, {15.0, 13.0, 0, 1}, {16.0, 13.0, 0, 1}, {17.0, 13.0, 0, 1}, {18.0, 13.0, 0, 1},
{19.0, 13.0, 0, 1}, {-22.0, 14.0, 0, 1}, {-21.0, 14.0, 0, 1}, {-20.0, 14.0, 0, 1}, {-17.0, 14.0, 0, 1}, {-16.0, 14.0, 0, 1},
{-15.0, 14.0, 0, 1}, {-14.0, 14.0, 0, 1}, {-13.0, 14.0, 0, 1}, {-12.0, 14.0, 0, 1}, {-11.0, 14.0, 0, 1}, {-7.0, 14.0, 0, 1},
{-6.0, 14.0, 0, 1}, {-5.0, 14.0, 0, 1}, {-4.0, 14.0, 0, 1}, {-3.0, 14.0, 0, 1}, {-2.0, 14.0, 0, 1}, {-1.0, 14.0, 0, 1},
{0.0, 14.0, 0, 1}, {4.0, 14.0, 0, 1}, {5.0, 14.0, 0, 1}, {6.0, 14.0, 0, 1}, {7.0, 14.0, 0, 1}, {8.0, 14.0, 0, 1},
{9.0, 14.0, 0, 1}, {10.0, 14.0, 0, 1}, {11.0, 14.0, 0, 1}, {15.0, 14.0, 0, 1}, {16.0, 14.0, 0, 1}, {17.0, 14.0, 0, 1},
{18.0, 14.0, 0, 1}, {-21.0, 15.0, 0, 1}, {-20.0, 15.0, 0, 1}, {-17.0, 15.0, 0, 1}, {-16.0, 15.0, 0, 1}, {-15.0, 15.0, 0, 1},
{-14.0, 15.0, 0, 1}, {-13.0, 15.0, 0, 1}, {-12.0, 15.0, 0, 1}, {-11.0, 15.0, 0, 1}, {-7.0, 15.0, 0, 1}, {-6.0, 15.0, 0, 1},
{-5.0, 15.0, 0, 1}, {-4.0, 15.0, 0, 1}, {-3.0, 15.0, 0, 1}, {-2.0, 15.0, 0, 1}, {-1.0, 15.0, 0, 1}, {0.0, 15.0, 0, 1},
{4.0, 15.0, 0, 1}, {5.0, 15.0, 0, 1}, {6.0, 15.0, 0, 1}, {7.0, 15.0, 0, 1}, {8.0, 15.0, 0, 1}, {9.0, 15.0, 0, 1},
{10.0, 15.0, 0, 1}, {11.0, 15.0, 0, 1}, {-21.0, 16.0, 0, 1}, {-20.0, 16.0, 0, 1}, {-19.0, 16.0, 0, 1}, {-16.0, 16.0, 0, 1},
{-15.0, 16.0, 0, 1}, {-14.0, 16.0, 0, 1}, {-13.0, 16.0, 0, 1}, {-12.0, 16.0, 0, 1}, {-7.0, 16.0, 0, 1}, {-6.0, 16.0, 0, 1},
{-5.0, 16.0, 0, 1}, {-4.0, 16.0, 0, 1}, {-3.0, 16.0, 0, 1}, {-2.0, 16.0, 0, 1}, {-1.0, 16.0, 0, 1}, {0.0, 16.0, 0, 1},
{4.0, 16.0, 0, 1}, {5.0, 16.0, 0, 1}, {6.0, 16.0, 0, 1}, {7.0, 16.0, 0, 1}, {8.0, 16.0, 0, 1}, {9.0, 16.0, 0, 1},
{10.0, 16.0, 0, 1}, {11.0, 16.0, 0, 1}, {-20.0, 17.0, 0, 1}, {-19.0, 17.0, 0, 1}, {-18.0, 17.0, 0, 1}, {-7.0, 17.0, 0, 1},
{-6.0, 17.0, 0, 1}, {-5.0, 17.0, 0, 1}, {-4.0, 17.0, 0, 1}, {-3.0, 17.0, 0, 1}, {-2.0, 17.0, 0, 1}, {-1.0, 17.0, 0, 1},
{0.0, 17.0, 0, 1}, {4.0, 17.0, 0, 1}, {5.0, 17.0, 0, 1}, {6.0, 17.0, 0, 1}, {7.0, 17.0, 0, 1}, {8.0, 17.0, 0, 1},
{9.0, 17.0, 0, 1}, {10.0, 17.0, 0, 1}, {11.0, 17.0, 0, 1}, {19.0, 17.0, 0, 1}, {-19.0, 18.0, 0, 1}, {-18.0, 18.0, 0, 1},
{-17.0, 18.0, 0, 1}, {-7.0, 18.0, 0, 1}, {-6.0, 18.0, 0, 1}, {-5.0, 18.0, 0, 1}, {-4.0, 18.0, 0, 1}, {-3.0, 18.0, 0, 1},
{-2.0, 18.0, 0, 1}, {-1.0, 18.0, 0, 1}, {0.0, 18.0, 0, 1}, {4.0, 18.0, 0, 1}, {5.0, 18.0, 0, 1}, {6.0, 18.0, 0, 1},
{7.0, 18.0, 0, 1}, {8.0, 18.0, 0, 1}, {9.0, 18.0, 0, 1}, {10.0, 18.0, 0, 1}, {11.0, 18.0, 0, 1}, {18.0, 18.0, 0, 1},
{19.0, 18.0, 0, 1}, {20.0, 18.0, 0, 1}, {-18.0, 19.0, 0, 1}, {-17.0, 19.0, 0, 1}, {-16.0, 19.0, 0, 1}, {-15.0, 19.0, 0, 1},
{-8.0, 19.0, 0, 1}, {-7.0, 19.0, 0, 1}, {-6.0, 19.0, 0, 1}, {-5.0, 19.0, 0, 1}, {-4.0, 19.0, 0, 1}, {-3.0, 19.0, 0, 1},
{-2.0, 19.0, 0, 1}, {-1.0, 19.0, 0, 1}, {4.0, 19.0, 0, 1}, {5.0, 19.0, 0, 1}, {6.0, 19.0, 0, 1}, {7.0, 19.0, 0, 1},
{8.0, 19.0, 0, 1}, {9.0, 19.0, 0, 1}, {10.0, 19.0, 0, 1}, {17.0, 19.0, 0, 1}, {18.0, 19.0, 0, 1}, {19.0, 19.0, 0, 1},
{-17.0, 20.0, 0, 1}, {-16.0, 20.0, 0, 1}, {-15.0, 20.0, 0, 1}, {-14.0, 20.0, 0, 1}, {-7.0, 20.0, 0, 1}, {-6.0, 20.0, 0, 1},
{-5.0, 20.0, 0, 1}, {-4.0, 20.0, 0, 1}, {-3.0, 20.0, 0, 1}, {-2.0, 20.0, 0, 1}, {-1.0, 20.0, 0, 1}, {4.0, 20.0, 0, 1},
{5.0, 20.0, 0, 1}, {6.0, 20.0, 0, 1}, {7.0, 20.0, 0, 1}, {8.0, 20.0, 0, 1}, {9.0, 20.0, 0, 1}, {16.0, 20.0, 0, 1},
{17.0, 20.0, 0, 1}, {18.0, 20.0, 0, 1}, {-15.0, 21.0, 0, 1}, {-14.0, 21.0, 0, 1}, {-13.0, 21.0, 0, 1}, {-12.0, 21.0, 0, 1},
{-5.0, 21.0, 0, 1}, {-4.0, 21.0, 0, 1}, {-3.0, 21.0, 0, 1}, {-2.0, 21.0, 0, 1}, {-1.0, 21.0, 0, 1}, {14.0, 21.0, 0, 1},
{15.0, 21.0, 0, 1}, {16.0, 21.0, 0, 1}, {17.0, 21.0, 0, 1}, {-14.0, 22.0, 0, 1}, {-13.0, 22.0, 0, 1}, {-12.0, 22.0, 0, 1},
{-11.0, 22.0, 0, 1}, {-10.0, 22.0, 0, 1}, {12.0, 22.0, 0, 1}, {13.0, 22.0, 0, 1}, {14.0, 22.0, 0, 1}, {15.0, 22.0, 0, 1},
{-12.0, 23.0, 0, 1}, {-11.0, 23.0, 0, 1}, {-10.0, 23.0, 0, 1}, {-9.0, 23.0, 0, 1}, {-8.0, 23.0, 0, 1}, {9.0, 23.0, 0, 1},
{10.0, 23.0, 0, 1}, {11.0, 23.0, 0, 1}, {12.0, 23.0, 0, 1}, {13.0, 23.0, 0, 1}, {14.0, 23.0, 0, 1}, {-10.0, 24.0, 0, 1},
{-9.0, 24.0, 0, 1}, {-8.0, 24.0, 0, 1}, {-7.0, 24.0, 0, 1}, {-6.0, 24.0, 0, 1}, {-5.0, 24.0, 0, 1}, {-4.0, 24.0, 0, 1},
{-3.0, 24.0, 0, 1}, {5.0, 24.0, 0, 1}, {6.0, 24.0, 0, 1}, {7.0, 24.0, 0, 1}, {8.0, 24.0, 0, 1}, {9.0, 24.0, 0, 1},
{10.0, 24.0, 0, 1}, {11.0, 24.0, 0, 1}, {12.0, 24.0, 0, 1}, {-7.0, 25.0, 0, 1}, {-6.0, 25.0, 0, 1}, {-5.0, 25.0, 0, 1},
{-4.0, 25.0, 0, 1}, {-3.0, 25.0, 0, 1}, {-2.0, 25.0, 0, 1}, {-1.0, 25.0, 0, 1}, {0.0, 25.0, 0, 1}, {1.0, 25.0, 0, 1},
{2.0, 25.0, 0, 1}, {3.0, 25.0, 0, 1}, {4.0, 25.0, 0, 1}, {5.0, 25.0, 0, 1}, {6.0, 25.0, 0, 1}, {7.0, 25.0, 0, 1},
{8.0, 25.0, 0, 1}, {9.0, 25.0, 0, 1}, {-3.0, 26.0, 0, 1}, {-2.0, 26.0, 0, 1}, {-1.0, 26.0, 0, 1}, {0.0, 26.0, 0, 1},
{1.0, 26.0, 0, 1}, {2.0, 26.0, 0, 1}, {3.0, 26.0, 0, 1}, {4.0, 26.0, 0, 1}, {5.0, 26.0, 0, 1}
};
#endif // CONFIG_3D_OBJECT_ESP_LOGO

View File

@@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
extern const uint8_t image_bmp_array_esp_logo[512];
extern const float image_3d_matrix_esp_logo[1427][4];
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,252 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_text.h"
const uint8_t image_bmp_array_esp_text[384] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3f, 0xf8, 0x7f, 0xf1, 0xff, 0xe1, 0xff, 0xe0, 0x7f, 0xe0, 0xff, 0xc1, 0xff, 0xc7, 0x07, 0xfe,
0x7f, 0xf8, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xf0, 0xff, 0xe1, 0xff, 0xc3, 0xff, 0xc7, 0x0f, 0xfe,
0x7f, 0xf8, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xe3, 0xff, 0xc3, 0xff, 0xc7, 0x1f, 0xfe,
0x70, 0x00, 0xe0, 0x01, 0xe0, 0x79, 0xe0, 0x71, 0xc0, 0x03, 0x80, 0x07, 0x80, 0x07, 0x1e, 0x00,
0x70, 0x00, 0xe0, 0x01, 0xe0, 0x39, 0xe0, 0x71, 0xc0, 0x03, 0x80, 0x07, 0x80, 0x07, 0x1c, 0x00,
0x70, 0x00, 0xe0, 0x01, 0xe0, 0x39, 0xe0, 0x71, 0xc0, 0x03, 0x80, 0x07, 0x80, 0x07, 0x1c, 0x00,
0x70, 0x00, 0xe0, 0x01, 0xe0, 0x39, 0xe0, 0x71, 0xc0, 0x03, 0x80, 0x07, 0x80, 0x07, 0x1c, 0x00,
0x70, 0x00, 0xe0, 0x01, 0xe0, 0x39, 0xe0, 0x71, 0xc0, 0x03, 0x80, 0x07, 0x80, 0x07, 0x1c, 0x00,
0x70, 0x00, 0xe0, 0x01, 0xe0, 0x39, 0xe0, 0x71, 0xc0, 0x03, 0x80, 0x07, 0x80, 0x07, 0x1c, 0x00,
0x7f, 0xf0, 0xff, 0xe1, 0xe0, 0x79, 0xe0, 0x71, 0xff, 0xc3, 0xff, 0x83, 0xff, 0x87, 0x1f, 0xfc,
0x7f, 0xf0, 0xff, 0xf1, 0xff, 0xf9, 0xff, 0xf1, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xc7, 0x1f, 0xfc,
0x7f, 0xf0, 0x7f, 0xf1, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xc1, 0xff, 0xe1, 0xff, 0xc7, 0x1f, 0xfc,
0x70, 0x00, 0x00, 0x79, 0xff, 0xf1, 0xff, 0xe1, 0xc0, 0x00, 0x01, 0xe0, 0x03, 0xc7, 0x1c, 0x00,
0x70, 0x00, 0x00, 0x79, 0xff, 0xc1, 0xe1, 0xe1, 0xc0, 0x00, 0x00, 0xe0, 0x01, 0xc7, 0x1c, 0x00,
0x70, 0x00, 0x00, 0x79, 0xe0, 0x01, 0xe0, 0xe1, 0xc0, 0x00, 0x00, 0xe0, 0x01, 0xc7, 0x1c, 0x00,
0x70, 0x00, 0x00, 0x79, 0xe0, 0x01, 0xe0, 0x71, 0xc0, 0x00, 0x00, 0xe0, 0x01, 0xc7, 0x1c, 0x00,
0x70, 0x00, 0x00, 0x79, 0xe0, 0x01, 0xe0, 0x71, 0xc0, 0x00, 0x00, 0xe0, 0x01, 0xc7, 0x1c, 0x00,
0x70, 0x00, 0x00, 0x79, 0xe0, 0x01, 0xe0, 0x71, 0xc0, 0x00, 0x00, 0xe0, 0x01, 0xc7, 0x1c, 0x00,
0x70, 0x00, 0x00, 0x79, 0xe0, 0x01, 0xe0, 0x71, 0xc0, 0x00, 0x00, 0xe0, 0x01, 0xc7, 0x1c, 0x00,
0x7f, 0xf8, 0xff, 0xf1, 0xe0, 0x01, 0xe0, 0x79, 0xff, 0xe3, 0xff, 0xe7, 0xff, 0xc7, 0x1c, 0x00,
0x7f, 0xf8, 0xff, 0xf1, 0xe0, 0x01, 0xe0, 0x38, 0xff, 0xe3, 0xff, 0xc7, 0xff, 0xc7, 0x1c, 0x00,
0x3f, 0xf8, 0xff, 0xe1, 0xe0, 0x01, 0xe0, 0x38, 0xff, 0xe3, 0xff, 0x87, 0xff, 0x87, 0x1c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const float image_3d_array_esp_text[1271][4] = {
{-62.0, -11.0, 0, 1}, {-61.0, -11.0, 0, 1}, {-60.0, -11.0, 0, 1}, {-59.0, -11.0, 0, 1}, {-58.0, -11.0, 0, 1}, {-57.0, -11.0, 0, 1},
{-56.0, -11.0, 0, 1}, {-55.0, -11.0, 0, 1}, {-54.0, -11.0, 0, 1}, {-53.0, -11.0, 0, 1}, {-52.0, -11.0, 0, 1}, {-47.0, -11.0, 0, 1},
{-46.0, -11.0, 0, 1}, {-45.0, -11.0, 0, 1}, {-44.0, -11.0, 0, 1}, {-43.0, -11.0, 0, 1}, {-42.0, -11.0, 0, 1}, {-41.0, -11.0, 0, 1},
{-40.0, -11.0, 0, 1}, {-39.0, -11.0, 0, 1}, {-38.0, -11.0, 0, 1}, {-37.0, -11.0, 0, 1}, {-33.0, -11.0, 0, 1}, {-32.0, -11.0, 0, 1},
{-31.0, -11.0, 0, 1}, {-30.0, -11.0, 0, 1}, {-29.0, -11.0, 0, 1}, {-28.0, -11.0, 0, 1}, {-27.0, -11.0, 0, 1}, {-26.0, -11.0, 0, 1},
{-25.0, -11.0, 0, 1}, {-24.0, -11.0, 0, 1}, {-23.0, -11.0, 0, 1}, {-22.0, -11.0, 0, 1}, {-17.0, -11.0, 0, 1}, {-16.0, -11.0, 0, 1},
{-15.0, -11.0, 0, 1}, {-14.0, -11.0, 0, 1}, {-13.0, -11.0, 0, 1}, {-12.0, -11.0, 0, 1}, {-11.0, -11.0, 0, 1}, {-10.0, -11.0, 0, 1},
{-9.0, -11.0, 0, 1}, {-8.0, -11.0, 0, 1}, {-7.0, -11.0, 0, 1}, {-6.0, -11.0, 0, 1}, {1.0, -11.0, 0, 1}, {2.0, -11.0, 0, 1},
{3.0, -11.0, 0, 1}, {4.0, -11.0, 0, 1}, {5.0, -11.0, 0, 1}, {6.0, -11.0, 0, 1}, {7.0, -11.0, 0, 1}, {8.0, -11.0, 0, 1},
{9.0, -11.0, 0, 1}, {10.0, -11.0, 0, 1}, {16.0, -11.0, 0, 1}, {17.0, -11.0, 0, 1}, {18.0, -11.0, 0, 1}, {19.0, -11.0, 0, 1},
{20.0, -11.0, 0, 1}, {21.0, -11.0, 0, 1}, {22.0, -11.0, 0, 1}, {23.0, -11.0, 0, 1}, {24.0, -11.0, 0, 1}, {25.0, -11.0, 0, 1},
{31.0, -11.0, 0, 1}, {32.0, -11.0, 0, 1}, {33.0, -11.0, 0, 1}, {34.0, -11.0, 0, 1}, {35.0, -11.0, 0, 1}, {36.0, -11.0, 0, 1},
{37.0, -11.0, 0, 1}, {38.0, -11.0, 0, 1}, {39.0, -11.0, 0, 1}, {40.0, -11.0, 0, 1}, {41.0, -11.0, 0, 1}, {45.0, -11.0, 0, 1},
{46.0, -11.0, 0, 1}, {47.0, -11.0, 0, 1}, {53.0, -11.0, 0, 1}, {54.0, -11.0, 0, 1}, {55.0, -11.0, 0, 1}, {56.0, -11.0, 0, 1},
{57.0, -11.0, 0, 1}, {58.0, -11.0, 0, 1}, {59.0, -11.0, 0, 1}, {60.0, -11.0, 0, 1}, {61.0, -11.0, 0, 1}, {62.0, -11.0, 0, 1},
{-63.0, -10.0, 0, 1}, {-62.0, -10.0, 0, 1}, {-61.0, -10.0, 0, 1}, {-60.0, -10.0, 0, 1}, {-59.0, -10.0, 0, 1}, {-58.0, -10.0, 0, 1},
{-57.0, -10.0, 0, 1}, {-56.0, -10.0, 0, 1}, {-55.0, -10.0, 0, 1}, {-54.0, -10.0, 0, 1}, {-53.0, -10.0, 0, 1}, {-52.0, -10.0, 0, 1},
{-48.0, -10.0, 0, 1}, {-47.0, -10.0, 0, 1}, {-46.0, -10.0, 0, 1}, {-45.0, -10.0, 0, 1}, {-44.0, -10.0, 0, 1}, {-43.0, -10.0, 0, 1},
{-42.0, -10.0, 0, 1}, {-41.0, -10.0, 0, 1}, {-40.0, -10.0, 0, 1}, {-39.0, -10.0, 0, 1}, {-38.0, -10.0, 0, 1}, {-37.0, -10.0, 0, 1},
{-33.0, -10.0, 0, 1}, {-32.0, -10.0, 0, 1}, {-31.0, -10.0, 0, 1}, {-30.0, -10.0, 0, 1}, {-29.0, -10.0, 0, 1}, {-28.0, -10.0, 0, 1},
{-27.0, -10.0, 0, 1}, {-26.0, -10.0, 0, 1}, {-25.0, -10.0, 0, 1}, {-24.0, -10.0, 0, 1}, {-23.0, -10.0, 0, 1}, {-22.0, -10.0, 0, 1},
{-21.0, -10.0, 0, 1}, {-17.0, -10.0, 0, 1}, {-16.0, -10.0, 0, 1}, {-15.0, -10.0, 0, 1}, {-14.0, -10.0, 0, 1}, {-13.0, -10.0, 0, 1},
{-12.0, -10.0, 0, 1}, {-11.0, -10.0, 0, 1}, {-10.0, -10.0, 0, 1}, {-9.0, -10.0, 0, 1}, {-8.0, -10.0, 0, 1}, {-7.0, -10.0, 0, 1},
{-6.0, -10.0, 0, 1}, {-5.0, -10.0, 0, 1}, {0.0, -10.0, 0, 1}, {1.0, -10.0, 0, 1}, {2.0, -10.0, 0, 1}, {3.0, -10.0, 0, 1},
{4.0, -10.0, 0, 1}, {5.0, -10.0, 0, 1}, {6.0, -10.0, 0, 1}, {7.0, -10.0, 0, 1}, {8.0, -10.0, 0, 1}, {9.0, -10.0, 0, 1},
{10.0, -10.0, 0, 1}, {15.0, -10.0, 0, 1}, {16.0, -10.0, 0, 1}, {17.0, -10.0, 0, 1}, {18.0, -10.0, 0, 1}, {19.0, -10.0, 0, 1},
{20.0, -10.0, 0, 1}, {21.0, -10.0, 0, 1}, {22.0, -10.0, 0, 1}, {23.0, -10.0, 0, 1}, {24.0, -10.0, 0, 1}, {25.0, -10.0, 0, 1},
{30.0, -10.0, 0, 1}, {31.0, -10.0, 0, 1}, {32.0, -10.0, 0, 1}, {33.0, -10.0, 0, 1}, {34.0, -10.0, 0, 1}, {35.0, -10.0, 0, 1},
{36.0, -10.0, 0, 1}, {37.0, -10.0, 0, 1}, {38.0, -10.0, 0, 1}, {39.0, -10.0, 0, 1}, {40.0, -10.0, 0, 1}, {41.0, -10.0, 0, 1},
{45.0, -10.0, 0, 1}, {46.0, -10.0, 0, 1}, {47.0, -10.0, 0, 1}, {52.0, -10.0, 0, 1}, {53.0, -10.0, 0, 1}, {54.0, -10.0, 0, 1},
{55.0, -10.0, 0, 1}, {56.0, -10.0, 0, 1}, {57.0, -10.0, 0, 1}, {58.0, -10.0, 0, 1}, {59.0, -10.0, 0, 1}, {60.0, -10.0, 0, 1},
{61.0, -10.0, 0, 1}, {62.0, -10.0, 0, 1}, {-63.0, -9.0, 0, 1}, {-62.0, -9.0, 0, 1}, {-61.0, -9.0, 0, 1}, {-60.0, -9.0, 0, 1},
{-59.0, -9.0, 0, 1}, {-58.0, -9.0, 0, 1}, {-57.0, -9.0, 0, 1}, {-56.0, -9.0, 0, 1}, {-55.0, -9.0, 0, 1}, {-54.0, -9.0, 0, 1},
{-53.0, -9.0, 0, 1}, {-52.0, -9.0, 0, 1}, {-48.0, -9.0, 0, 1}, {-47.0, -9.0, 0, 1}, {-46.0, -9.0, 0, 1}, {-45.0, -9.0, 0, 1},
{-44.0, -9.0, 0, 1}, {-43.0, -9.0, 0, 1}, {-42.0, -9.0, 0, 1}, {-41.0, -9.0, 0, 1}, {-40.0, -9.0, 0, 1}, {-39.0, -9.0, 0, 1},
{-38.0, -9.0, 0, 1}, {-37.0, -9.0, 0, 1}, {-33.0, -9.0, 0, 1}, {-32.0, -9.0, 0, 1}, {-31.0, -9.0, 0, 1}, {-30.0, -9.0, 0, 1},
{-29.0, -9.0, 0, 1}, {-28.0, -9.0, 0, 1}, {-27.0, -9.0, 0, 1}, {-26.0, -9.0, 0, 1}, {-25.0, -9.0, 0, 1}, {-24.0, -9.0, 0, 1},
{-23.0, -9.0, 0, 1}, {-22.0, -9.0, 0, 1}, {-21.0, -9.0, 0, 1}, {-17.0, -9.0, 0, 1}, {-16.0, -9.0, 0, 1}, {-15.0, -9.0, 0, 1},
{-14.0, -9.0, 0, 1}, {-13.0, -9.0, 0, 1}, {-12.0, -9.0, 0, 1}, {-11.0, -9.0, 0, 1}, {-10.0, -9.0, 0, 1}, {-9.0, -9.0, 0, 1},
{-8.0, -9.0, 0, 1}, {-7.0, -9.0, 0, 1}, {-6.0, -9.0, 0, 1}, {-5.0, -9.0, 0, 1}, {-1.0, -9.0, 0, 1}, {0.0, -9.0, 0, 1},
{1.0, -9.0, 0, 1}, {2.0, -9.0, 0, 1}, {3.0, -9.0, 0, 1}, {4.0, -9.0, 0, 1}, {5.0, -9.0, 0, 1}, {6.0, -9.0, 0, 1},
{7.0, -9.0, 0, 1}, {8.0, -9.0, 0, 1}, {9.0, -9.0, 0, 1}, {10.0, -9.0, 0, 1}, {14.0, -9.0, 0, 1}, {15.0, -9.0, 0, 1},
{16.0, -9.0, 0, 1}, {17.0, -9.0, 0, 1}, {18.0, -9.0, 0, 1}, {19.0, -9.0, 0, 1}, {20.0, -9.0, 0, 1}, {21.0, -9.0, 0, 1},
{22.0, -9.0, 0, 1}, {23.0, -9.0, 0, 1}, {24.0, -9.0, 0, 1}, {25.0, -9.0, 0, 1}, {30.0, -9.0, 0, 1}, {31.0, -9.0, 0, 1},
{32.0, -9.0, 0, 1}, {33.0, -9.0, 0, 1}, {34.0, -9.0, 0, 1}, {35.0, -9.0, 0, 1}, {36.0, -9.0, 0, 1}, {37.0, -9.0, 0, 1},
{38.0, -9.0, 0, 1}, {39.0, -9.0, 0, 1}, {40.0, -9.0, 0, 1}, {41.0, -9.0, 0, 1}, {45.0, -9.0, 0, 1}, {46.0, -9.0, 0, 1},
{47.0, -9.0, 0, 1}, {51.0, -9.0, 0, 1}, {52.0, -9.0, 0, 1}, {53.0, -9.0, 0, 1}, {54.0, -9.0, 0, 1}, {55.0, -9.0, 0, 1},
{56.0, -9.0, 0, 1}, {57.0, -9.0, 0, 1}, {58.0, -9.0, 0, 1}, {59.0, -9.0, 0, 1}, {60.0, -9.0, 0, 1}, {61.0, -9.0, 0, 1},
{62.0, -9.0, 0, 1}, {-63.0, -8.0, 0, 1}, {-62.0, -8.0, 0, 1}, {-61.0, -8.0, 0, 1}, {-48.0, -8.0, 0, 1}, {-47.0, -8.0, 0, 1},
{-46.0, -8.0, 0, 1}, {-33.0, -8.0, 0, 1}, {-32.0, -8.0, 0, 1}, {-31.0, -8.0, 0, 1}, {-30.0, -8.0, 0, 1}, {-23.0, -8.0, 0, 1},
{-22.0, -8.0, 0, 1}, {-21.0, -8.0, 0, 1}, {-20.0, -8.0, 0, 1}, {-17.0, -8.0, 0, 1}, {-16.0, -8.0, 0, 1}, {-15.0, -8.0, 0, 1},
{-14.0, -8.0, 0, 1}, {-7.0, -8.0, 0, 1}, {-6.0, -8.0, 0, 1}, {-5.0, -8.0, 0, 1}, {-1.0, -8.0, 0, 1}, {0.0, -8.0, 0, 1},
{1.0, -8.0, 0, 1}, {14.0, -8.0, 0, 1}, {15.0, -8.0, 0, 1}, {16.0, -8.0, 0, 1}, {29.0, -8.0, 0, 1}, {30.0, -8.0, 0, 1},
{31.0, -8.0, 0, 1}, {32.0, -8.0, 0, 1}, {45.0, -8.0, 0, 1}, {46.0, -8.0, 0, 1}, {47.0, -8.0, 0, 1}, {51.0, -8.0, 0, 1},
{52.0, -8.0, 0, 1}, {53.0, -8.0, 0, 1}, {54.0, -8.0, 0, 1}, {-63.0, -7.0, 0, 1}, {-62.0, -7.0, 0, 1}, {-61.0, -7.0, 0, 1},
{-48.0, -7.0, 0, 1}, {-47.0, -7.0, 0, 1}, {-46.0, -7.0, 0, 1}, {-33.0, -7.0, 0, 1}, {-32.0, -7.0, 0, 1}, {-31.0, -7.0, 0, 1},
{-30.0, -7.0, 0, 1}, {-22.0, -7.0, 0, 1}, {-21.0, -7.0, 0, 1}, {-20.0, -7.0, 0, 1}, {-17.0, -7.0, 0, 1}, {-16.0, -7.0, 0, 1},
{-15.0, -7.0, 0, 1}, {-14.0, -7.0, 0, 1}, {-7.0, -7.0, 0, 1}, {-6.0, -7.0, 0, 1}, {-5.0, -7.0, 0, 1}, {-1.0, -7.0, 0, 1},
{0.0, -7.0, 0, 1}, {1.0, -7.0, 0, 1}, {14.0, -7.0, 0, 1}, {15.0, -7.0, 0, 1}, {16.0, -7.0, 0, 1}, {29.0, -7.0, 0, 1},
{30.0, -7.0, 0, 1}, {31.0, -7.0, 0, 1}, {32.0, -7.0, 0, 1}, {45.0, -7.0, 0, 1}, {46.0, -7.0, 0, 1}, {47.0, -7.0, 0, 1},
{51.0, -7.0, 0, 1}, {52.0, -7.0, 0, 1}, {53.0, -7.0, 0, 1}, {-63.0, -6.0, 0, 1}, {-62.0, -6.0, 0, 1}, {-61.0, -6.0, 0, 1},
{-48.0, -6.0, 0, 1}, {-47.0, -6.0, 0, 1}, {-46.0, -6.0, 0, 1}, {-33.0, -6.0, 0, 1}, {-32.0, -6.0, 0, 1}, {-31.0, -6.0, 0, 1},
{-30.0, -6.0, 0, 1}, {-22.0, -6.0, 0, 1}, {-21.0, -6.0, 0, 1}, {-20.0, -6.0, 0, 1}, {-17.0, -6.0, 0, 1}, {-16.0, -6.0, 0, 1},
{-15.0, -6.0, 0, 1}, {-14.0, -6.0, 0, 1}, {-7.0, -6.0, 0, 1}, {-6.0, -6.0, 0, 1}, {-5.0, -6.0, 0, 1}, {-1.0, -6.0, 0, 1},
{0.0, -6.0, 0, 1}, {1.0, -6.0, 0, 1}, {14.0, -6.0, 0, 1}, {15.0, -6.0, 0, 1}, {16.0, -6.0, 0, 1}, {29.0, -6.0, 0, 1},
{30.0, -6.0, 0, 1}, {31.0, -6.0, 0, 1}, {32.0, -6.0, 0, 1}, {45.0, -6.0, 0, 1}, {46.0, -6.0, 0, 1}, {47.0, -6.0, 0, 1},
{51.0, -6.0, 0, 1}, {52.0, -6.0, 0, 1}, {53.0, -6.0, 0, 1}, {-63.0, -5.0, 0, 1}, {-62.0, -5.0, 0, 1}, {-61.0, -5.0, 0, 1},
{-48.0, -5.0, 0, 1}, {-47.0, -5.0, 0, 1}, {-46.0, -5.0, 0, 1}, {-33.0, -5.0, 0, 1}, {-32.0, -5.0, 0, 1}, {-31.0, -5.0, 0, 1},
{-30.0, -5.0, 0, 1}, {-22.0, -5.0, 0, 1}, {-21.0, -5.0, 0, 1}, {-20.0, -5.0, 0, 1}, {-17.0, -5.0, 0, 1}, {-16.0, -5.0, 0, 1},
{-15.0, -5.0, 0, 1}, {-14.0, -5.0, 0, 1}, {-7.0, -5.0, 0, 1}, {-6.0, -5.0, 0, 1}, {-5.0, -5.0, 0, 1}, {-1.0, -5.0, 0, 1},
{0.0, -5.0, 0, 1}, {1.0, -5.0, 0, 1}, {14.0, -5.0, 0, 1}, {15.0, -5.0, 0, 1}, {16.0, -5.0, 0, 1}, {29.0, -5.0, 0, 1},
{30.0, -5.0, 0, 1}, {31.0, -5.0, 0, 1}, {32.0, -5.0, 0, 1}, {45.0, -5.0, 0, 1}, {46.0, -5.0, 0, 1}, {47.0, -5.0, 0, 1},
{51.0, -5.0, 0, 1}, {52.0, -5.0, 0, 1}, {53.0, -5.0, 0, 1}, {-63.0, -4.0, 0, 1}, {-62.0, -4.0, 0, 1}, {-61.0, -4.0, 0, 1},
{-48.0, -4.0, 0, 1}, {-47.0, -4.0, 0, 1}, {-46.0, -4.0, 0, 1}, {-33.0, -4.0, 0, 1}, {-32.0, -4.0, 0, 1}, {-31.0, -4.0, 0, 1},
{-30.0, -4.0, 0, 1}, {-22.0, -4.0, 0, 1}, {-21.0, -4.0, 0, 1}, {-20.0, -4.0, 0, 1}, {-17.0, -4.0, 0, 1}, {-16.0, -4.0, 0, 1},
{-15.0, -4.0, 0, 1}, {-14.0, -4.0, 0, 1}, {-7.0, -4.0, 0, 1}, {-6.0, -4.0, 0, 1}, {-5.0, -4.0, 0, 1}, {-1.0, -4.0, 0, 1},
{0.0, -4.0, 0, 1}, {1.0, -4.0, 0, 1}, {14.0, -4.0, 0, 1}, {15.0, -4.0, 0, 1}, {16.0, -4.0, 0, 1}, {29.0, -4.0, 0, 1},
{30.0, -4.0, 0, 1}, {31.0, -4.0, 0, 1}, {32.0, -4.0, 0, 1}, {45.0, -4.0, 0, 1}, {46.0, -4.0, 0, 1}, {47.0, -4.0, 0, 1},
{51.0, -4.0, 0, 1}, {52.0, -4.0, 0, 1}, {53.0, -4.0, 0, 1}, {-63.0, -3.0, 0, 1}, {-62.0, -3.0, 0, 1}, {-61.0, -3.0, 0, 1},
{-48.0, -3.0, 0, 1}, {-47.0, -3.0, 0, 1}, {-46.0, -3.0, 0, 1}, {-33.0, -3.0, 0, 1}, {-32.0, -3.0, 0, 1}, {-31.0, -3.0, 0, 1},
{-30.0, -3.0, 0, 1}, {-22.0, -3.0, 0, 1}, {-21.0, -3.0, 0, 1}, {-20.0, -3.0, 0, 1}, {-17.0, -3.0, 0, 1}, {-16.0, -3.0, 0, 1},
{-15.0, -3.0, 0, 1}, {-14.0, -3.0, 0, 1}, {-7.0, -3.0, 0, 1}, {-6.0, -3.0, 0, 1}, {-5.0, -3.0, 0, 1}, {-1.0, -3.0, 0, 1},
{0.0, -3.0, 0, 1}, {1.0, -3.0, 0, 1}, {14.0, -3.0, 0, 1}, {15.0, -3.0, 0, 1}, {16.0, -3.0, 0, 1}, {29.0, -3.0, 0, 1},
{30.0, -3.0, 0, 1}, {31.0, -3.0, 0, 1}, {32.0, -3.0, 0, 1}, {45.0, -3.0, 0, 1}, {46.0, -3.0, 0, 1}, {47.0, -3.0, 0, 1},
{51.0, -3.0, 0, 1}, {52.0, -3.0, 0, 1}, {53.0, -3.0, 0, 1}, {-63.0, -2.0, 0, 1}, {-62.0, -2.0, 0, 1}, {-61.0, -2.0, 0, 1},
{-60.0, -2.0, 0, 1}, {-59.0, -2.0, 0, 1}, {-58.0, -2.0, 0, 1}, {-57.0, -2.0, 0, 1}, {-56.0, -2.0, 0, 1}, {-55.0, -2.0, 0, 1},
{-54.0, -2.0, 0, 1}, {-53.0, -2.0, 0, 1}, {-48.0, -2.0, 0, 1}, {-47.0, -2.0, 0, 1}, {-46.0, -2.0, 0, 1}, {-45.0, -2.0, 0, 1},
{-44.0, -2.0, 0, 1}, {-43.0, -2.0, 0, 1}, {-42.0, -2.0, 0, 1}, {-41.0, -2.0, 0, 1}, {-40.0, -2.0, 0, 1}, {-39.0, -2.0, 0, 1},
{-38.0, -2.0, 0, 1}, {-33.0, -2.0, 0, 1}, {-32.0, -2.0, 0, 1}, {-31.0, -2.0, 0, 1}, {-30.0, -2.0, 0, 1}, {-23.0, -2.0, 0, 1},
{-22.0, -2.0, 0, 1}, {-21.0, -2.0, 0, 1}, {-20.0, -2.0, 0, 1}, {-17.0, -2.0, 0, 1}, {-16.0, -2.0, 0, 1}, {-15.0, -2.0, 0, 1},
{-14.0, -2.0, 0, 1}, {-7.0, -2.0, 0, 1}, {-6.0, -2.0, 0, 1}, {-5.0, -2.0, 0, 1}, {-1.0, -2.0, 0, 1}, {0.0, -2.0, 0, 1},
{1.0, -2.0, 0, 1}, {2.0, -2.0, 0, 1}, {3.0, -2.0, 0, 1}, {4.0, -2.0, 0, 1}, {5.0, -2.0, 0, 1}, {6.0, -2.0, 0, 1},
{7.0, -2.0, 0, 1}, {8.0, -2.0, 0, 1}, {9.0, -2.0, 0, 1}, {14.0, -2.0, 0, 1}, {15.0, -2.0, 0, 1}, {16.0, -2.0, 0, 1},
{17.0, -2.0, 0, 1}, {18.0, -2.0, 0, 1}, {19.0, -2.0, 0, 1}, {20.0, -2.0, 0, 1}, {21.0, -2.0, 0, 1}, {22.0, -2.0, 0, 1},
{23.0, -2.0, 0, 1}, {24.0, -2.0, 0, 1}, {30.0, -2.0, 0, 1}, {31.0, -2.0, 0, 1}, {32.0, -2.0, 0, 1}, {33.0, -2.0, 0, 1},
{34.0, -2.0, 0, 1}, {35.0, -2.0, 0, 1}, {36.0, -2.0, 0, 1}, {37.0, -2.0, 0, 1}, {38.0, -2.0, 0, 1}, {39.0, -2.0, 0, 1},
{40.0, -2.0, 0, 1}, {45.0, -2.0, 0, 1}, {46.0, -2.0, 0, 1}, {47.0, -2.0, 0, 1}, {51.0, -2.0, 0, 1}, {52.0, -2.0, 0, 1},
{53.0, -2.0, 0, 1}, {54.0, -2.0, 0, 1}, {55.0, -2.0, 0, 1}, {56.0, -2.0, 0, 1}, {57.0, -2.0, 0, 1}, {58.0, -2.0, 0, 1},
{59.0, -2.0, 0, 1}, {60.0, -2.0, 0, 1}, {61.0, -2.0, 0, 1}, {-63.0, -1.0, 0, 1}, {-62.0, -1.0, 0, 1}, {-61.0, -1.0, 0, 1},
{-60.0, -1.0, 0, 1}, {-59.0, -1.0, 0, 1}, {-58.0, -1.0, 0, 1}, {-57.0, -1.0, 0, 1}, {-56.0, -1.0, 0, 1}, {-55.0, -1.0, 0, 1},
{-54.0, -1.0, 0, 1}, {-53.0, -1.0, 0, 1}, {-48.0, -1.0, 0, 1}, {-47.0, -1.0, 0, 1}, {-46.0, -1.0, 0, 1}, {-45.0, -1.0, 0, 1},
{-44.0, -1.0, 0, 1}, {-43.0, -1.0, 0, 1}, {-42.0, -1.0, 0, 1}, {-41.0, -1.0, 0, 1}, {-40.0, -1.0, 0, 1}, {-39.0, -1.0, 0, 1},
{-38.0, -1.0, 0, 1}, {-37.0, -1.0, 0, 1}, {-33.0, -1.0, 0, 1}, {-32.0, -1.0, 0, 1}, {-31.0, -1.0, 0, 1}, {-30.0, -1.0, 0, 1},
{-29.0, -1.0, 0, 1}, {-28.0, -1.0, 0, 1}, {-27.0, -1.0, 0, 1}, {-26.0, -1.0, 0, 1}, {-25.0, -1.0, 0, 1}, {-24.0, -1.0, 0, 1},
{-23.0, -1.0, 0, 1}, {-22.0, -1.0, 0, 1}, {-21.0, -1.0, 0, 1}, {-20.0, -1.0, 0, 1}, {-17.0, -1.0, 0, 1}, {-16.0, -1.0, 0, 1},
{-15.0, -1.0, 0, 1}, {-14.0, -1.0, 0, 1}, {-13.0, -1.0, 0, 1}, {-12.0, -1.0, 0, 1}, {-11.0, -1.0, 0, 1}, {-10.0, -1.0, 0, 1},
{-9.0, -1.0, 0, 1}, {-8.0, -1.0, 0, 1}, {-7.0, -1.0, 0, 1}, {-6.0, -1.0, 0, 1}, {-5.0, -1.0, 0, 1}, {-1.0, -1.0, 0, 1},
{0.0, -1.0, 0, 1}, {1.0, -1.0, 0, 1}, {2.0, -1.0, 0, 1}, {3.0, -1.0, 0, 1}, {4.0, -1.0, 0, 1}, {5.0, -1.0, 0, 1},
{6.0, -1.0, 0, 1}, {7.0, -1.0, 0, 1}, {8.0, -1.0, 0, 1}, {9.0, -1.0, 0, 1}, {14.0, -1.0, 0, 1}, {15.0, -1.0, 0, 1},
{16.0, -1.0, 0, 1}, {17.0, -1.0, 0, 1}, {18.0, -1.0, 0, 1}, {19.0, -1.0, 0, 1}, {20.0, -1.0, 0, 1}, {21.0, -1.0, 0, 1},
{22.0, -1.0, 0, 1}, {23.0, -1.0, 0, 1}, {24.0, -1.0, 0, 1}, {25.0, -1.0, 0, 1}, {30.0, -1.0, 0, 1}, {31.0, -1.0, 0, 1},
{32.0, -1.0, 0, 1}, {33.0, -1.0, 0, 1}, {34.0, -1.0, 0, 1}, {35.0, -1.0, 0, 1}, {36.0, -1.0, 0, 1}, {37.0, -1.0, 0, 1},
{38.0, -1.0, 0, 1}, {39.0, -1.0, 0, 1}, {40.0, -1.0, 0, 1}, {41.0, -1.0, 0, 1}, {45.0, -1.0, 0, 1}, {46.0, -1.0, 0, 1},
{47.0, -1.0, 0, 1}, {51.0, -1.0, 0, 1}, {52.0, -1.0, 0, 1}, {53.0, -1.0, 0, 1}, {54.0, -1.0, 0, 1}, {55.0, -1.0, 0, 1},
{56.0, -1.0, 0, 1}, {57.0, -1.0, 0, 1}, {58.0, -1.0, 0, 1}, {59.0, -1.0, 0, 1}, {60.0, -1.0, 0, 1}, {61.0, -1.0, 0, 1},
{-63.0, 0.0, 0, 1}, {-62.0, 0.0, 0, 1}, {-61.0, 0.0, 0, 1}, {-60.0, 0.0, 0, 1}, {-59.0, 0.0, 0, 1}, {-58.0, 0.0, 0, 1},
{-57.0, 0.0, 0, 1}, {-56.0, 0.0, 0, 1}, {-55.0, 0.0, 0, 1}, {-54.0, 0.0, 0, 1}, {-53.0, 0.0, 0, 1}, {-47.0, 0.0, 0, 1},
{-46.0, 0.0, 0, 1}, {-45.0, 0.0, 0, 1}, {-44.0, 0.0, 0, 1}, {-43.0, 0.0, 0, 1}, {-42.0, 0.0, 0, 1}, {-41.0, 0.0, 0, 1},
{-40.0, 0.0, 0, 1}, {-39.0, 0.0, 0, 1}, {-38.0, 0.0, 0, 1}, {-37.0, 0.0, 0, 1}, {-33.0, 0.0, 0, 1}, {-32.0, 0.0, 0, 1},
{-31.0, 0.0, 0, 1}, {-30.0, 0.0, 0, 1}, {-29.0, 0.0, 0, 1}, {-28.0, 0.0, 0, 1}, {-27.0, 0.0, 0, 1}, {-26.0, 0.0, 0, 1},
{-25.0, 0.0, 0, 1}, {-24.0, 0.0, 0, 1}, {-23.0, 0.0, 0, 1}, {-22.0, 0.0, 0, 1}, {-21.0, 0.0, 0, 1}, {-17.0, 0.0, 0, 1},
{-16.0, 0.0, 0, 1}, {-15.0, 0.0, 0, 1}, {-14.0, 0.0, 0, 1}, {-13.0, 0.0, 0, 1}, {-12.0, 0.0, 0, 1}, {-11.0, 0.0, 0, 1},
{-10.0, 0.0, 0, 1}, {-9.0, 0.0, 0, 1}, {-8.0, 0.0, 0, 1}, {-7.0, 0.0, 0, 1}, {-6.0, 0.0, 0, 1}, {-5.0, 0.0, 0, 1},
{-1.0, 0.0, 0, 1}, {0.0, 0.0, 0, 1}, {1.0, 0.0, 0, 1}, {2.0, 0.0, 0, 1}, {3.0, 0.0, 0, 1}, {4.0, 0.0, 0, 1},
{5.0, 0.0, 0, 1}, {6.0, 0.0, 0, 1}, {7.0, 0.0, 0, 1}, {8.0, 0.0, 0, 1}, {9.0, 0.0, 0, 1}, {15.0, 0.0, 0, 1},
{16.0, 0.0, 0, 1}, {17.0, 0.0, 0, 1}, {18.0, 0.0, 0, 1}, {19.0, 0.0, 0, 1}, {20.0, 0.0, 0, 1}, {21.0, 0.0, 0, 1},
{22.0, 0.0, 0, 1}, {23.0, 0.0, 0, 1}, {24.0, 0.0, 0, 1}, {25.0, 0.0, 0, 1}, {26.0, 0.0, 0, 1}, {31.0, 0.0, 0, 1},
{32.0, 0.0, 0, 1}, {33.0, 0.0, 0, 1}, {34.0, 0.0, 0, 1}, {35.0, 0.0, 0, 1}, {36.0, 0.0, 0, 1}, {37.0, 0.0, 0, 1},
{38.0, 0.0, 0, 1}, {39.0, 0.0, 0, 1}, {40.0, 0.0, 0, 1}, {41.0, 0.0, 0, 1}, {45.0, 0.0, 0, 1}, {46.0, 0.0, 0, 1},
{47.0, 0.0, 0, 1}, {51.0, 0.0, 0, 1}, {52.0, 0.0, 0, 1}, {53.0, 0.0, 0, 1}, {54.0, 0.0, 0, 1}, {55.0, 0.0, 0, 1},
{56.0, 0.0, 0, 1}, {57.0, 0.0, 0, 1}, {58.0, 0.0, 0, 1}, {59.0, 0.0, 0, 1}, {60.0, 0.0, 0, 1}, {61.0, 0.0, 0, 1},
{-63.0, 1.0, 0, 1}, {-62.0, 1.0, 0, 1}, {-61.0, 1.0, 0, 1}, {-39.0, 1.0, 0, 1}, {-38.0, 1.0, 0, 1}, {-37.0, 1.0, 0, 1},
{-36.0, 1.0, 0, 1}, {-33.0, 1.0, 0, 1}, {-32.0, 1.0, 0, 1}, {-31.0, 1.0, 0, 1}, {-30.0, 1.0, 0, 1}, {-29.0, 1.0, 0, 1},
{-28.0, 1.0, 0, 1}, {-27.0, 1.0, 0, 1}, {-26.0, 1.0, 0, 1}, {-25.0, 1.0, 0, 1}, {-24.0, 1.0, 0, 1}, {-23.0, 1.0, 0, 1},
{-22.0, 1.0, 0, 1}, {-21.0, 1.0, 0, 1}, {-17.0, 1.0, 0, 1}, {-16.0, 1.0, 0, 1}, {-15.0, 1.0, 0, 1}, {-14.0, 1.0, 0, 1},
{-13.0, 1.0, 0, 1}, {-12.0, 1.0, 0, 1}, {-11.0, 1.0, 0, 1}, {-10.0, 1.0, 0, 1}, {-9.0, 1.0, 0, 1}, {-8.0, 1.0, 0, 1},
{-7.0, 1.0, 0, 1}, {-6.0, 1.0, 0, 1}, {-1.0, 1.0, 0, 1}, {0.0, 1.0, 0, 1}, {1.0, 1.0, 0, 1}, {23.0, 1.0, 0, 1},
{24.0, 1.0, 0, 1}, {25.0, 1.0, 0, 1}, {26.0, 1.0, 0, 1}, {38.0, 1.0, 0, 1}, {39.0, 1.0, 0, 1}, {40.0, 1.0, 0, 1},
{41.0, 1.0, 0, 1}, {45.0, 1.0, 0, 1}, {46.0, 1.0, 0, 1}, {47.0, 1.0, 0, 1}, {51.0, 1.0, 0, 1}, {52.0, 1.0, 0, 1},
{53.0, 1.0, 0, 1}, {-63.0, 2.0, 0, 1}, {-62.0, 2.0, 0, 1}, {-61.0, 2.0, 0, 1}, {-39.0, 2.0, 0, 1}, {-38.0, 2.0, 0, 1},
{-37.0, 2.0, 0, 1}, {-36.0, 2.0, 0, 1}, {-33.0, 2.0, 0, 1}, {-32.0, 2.0, 0, 1}, {-31.0, 2.0, 0, 1}, {-30.0, 2.0, 0, 1},
{-29.0, 2.0, 0, 1}, {-28.0, 2.0, 0, 1}, {-27.0, 2.0, 0, 1}, {-26.0, 2.0, 0, 1}, {-25.0, 2.0, 0, 1}, {-24.0, 2.0, 0, 1},
{-23.0, 2.0, 0, 1}, {-17.0, 2.0, 0, 1}, {-16.0, 2.0, 0, 1}, {-15.0, 2.0, 0, 1}, {-14.0, 2.0, 0, 1}, {-9.0, 2.0, 0, 1},
{-8.0, 2.0, 0, 1}, {-7.0, 2.0, 0, 1}, {-6.0, 2.0, 0, 1}, {-1.0, 2.0, 0, 1}, {0.0, 2.0, 0, 1}, {1.0, 2.0, 0, 1},
{24.0, 2.0, 0, 1}, {25.0, 2.0, 0, 1}, {26.0, 2.0, 0, 1}, {39.0, 2.0, 0, 1}, {40.0, 2.0, 0, 1}, {41.0, 2.0, 0, 1},
{45.0, 2.0, 0, 1}, {46.0, 2.0, 0, 1}, {47.0, 2.0, 0, 1}, {51.0, 2.0, 0, 1}, {52.0, 2.0, 0, 1}, {53.0, 2.0, 0, 1},
{-63.0, 3.0, 0, 1}, {-62.0, 3.0, 0, 1}, {-61.0, 3.0, 0, 1}, {-39.0, 3.0, 0, 1}, {-38.0, 3.0, 0, 1}, {-37.0, 3.0, 0, 1},
{-36.0, 3.0, 0, 1}, {-33.0, 3.0, 0, 1}, {-32.0, 3.0, 0, 1}, {-31.0, 3.0, 0, 1}, {-30.0, 3.0, 0, 1}, {-17.0, 3.0, 0, 1},
{-16.0, 3.0, 0, 1}, {-15.0, 3.0, 0, 1}, {-14.0, 3.0, 0, 1}, {-8.0, 3.0, 0, 1}, {-7.0, 3.0, 0, 1}, {-6.0, 3.0, 0, 1},
{-1.0, 3.0, 0, 1}, {0.0, 3.0, 0, 1}, {1.0, 3.0, 0, 1}, {24.0, 3.0, 0, 1}, {25.0, 3.0, 0, 1}, {26.0, 3.0, 0, 1},
{39.0, 3.0, 0, 1}, {40.0, 3.0, 0, 1}, {41.0, 3.0, 0, 1}, {45.0, 3.0, 0, 1}, {46.0, 3.0, 0, 1}, {47.0, 3.0, 0, 1},
{51.0, 3.0, 0, 1}, {52.0, 3.0, 0, 1}, {53.0, 3.0, 0, 1}, {-63.0, 4.0, 0, 1}, {-62.0, 4.0, 0, 1}, {-61.0, 4.0, 0, 1},
{-39.0, 4.0, 0, 1}, {-38.0, 4.0, 0, 1}, {-37.0, 4.0, 0, 1}, {-36.0, 4.0, 0, 1}, {-33.0, 4.0, 0, 1}, {-32.0, 4.0, 0, 1},
{-31.0, 4.0, 0, 1}, {-30.0, 4.0, 0, 1}, {-17.0, 4.0, 0, 1}, {-16.0, 4.0, 0, 1}, {-15.0, 4.0, 0, 1}, {-14.0, 4.0, 0, 1},
{-7.0, 4.0, 0, 1}, {-6.0, 4.0, 0, 1}, {-5.0, 4.0, 0, 1}, {-1.0, 4.0, 0, 1}, {0.0, 4.0, 0, 1}, {1.0, 4.0, 0, 1},
{24.0, 4.0, 0, 1}, {25.0, 4.0, 0, 1}, {26.0, 4.0, 0, 1}, {39.0, 4.0, 0, 1}, {40.0, 4.0, 0, 1}, {41.0, 4.0, 0, 1},
{45.0, 4.0, 0, 1}, {46.0, 4.0, 0, 1}, {47.0, 4.0, 0, 1}, {51.0, 4.0, 0, 1}, {52.0, 4.0, 0, 1}, {53.0, 4.0, 0, 1},
{-63.0, 5.0, 0, 1}, {-62.0, 5.0, 0, 1}, {-61.0, 5.0, 0, 1}, {-39.0, 5.0, 0, 1}, {-38.0, 5.0, 0, 1}, {-37.0, 5.0, 0, 1},
{-36.0, 5.0, 0, 1}, {-33.0, 5.0, 0, 1}, {-32.0, 5.0, 0, 1}, {-31.0, 5.0, 0, 1}, {-30.0, 5.0, 0, 1}, {-17.0, 5.0, 0, 1},
{-16.0, 5.0, 0, 1}, {-15.0, 5.0, 0, 1}, {-14.0, 5.0, 0, 1}, {-7.0, 5.0, 0, 1}, {-6.0, 5.0, 0, 1}, {-5.0, 5.0, 0, 1},
{-1.0, 5.0, 0, 1}, {0.0, 5.0, 0, 1}, {1.0, 5.0, 0, 1}, {24.0, 5.0, 0, 1}, {25.0, 5.0, 0, 1}, {26.0, 5.0, 0, 1},
{39.0, 5.0, 0, 1}, {40.0, 5.0, 0, 1}, {41.0, 5.0, 0, 1}, {45.0, 5.0, 0, 1}, {46.0, 5.0, 0, 1}, {47.0, 5.0, 0, 1},
{51.0, 5.0, 0, 1}, {52.0, 5.0, 0, 1}, {53.0, 5.0, 0, 1}, {-63.0, 6.0, 0, 1}, {-62.0, 6.0, 0, 1}, {-61.0, 6.0, 0, 1},
{-39.0, 6.0, 0, 1}, {-38.0, 6.0, 0, 1}, {-37.0, 6.0, 0, 1}, {-36.0, 6.0, 0, 1}, {-33.0, 6.0, 0, 1}, {-32.0, 6.0, 0, 1},
{-31.0, 6.0, 0, 1}, {-30.0, 6.0, 0, 1}, {-17.0, 6.0, 0, 1}, {-16.0, 6.0, 0, 1}, {-15.0, 6.0, 0, 1}, {-14.0, 6.0, 0, 1},
{-7.0, 6.0, 0, 1}, {-6.0, 6.0, 0, 1}, {-5.0, 6.0, 0, 1}, {-1.0, 6.0, 0, 1}, {0.0, 6.0, 0, 1}, {1.0, 6.0, 0, 1},
{24.0, 6.0, 0, 1}, {25.0, 6.0, 0, 1}, {26.0, 6.0, 0, 1}, {39.0, 6.0, 0, 1}, {40.0, 6.0, 0, 1}, {41.0, 6.0, 0, 1},
{45.0, 6.0, 0, 1}, {46.0, 6.0, 0, 1}, {47.0, 6.0, 0, 1}, {51.0, 6.0, 0, 1}, {52.0, 6.0, 0, 1}, {53.0, 6.0, 0, 1},
{-63.0, 7.0, 0, 1}, {-62.0, 7.0, 0, 1}, {-61.0, 7.0, 0, 1}, {-39.0, 7.0, 0, 1}, {-38.0, 7.0, 0, 1}, {-37.0, 7.0, 0, 1},
{-36.0, 7.0, 0, 1}, {-33.0, 7.0, 0, 1}, {-32.0, 7.0, 0, 1}, {-31.0, 7.0, 0, 1}, {-30.0, 7.0, 0, 1}, {-17.0, 7.0, 0, 1},
{-16.0, 7.0, 0, 1}, {-15.0, 7.0, 0, 1}, {-14.0, 7.0, 0, 1}, {-7.0, 7.0, 0, 1}, {-6.0, 7.0, 0, 1}, {-5.0, 7.0, 0, 1},
{-1.0, 7.0, 0, 1}, {0.0, 7.0, 0, 1}, {1.0, 7.0, 0, 1}, {24.0, 7.0, 0, 1}, {25.0, 7.0, 0, 1}, {26.0, 7.0, 0, 1},
{39.0, 7.0, 0, 1}, {40.0, 7.0, 0, 1}, {41.0, 7.0, 0, 1}, {45.0, 7.0, 0, 1}, {46.0, 7.0, 0, 1}, {47.0, 7.0, 0, 1},
{51.0, 7.0, 0, 1}, {52.0, 7.0, 0, 1}, {53.0, 7.0, 0, 1}, {-63.0, 8.0, 0, 1}, {-62.0, 8.0, 0, 1}, {-61.0, 8.0, 0, 1},
{-60.0, 8.0, 0, 1}, {-59.0, 8.0, 0, 1}, {-58.0, 8.0, 0, 1}, {-57.0, 8.0, 0, 1}, {-56.0, 8.0, 0, 1}, {-55.0, 8.0, 0, 1},
{-54.0, 8.0, 0, 1}, {-53.0, 8.0, 0, 1}, {-52.0, 8.0, 0, 1}, {-48.0, 8.0, 0, 1}, {-47.0, 8.0, 0, 1}, {-46.0, 8.0, 0, 1},
{-45.0, 8.0, 0, 1}, {-44.0, 8.0, 0, 1}, {-43.0, 8.0, 0, 1}, {-42.0, 8.0, 0, 1}, {-41.0, 8.0, 0, 1}, {-40.0, 8.0, 0, 1},
{-39.0, 8.0, 0, 1}, {-38.0, 8.0, 0, 1}, {-37.0, 8.0, 0, 1}, {-33.0, 8.0, 0, 1}, {-32.0, 8.0, 0, 1}, {-31.0, 8.0, 0, 1},
{-30.0, 8.0, 0, 1}, {-17.0, 8.0, 0, 1}, {-16.0, 8.0, 0, 1}, {-15.0, 8.0, 0, 1}, {-14.0, 8.0, 0, 1}, {-7.0, 8.0, 0, 1},
{-6.0, 8.0, 0, 1}, {-5.0, 8.0, 0, 1}, {-4.0, 8.0, 0, 1}, {-1.0, 8.0, 0, 1}, {0.0, 8.0, 0, 1}, {1.0, 8.0, 0, 1},
{2.0, 8.0, 0, 1}, {3.0, 8.0, 0, 1}, {4.0, 8.0, 0, 1}, {5.0, 8.0, 0, 1}, {6.0, 8.0, 0, 1}, {7.0, 8.0, 0, 1},
{8.0, 8.0, 0, 1}, {9.0, 8.0, 0, 1}, {10.0, 8.0, 0, 1}, {14.0, 8.0, 0, 1}, {15.0, 8.0, 0, 1}, {16.0, 8.0, 0, 1},
{17.0, 8.0, 0, 1}, {18.0, 8.0, 0, 1}, {19.0, 8.0, 0, 1}, {20.0, 8.0, 0, 1}, {21.0, 8.0, 0, 1}, {22.0, 8.0, 0, 1},
{23.0, 8.0, 0, 1}, {24.0, 8.0, 0, 1}, {25.0, 8.0, 0, 1}, {26.0, 8.0, 0, 1}, {29.0, 8.0, 0, 1}, {30.0, 8.0, 0, 1},
{31.0, 8.0, 0, 1}, {32.0, 8.0, 0, 1}, {33.0, 8.0, 0, 1}, {34.0, 8.0, 0, 1}, {35.0, 8.0, 0, 1}, {36.0, 8.0, 0, 1},
{37.0, 8.0, 0, 1}, {38.0, 8.0, 0, 1}, {39.0, 8.0, 0, 1}, {40.0, 8.0, 0, 1}, {41.0, 8.0, 0, 1}, {45.0, 8.0, 0, 1},
{46.0, 8.0, 0, 1}, {47.0, 8.0, 0, 1}, {51.0, 8.0, 0, 1}, {52.0, 8.0, 0, 1}, {53.0, 8.0, 0, 1}, {-63.0, 9.0, 0, 1},
{-62.0, 9.0, 0, 1}, {-61.0, 9.0, 0, 1}, {-60.0, 9.0, 0, 1}, {-59.0, 9.0, 0, 1}, {-58.0, 9.0, 0, 1}, {-57.0, 9.0, 0, 1},
{-56.0, 9.0, 0, 1}, {-55.0, 9.0, 0, 1}, {-54.0, 9.0, 0, 1}, {-53.0, 9.0, 0, 1}, {-52.0, 9.0, 0, 1}, {-48.0, 9.0, 0, 1},
{-47.0, 9.0, 0, 1}, {-46.0, 9.0, 0, 1}, {-45.0, 9.0, 0, 1}, {-44.0, 9.0, 0, 1}, {-43.0, 9.0, 0, 1}, {-42.0, 9.0, 0, 1},
{-41.0, 9.0, 0, 1}, {-40.0, 9.0, 0, 1}, {-39.0, 9.0, 0, 1}, {-38.0, 9.0, 0, 1}, {-37.0, 9.0, 0, 1}, {-33.0, 9.0, 0, 1},
{-32.0, 9.0, 0, 1}, {-31.0, 9.0, 0, 1}, {-30.0, 9.0, 0, 1}, {-17.0, 9.0, 0, 1}, {-16.0, 9.0, 0, 1}, {-15.0, 9.0, 0, 1},
{-14.0, 9.0, 0, 1}, {-6.0, 9.0, 0, 1}, {-5.0, 9.0, 0, 1}, {-4.0, 9.0, 0, 1}, {0.0, 9.0, 0, 1}, {1.0, 9.0, 0, 1},
{2.0, 9.0, 0, 1}, {3.0, 9.0, 0, 1}, {4.0, 9.0, 0, 1}, {5.0, 9.0, 0, 1}, {6.0, 9.0, 0, 1}, {7.0, 9.0, 0, 1},
{8.0, 9.0, 0, 1}, {9.0, 9.0, 0, 1}, {10.0, 9.0, 0, 1}, {14.0, 9.0, 0, 1}, {15.0, 9.0, 0, 1}, {16.0, 9.0, 0, 1},
{17.0, 9.0, 0, 1}, {18.0, 9.0, 0, 1}, {19.0, 9.0, 0, 1}, {20.0, 9.0, 0, 1}, {21.0, 9.0, 0, 1}, {22.0, 9.0, 0, 1},
{23.0, 9.0, 0, 1}, {24.0, 9.0, 0, 1}, {25.0, 9.0, 0, 1}, {29.0, 9.0, 0, 1}, {30.0, 9.0, 0, 1}, {31.0, 9.0, 0, 1},
{32.0, 9.0, 0, 1}, {33.0, 9.0, 0, 1}, {34.0, 9.0, 0, 1}, {35.0, 9.0, 0, 1}, {36.0, 9.0, 0, 1}, {37.0, 9.0, 0, 1},
{38.0, 9.0, 0, 1}, {39.0, 9.0, 0, 1}, {40.0, 9.0, 0, 1}, {41.0, 9.0, 0, 1}, {45.0, 9.0, 0, 1}, {46.0, 9.0, 0, 1},
{47.0, 9.0, 0, 1}, {51.0, 9.0, 0, 1}, {52.0, 9.0, 0, 1}, {53.0, 9.0, 0, 1}, {-62.0, 10.0, 0, 1}, {-61.0, 10.0, 0, 1},
{-60.0, 10.0, 0, 1}, {-59.0, 10.0, 0, 1}, {-58.0, 10.0, 0, 1}, {-57.0, 10.0, 0, 1}, {-56.0, 10.0, 0, 1}, {-55.0, 10.0, 0, 1},
{-54.0, 10.0, 0, 1}, {-53.0, 10.0, 0, 1}, {-52.0, 10.0, 0, 1}, {-48.0, 10.0, 0, 1}, {-47.0, 10.0, 0, 1}, {-46.0, 10.0, 0, 1},
{-45.0, 10.0, 0, 1}, {-44.0, 10.0, 0, 1}, {-43.0, 10.0, 0, 1}, {-42.0, 10.0, 0, 1}, {-41.0, 10.0, 0, 1}, {-40.0, 10.0, 0, 1},
{-39.0, 10.0, 0, 1}, {-38.0, 10.0, 0, 1}, {-33.0, 10.0, 0, 1}, {-32.0, 10.0, 0, 1}, {-31.0, 10.0, 0, 1}, {-30.0, 10.0, 0, 1},
{-17.0, 10.0, 0, 1}, {-16.0, 10.0, 0, 1}, {-15.0, 10.0, 0, 1}, {-14.0, 10.0, 0, 1}, {-6.0, 10.0, 0, 1}, {-5.0, 10.0, 0, 1},
{-4.0, 10.0, 0, 1}, {0.0, 10.0, 0, 1}, {1.0, 10.0, 0, 1}, {2.0, 10.0, 0, 1}, {3.0, 10.0, 0, 1}, {4.0, 10.0, 0, 1},
{5.0, 10.0, 0, 1}, {6.0, 10.0, 0, 1}, {7.0, 10.0, 0, 1}, {8.0, 10.0, 0, 1}, {9.0, 10.0, 0, 1}, {10.0, 10.0, 0, 1},
{14.0, 10.0, 0, 1}, {15.0, 10.0, 0, 1}, {16.0, 10.0, 0, 1}, {17.0, 10.0, 0, 1}, {18.0, 10.0, 0, 1}, {19.0, 10.0, 0, 1},
{20.0, 10.0, 0, 1}, {21.0, 10.0, 0, 1}, {22.0, 10.0, 0, 1}, {23.0, 10.0, 0, 1}, {24.0, 10.0, 0, 1}, {29.0, 10.0, 0, 1},
{30.0, 10.0, 0, 1}, {31.0, 10.0, 0, 1}, {32.0, 10.0, 0, 1}, {33.0, 10.0, 0, 1}, {34.0, 10.0, 0, 1}, {35.0, 10.0, 0, 1},
{36.0, 10.0, 0, 1}, {37.0, 10.0, 0, 1}, {38.0, 10.0, 0, 1}, {39.0, 10.0, 0, 1}, {40.0, 10.0, 0, 1}, {45.0, 10.0, 0, 1},
{46.0, 10.0, 0, 1}, {47.0, 10.0, 0, 1}, {51.0, 10.0, 0, 1}, {52.0, 10.0, 0, 1}, {53.0, 10.0, 0, 1}
};

View File

@@ -0,0 +1,16 @@
// File generated by image_to_3d_array.py
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern const uint8_t image_bmp_array_esp_text[384];
extern const float image_3d_array_esp_text[1271][4];
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,338 @@
// File generated by ImgTo3D.py
// Image file converted to 3D matrix cpu_logo.png
#include "image_to_3d_matrix.h"
#ifdef CONFIG_3D_OBJECT_CUSTOM
const uint8_t image_to_bmp_array_custom[512] = {
0x00, 0x00, 0x0e, 0x1c, 0x38, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00,
0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00,
0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00,
0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00,
0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe,
0xff, 0xfe, 0x0f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xf0, 0x7f, 0xff,
0xff, 0xfe, 0x0f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0x00, 0x1e, 0x0f, 0xff, 0xff, 0xf0, 0x78, 0x00,
0x00, 0x1e, 0x0f, 0x00, 0x00, 0xf0, 0x78, 0x00, 0x00, 0x1e, 0x0f, 0x00, 0x00, 0xf0, 0x78, 0x00,
0x7f, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xfe, 0xff, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xff,
0xff, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xff, 0xff, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xff,
0x7f, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xfc, 0x00, 0x1e, 0x0f, 0x00, 0x00, 0xf0, 0x78, 0x00,
0x00, 0x1e, 0x0f, 0x00, 0x00, 0xf0, 0x78, 0x00, 0x7f, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xfe,
0xff, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xff, 0xff, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xff,
0xff, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xff, 0x7f, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xfe,
0x00, 0x1e, 0x0f, 0x00, 0x00, 0xf0, 0x78, 0x00, 0x00, 0x1e, 0x0f, 0x00, 0x00, 0xf0, 0x78, 0x00,
0x7f, 0xfe, 0x0f, 0xff, 0xff, 0xf0, 0x7f, 0xfc, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xf0, 0x7f, 0xff,
0xff, 0xfe, 0x0f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xf0, 0x7f, 0xff,
0x7f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00,
0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00,
0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00,
0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00,
0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3c, 0x7c, 0x78, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x38, 0x70, 0x00, 0x00
};
const float image_to_3d_matrix_custom[1732][4] = {
{-12.0, -32.0, 0, 1}, {-11.0, -32.0, 0, 1}, {-10.0, -32.0, 0, 1}, {-5.0, -32.0, 0, 1}, {-4.0, -32.0, 0, 1}, {-3.0, -32.0, 0, 1},
{2.0, -32.0, 0, 1}, {3.0, -32.0, 0, 1}, {4.0, -32.0, 0, 1}, {9.0, -32.0, 0, 1}, {10.0, -32.0, 0, 1}, {11.0, -32.0, 0, 1},
{-13.0, -31.0, 0, 1}, {-12.0, -31.0, 0, 1}, {-11.0, -31.0, 0, 1}, {-10.0, -31.0, 0, 1}, {-6.0, -31.0, 0, 1}, {-5.0, -31.0, 0, 1},
{-4.0, -31.0, 0, 1}, {-3.0, -31.0, 0, 1}, {-2.0, -31.0, 0, 1}, {1.0, -31.0, 0, 1}, {2.0, -31.0, 0, 1}, {3.0, -31.0, 0, 1},
{4.0, -31.0, 0, 1}, {5.0, -31.0, 0, 1}, {8.0, -31.0, 0, 1}, {9.0, -31.0, 0, 1}, {10.0, -31.0, 0, 1}, {11.0, -31.0, 0, 1},
{12.0, -31.0, 0, 1}, {-13.0, -30.0, 0, 1}, {-12.0, -30.0, 0, 1}, {-11.0, -30.0, 0, 1}, {-10.0, -30.0, 0, 1}, {-6.0, -30.0, 0, 1},
{-5.0, -30.0, 0, 1}, {-4.0, -30.0, 0, 1}, {-3.0, -30.0, 0, 1}, {-2.0, -30.0, 0, 1}, {1.0, -30.0, 0, 1}, {2.0, -30.0, 0, 1},
{3.0, -30.0, 0, 1}, {4.0, -30.0, 0, 1}, {5.0, -30.0, 0, 1}, {8.0, -30.0, 0, 1}, {9.0, -30.0, 0, 1}, {10.0, -30.0, 0, 1},
{11.0, -30.0, 0, 1}, {12.0, -30.0, 0, 1}, {-13.0, -29.0, 0, 1}, {-12.0, -29.0, 0, 1}, {-11.0, -29.0, 0, 1}, {-10.0, -29.0, 0, 1},
{-6.0, -29.0, 0, 1}, {-5.0, -29.0, 0, 1}, {-4.0, -29.0, 0, 1}, {-3.0, -29.0, 0, 1}, {-2.0, -29.0, 0, 1}, {1.0, -29.0, 0, 1},
{2.0, -29.0, 0, 1}, {3.0, -29.0, 0, 1}, {4.0, -29.0, 0, 1}, {5.0, -29.0, 0, 1}, {8.0, -29.0, 0, 1}, {9.0, -29.0, 0, 1},
{10.0, -29.0, 0, 1}, {11.0, -29.0, 0, 1}, {12.0, -29.0, 0, 1}, {-13.0, -28.0, 0, 1}, {-12.0, -28.0, 0, 1}, {-11.0, -28.0, 0, 1},
{-10.0, -28.0, 0, 1}, {-6.0, -28.0, 0, 1}, {-5.0, -28.0, 0, 1}, {-4.0, -28.0, 0, 1}, {-3.0, -28.0, 0, 1}, {-2.0, -28.0, 0, 1},
{1.0, -28.0, 0, 1}, {2.0, -28.0, 0, 1}, {3.0, -28.0, 0, 1}, {4.0, -28.0, 0, 1}, {5.0, -28.0, 0, 1}, {8.0, -28.0, 0, 1},
{9.0, -28.0, 0, 1}, {10.0, -28.0, 0, 1}, {11.0, -28.0, 0, 1}, {12.0, -28.0, 0, 1}, {-13.0, -27.0, 0, 1}, {-12.0, -27.0, 0, 1},
{-11.0, -27.0, 0, 1}, {-10.0, -27.0, 0, 1}, {-6.0, -27.0, 0, 1}, {-5.0, -27.0, 0, 1}, {-4.0, -27.0, 0, 1}, {-3.0, -27.0, 0, 1},
{-2.0, -27.0, 0, 1}, {1.0, -27.0, 0, 1}, {2.0, -27.0, 0, 1}, {3.0, -27.0, 0, 1}, {4.0, -27.0, 0, 1}, {5.0, -27.0, 0, 1},
{8.0, -27.0, 0, 1}, {9.0, -27.0, 0, 1}, {10.0, -27.0, 0, 1}, {11.0, -27.0, 0, 1}, {12.0, -27.0, 0, 1}, {-13.0, -26.0, 0, 1},
{-12.0, -26.0, 0, 1}, {-11.0, -26.0, 0, 1}, {-10.0, -26.0, 0, 1}, {-6.0, -26.0, 0, 1}, {-5.0, -26.0, 0, 1}, {-4.0, -26.0, 0, 1},
{-3.0, -26.0, 0, 1}, {-2.0, -26.0, 0, 1}, {1.0, -26.0, 0, 1}, {2.0, -26.0, 0, 1}, {3.0, -26.0, 0, 1}, {4.0, -26.0, 0, 1},
{5.0, -26.0, 0, 1}, {8.0, -26.0, 0, 1}, {9.0, -26.0, 0, 1}, {10.0, -26.0, 0, 1}, {11.0, -26.0, 0, 1}, {12.0, -26.0, 0, 1},
{-13.0, -25.0, 0, 1}, {-12.0, -25.0, 0, 1}, {-11.0, -25.0, 0, 1}, {-10.0, -25.0, 0, 1}, {-6.0, -25.0, 0, 1}, {-5.0, -25.0, 0, 1},
{-4.0, -25.0, 0, 1}, {-3.0, -25.0, 0, 1}, {-2.0, -25.0, 0, 1}, {1.0, -25.0, 0, 1}, {2.0, -25.0, 0, 1}, {3.0, -25.0, 0, 1},
{4.0, -25.0, 0, 1}, {5.0, -25.0, 0, 1}, {8.0, -25.0, 0, 1}, {9.0, -25.0, 0, 1}, {10.0, -25.0, 0, 1}, {11.0, -25.0, 0, 1},
{12.0, -25.0, 0, 1}, {-13.0, -24.0, 0, 1}, {-12.0, -24.0, 0, 1}, {-11.0, -24.0, 0, 1}, {-10.0, -24.0, 0, 1}, {-6.0, -24.0, 0, 1},
{-5.0, -24.0, 0, 1}, {-4.0, -24.0, 0, 1}, {-3.0, -24.0, 0, 1}, {-2.0, -24.0, 0, 1}, {1.0, -24.0, 0, 1}, {2.0, -24.0, 0, 1},
{3.0, -24.0, 0, 1}, {4.0, -24.0, 0, 1}, {5.0, -24.0, 0, 1}, {8.0, -24.0, 0, 1}, {9.0, -24.0, 0, 1}, {10.0, -24.0, 0, 1},
{11.0, -24.0, 0, 1}, {12.0, -24.0, 0, 1}, {-13.0, -23.0, 0, 1}, {-12.0, -23.0, 0, 1}, {-11.0, -23.0, 0, 1}, {-10.0, -23.0, 0, 1},
{-6.0, -23.0, 0, 1}, {-5.0, -23.0, 0, 1}, {-4.0, -23.0, 0, 1}, {-3.0, -23.0, 0, 1}, {-2.0, -23.0, 0, 1}, {1.0, -23.0, 0, 1},
{2.0, -23.0, 0, 1}, {3.0, -23.0, 0, 1}, {4.0, -23.0, 0, 1}, {5.0, -23.0, 0, 1}, {8.0, -23.0, 0, 1}, {9.0, -23.0, 0, 1},
{10.0, -23.0, 0, 1}, {11.0, -23.0, 0, 1}, {12.0, -23.0, 0, 1}, {-13.0, -22.0, 0, 1}, {-12.0, -22.0, 0, 1}, {-11.0, -22.0, 0, 1},
{-10.0, -22.0, 0, 1}, {-6.0, -22.0, 0, 1}, {-5.0, -22.0, 0, 1}, {-4.0, -22.0, 0, 1}, {-3.0, -22.0, 0, 1}, {-2.0, -22.0, 0, 1},
{1.0, -22.0, 0, 1}, {2.0, -22.0, 0, 1}, {3.0, -22.0, 0, 1}, {4.0, -22.0, 0, 1}, {5.0, -22.0, 0, 1}, {8.0, -22.0, 0, 1},
{9.0, -22.0, 0, 1}, {10.0, -22.0, 0, 1}, {11.0, -22.0, 0, 1}, {12.0, -22.0, 0, 1}, {-21.0, -21.0, 0, 1}, {-20.0, -21.0, 0, 1},
{-19.0, -21.0, 0, 1}, {-18.0, -21.0, 0, 1}, {-17.0, -21.0, 0, 1}, {-16.0, -21.0, 0, 1}, {-15.0, -21.0, 0, 1}, {-14.0, -21.0, 0, 1},
{-13.0, -21.0, 0, 1}, {-12.0, -21.0, 0, 1}, {-11.0, -21.0, 0, 1}, {-10.0, -21.0, 0, 1}, {-9.0, -21.0, 0, 1}, {-8.0, -21.0, 0, 1},
{-7.0, -21.0, 0, 1}, {-6.0, -21.0, 0, 1}, {-5.0, -21.0, 0, 1}, {-4.0, -21.0, 0, 1}, {-3.0, -21.0, 0, 1}, {-2.0, -21.0, 0, 1},
{-1.0, -21.0, 0, 1}, {0.0, -21.0, 0, 1}, {1.0, -21.0, 0, 1}, {2.0, -21.0, 0, 1}, {3.0, -21.0, 0, 1}, {4.0, -21.0, 0, 1},
{5.0, -21.0, 0, 1}, {6.0, -21.0, 0, 1}, {7.0, -21.0, 0, 1}, {8.0, -21.0, 0, 1}, {9.0, -21.0, 0, 1}, {10.0, -21.0, 0, 1},
{11.0, -21.0, 0, 1}, {12.0, -21.0, 0, 1}, {13.0, -21.0, 0, 1}, {14.0, -21.0, 0, 1}, {15.0, -21.0, 0, 1}, {16.0, -21.0, 0, 1},
{17.0, -21.0, 0, 1}, {18.0, -21.0, 0, 1}, {19.0, -21.0, 0, 1}, {20.0, -21.0, 0, 1}, {-21.0, -20.0, 0, 1}, {-20.0, -20.0, 0, 1},
{-19.0, -20.0, 0, 1}, {-18.0, -20.0, 0, 1}, {-17.0, -20.0, 0, 1}, {-16.0, -20.0, 0, 1}, {-15.0, -20.0, 0, 1}, {-14.0, -20.0, 0, 1},
{-13.0, -20.0, 0, 1}, {-12.0, -20.0, 0, 1}, {-11.0, -20.0, 0, 1}, {-10.0, -20.0, 0, 1}, {-9.0, -20.0, 0, 1}, {-8.0, -20.0, 0, 1},
{-7.0, -20.0, 0, 1}, {-6.0, -20.0, 0, 1}, {-5.0, -20.0, 0, 1}, {-4.0, -20.0, 0, 1}, {-3.0, -20.0, 0, 1}, {-2.0, -20.0, 0, 1},
{-1.0, -20.0, 0, 1}, {0.0, -20.0, 0, 1}, {1.0, -20.0, 0, 1}, {2.0, -20.0, 0, 1}, {3.0, -20.0, 0, 1}, {4.0, -20.0, 0, 1},
{5.0, -20.0, 0, 1}, {6.0, -20.0, 0, 1}, {7.0, -20.0, 0, 1}, {8.0, -20.0, 0, 1}, {9.0, -20.0, 0, 1}, {10.0, -20.0, 0, 1},
{11.0, -20.0, 0, 1}, {12.0, -20.0, 0, 1}, {13.0, -20.0, 0, 1}, {14.0, -20.0, 0, 1}, {15.0, -20.0, 0, 1}, {16.0, -20.0, 0, 1},
{17.0, -20.0, 0, 1}, {18.0, -20.0, 0, 1}, {19.0, -20.0, 0, 1}, {20.0, -20.0, 0, 1}, {-21.0, -19.0, 0, 1}, {-20.0, -19.0, 0, 1},
{-19.0, -19.0, 0, 1}, {-18.0, -19.0, 0, 1}, {-17.0, -19.0, 0, 1}, {-16.0, -19.0, 0, 1}, {-15.0, -19.0, 0, 1}, {-14.0, -19.0, 0, 1},
{-13.0, -19.0, 0, 1}, {-12.0, -19.0, 0, 1}, {-11.0, -19.0, 0, 1}, {-10.0, -19.0, 0, 1}, {-9.0, -19.0, 0, 1}, {-8.0, -19.0, 0, 1},
{-7.0, -19.0, 0, 1}, {-6.0, -19.0, 0, 1}, {-5.0, -19.0, 0, 1}, {-4.0, -19.0, 0, 1}, {-3.0, -19.0, 0, 1}, {-2.0, -19.0, 0, 1},
{-1.0, -19.0, 0, 1}, {0.0, -19.0, 0, 1}, {1.0, -19.0, 0, 1}, {2.0, -19.0, 0, 1}, {3.0, -19.0, 0, 1}, {4.0, -19.0, 0, 1},
{5.0, -19.0, 0, 1}, {6.0, -19.0, 0, 1}, {7.0, -19.0, 0, 1}, {8.0, -19.0, 0, 1}, {9.0, -19.0, 0, 1}, {10.0, -19.0, 0, 1},
{11.0, -19.0, 0, 1}, {12.0, -19.0, 0, 1}, {13.0, -19.0, 0, 1}, {14.0, -19.0, 0, 1}, {15.0, -19.0, 0, 1}, {16.0, -19.0, 0, 1},
{17.0, -19.0, 0, 1}, {18.0, -19.0, 0, 1}, {19.0, -19.0, 0, 1}, {20.0, -19.0, 0, 1}, {-21.0, -18.0, 0, 1}, {-20.0, -18.0, 0, 1},
{-19.0, -18.0, 0, 1}, {-18.0, -18.0, 0, 1}, {-17.0, -18.0, 0, 1}, {-16.0, -18.0, 0, 1}, {-15.0, -18.0, 0, 1}, {-14.0, -18.0, 0, 1},
{-13.0, -18.0, 0, 1}, {-12.0, -18.0, 0, 1}, {-11.0, -18.0, 0, 1}, {-10.0, -18.0, 0, 1}, {-9.0, -18.0, 0, 1}, {-8.0, -18.0, 0, 1},
{-7.0, -18.0, 0, 1}, {-6.0, -18.0, 0, 1}, {-5.0, -18.0, 0, 1}, {-4.0, -18.0, 0, 1}, {-3.0, -18.0, 0, 1}, {-2.0, -18.0, 0, 1},
{-1.0, -18.0, 0, 1}, {0.0, -18.0, 0, 1}, {1.0, -18.0, 0, 1}, {2.0, -18.0, 0, 1}, {3.0, -18.0, 0, 1}, {4.0, -18.0, 0, 1},
{5.0, -18.0, 0, 1}, {6.0, -18.0, 0, 1}, {7.0, -18.0, 0, 1}, {8.0, -18.0, 0, 1}, {9.0, -18.0, 0, 1}, {10.0, -18.0, 0, 1},
{11.0, -18.0, 0, 1}, {12.0, -18.0, 0, 1}, {13.0, -18.0, 0, 1}, {14.0, -18.0, 0, 1}, {15.0, -18.0, 0, 1}, {16.0, -18.0, 0, 1},
{17.0, -18.0, 0, 1}, {18.0, -18.0, 0, 1}, {19.0, -18.0, 0, 1}, {20.0, -18.0, 0, 1}, {-21.0, -17.0, 0, 1}, {-20.0, -17.0, 0, 1},
{-19.0, -17.0, 0, 1}, {-18.0, -17.0, 0, 1}, {17.0, -17.0, 0, 1}, {18.0, -17.0, 0, 1}, {19.0, -17.0, 0, 1}, {20.0, -17.0, 0, 1},
{-21.0, -16.0, 0, 1}, {-20.0, -16.0, 0, 1}, {-19.0, -16.0, 0, 1}, {-18.0, -16.0, 0, 1}, {17.0, -16.0, 0, 1}, {18.0, -16.0, 0, 1},
{19.0, -16.0, 0, 1}, {20.0, -16.0, 0, 1}, {-21.0, -15.0, 0, 1}, {-20.0, -15.0, 0, 1}, {-19.0, -15.0, 0, 1}, {-18.0, -15.0, 0, 1},
{17.0, -15.0, 0, 1}, {18.0, -15.0, 0, 1}, {19.0, -15.0, 0, 1}, {20.0, -15.0, 0, 1}, {-21.0, -14.0, 0, 1}, {-20.0, -14.0, 0, 1},
{-19.0, -14.0, 0, 1}, {-18.0, -14.0, 0, 1}, {17.0, -14.0, 0, 1}, {18.0, -14.0, 0, 1}, {19.0, -14.0, 0, 1}, {20.0, -14.0, 0, 1},
{-31.0, -13.0, 0, 1}, {-30.0, -13.0, 0, 1}, {-29.0, -13.0, 0, 1}, {-28.0, -13.0, 0, 1}, {-27.0, -13.0, 0, 1}, {-26.0, -13.0, 0, 1},
{-25.0, -13.0, 0, 1}, {-24.0, -13.0, 0, 1}, {-23.0, -13.0, 0, 1}, {-22.0, -13.0, 0, 1}, {-21.0, -13.0, 0, 1}, {-20.0, -13.0, 0, 1},
{-19.0, -13.0, 0, 1}, {-18.0, -13.0, 0, 1}, {17.0, -13.0, 0, 1}, {18.0, -13.0, 0, 1}, {19.0, -13.0, 0, 1}, {20.0, -13.0, 0, 1},
{21.0, -13.0, 0, 1}, {22.0, -13.0, 0, 1}, {23.0, -13.0, 0, 1}, {24.0, -13.0, 0, 1}, {25.0, -13.0, 0, 1}, {26.0, -13.0, 0, 1},
{27.0, -13.0, 0, 1}, {28.0, -13.0, 0, 1}, {29.0, -13.0, 0, 1}, {30.0, -13.0, 0, 1}, {-32.0, -12.0, 0, 1}, {-31.0, -12.0, 0, 1},
{-30.0, -12.0, 0, 1}, {-29.0, -12.0, 0, 1}, {-28.0, -12.0, 0, 1}, {-27.0, -12.0, 0, 1}, {-26.0, -12.0, 0, 1}, {-25.0, -12.0, 0, 1},
{-24.0, -12.0, 0, 1}, {-23.0, -12.0, 0, 1}, {-22.0, -12.0, 0, 1}, {-21.0, -12.0, 0, 1}, {-20.0, -12.0, 0, 1}, {-19.0, -12.0, 0, 1},
{-18.0, -12.0, 0, 1}, {-12.0, -12.0, 0, 1}, {-11.0, -12.0, 0, 1}, {-10.0, -12.0, 0, 1}, {-9.0, -12.0, 0, 1}, {-8.0, -12.0, 0, 1},
{-7.0, -12.0, 0, 1}, {-6.0, -12.0, 0, 1}, {-5.0, -12.0, 0, 1}, {-4.0, -12.0, 0, 1}, {-3.0, -12.0, 0, 1}, {-2.0, -12.0, 0, 1},
{-1.0, -12.0, 0, 1}, {0.0, -12.0, 0, 1}, {1.0, -12.0, 0, 1}, {2.0, -12.0, 0, 1}, {3.0, -12.0, 0, 1}, {4.0, -12.0, 0, 1},
{5.0, -12.0, 0, 1}, {6.0, -12.0, 0, 1}, {7.0, -12.0, 0, 1}, {8.0, -12.0, 0, 1}, {9.0, -12.0, 0, 1}, {10.0, -12.0, 0, 1},
{11.0, -12.0, 0, 1}, {17.0, -12.0, 0, 1}, {18.0, -12.0, 0, 1}, {19.0, -12.0, 0, 1}, {20.0, -12.0, 0, 1}, {21.0, -12.0, 0, 1},
{22.0, -12.0, 0, 1}, {23.0, -12.0, 0, 1}, {24.0, -12.0, 0, 1}, {25.0, -12.0, 0, 1}, {26.0, -12.0, 0, 1}, {27.0, -12.0, 0, 1},
{28.0, -12.0, 0, 1}, {29.0, -12.0, 0, 1}, {30.0, -12.0, 0, 1}, {31.0, -12.0, 0, 1}, {-32.0, -11.0, 0, 1}, {-31.0, -11.0, 0, 1},
{-30.0, -11.0, 0, 1}, {-29.0, -11.0, 0, 1}, {-28.0, -11.0, 0, 1}, {-27.0, -11.0, 0, 1}, {-26.0, -11.0, 0, 1}, {-25.0, -11.0, 0, 1},
{-24.0, -11.0, 0, 1}, {-23.0, -11.0, 0, 1}, {-22.0, -11.0, 0, 1}, {-21.0, -11.0, 0, 1}, {-20.0, -11.0, 0, 1}, {-19.0, -11.0, 0, 1},
{-18.0, -11.0, 0, 1}, {-12.0, -11.0, 0, 1}, {-11.0, -11.0, 0, 1}, {-10.0, -11.0, 0, 1}, {-9.0, -11.0, 0, 1}, {-8.0, -11.0, 0, 1},
{-7.0, -11.0, 0, 1}, {-6.0, -11.0, 0, 1}, {-5.0, -11.0, 0, 1}, {-4.0, -11.0, 0, 1}, {-3.0, -11.0, 0, 1}, {-2.0, -11.0, 0, 1},
{-1.0, -11.0, 0, 1}, {0.0, -11.0, 0, 1}, {1.0, -11.0, 0, 1}, {2.0, -11.0, 0, 1}, {3.0, -11.0, 0, 1}, {4.0, -11.0, 0, 1},
{5.0, -11.0, 0, 1}, {6.0, -11.0, 0, 1}, {7.0, -11.0, 0, 1}, {8.0, -11.0, 0, 1}, {9.0, -11.0, 0, 1}, {10.0, -11.0, 0, 1},
{11.0, -11.0, 0, 1}, {17.0, -11.0, 0, 1}, {18.0, -11.0, 0, 1}, {19.0, -11.0, 0, 1}, {20.0, -11.0, 0, 1}, {21.0, -11.0, 0, 1},
{22.0, -11.0, 0, 1}, {23.0, -11.0, 0, 1}, {24.0, -11.0, 0, 1}, {25.0, -11.0, 0, 1}, {26.0, -11.0, 0, 1}, {27.0, -11.0, 0, 1},
{28.0, -11.0, 0, 1}, {29.0, -11.0, 0, 1}, {30.0, -11.0, 0, 1}, {31.0, -11.0, 0, 1}, {-32.0, -10.0, 0, 1}, {-31.0, -10.0, 0, 1},
{-30.0, -10.0, 0, 1}, {-29.0, -10.0, 0, 1}, {-28.0, -10.0, 0, 1}, {-27.0, -10.0, 0, 1}, {-26.0, -10.0, 0, 1}, {-25.0, -10.0, 0, 1},
{-24.0, -10.0, 0, 1}, {-23.0, -10.0, 0, 1}, {-22.0, -10.0, 0, 1}, {-21.0, -10.0, 0, 1}, {-20.0, -10.0, 0, 1}, {-19.0, -10.0, 0, 1},
{-18.0, -10.0, 0, 1}, {-12.0, -10.0, 0, 1}, {-11.0, -10.0, 0, 1}, {-10.0, -10.0, 0, 1}, {-9.0, -10.0, 0, 1}, {-8.0, -10.0, 0, 1},
{-7.0, -10.0, 0, 1}, {-6.0, -10.0, 0, 1}, {-5.0, -10.0, 0, 1}, {-4.0, -10.0, 0, 1}, {-3.0, -10.0, 0, 1}, {-2.0, -10.0, 0, 1},
{-1.0, -10.0, 0, 1}, {0.0, -10.0, 0, 1}, {1.0, -10.0, 0, 1}, {2.0, -10.0, 0, 1}, {3.0, -10.0, 0, 1}, {4.0, -10.0, 0, 1},
{5.0, -10.0, 0, 1}, {6.0, -10.0, 0, 1}, {7.0, -10.0, 0, 1}, {8.0, -10.0, 0, 1}, {9.0, -10.0, 0, 1}, {10.0, -10.0, 0, 1},
{11.0, -10.0, 0, 1}, {17.0, -10.0, 0, 1}, {18.0, -10.0, 0, 1}, {19.0, -10.0, 0, 1}, {20.0, -10.0, 0, 1}, {21.0, -10.0, 0, 1},
{22.0, -10.0, 0, 1}, {23.0, -10.0, 0, 1}, {24.0, -10.0, 0, 1}, {25.0, -10.0, 0, 1}, {26.0, -10.0, 0, 1}, {27.0, -10.0, 0, 1},
{28.0, -10.0, 0, 1}, {29.0, -10.0, 0, 1}, {30.0, -10.0, 0, 1}, {31.0, -10.0, 0, 1}, {-21.0, -9.0, 0, 1}, {-20.0, -9.0, 0, 1},
{-19.0, -9.0, 0, 1}, {-18.0, -9.0, 0, 1}, {-12.0, -9.0, 0, 1}, {-11.0, -9.0, 0, 1}, {-10.0, -9.0, 0, 1}, {-9.0, -9.0, 0, 1},
{-8.0, -9.0, 0, 1}, {-7.0, -9.0, 0, 1}, {-6.0, -9.0, 0, 1}, {-5.0, -9.0, 0, 1}, {-4.0, -9.0, 0, 1}, {-3.0, -9.0, 0, 1},
{-2.0, -9.0, 0, 1}, {-1.0, -9.0, 0, 1}, {0.0, -9.0, 0, 1}, {1.0, -9.0, 0, 1}, {2.0, -9.0, 0, 1}, {3.0, -9.0, 0, 1},
{4.0, -9.0, 0, 1}, {5.0, -9.0, 0, 1}, {6.0, -9.0, 0, 1}, {7.0, -9.0, 0, 1}, {8.0, -9.0, 0, 1}, {9.0, -9.0, 0, 1},
{10.0, -9.0, 0, 1}, {11.0, -9.0, 0, 1}, {17.0, -9.0, 0, 1}, {18.0, -9.0, 0, 1}, {19.0, -9.0, 0, 1}, {20.0, -9.0, 0, 1},
{-21.0, -8.0, 0, 1}, {-20.0, -8.0, 0, 1}, {-19.0, -8.0, 0, 1}, {-18.0, -8.0, 0, 1}, {-12.0, -8.0, 0, 1}, {-11.0, -8.0, 0, 1},
{-10.0, -8.0, 0, 1}, {-9.0, -8.0, 0, 1}, {8.0, -8.0, 0, 1}, {9.0, -8.0, 0, 1}, {10.0, -8.0, 0, 1}, {11.0, -8.0, 0, 1},
{17.0, -8.0, 0, 1}, {18.0, -8.0, 0, 1}, {19.0, -8.0, 0, 1}, {20.0, -8.0, 0, 1}, {-21.0, -7.0, 0, 1}, {-20.0, -7.0, 0, 1},
{-19.0, -7.0, 0, 1}, {-18.0, -7.0, 0, 1}, {-12.0, -7.0, 0, 1}, {-11.0, -7.0, 0, 1}, {-10.0, -7.0, 0, 1}, {-9.0, -7.0, 0, 1},
{8.0, -7.0, 0, 1}, {9.0, -7.0, 0, 1}, {10.0, -7.0, 0, 1}, {11.0, -7.0, 0, 1}, {17.0, -7.0, 0, 1}, {18.0, -7.0, 0, 1},
{19.0, -7.0, 0, 1}, {20.0, -7.0, 0, 1}, {-31.0, -6.0, 0, 1}, {-30.0, -6.0, 0, 1}, {-29.0, -6.0, 0, 1}, {-28.0, -6.0, 0, 1},
{-27.0, -6.0, 0, 1}, {-26.0, -6.0, 0, 1}, {-25.0, -6.0, 0, 1}, {-24.0, -6.0, 0, 1}, {-23.0, -6.0, 0, 1}, {-22.0, -6.0, 0, 1},
{-21.0, -6.0, 0, 1}, {-20.0, -6.0, 0, 1}, {-19.0, -6.0, 0, 1}, {-18.0, -6.0, 0, 1}, {-12.0, -6.0, 0, 1}, {-11.0, -6.0, 0, 1},
{-10.0, -6.0, 0, 1}, {-9.0, -6.0, 0, 1}, {8.0, -6.0, 0, 1}, {9.0, -6.0, 0, 1}, {10.0, -6.0, 0, 1}, {11.0, -6.0, 0, 1},
{17.0, -6.0, 0, 1}, {18.0, -6.0, 0, 1}, {19.0, -6.0, 0, 1}, {20.0, -6.0, 0, 1}, {21.0, -6.0, 0, 1}, {22.0, -6.0, 0, 1},
{23.0, -6.0, 0, 1}, {24.0, -6.0, 0, 1}, {25.0, -6.0, 0, 1}, {26.0, -6.0, 0, 1}, {27.0, -6.0, 0, 1}, {28.0, -6.0, 0, 1},
{29.0, -6.0, 0, 1}, {30.0, -6.0, 0, 1}, {-32.0, -5.0, 0, 1}, {-31.0, -5.0, 0, 1}, {-30.0, -5.0, 0, 1}, {-29.0, -5.0, 0, 1},
{-28.0, -5.0, 0, 1}, {-27.0, -5.0, 0, 1}, {-26.0, -5.0, 0, 1}, {-25.0, -5.0, 0, 1}, {-24.0, -5.0, 0, 1}, {-23.0, -5.0, 0, 1},
{-22.0, -5.0, 0, 1}, {-21.0, -5.0, 0, 1}, {-20.0, -5.0, 0, 1}, {-19.0, -5.0, 0, 1}, {-18.0, -5.0, 0, 1}, {-12.0, -5.0, 0, 1},
{-11.0, -5.0, 0, 1}, {-10.0, -5.0, 0, 1}, {-9.0, -5.0, 0, 1}, {8.0, -5.0, 0, 1}, {9.0, -5.0, 0, 1}, {10.0, -5.0, 0, 1},
{11.0, -5.0, 0, 1}, {17.0, -5.0, 0, 1}, {18.0, -5.0, 0, 1}, {19.0, -5.0, 0, 1}, {20.0, -5.0, 0, 1}, {21.0, -5.0, 0, 1},
{22.0, -5.0, 0, 1}, {23.0, -5.0, 0, 1}, {24.0, -5.0, 0, 1}, {25.0, -5.0, 0, 1}, {26.0, -5.0, 0, 1}, {27.0, -5.0, 0, 1},
{28.0, -5.0, 0, 1}, {29.0, -5.0, 0, 1}, {30.0, -5.0, 0, 1}, {31.0, -5.0, 0, 1}, {-32.0, -4.0, 0, 1}, {-31.0, -4.0, 0, 1},
{-30.0, -4.0, 0, 1}, {-29.0, -4.0, 0, 1}, {-28.0, -4.0, 0, 1}, {-27.0, -4.0, 0, 1}, {-26.0, -4.0, 0, 1}, {-25.0, -4.0, 0, 1},
{-24.0, -4.0, 0, 1}, {-23.0, -4.0, 0, 1}, {-22.0, -4.0, 0, 1}, {-21.0, -4.0, 0, 1}, {-20.0, -4.0, 0, 1}, {-19.0, -4.0, 0, 1},
{-18.0, -4.0, 0, 1}, {-12.0, -4.0, 0, 1}, {-11.0, -4.0, 0, 1}, {-10.0, -4.0, 0, 1}, {-9.0, -4.0, 0, 1}, {8.0, -4.0, 0, 1},
{9.0, -4.0, 0, 1}, {10.0, -4.0, 0, 1}, {11.0, -4.0, 0, 1}, {17.0, -4.0, 0, 1}, {18.0, -4.0, 0, 1}, {19.0, -4.0, 0, 1},
{20.0, -4.0, 0, 1}, {21.0, -4.0, 0, 1}, {22.0, -4.0, 0, 1}, {23.0, -4.0, 0, 1}, {24.0, -4.0, 0, 1}, {25.0, -4.0, 0, 1},
{26.0, -4.0, 0, 1}, {27.0, -4.0, 0, 1}, {28.0, -4.0, 0, 1}, {29.0, -4.0, 0, 1}, {30.0, -4.0, 0, 1}, {31.0, -4.0, 0, 1},
{-32.0, -3.0, 0, 1}, {-31.0, -3.0, 0, 1}, {-30.0, -3.0, 0, 1}, {-29.0, -3.0, 0, 1}, {-28.0, -3.0, 0, 1}, {-27.0, -3.0, 0, 1},
{-26.0, -3.0, 0, 1}, {-25.0, -3.0, 0, 1}, {-24.0, -3.0, 0, 1}, {-23.0, -3.0, 0, 1}, {-22.0, -3.0, 0, 1}, {-21.0, -3.0, 0, 1},
{-20.0, -3.0, 0, 1}, {-19.0, -3.0, 0, 1}, {-18.0, -3.0, 0, 1}, {-12.0, -3.0, 0, 1}, {-11.0, -3.0, 0, 1}, {-10.0, -3.0, 0, 1},
{-9.0, -3.0, 0, 1}, {8.0, -3.0, 0, 1}, {9.0, -3.0, 0, 1}, {10.0, -3.0, 0, 1}, {11.0, -3.0, 0, 1}, {17.0, -3.0, 0, 1},
{18.0, -3.0, 0, 1}, {19.0, -3.0, 0, 1}, {20.0, -3.0, 0, 1}, {21.0, -3.0, 0, 1}, {22.0, -3.0, 0, 1}, {23.0, -3.0, 0, 1},
{24.0, -3.0, 0, 1}, {25.0, -3.0, 0, 1}, {26.0, -3.0, 0, 1}, {27.0, -3.0, 0, 1}, {28.0, -3.0, 0, 1}, {29.0, -3.0, 0, 1},
{30.0, -3.0, 0, 1}, {31.0, -3.0, 0, 1}, {-31.0, -2.0, 0, 1}, {-30.0, -2.0, 0, 1}, {-29.0, -2.0, 0, 1}, {-28.0, -2.0, 0, 1},
{-27.0, -2.0, 0, 1}, {-26.0, -2.0, 0, 1}, {-25.0, -2.0, 0, 1}, {-24.0, -2.0, 0, 1}, {-23.0, -2.0, 0, 1}, {-22.0, -2.0, 0, 1},
{-21.0, -2.0, 0, 1}, {-20.0, -2.0, 0, 1}, {-19.0, -2.0, 0, 1}, {-18.0, -2.0, 0, 1}, {-12.0, -2.0, 0, 1}, {-11.0, -2.0, 0, 1},
{-10.0, -2.0, 0, 1}, {-9.0, -2.0, 0, 1}, {8.0, -2.0, 0, 1}, {9.0, -2.0, 0, 1}, {10.0, -2.0, 0, 1}, {11.0, -2.0, 0, 1},
{17.0, -2.0, 0, 1}, {18.0, -2.0, 0, 1}, {19.0, -2.0, 0, 1}, {20.0, -2.0, 0, 1}, {21.0, -2.0, 0, 1}, {22.0, -2.0, 0, 1},
{23.0, -2.0, 0, 1}, {24.0, -2.0, 0, 1}, {25.0, -2.0, 0, 1}, {26.0, -2.0, 0, 1}, {27.0, -2.0, 0, 1}, {28.0, -2.0, 0, 1},
{29.0, -2.0, 0, 1}, {-21.0, -1.0, 0, 1}, {-20.0, -1.0, 0, 1}, {-19.0, -1.0, 0, 1}, {-18.0, -1.0, 0, 1}, {-12.0, -1.0, 0, 1},
{-11.0, -1.0, 0, 1}, {-10.0, -1.0, 0, 1}, {-9.0, -1.0, 0, 1}, {8.0, -1.0, 0, 1}, {9.0, -1.0, 0, 1}, {10.0, -1.0, 0, 1},
{11.0, -1.0, 0, 1}, {17.0, -1.0, 0, 1}, {18.0, -1.0, 0, 1}, {19.0, -1.0, 0, 1}, {20.0, -1.0, 0, 1}, {-21.0, 0.0, 0, 1},
{-20.0, 0.0, 0, 1}, {-19.0, 0.0, 0, 1}, {-18.0, 0.0, 0, 1}, {-12.0, 0.0, 0, 1}, {-11.0, 0.0, 0, 1}, {-10.0, 0.0, 0, 1},
{-9.0, 0.0, 0, 1}, {8.0, 0.0, 0, 1}, {9.0, 0.0, 0, 1}, {10.0, 0.0, 0, 1}, {11.0, 0.0, 0, 1}, {17.0, 0.0, 0, 1},
{18.0, 0.0, 0, 1}, {19.0, 0.0, 0, 1}, {20.0, 0.0, 0, 1}, {-31.0, 1.0, 0, 1}, {-30.0, 1.0, 0, 1}, {-29.0, 1.0, 0, 1},
{-28.0, 1.0, 0, 1}, {-27.0, 1.0, 0, 1}, {-26.0, 1.0, 0, 1}, {-25.0, 1.0, 0, 1}, {-24.0, 1.0, 0, 1}, {-23.0, 1.0, 0, 1},
{-22.0, 1.0, 0, 1}, {-21.0, 1.0, 0, 1}, {-20.0, 1.0, 0, 1}, {-19.0, 1.0, 0, 1}, {-18.0, 1.0, 0, 1}, {-12.0, 1.0, 0, 1},
{-11.0, 1.0, 0, 1}, {-10.0, 1.0, 0, 1}, {-9.0, 1.0, 0, 1}, {8.0, 1.0, 0, 1}, {9.0, 1.0, 0, 1}, {10.0, 1.0, 0, 1},
{11.0, 1.0, 0, 1}, {17.0, 1.0, 0, 1}, {18.0, 1.0, 0, 1}, {19.0, 1.0, 0, 1}, {20.0, 1.0, 0, 1}, {21.0, 1.0, 0, 1},
{22.0, 1.0, 0, 1}, {23.0, 1.0, 0, 1}, {24.0, 1.0, 0, 1}, {25.0, 1.0, 0, 1}, {26.0, 1.0, 0, 1}, {27.0, 1.0, 0, 1},
{28.0, 1.0, 0, 1}, {29.0, 1.0, 0, 1}, {30.0, 1.0, 0, 1}, {-32.0, 2.0, 0, 1}, {-31.0, 2.0, 0, 1}, {-30.0, 2.0, 0, 1},
{-29.0, 2.0, 0, 1}, {-28.0, 2.0, 0, 1}, {-27.0, 2.0, 0, 1}, {-26.0, 2.0, 0, 1}, {-25.0, 2.0, 0, 1}, {-24.0, 2.0, 0, 1},
{-23.0, 2.0, 0, 1}, {-22.0, 2.0, 0, 1}, {-21.0, 2.0, 0, 1}, {-20.0, 2.0, 0, 1}, {-19.0, 2.0, 0, 1}, {-18.0, 2.0, 0, 1},
{-12.0, 2.0, 0, 1}, {-11.0, 2.0, 0, 1}, {-10.0, 2.0, 0, 1}, {-9.0, 2.0, 0, 1}, {8.0, 2.0, 0, 1}, {9.0, 2.0, 0, 1},
{10.0, 2.0, 0, 1}, {11.0, 2.0, 0, 1}, {17.0, 2.0, 0, 1}, {18.0, 2.0, 0, 1}, {19.0, 2.0, 0, 1}, {20.0, 2.0, 0, 1},
{21.0, 2.0, 0, 1}, {22.0, 2.0, 0, 1}, {23.0, 2.0, 0, 1}, {24.0, 2.0, 0, 1}, {25.0, 2.0, 0, 1}, {26.0, 2.0, 0, 1},
{27.0, 2.0, 0, 1}, {28.0, 2.0, 0, 1}, {29.0, 2.0, 0, 1}, {30.0, 2.0, 0, 1}, {31.0, 2.0, 0, 1}, {-32.0, 3.0, 0, 1},
{-31.0, 3.0, 0, 1}, {-30.0, 3.0, 0, 1}, {-29.0, 3.0, 0, 1}, {-28.0, 3.0, 0, 1}, {-27.0, 3.0, 0, 1}, {-26.0, 3.0, 0, 1},
{-25.0, 3.0, 0, 1}, {-24.0, 3.0, 0, 1}, {-23.0, 3.0, 0, 1}, {-22.0, 3.0, 0, 1}, {-21.0, 3.0, 0, 1}, {-20.0, 3.0, 0, 1},
{-19.0, 3.0, 0, 1}, {-18.0, 3.0, 0, 1}, {-12.0, 3.0, 0, 1}, {-11.0, 3.0, 0, 1}, {-10.0, 3.0, 0, 1}, {-9.0, 3.0, 0, 1},
{8.0, 3.0, 0, 1}, {9.0, 3.0, 0, 1}, {10.0, 3.0, 0, 1}, {11.0, 3.0, 0, 1}, {17.0, 3.0, 0, 1}, {18.0, 3.0, 0, 1},
{19.0, 3.0, 0, 1}, {20.0, 3.0, 0, 1}, {21.0, 3.0, 0, 1}, {22.0, 3.0, 0, 1}, {23.0, 3.0, 0, 1}, {24.0, 3.0, 0, 1},
{25.0, 3.0, 0, 1}, {26.0, 3.0, 0, 1}, {27.0, 3.0, 0, 1}, {28.0, 3.0, 0, 1}, {29.0, 3.0, 0, 1}, {30.0, 3.0, 0, 1},
{31.0, 3.0, 0, 1}, {-32.0, 4.0, 0, 1}, {-31.0, 4.0, 0, 1}, {-30.0, 4.0, 0, 1}, {-29.0, 4.0, 0, 1}, {-28.0, 4.0, 0, 1},
{-27.0, 4.0, 0, 1}, {-26.0, 4.0, 0, 1}, {-25.0, 4.0, 0, 1}, {-24.0, 4.0, 0, 1}, {-23.0, 4.0, 0, 1}, {-22.0, 4.0, 0, 1},
{-21.0, 4.0, 0, 1}, {-20.0, 4.0, 0, 1}, {-19.0, 4.0, 0, 1}, {-18.0, 4.0, 0, 1}, {-12.0, 4.0, 0, 1}, {-11.0, 4.0, 0, 1},
{-10.0, 4.0, 0, 1}, {-9.0, 4.0, 0, 1}, {8.0, 4.0, 0, 1}, {9.0, 4.0, 0, 1}, {10.0, 4.0, 0, 1}, {11.0, 4.0, 0, 1},
{17.0, 4.0, 0, 1}, {18.0, 4.0, 0, 1}, {19.0, 4.0, 0, 1}, {20.0, 4.0, 0, 1}, {21.0, 4.0, 0, 1}, {22.0, 4.0, 0, 1},
{23.0, 4.0, 0, 1}, {24.0, 4.0, 0, 1}, {25.0, 4.0, 0, 1}, {26.0, 4.0, 0, 1}, {27.0, 4.0, 0, 1}, {28.0, 4.0, 0, 1},
{29.0, 4.0, 0, 1}, {30.0, 4.0, 0, 1}, {31.0, 4.0, 0, 1}, {-31.0, 5.0, 0, 1}, {-30.0, 5.0, 0, 1}, {-29.0, 5.0, 0, 1},
{-28.0, 5.0, 0, 1}, {-27.0, 5.0, 0, 1}, {-26.0, 5.0, 0, 1}, {-25.0, 5.0, 0, 1}, {-24.0, 5.0, 0, 1}, {-23.0, 5.0, 0, 1},
{-22.0, 5.0, 0, 1}, {-21.0, 5.0, 0, 1}, {-20.0, 5.0, 0, 1}, {-19.0, 5.0, 0, 1}, {-18.0, 5.0, 0, 1}, {-12.0, 5.0, 0, 1},
{-11.0, 5.0, 0, 1}, {-10.0, 5.0, 0, 1}, {-9.0, 5.0, 0, 1}, {8.0, 5.0, 0, 1}, {9.0, 5.0, 0, 1}, {10.0, 5.0, 0, 1},
{11.0, 5.0, 0, 1}, {17.0, 5.0, 0, 1}, {18.0, 5.0, 0, 1}, {19.0, 5.0, 0, 1}, {20.0, 5.0, 0, 1}, {21.0, 5.0, 0, 1},
{22.0, 5.0, 0, 1}, {23.0, 5.0, 0, 1}, {24.0, 5.0, 0, 1}, {25.0, 5.0, 0, 1}, {26.0, 5.0, 0, 1}, {27.0, 5.0, 0, 1},
{28.0, 5.0, 0, 1}, {29.0, 5.0, 0, 1}, {30.0, 5.0, 0, 1}, {-21.0, 6.0, 0, 1}, {-20.0, 6.0, 0, 1}, {-19.0, 6.0, 0, 1},
{-18.0, 6.0, 0, 1}, {-12.0, 6.0, 0, 1}, {-11.0, 6.0, 0, 1}, {-10.0, 6.0, 0, 1}, {-9.0, 6.0, 0, 1}, {8.0, 6.0, 0, 1},
{9.0, 6.0, 0, 1}, {10.0, 6.0, 0, 1}, {11.0, 6.0, 0, 1}, {17.0, 6.0, 0, 1}, {18.0, 6.0, 0, 1}, {19.0, 6.0, 0, 1},
{20.0, 6.0, 0, 1}, {-21.0, 7.0, 0, 1}, {-20.0, 7.0, 0, 1}, {-19.0, 7.0, 0, 1}, {-18.0, 7.0, 0, 1}, {-12.0, 7.0, 0, 1},
{-11.0, 7.0, 0, 1}, {-10.0, 7.0, 0, 1}, {-9.0, 7.0, 0, 1}, {8.0, 7.0, 0, 1}, {9.0, 7.0, 0, 1}, {10.0, 7.0, 0, 1},
{11.0, 7.0, 0, 1}, {17.0, 7.0, 0, 1}, {18.0, 7.0, 0, 1}, {19.0, 7.0, 0, 1}, {20.0, 7.0, 0, 1}, {-31.0, 8.0, 0, 1},
{-30.0, 8.0, 0, 1}, {-29.0, 8.0, 0, 1}, {-28.0, 8.0, 0, 1}, {-27.0, 8.0, 0, 1}, {-26.0, 8.0, 0, 1}, {-25.0, 8.0, 0, 1},
{-24.0, 8.0, 0, 1}, {-23.0, 8.0, 0, 1}, {-22.0, 8.0, 0, 1}, {-21.0, 8.0, 0, 1}, {-20.0, 8.0, 0, 1}, {-19.0, 8.0, 0, 1},
{-18.0, 8.0, 0, 1}, {-12.0, 8.0, 0, 1}, {-11.0, 8.0, 0, 1}, {-10.0, 8.0, 0, 1}, {-9.0, 8.0, 0, 1}, {-8.0, 8.0, 0, 1},
{-7.0, 8.0, 0, 1}, {-6.0, 8.0, 0, 1}, {-5.0, 8.0, 0, 1}, {-4.0, 8.0, 0, 1}, {-3.0, 8.0, 0, 1}, {-2.0, 8.0, 0, 1},
{-1.0, 8.0, 0, 1}, {0.0, 8.0, 0, 1}, {1.0, 8.0, 0, 1}, {2.0, 8.0, 0, 1}, {3.0, 8.0, 0, 1}, {4.0, 8.0, 0, 1},
{5.0, 8.0, 0, 1}, {6.0, 8.0, 0, 1}, {7.0, 8.0, 0, 1}, {8.0, 8.0, 0, 1}, {9.0, 8.0, 0, 1}, {10.0, 8.0, 0, 1},
{11.0, 8.0, 0, 1}, {17.0, 8.0, 0, 1}, {18.0, 8.0, 0, 1}, {19.0, 8.0, 0, 1}, {20.0, 8.0, 0, 1}, {21.0, 8.0, 0, 1},
{22.0, 8.0, 0, 1}, {23.0, 8.0, 0, 1}, {24.0, 8.0, 0, 1}, {25.0, 8.0, 0, 1}, {26.0, 8.0, 0, 1}, {27.0, 8.0, 0, 1},
{28.0, 8.0, 0, 1}, {29.0, 8.0, 0, 1}, {-32.0, 9.0, 0, 1}, {-31.0, 9.0, 0, 1}, {-30.0, 9.0, 0, 1}, {-29.0, 9.0, 0, 1},
{-28.0, 9.0, 0, 1}, {-27.0, 9.0, 0, 1}, {-26.0, 9.0, 0, 1}, {-25.0, 9.0, 0, 1}, {-24.0, 9.0, 0, 1}, {-23.0, 9.0, 0, 1},
{-22.0, 9.0, 0, 1}, {-21.0, 9.0, 0, 1}, {-20.0, 9.0, 0, 1}, {-19.0, 9.0, 0, 1}, {-18.0, 9.0, 0, 1}, {-12.0, 9.0, 0, 1},
{-11.0, 9.0, 0, 1}, {-10.0, 9.0, 0, 1}, {-9.0, 9.0, 0, 1}, {-8.0, 9.0, 0, 1}, {-7.0, 9.0, 0, 1}, {-6.0, 9.0, 0, 1},
{-5.0, 9.0, 0, 1}, {-4.0, 9.0, 0, 1}, {-3.0, 9.0, 0, 1}, {-2.0, 9.0, 0, 1}, {-1.0, 9.0, 0, 1}, {0.0, 9.0, 0, 1},
{1.0, 9.0, 0, 1}, {2.0, 9.0, 0, 1}, {3.0, 9.0, 0, 1}, {4.0, 9.0, 0, 1}, {5.0, 9.0, 0, 1}, {6.0, 9.0, 0, 1},
{7.0, 9.0, 0, 1}, {8.0, 9.0, 0, 1}, {9.0, 9.0, 0, 1}, {10.0, 9.0, 0, 1}, {11.0, 9.0, 0, 1}, {17.0, 9.0, 0, 1},
{18.0, 9.0, 0, 1}, {19.0, 9.0, 0, 1}, {20.0, 9.0, 0, 1}, {21.0, 9.0, 0, 1}, {22.0, 9.0, 0, 1}, {23.0, 9.0, 0, 1},
{24.0, 9.0, 0, 1}, {25.0, 9.0, 0, 1}, {26.0, 9.0, 0, 1}, {27.0, 9.0, 0, 1}, {28.0, 9.0, 0, 1}, {29.0, 9.0, 0, 1},
{30.0, 9.0, 0, 1}, {31.0, 9.0, 0, 1}, {-32.0, 10.0, 0, 1}, {-31.0, 10.0, 0, 1}, {-30.0, 10.0, 0, 1}, {-29.0, 10.0, 0, 1},
{-28.0, 10.0, 0, 1}, {-27.0, 10.0, 0, 1}, {-26.0, 10.0, 0, 1}, {-25.0, 10.0, 0, 1}, {-24.0, 10.0, 0, 1}, {-23.0, 10.0, 0, 1},
{-22.0, 10.0, 0, 1}, {-21.0, 10.0, 0, 1}, {-20.0, 10.0, 0, 1}, {-19.0, 10.0, 0, 1}, {-18.0, 10.0, 0, 1}, {-12.0, 10.0, 0, 1},
{-11.0, 10.0, 0, 1}, {-10.0, 10.0, 0, 1}, {-9.0, 10.0, 0, 1}, {-8.0, 10.0, 0, 1}, {-7.0, 10.0, 0, 1}, {-6.0, 10.0, 0, 1},
{-5.0, 10.0, 0, 1}, {-4.0, 10.0, 0, 1}, {-3.0, 10.0, 0, 1}, {-2.0, 10.0, 0, 1}, {-1.0, 10.0, 0, 1}, {0.0, 10.0, 0, 1},
{1.0, 10.0, 0, 1}, {2.0, 10.0, 0, 1}, {3.0, 10.0, 0, 1}, {4.0, 10.0, 0, 1}, {5.0, 10.0, 0, 1}, {6.0, 10.0, 0, 1},
{7.0, 10.0, 0, 1}, {8.0, 10.0, 0, 1}, {9.0, 10.0, 0, 1}, {10.0, 10.0, 0, 1}, {11.0, 10.0, 0, 1}, {17.0, 10.0, 0, 1},
{18.0, 10.0, 0, 1}, {19.0, 10.0, 0, 1}, {20.0, 10.0, 0, 1}, {21.0, 10.0, 0, 1}, {22.0, 10.0, 0, 1}, {23.0, 10.0, 0, 1},
{24.0, 10.0, 0, 1}, {25.0, 10.0, 0, 1}, {26.0, 10.0, 0, 1}, {27.0, 10.0, 0, 1}, {28.0, 10.0, 0, 1}, {29.0, 10.0, 0, 1},
{30.0, 10.0, 0, 1}, {31.0, 10.0, 0, 1}, {-32.0, 11.0, 0, 1}, {-31.0, 11.0, 0, 1}, {-30.0, 11.0, 0, 1}, {-29.0, 11.0, 0, 1},
{-28.0, 11.0, 0, 1}, {-27.0, 11.0, 0, 1}, {-26.0, 11.0, 0, 1}, {-25.0, 11.0, 0, 1}, {-24.0, 11.0, 0, 1}, {-23.0, 11.0, 0, 1},
{-22.0, 11.0, 0, 1}, {-21.0, 11.0, 0, 1}, {-20.0, 11.0, 0, 1}, {-19.0, 11.0, 0, 1}, {-18.0, 11.0, 0, 1}, {-12.0, 11.0, 0, 1},
{-11.0, 11.0, 0, 1}, {-10.0, 11.0, 0, 1}, {-9.0, 11.0, 0, 1}, {-8.0, 11.0, 0, 1}, {-7.0, 11.0, 0, 1}, {-6.0, 11.0, 0, 1},
{-5.0, 11.0, 0, 1}, {-4.0, 11.0, 0, 1}, {-3.0, 11.0, 0, 1}, {-2.0, 11.0, 0, 1}, {-1.0, 11.0, 0, 1}, {0.0, 11.0, 0, 1},
{1.0, 11.0, 0, 1}, {2.0, 11.0, 0, 1}, {3.0, 11.0, 0, 1}, {4.0, 11.0, 0, 1}, {5.0, 11.0, 0, 1}, {6.0, 11.0, 0, 1},
{7.0, 11.0, 0, 1}, {8.0, 11.0, 0, 1}, {9.0, 11.0, 0, 1}, {10.0, 11.0, 0, 1}, {11.0, 11.0, 0, 1}, {17.0, 11.0, 0, 1},
{18.0, 11.0, 0, 1}, {19.0, 11.0, 0, 1}, {20.0, 11.0, 0, 1}, {21.0, 11.0, 0, 1}, {22.0, 11.0, 0, 1}, {23.0, 11.0, 0, 1},
{24.0, 11.0, 0, 1}, {25.0, 11.0, 0, 1}, {26.0, 11.0, 0, 1}, {27.0, 11.0, 0, 1}, {28.0, 11.0, 0, 1}, {29.0, 11.0, 0, 1},
{30.0, 11.0, 0, 1}, {31.0, 11.0, 0, 1}, {-31.0, 12.0, 0, 1}, {-30.0, 12.0, 0, 1}, {-29.0, 12.0, 0, 1}, {-28.0, 12.0, 0, 1},
{-27.0, 12.0, 0, 1}, {-26.0, 12.0, 0, 1}, {-25.0, 12.0, 0, 1}, {-24.0, 12.0, 0, 1}, {-23.0, 12.0, 0, 1}, {-22.0, 12.0, 0, 1},
{-21.0, 12.0, 0, 1}, {-20.0, 12.0, 0, 1}, {-19.0, 12.0, 0, 1}, {-18.0, 12.0, 0, 1}, {17.0, 12.0, 0, 1}, {18.0, 12.0, 0, 1},
{19.0, 12.0, 0, 1}, {20.0, 12.0, 0, 1}, {21.0, 12.0, 0, 1}, {22.0, 12.0, 0, 1}, {23.0, 12.0, 0, 1}, {24.0, 12.0, 0, 1},
{25.0, 12.0, 0, 1}, {26.0, 12.0, 0, 1}, {27.0, 12.0, 0, 1}, {28.0, 12.0, 0, 1}, {29.0, 12.0, 0, 1}, {30.0, 12.0, 0, 1},
{-21.0, 13.0, 0, 1}, {-20.0, 13.0, 0, 1}, {-19.0, 13.0, 0, 1}, {-18.0, 13.0, 0, 1}, {17.0, 13.0, 0, 1}, {18.0, 13.0, 0, 1},
{19.0, 13.0, 0, 1}, {20.0, 13.0, 0, 1}, {-21.0, 14.0, 0, 1}, {-20.0, 14.0, 0, 1}, {-19.0, 14.0, 0, 1}, {-18.0, 14.0, 0, 1},
{17.0, 14.0, 0, 1}, {18.0, 14.0, 0, 1}, {19.0, 14.0, 0, 1}, {20.0, 14.0, 0, 1}, {-21.0, 15.0, 0, 1}, {-20.0, 15.0, 0, 1},
{-19.0, 15.0, 0, 1}, {-18.0, 15.0, 0, 1}, {17.0, 15.0, 0, 1}, {18.0, 15.0, 0, 1}, {19.0, 15.0, 0, 1}, {20.0, 15.0, 0, 1},
{-21.0, 16.0, 0, 1}, {-20.0, 16.0, 0, 1}, {-19.0, 16.0, 0, 1}, {-18.0, 16.0, 0, 1}, {17.0, 16.0, 0, 1}, {18.0, 16.0, 0, 1},
{19.0, 16.0, 0, 1}, {20.0, 16.0, 0, 1}, {-21.0, 17.0, 0, 1}, {-20.0, 17.0, 0, 1}, {-19.0, 17.0, 0, 1}, {-18.0, 17.0, 0, 1},
{-17.0, 17.0, 0, 1}, {-16.0, 17.0, 0, 1}, {-15.0, 17.0, 0, 1}, {-14.0, 17.0, 0, 1}, {-13.0, 17.0, 0, 1}, {-12.0, 17.0, 0, 1},
{-11.0, 17.0, 0, 1}, {-10.0, 17.0, 0, 1}, {-9.0, 17.0, 0, 1}, {-8.0, 17.0, 0, 1}, {-7.0, 17.0, 0, 1}, {-6.0, 17.0, 0, 1},
{-5.0, 17.0, 0, 1}, {-4.0, 17.0, 0, 1}, {-3.0, 17.0, 0, 1}, {-2.0, 17.0, 0, 1}, {-1.0, 17.0, 0, 1}, {0.0, 17.0, 0, 1},
{1.0, 17.0, 0, 1}, {2.0, 17.0, 0, 1}, {3.0, 17.0, 0, 1}, {4.0, 17.0, 0, 1}, {5.0, 17.0, 0, 1}, {6.0, 17.0, 0, 1},
{7.0, 17.0, 0, 1}, {8.0, 17.0, 0, 1}, {9.0, 17.0, 0, 1}, {10.0, 17.0, 0, 1}, {11.0, 17.0, 0, 1}, {12.0, 17.0, 0, 1},
{13.0, 17.0, 0, 1}, {14.0, 17.0, 0, 1}, {15.0, 17.0, 0, 1}, {16.0, 17.0, 0, 1}, {17.0, 17.0, 0, 1}, {18.0, 17.0, 0, 1},
{19.0, 17.0, 0, 1}, {20.0, 17.0, 0, 1}, {-21.0, 18.0, 0, 1}, {-20.0, 18.0, 0, 1}, {-19.0, 18.0, 0, 1}, {-18.0, 18.0, 0, 1},
{-17.0, 18.0, 0, 1}, {-16.0, 18.0, 0, 1}, {-15.0, 18.0, 0, 1}, {-14.0, 18.0, 0, 1}, {-13.0, 18.0, 0, 1}, {-12.0, 18.0, 0, 1},
{-11.0, 18.0, 0, 1}, {-10.0, 18.0, 0, 1}, {-9.0, 18.0, 0, 1}, {-8.0, 18.0, 0, 1}, {-7.0, 18.0, 0, 1}, {-6.0, 18.0, 0, 1},
{-5.0, 18.0, 0, 1}, {-4.0, 18.0, 0, 1}, {-3.0, 18.0, 0, 1}, {-2.0, 18.0, 0, 1}, {-1.0, 18.0, 0, 1}, {0.0, 18.0, 0, 1},
{1.0, 18.0, 0, 1}, {2.0, 18.0, 0, 1}, {3.0, 18.0, 0, 1}, {4.0, 18.0, 0, 1}, {5.0, 18.0, 0, 1}, {6.0, 18.0, 0, 1},
{7.0, 18.0, 0, 1}, {8.0, 18.0, 0, 1}, {9.0, 18.0, 0, 1}, {10.0, 18.0, 0, 1}, {11.0, 18.0, 0, 1}, {12.0, 18.0, 0, 1},
{13.0, 18.0, 0, 1}, {14.0, 18.0, 0, 1}, {15.0, 18.0, 0, 1}, {16.0, 18.0, 0, 1}, {17.0, 18.0, 0, 1}, {18.0, 18.0, 0, 1},
{19.0, 18.0, 0, 1}, {20.0, 18.0, 0, 1}, {-21.0, 19.0, 0, 1}, {-20.0, 19.0, 0, 1}, {-19.0, 19.0, 0, 1}, {-18.0, 19.0, 0, 1},
{-17.0, 19.0, 0, 1}, {-16.0, 19.0, 0, 1}, {-15.0, 19.0, 0, 1}, {-14.0, 19.0, 0, 1}, {-13.0, 19.0, 0, 1}, {-12.0, 19.0, 0, 1},
{-11.0, 19.0, 0, 1}, {-10.0, 19.0, 0, 1}, {-9.0, 19.0, 0, 1}, {-8.0, 19.0, 0, 1}, {-7.0, 19.0, 0, 1}, {-6.0, 19.0, 0, 1},
{-5.0, 19.0, 0, 1}, {-4.0, 19.0, 0, 1}, {-3.0, 19.0, 0, 1}, {-2.0, 19.0, 0, 1}, {-1.0, 19.0, 0, 1}, {0.0, 19.0, 0, 1},
{1.0, 19.0, 0, 1}, {2.0, 19.0, 0, 1}, {3.0, 19.0, 0, 1}, {4.0, 19.0, 0, 1}, {5.0, 19.0, 0, 1}, {6.0, 19.0, 0, 1},
{7.0, 19.0, 0, 1}, {8.0, 19.0, 0, 1}, {9.0, 19.0, 0, 1}, {10.0, 19.0, 0, 1}, {11.0, 19.0, 0, 1}, {12.0, 19.0, 0, 1},
{13.0, 19.0, 0, 1}, {14.0, 19.0, 0, 1}, {15.0, 19.0, 0, 1}, {16.0, 19.0, 0, 1}, {17.0, 19.0, 0, 1}, {18.0, 19.0, 0, 1},
{19.0, 19.0, 0, 1}, {20.0, 19.0, 0, 1}, {-21.0, 20.0, 0, 1}, {-20.0, 20.0, 0, 1}, {-19.0, 20.0, 0, 1}, {-18.0, 20.0, 0, 1},
{-17.0, 20.0, 0, 1}, {-16.0, 20.0, 0, 1}, {-15.0, 20.0, 0, 1}, {-14.0, 20.0, 0, 1}, {-13.0, 20.0, 0, 1}, {-12.0, 20.0, 0, 1},
{-11.0, 20.0, 0, 1}, {-10.0, 20.0, 0, 1}, {-9.0, 20.0, 0, 1}, {-8.0, 20.0, 0, 1}, {-7.0, 20.0, 0, 1}, {-6.0, 20.0, 0, 1},
{-5.0, 20.0, 0, 1}, {-4.0, 20.0, 0, 1}, {-3.0, 20.0, 0, 1}, {-2.0, 20.0, 0, 1}, {-1.0, 20.0, 0, 1}, {0.0, 20.0, 0, 1},
{1.0, 20.0, 0, 1}, {2.0, 20.0, 0, 1}, {3.0, 20.0, 0, 1}, {4.0, 20.0, 0, 1}, {5.0, 20.0, 0, 1}, {6.0, 20.0, 0, 1},
{7.0, 20.0, 0, 1}, {8.0, 20.0, 0, 1}, {9.0, 20.0, 0, 1}, {10.0, 20.0, 0, 1}, {11.0, 20.0, 0, 1}, {12.0, 20.0, 0, 1},
{13.0, 20.0, 0, 1}, {14.0, 20.0, 0, 1}, {15.0, 20.0, 0, 1}, {16.0, 20.0, 0, 1}, {17.0, 20.0, 0, 1}, {18.0, 20.0, 0, 1},
{19.0, 20.0, 0, 1}, {20.0, 20.0, 0, 1}, {-13.0, 21.0, 0, 1}, {-12.0, 21.0, 0, 1}, {-11.0, 21.0, 0, 1}, {-10.0, 21.0, 0, 1},
{-6.0, 21.0, 0, 1}, {-5.0, 21.0, 0, 1}, {-4.0, 21.0, 0, 1}, {-3.0, 21.0, 0, 1}, {-2.0, 21.0, 0, 1}, {1.0, 21.0, 0, 1},
{2.0, 21.0, 0, 1}, {3.0, 21.0, 0, 1}, {4.0, 21.0, 0, 1}, {5.0, 21.0, 0, 1}, {8.0, 21.0, 0, 1}, {9.0, 21.0, 0, 1},
{10.0, 21.0, 0, 1}, {11.0, 21.0, 0, 1}, {12.0, 21.0, 0, 1}, {-13.0, 22.0, 0, 1}, {-12.0, 22.0, 0, 1}, {-11.0, 22.0, 0, 1},
{-10.0, 22.0, 0, 1}, {-6.0, 22.0, 0, 1}, {-5.0, 22.0, 0, 1}, {-4.0, 22.0, 0, 1}, {-3.0, 22.0, 0, 1}, {-2.0, 22.0, 0, 1},
{1.0, 22.0, 0, 1}, {2.0, 22.0, 0, 1}, {3.0, 22.0, 0, 1}, {4.0, 22.0, 0, 1}, {5.0, 22.0, 0, 1}, {8.0, 22.0, 0, 1},
{9.0, 22.0, 0, 1}, {10.0, 22.0, 0, 1}, {11.0, 22.0, 0, 1}, {12.0, 22.0, 0, 1}, {-13.0, 23.0, 0, 1}, {-12.0, 23.0, 0, 1},
{-11.0, 23.0, 0, 1}, {-10.0, 23.0, 0, 1}, {-6.0, 23.0, 0, 1}, {-5.0, 23.0, 0, 1}, {-4.0, 23.0, 0, 1}, {-3.0, 23.0, 0, 1},
{-2.0, 23.0, 0, 1}, {1.0, 23.0, 0, 1}, {2.0, 23.0, 0, 1}, {3.0, 23.0, 0, 1}, {4.0, 23.0, 0, 1}, {5.0, 23.0, 0, 1},
{8.0, 23.0, 0, 1}, {9.0, 23.0, 0, 1}, {10.0, 23.0, 0, 1}, {11.0, 23.0, 0, 1}, {12.0, 23.0, 0, 1}, {-13.0, 24.0, 0, 1},
{-12.0, 24.0, 0, 1}, {-11.0, 24.0, 0, 1}, {-10.0, 24.0, 0, 1}, {-6.0, 24.0, 0, 1}, {-5.0, 24.0, 0, 1}, {-4.0, 24.0, 0, 1},
{-3.0, 24.0, 0, 1}, {-2.0, 24.0, 0, 1}, {1.0, 24.0, 0, 1}, {2.0, 24.0, 0, 1}, {3.0, 24.0, 0, 1}, {4.0, 24.0, 0, 1},
{5.0, 24.0, 0, 1}, {8.0, 24.0, 0, 1}, {9.0, 24.0, 0, 1}, {10.0, 24.0, 0, 1}, {11.0, 24.0, 0, 1}, {12.0, 24.0, 0, 1},
{-13.0, 25.0, 0, 1}, {-12.0, 25.0, 0, 1}, {-11.0, 25.0, 0, 1}, {-10.0, 25.0, 0, 1}, {-6.0, 25.0, 0, 1}, {-5.0, 25.0, 0, 1},
{-4.0, 25.0, 0, 1}, {-3.0, 25.0, 0, 1}, {-2.0, 25.0, 0, 1}, {1.0, 25.0, 0, 1}, {2.0, 25.0, 0, 1}, {3.0, 25.0, 0, 1},
{4.0, 25.0, 0, 1}, {5.0, 25.0, 0, 1}, {8.0, 25.0, 0, 1}, {9.0, 25.0, 0, 1}, {10.0, 25.0, 0, 1}, {11.0, 25.0, 0, 1},
{12.0, 25.0, 0, 1}, {-13.0, 26.0, 0, 1}, {-12.0, 26.0, 0, 1}, {-11.0, 26.0, 0, 1}, {-10.0, 26.0, 0, 1}, {-6.0, 26.0, 0, 1},
{-5.0, 26.0, 0, 1}, {-4.0, 26.0, 0, 1}, {-3.0, 26.0, 0, 1}, {-2.0, 26.0, 0, 1}, {1.0, 26.0, 0, 1}, {2.0, 26.0, 0, 1},
{3.0, 26.0, 0, 1}, {4.0, 26.0, 0, 1}, {5.0, 26.0, 0, 1}, {8.0, 26.0, 0, 1}, {9.0, 26.0, 0, 1}, {10.0, 26.0, 0, 1},
{11.0, 26.0, 0, 1}, {12.0, 26.0, 0, 1}, {-13.0, 27.0, 0, 1}, {-12.0, 27.0, 0, 1}, {-11.0, 27.0, 0, 1}, {-10.0, 27.0, 0, 1},
{-6.0, 27.0, 0, 1}, {-5.0, 27.0, 0, 1}, {-4.0, 27.0, 0, 1}, {-3.0, 27.0, 0, 1}, {-2.0, 27.0, 0, 1}, {1.0, 27.0, 0, 1},
{2.0, 27.0, 0, 1}, {3.0, 27.0, 0, 1}, {4.0, 27.0, 0, 1}, {5.0, 27.0, 0, 1}, {8.0, 27.0, 0, 1}, {9.0, 27.0, 0, 1},
{10.0, 27.0, 0, 1}, {11.0, 27.0, 0, 1}, {12.0, 27.0, 0, 1}, {-13.0, 28.0, 0, 1}, {-12.0, 28.0, 0, 1}, {-11.0, 28.0, 0, 1},
{-10.0, 28.0, 0, 1}, {-6.0, 28.0, 0, 1}, {-5.0, 28.0, 0, 1}, {-4.0, 28.0, 0, 1}, {-3.0, 28.0, 0, 1}, {-2.0, 28.0, 0, 1},
{1.0, 28.0, 0, 1}, {2.0, 28.0, 0, 1}, {3.0, 28.0, 0, 1}, {4.0, 28.0, 0, 1}, {5.0, 28.0, 0, 1}, {8.0, 28.0, 0, 1},
{9.0, 28.0, 0, 1}, {10.0, 28.0, 0, 1}, {11.0, 28.0, 0, 1}, {12.0, 28.0, 0, 1}, {-13.0, 29.0, 0, 1}, {-12.0, 29.0, 0, 1},
{-11.0, 29.0, 0, 1}, {-10.0, 29.0, 0, 1}, {-6.0, 29.0, 0, 1}, {-5.0, 29.0, 0, 1}, {-4.0, 29.0, 0, 1}, {-3.0, 29.0, 0, 1},
{-2.0, 29.0, 0, 1}, {1.0, 29.0, 0, 1}, {2.0, 29.0, 0, 1}, {3.0, 29.0, 0, 1}, {4.0, 29.0, 0, 1}, {5.0, 29.0, 0, 1},
{8.0, 29.0, 0, 1}, {9.0, 29.0, 0, 1}, {10.0, 29.0, 0, 1}, {11.0, 29.0, 0, 1}, {12.0, 29.0, 0, 1}, {-13.0, 30.0, 0, 1},
{-12.0, 30.0, 0, 1}, {-11.0, 30.0, 0, 1}, {-10.0, 30.0, 0, 1}, {-6.0, 30.0, 0, 1}, {-5.0, 30.0, 0, 1}, {-4.0, 30.0, 0, 1},
{-3.0, 30.0, 0, 1}, {1.0, 30.0, 0, 1}, {2.0, 30.0, 0, 1}, {3.0, 30.0, 0, 1}, {4.0, 30.0, 0, 1}, {5.0, 30.0, 0, 1},
{9.0, 30.0, 0, 1}, {10.0, 30.0, 0, 1}, {11.0, 30.0, 0, 1}, {12.0, 30.0, 0, 1}, {-12.0, 31.0, 0, 1}, {-11.0, 31.0, 0, 1},
{-10.0, 31.0, 0, 1}, {-5.0, 31.0, 0, 1}, {-4.0, 31.0, 0, 1}, {-3.0, 31.0, 0, 1}, {2.0, 31.0, 0, 1}, {3.0, 31.0, 0, 1},
{4.0, 31.0, 0, 1}, {9.0, 31.0, 0, 1}, {10.0, 31.0, 0, 1}, {11.0, 31.0, 0, 1}
};
#endif // CONFIG_3D_OBJECT_CUSTOM

View File

@@ -0,0 +1,18 @@
// File generated by ImgTo3D.py
// Image file converted to 3D matrix: cpu_logo.png
#pragma once
#include <stdint.h>
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
extern const uint8_t image_to_bmp_array_custom[512];
extern const float image_to_3d_matrix_custom[1732][4];
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,114 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <malloc.h>
#include <math.h>
#include "graphics_support.h"
void init_perspective_matrix(dspm::Mat &P_m)
{
const float fov = 90; // field of view in degrees
const float near = 0.0001;
const float far = 1;
const float S = 1 / (tan((fov / 2) * DEG_TO_RAD));
// Initialize matrix to zero
for (int row = 0; row < P_m.rows; row++) {
for (int col = 0; col < P_m.cols; col++) {
P_m(row, col) = 0;
}
}
P_m(0, 0) = S;
P_m(1, 1) = S;
P_m(2, 2) = -far / (far - near);
P_m(3, 2) = (-far * near) / (far - near);
P_m(2, 3) = -1;
P_m(3, 3) = 1;
}
void update_perspective_matrix(dspm::Mat &P_m, float fov)
{
const float near = 0.0001;
const float far = 1;
const float S = 1 / (tan((fov / 2) * DEG_TO_RAD));
// Initialize matrix to zero
for (int row = 0; row < P_m.rows; row++) {
for (int col = 0; col < P_m.cols; col++) {
P_m(row, col) = 0;
}
}
P_m(0, 0) = S;
P_m(1, 1) = S;
P_m(2, 2) = -far / (far - near);
P_m(3, 2) = (-far * near) / (far - near);
P_m(2, 3) = -1;
P_m(3, 3) = 1;
P_m(3, 0) = (float)SSD1606_X_CENTER;
P_m(3, 1) = (float)SSD1606_Y_CENTER;
}
void update_scaling_matrix(dspm::Mat &T_m, bool keep_diagonal, float scale_x, float scale_y, float scale_z)
{
if (keep_diagonal) { // Multiply the diagonal values of the transformation matrix with the scaling
T_m(0, 0) *= scale_x; // (in case a rotation is already applied)
T_m(1, 1) *= scale_y;
T_m(2, 2) *= scale_z;
} else {
T_m(0, 0) = scale_x;
T_m(1, 1) = scale_y;
T_m(2, 2) = scale_z;
}
}
void update_translation_matrix(dspm::Mat &T_m, bool row, float move_x, float move_y, float move_z)
{
if (row) { // update values in 4-th row, if translation matrix is the second multiplier
T_m(3, 0) = move_x;
T_m(3, 1) = move_y;
T_m(3, 2) = move_z;
} else { // update values in 4-th collum, if translation matrix is the first multiplier
T_m(0, 3) = move_x;
T_m(1, 3) = move_y;
T_m(2, 3) = move_z;
}
}
void update_rotation_matrix(dspm::Mat &T_m, float rot_x, float rot_y, float rot_z)
{
dspm::Mat rotation_data(3, 1); // matrix(3x1) that holds x, y, z rotation data
rotation_data(0, 0) = DEG_TO_RAD * rot_x; // rotation data x
rotation_data(1, 0) = DEG_TO_RAD * rot_y; // rotation data y
rotation_data(2, 0) = DEG_TO_RAD * rot_z; // rotation data z
// Create and populate rotation matrix R(3x3). Then inverse it
dspm::Mat R = ekf::eul2rotm(rotation_data.data).t();
// Enlarge rotation matrix from 3x3 to 4x4
for (int row = 0; row < R.rows; row++) { // Copy rotation matrix R(3x3) to transformation matrix T_m(4x4)
for (int col = 0; col < R.cols; col++) {
T_m(row, col) = R(row, col);
}
}
}
void print_matrix(dspm::Mat matrix)
{
for (int rows = 0; rows < matrix.rows; rows++) {
for (int cols = 0; cols < matrix.cols; cols++) {
std::cout << matrix(rows, cols) << ", \t";
}
std::cout << std::endl;
}
std::cout << std::endl << std::endl;
}

View File

@@ -0,0 +1,128 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_dsp.h"
#include "ekf_imu13states.h"
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
#define DEG_TO_RAD 0.01745329252f // Degrees to radians conversion
#define RAD_TO_DEG 57.29577951f // Radians to degrees conversion
#define MATRIX_SIZE 4 // 4x4 matrices are used
#define SSD1306_WIDTH 128 // Display widh in pixels
#define SSD1306_HEIGHT 64 // DIsplay height
#define SSD1606_X_CENTER (SSD1306_WIDTH / 2) // Width center point
#define SSD1606_Y_CENTER (SSD1306_HEIGHT / 2) // Height center point
/**
* @brief Data struct of 3d image matrix
*
* This structure is used to hold a 3d coordinates of a monochromatic image centered to the origin of the
* cartesian space (0, 0, 0), that has ben processed by the image_to_3d_array.py.
*/
typedef struct image_3d_matrix_s {
const float (*matrix)[MATRIX_SIZE]; /*!< matrix holding xyz coordinates for each point of the converted image.*/
uint32_t matrix_len; /*!< image matrix length.*/
} image_3d_matrix_t;
/**
* @brief Data struct of 3d image matrix with kalman filter object
*
* This structure is used to hold a 3d coordinates of a monochromatic image centered to the origin of the
* cartesian space (0, 0, 0), that has ben processed by the image_to_3d_array.py.
* Kalman filter object is added to the matrix, for the purpose of RTOS task arguments.
*/
typedef struct image_3d_matrix_kalman_s {
const float (*matrix)[MATRIX_SIZE]; /*!< matrix holding xyz coordinates for each point of the converted image.*/
uint32_t matrix_len; /*!< image matrix length.*/
ekf_imu13states *ekf13; /*!< kalman filter object.*/
} image_3d_matrix_kalman_t;
/**
* @brief initialize perspective projection matrix
*
* Function initializes Mat class object holding perspective projection matrix.
*
* @param P_m: perspective projection matrix object from the Mat class
*/
void init_perspective_matrix(dspm::Mat &P_m);
/**
* @brief update scaling matrix
*
* Function updates scaling part of the transformation matrix.
*
* @param T_m: transformation matrix object from the Mat class
* @param keep_diagonal: if true: diagonal row of the transformation matrix T_m will be mulitplied with the scaling values
* if false: diagonal row of the transformation matrix T_m will be substituted with new scaling values
* @param scale_x: scaling value for x coordinate of the vector
* @param scale_y: scaling value for y coordinate of the vector
* @param scale_z: scaling value for z coordinate of the vector
*/
void update_scaling_matrix(dspm::Mat &T_m, bool keep_diagonal, float scale_x, float scale_y, float scale_z);
/**
* @brief update translation matrix
*
* Function updates translation part of the transformation matrix.
*
* @param T_m: transformation matrix object from the Mat class
* @param row: if true: translation values will be placed to the 3rd row of the transformation matrix T_m
* if false: translation values will be placed to the 3rd col of the transformation matrix T_m
* @param move_x: translation value for x coordinate of the vector
* @param move_y: translation value for y coordinate of the vector
* @param move_z: translation value for z coordinate of the vector
*/
void update_translation_matrix(dspm::Mat &T_m, bool row, float move_x, float move_y, float move_z);
/**
* @brief update rotation matrix
*
* Function updates rotation part of the tranformation matrix
*
* @param T_m: transformation matrix object from the Mat class
* @param rot_x: rotation angle for x direction of the vector
* @param rot_y: rotation angle for y direction of the vector
* @param rot_z: rotation angle for z direction of the vector
*/
void update_rotation_matrix(dspm::Mat &T_m, float rot_x, float rot_y, float rot_z);
/**
* @brief update perspective matrix
*
* Function updates perspective matrix with a new value of field of view
*
* @param P_m: perspective projection matrix object from the Mat class
* @param fov: field of view in degrees
*/
void update_perspective_matrix(dspm::Mat &P_m, float fov);
/**
* @brief printf matrix to the terminal output
*
* Print matrix for debug purposes
*
* @param matrix: matrix to be printed
*/
void print_matrix(dspm::Mat matrix);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,390 @@
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import sys
import os
import subprocess
PIL_INSTALLED = True
PYTHON_FILE_NAME = os.path.basename(__file__) # name of the Python file itself
OUTPUT_FILE_NAME = "image_to_3d_matrix" # generated output .c and .h file names
OUTPUT_3D_MATRIX_NAME = "image_to_3d_matrix_custom" # generated output 3D matrix in the .c and .h file
OUTPUT_BMP_ARRAY_NAME = "image_to_bmp_array_custom" # generated output BMP array in the .c and .h file
TEMPLATE_FILE_NAME = "template_img_to_3d" # name of the .c and .h template files
ESP_IOT_AZURE_DISPLAY_WIDTH = 128 # ESP_IOT_AZURE board display width
ESP_IOT_AZURE_DISPLAY_HEIGHT = 64 # ESP_IOT_AZURE board display height
try:
from PIL import Image, ImageOps
except ImportError as e:
PIL_INSTALLED = False
print(e)
if not PIL_INSTALLED:
print("Installing Pillow package by running command -m pip install --upgrade Pillow")
try:
subprocess.check_call([sys.executable, "-m", "pip", "install", "--upgrade", "Pillow"])
except subprocess.CalledProcessError as e:
print(e)
class Image3DMatrix:
""" class for 3d image matrix """
def __init__(self):
self.terminal_args = sys.argv # get command line arguments
self.img_path = None # path to the image
self.img_name = None # image name
self.img_ext = None # image extension
self.img_width = None # image target width
self.img_height = None # image target height
self.img_invert = False # invert monochromatic
self.img_include_bmp = False # include BMP form of the image
self.converted_img_dir = None # location to save the converted image
self.result_dir = None # location to save the .c and .h files
self.templates_dir = None # location where template files are saved
self.z_dist = 0 # Z distance of the 3D matrix
self.get_termianl_input()
def get_optional_args(self):
""" take optional arguments from the terminal, if there are any """
# take all the optional arguments
if len(self.terminal_args) > 4:
opt_args = self.terminal_args[4:len(self.terminal_args)]
# check the optional arguments "invert" "bmp" and z_dist
for arg in opt_args:
if arg.isdecimal():
self.z_dist = int(arg)
elif arg.lower() == "invert":
self.img_invert = True
elif arg.lower() == "bmp":
self.img_include_bmp = True
@staticmethod
def check_if_img_file_exists(path: str):
""" check, if provided image file path from terminal input is valid and an image file exits """
# check if a file exists on the provided absolute path
if os.path.isabs(path):
if not os.path.isfile(path):
print(f"Provided file {path} does not exist")
sys.exit()
# check if a file exists on the provided relative path
else:
absolute_path = os.path.join(os.getcwd(), path)
if not os.path.isfile(absolute_path):
print(f"Provided file {path} does not exist")
sys.exit()
else:
return absolute_path
return path
@staticmethod
def check_if_templates_exist():
""" Check if template .c and .h files exist """
# check if templates folder exists
templates_dir = os.path.join(os.getcwd(), "templates")
if not os.path.exists(templates_dir):
print(f"templates folder does not exist at location: {templates_dir}")
sys.exit()
# check if template .c file exists
template_c_file = os.path.join(templates_dir, f"{TEMPLATE_FILE_NAME}.c")
if not os.path.isfile(template_c_file):
print(f".c template file does not exist at location {template_c_file}")
sys.exit()
# check if template .h file exists
template_h_file = os.path.join(templates_dir, f"{TEMPLATE_FILE_NAME}.h")
if not os.path.isfile(template_h_file):
print(f".h template file does not exist at location {template_h_file}")
sys.exit()
return templates_dir
def get_img_name_extension(self):
""" extract image file name and image file extension """
img_file = os.path.basename(self.img_path) # image file with extension
self.img_name = os.path.splitext(img_file)[0] # extract file name
# Extract the file extension, to CAPS and remove the first character being dot
self.img_ext = os.path.splitext(img_file)[1].upper()[1:]
@staticmethod
def check_if_is_img(path: str, filename: str):
""" check if the provided file is an image and if its extension is supported """
# check if a file (which exits) is an image file
if not path.lower().endswith(('.png', '.jpg', '.jpeg', '.tiff', '.bmp', '.gif')):
print(f"provided file {filename} is not a supported image file")
sys.exit()
@staticmethod
def check_pixels(height: str, width: str):
""" check if the provided result image height and width are decimal numbers """
# check if provided resulting image width and height are decimal numbers
if not height.isdecimal() and width.isdecimal():
print(f"Provided image target width {width} and/or height {height} not valid")
sys.exit()
@staticmethod
def check_if_pixels_in_range(height: int, width: int):
""" check if the provided result image height and width are in a valid range """
# check if the height and width are in the display's range
if (height > ESP_IOT_AZURE_DISPLAY_HEIGHT + 1 or width > ESP_IOT_AZURE_DISPLAY_WIDTH + 1 or
height < 1 or width < 1):
print(f"Provided image target width {width} and/or height {height} \
is out of range of the display's dimensions ({ESP_IOT_AZURE_DISPLAY_WIDTH}x{ESP_IOT_AZURE_DISPLAY_HEIGHT})")
sys.exit()
if height % 2 or width % 2:
print(f"Provided image target width {width} and height {height} must be even")
sys.exit()
def create_paths(self):
""" create paths for the result files """
# if running from the example folder, leave the results there
# if running from anywhere else, change cwd to dir, where the python is located
cwd = os.getcwd() # current working directory
abspath = os.path.abspath(__file__) # get the absolute path of the python script
python_dir = os.path.dirname(abspath) # get the absolute path of the folder, in which the python script is located
if os.path.join("img_to_3d_matrix", "example") not in cwd:
os.chdir(python_dir) # go to a directory where the python is located
# create an absolute path for the folder in which the image after conversion will be saved
self.converted_img_dir = os.path.join(os.getcwd(), "converted_image")
if not os.path.exists(self.converted_img_dir):
# if the path does not exist, create it
os.makedirs(self.converted_img_dir)
# create an absolute path for the folder, to which the resulting .c and .h files will be saved
self.result_dir = os.path.join(os.path.dirname(os.getcwd()), "3d_matrix", "3d_matrix_data")
if not os.path.exists(self.result_dir):
# if the path does not exist, use the current path instead
self.result_dir = os.getcwd()
if os.path.join("img_to_3d_matrix", "example") in cwd:
os.chdir(python_dir) # go to a directory where the python is located
def get_termianl_input(self):
""" get input parameters from terminal """
if ((len(self.terminal_args) == 2) and (str(self.terminal_args[1]) == "--help")):
query = '\n'.join([
f"\npython {PYTHON_FILE_NAME} -image_path -image_width -image_height -z_distance -invert -bmp\n\n"
"-image_path absolute or relative path to an image to be processed",
"-image_width width (in pixels) of the resulting 3D image",
"-image_height height (in pixels) of the resulting 3D image",
"-z_distance (optional) Z distance (in pixels) of the resulting 3D image, leave blank otherwise",
"-invert (optional) to invert colors, leave blank otherwise",
"-bmp (optional) to include BMP from of the provided image, leave blank otherwise"])
print(query)
sys.exit()
elif len(self.terminal_args) < 4:
print(f"Too few arguments run following command for help\npython {PYTHON_FILE_NAME} --help")
sys.exit()
else:
self.img_path = self.terminal_args[1]
self.img_width = self.terminal_args[2]
self.img_height = self.terminal_args[3]
self.get_optional_args()
self.img_path = self.check_if_img_file_exists(self.img_path)
self.get_img_name_extension()
self.check_if_is_img(self.img_path, self.img_name)
self.check_pixels(self.img_height, self.img_width)
self.img_height = int(self.img_height)
self.img_width = int(self.img_width)
self.check_if_pixels_in_range(self.img_height, self.img_width)
self.create_paths()
self.templates_dir = self.check_if_templates_exist()
def fromat_comas_spaces(element_index: int, array_len: int, elements_per_line: int, c_file):
""" Formating of the spaces, commas and new lines for arrays in the .c file """
# Dont put comma after the last array member
if element_index != array_len:
c_file.write(",")
# new line after each elements_per_line
if not element_index % elements_per_line:
c_file.write("\n")
# start a new line with tab
if element_index != array_len:
c_file.write(" ")
# put space after each coma
# except after the last array member and before a new line
else:
if element_index != array_len:
c_file.write(" ")
def ouptput_files_gen(img3d: Image3DMatrix, bmp_arr: list, matrix_arr: list):
""" write 3d matrix array and optional BMP array to .c and .h files """
# generate a c file and save it to the main folder (if exists in the file structure)
output_c_file_name = f"{OUTPUT_FILE_NAME}.c"
with open(os.path.join(img3d.templates_dir, f"{TEMPLATE_FILE_NAME}.c"), "r", encoding="utf8") as c_template_file:
with open(os.path.join(img3d.result_dir, output_c_file_name), "w+", encoding="utf8") as c_file:
c_file.write(f"// File generated by {PYTHON_FILE_NAME}\n") # write first line to c_file
c_file.write(f"// Image file converted to 3D matrix {img3d.img_name}.{img3d.img_ext.lower()}\n")
next(c_template_file)
next(c_template_file) # skip first 2 lines from c_template_file
for line in c_template_file:
if "const" in line:
# include BMP form if requested
if img3d.img_include_bmp:
c_file.write(f"const uint8_t {OUTPUT_BMP_ARRAY_NAME}[{len(bmp_arr)}] = {{\n\n ")
for index, bmp_byte in enumerate(bmp_arr, start=1):
c_file.write(f"0x{bmp_byte:02x}")
fromat_comas_spaces(index, len(bmp_arr), 16, c_file)
c_file.write("\n};\n\n")
# write 3d matrix form
c_file.write(f"const float {OUTPUT_3D_MATRIX_NAME}[{len(matrix_arr)}][4] = {{\n\n ")
for index, line in enumerate(matrix_arr, start=1):
line_joined = ', '.join(map(str, line))
c_file.write(f"{{{line_joined}}}")
fromat_comas_spaces(index, len(matrix_arr), 6, c_file)
c_file.write("\n};\n")
next(c_template_file)
continue
# copy line from c_template_file to c_file
c_file.write(line)
c_file.close()
c_template_file.close()
# generate an h file and save it to the main folder (if exists in the file structure)
output_h_file_name = f"{OUTPUT_FILE_NAME}.h"
with open(os.path.join(img3d.templates_dir, f"{TEMPLATE_FILE_NAME}.h"), "r", encoding="utf8") as h_template_file:
with open(os.path.join(img3d.result_dir, output_h_file_name), "w+", encoding="utf8") as h_file:
h_file.write(f"// File generated by {PYTHON_FILE_NAME}\n") # write first line to h_file
h_file.write(f"// Image file converted to 3D matrix: {img3d.img_name}.{img3d.img_ext.lower()}\n")
next(h_template_file)
next(h_template_file) # skip first 2 lines from h_template_file
for line in h_template_file:
if "extern const" in line:
# include BMP header if requested
if img3d.img_include_bmp:
h_file.write(f"extern const uint8_t {OUTPUT_BMP_ARRAY_NAME}[{len(bmp_arr)}];\n")
# include 3d matrix header
h_file.write(f"extern const float {OUTPUT_3D_MATRIX_NAME}[{len(matrix_arr)}][4];\n")
next(h_template_file)
continue
h_file.write(line)
h_file.close()
h_template_file.close()
query = '\n'.join([
"\nOutput files generation done!",
f"Output files {output_c_file_name} {output_h_file_name}",
f"Output files location {img3d.result_dir}"])
print(query)
def create_matrix(img3d: Image3DMatrix, pixels: list, bmp_img_array: list, matrix_img_array: list):
""" Create a 3D matrix and optional BMP form of the converted image """
multiplier = pow(2, 7)
byte = 0
# convert pixels to both, bmp and 3d from
for index, pixel in enumerate(pixels, start=1):
if pixel:
byte += multiplier
y_coord = int((index - 1) / img3d.img_width)
x_coord = (index - 1) - (y_coord * img3d.img_width) - (img3d.img_width / 2)
y_coord = y_coord - (img3d.img_height / 2)
matrix_img_array.append((x_coord, y_coord, img3d.z_dist, 1))
multiplier >>= 1
if not index % 8:
multiplier = pow(2, 7)
bmp_img_array.append(byte)
byte = 0
def convert_img(img3d: Image3DMatrix):
""" image conversion to list of monochromatic pixels """
# open an image and convert the image to monochromatic
img = Image.open(img3d.img_path)
img = img.convert(mode="1", dither=Image.NONE)
# if requested, invert black and white
if img3d.img_invert:
img = ImageOps.invert(img)
# resize the image and get the width and height of the resized image, to check
img = img.resize((int(img3d.img_width), int(img3d.img_height)), resample=Image.NEAREST)
res_width, res_height = img.size
# get image pixels as a list, after converting the image to monochromatic - pixels are either 0 or 255
pixels = list(img.getdata())
# check if the resized image has the same dimensions as the required dimensions
if (res_width, res_height) != (img3d.img_width, img3d.img_height):
query = '\n'.join([
"Image conversion was not successful!",
f"Required width and height: {img3d.img_width} {img3d.img_height}",
f"Real width and height: {res_width} {res_height}"])
print(query)
sys.exit()
else:
# if converted correctly, save the converted image
if img3d.img_invert:
invert = "_invert_conv."
else:
invert = "_conv."
converted_img_name = ''.join([img3d.img_name, invert, img3d.img_ext.lower()])
converted_img_location = os.path.join(img3d.converted_img_dir, converted_img_name)
img.save(converted_img_location, format=img3d.img_ext, subsampling=0, quality=100)
query = '\n'.join([
"Image conversion done!",
f"Converted image {converted_img_name}",
f"Converted image location {os.path.join(img3d.converted_img_dir)}"])
print(query)
return pixels
def main():
""" main function of the image_to_3d_matrix """
img3d = Image3DMatrix()
pixels = convert_img(img3d)
bmp_img_array = list()
matrix_img_array = list()
create_matrix(img3d, pixels, bmp_img_array, matrix_img_array)
ouptput_files_gen(img3d, bmp_img_array, matrix_img_array)
print("\nAll done!")
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,105 @@
# Getting the 3D matrix
`ImgTo3D.py` generates a 3D matrix for the monochromatic display, from a provided 2D graphics - image. As the output, `.c` and `.h` files containing the 3D matrix, are already included in the project structure, to `CMakeList.txt` and `.cpp` files. The output arrays are named `image_to_3d_matrix_custom` and `image_to_bmp_array_custom` by default. The converted image is saved for a preview.
The script can be called by following commands:
python ImgTo3D.py image_path image_width image_height
* `ImgTo3D.py` - absolute path to the python file
* `image_path` - absolute or relative path to the image, to be converted
* `image_width` - resulting width of the converted image (in pixels)
* `image_height` - resulting height of the converted image (in pixels)
The python script converts the provided image first to a monochromatic image, then resizes the image according to the provided dimensions, then converts the image to a 3D matrix and finally saves the 3D into a `.c` file.
python ImgTo3D.py --help
Run for help - prints hints, how to run the file and information about the arguments.
### Optional arguments
python ImgTo3D.py image_path image_width image_height z_dist invert bmp
* `z_dist` puts a distance (in pixels) into the Z direction of each matrix row - each 3D point. 0 is used otherwise
* `invert` inverts black and white in the converted monochromatic image, causing inverting pixels that will be lit on the display
* `bmp` includes a BMP form of the converted image into the output `.c` and `.h` files
The optional arguments can be added in any sequence.
# Example
To get example results, in the example folder, run the script from the example folder like so:
/example $ python ../ImgTo3D.py cpu_logo.png 64 64 invert bmp
To get the results already integrated into the project, run the script from any other location:
/any_location $ python abs_path/ImgTo3D.py cpu_logo.png 64 64 bmp invert
Converts `cpu_logo.png` image into a 3D matrix with dimensions of `64x64` pixels, with inverted colors and the BMP is included into the output file.
## Output files
python script produces the following output:
* `converted_image/cpu_logo_invert_conv.png` image after the conversion (monochromatic and resized image)
* `image_to_3d_matrix.c` c file with 3D and BMP matrices in `const` arrays
* `image_to_3d_matrix.h` h file with 3D and BMP arrays declarations in `extern const`
The output `.c` and `.h` files are based on template files `template_img_to_3d.c` and `template_img_to_3d.h`. From which, only the variables declarations are changed according to the converted image.
The expected output from the python script is the following:
Image conversion done!
Converted image cpu_logo_invert_conv.png
Converted image location ${workspaceFolder}/graphics/img_to_3d_matrix/example/converted_image
Output files generation done!
Output files image_to_3d_matrix.c image_to_3d_matrix.h
Output files location ${workspaceFolder}/graphics/img_to_3d_matrix/example
All done!
## Image conversion output example
<div align="center">
<table>
<tr>
<td style="height: 15px;">
<p align = "center">
Converted image (64x64)
</p>
</td>
<td style="height: 15px;">
<p align = "center">
Inverted colors (64x64)
</p>
</td>
</tr>
<tr>
<td>
<div align="center">
<img src= "converted_image/cpu_logo_conv.png">
</div>
</td>
<td>
<div align="center">
<img src= "converted_image/cpu_logo_invert_conv.png">
</div>
</td>
</tr>
<tr>
<td colspan="2" style="height: 15px;">
<p align = "center">
Original image (256x256)
</p>
</td>
</tr>
<tr>
<td colspan="2">
<div align="center">
<img src= "image/cpu_logo.png" style="width:50%">
</div>
</td>
</tr>
</table>
</div>

View File

@@ -0,0 +1,11 @@
// template file - template_img_to_3d.c
// arrays declarations will be modified by python script ImgTo3D.py
#include "image_to_3d_matrix.h"
#ifdef CONFIG_3D_OBJECT_CUSTOM
const uint8_t TEMPLATE_ARRAY_BMP_IMAGE[NUM_OF_BYTES] = {};
const float TEMPLATE_ARRAY_IMAGE_TO_3D_MATRIX[NUM_OF_POINTS][4] = {};
#endif // CONFIG_3D_OBJECT_CUSTOM

View File

@@ -0,0 +1,18 @@
// template file - template_img_to_3d.h
// arrays declarations will be modified by python script ImgTo3D.py
#pragma once
#include <stdint.h>
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
extern const uint8_t TEMPLATE_ARRAY_BMP_IMAGE[NUM_OF_BYTES];
extern const float TEMPLATE_ARRAY_IMAGE_TO_3D_MATRIX[NUM_OF_POINTS][4];
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,7 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(audio-lyraT)
spiffs_create_partition_image(storage spiffs FLASH_IN_PROJECT)

View File

@@ -0,0 +1,71 @@
# ESP-DSP LyraT Board audio processing application
The demo applications are developed for the ESP32-LyraT development board and demonstrate the usage of IIR filters from the ESP-DSP library.
This example showcases how to use IIR filter functionality to process audio stream data.
To hear the audio please connect headphones or speakers to the ESP32-LyraT audio output.
The example performs the following steps:
1. Read samples from a file
* read samples from file
* write audio samples to the triple buffer
2. Process audio samples
* process volume/bass/treble
* apply digital limiter to the audio data
* control audio buffer overflow
3. Pass samples to the audio codec
To control the volume/bass/treble, please select the value by press 'Set' button and adjust the value by '+/-' buttons.
## The Triple Audio Buffer
In audion processing, it's possible to have situation when one task write data to the processing buffer (processing task), and another task read data from the same buffer, and still in reading process.
Triple buffering is a technique used in audio processing to minimize latency and ensure smooth playback. It involves using three buffers to store audio data. Here's a description of how it works:
* Buffer A: This buffer holds the audio data that is currently being processed by the audio system. It is typically filled with samples from the audio source and processed in real-time.
* Buffer B: When Buffer A is full, the audio system begins reading from Buffer A and starts processing the data. At the same time, Buffer B is filled with new audio samples from the source.
* Buffer C: Once Buffer B is full, the audio system switches its attention to Buffer B and continues processing data. Buffer C is then filled with the latest audio samples.
The cycle continues, with the audio system always processing the data from a buffer while the other two buffers are being filled. This approach helps ensure a continuous and uninterrupted audio playback, as there is always a buffer ready to be processed. It reduces the chances of audio glitches or dropouts caused by delays in reading or processing the audio data.
Triple buffering is particularly useful when working with real-time audio processing applications, where low latency and uninterrupted playback are crucial.
## Audio Processing Flow
The audio processing flow contains next blocks:
1. Audio processing task
* Read data from file and store to the triple buffer
* Read from triple buffer and concert data from int16_t to float
* Process bass
* Process treble
* Process volume
* Apply digital limiter
* Convert data from float to int16_t and store to the triple buffer
2. Audio output task
* Write data from triple buffer to audio codec
3. Buttons control task
* React on buttons and adjust the control values
* Calculates IIR filter coefficients
## How to use the example
### Hardware required
This example require LyraT development board.
### Configure the project
Under Component Config ---> DSP Library ---> DSP Optimization, it's possible to choose either the optimized or ANSI implementation, to compare them.
### Build and flash
Build the project and flash it to the board, then run monitor tool to view serial output (replace PORT with serial port name):
```
idf.py flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

View File

@@ -0,0 +1 @@
idf_component_register(SRCS "audio_amp_main.c")

View File

@@ -0,0 +1,382 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include <stdio.h>
#include <inttypes.h>
#include <sdkconfig.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "esp_dsp.h"
#include "bsp/esp-bsp.h"
#include <stdint.h>
#include <math.h>
// Buffer for reading/writing to I2S driver. Same length as SPIFFS buffer and I2S buffer, for optimal read/write performance.
// Recording audio data path:
// I2S peripheral -> I2S buffer (DMA) -> App buffer (RAM) -> SPIFFS buffer -> External SPI Flash.
// Vice versa for playback.
#define BUFFER_SIZE (64)
#define SAMPLE_RATE (16000) // For recording
#define DEFAULT_VOLUME (100)
// Globals
static const char *TAG = "example";
static QueueHandle_t audio_button_q = NULL;
static void btn_handler(void *button_handle, void *usr_data)
{
int button_pressed = (int)usr_data;
xQueueSend(audio_button_q, &button_pressed, 0);
}
// Very simple WAV header, ignores most fields
typedef struct __attribute__((packed))
{
uint8_t ignore_0[22];
uint16_t num_channels;
uint32_t sample_rate;
uint8_t ignore_1[6];
uint16_t bits_per_sample;
uint8_t ignore_2[4];
uint32_t data_size;
uint8_t data[];
} dumb_wav_header_t;
typedef enum audio_set {
AUDIO_VOLUME,
AUDIO_BASS,
AUDIO_TREBLE,
} audio_set_t;
static esp_codec_dev_handle_t spk_codec_dev = NULL;
static FILE *play_file = NULL;
// Pointer to a file that is going to be played
static const char play_filename[] = BSP_SPIFFS_MOUNT_POINT"/16bit_mono_44_1_khz.wav";
// Definition for all tasks
static void buttons_process_task(void *arg);
static void audio_read_task(void *arg);
static void audio_process_task(void *arg);
// Wave file header
static dumb_wav_header_t wav_header;
static audio_set_t current_set = AUDIO_VOLUME;
// Data for IIR filters
float iir_coeffs_lpf[5];
float iir_w_lpf[5] = {0, 0};
float iir_coeffs_hpf[5];
float iir_w_hpf[5] = {0, 0};
// IIR filters parameters
// Parameters for low-pass filter (LPF)
float lpf_gain = 0;
float lpf_qFactor = 0.5;
float lpf_freq = 0.01;
// Parameters for high-pass filter (HPF)
float hpf_gain = 0;
float hpf_qFactor = 1;
float hpf_freq = 0.15;
// Volume control definitions
float full_volume = 1;
// Volume in dB
int full_volume_db = -12;
// Digital limiter envelope value
float full_envelope = 0;
// processing audio buffer
float processing_audio_buffer[BUFFER_SIZE] = {0};
// The triple_audio_buffer contains tree data arrays sizeof BUFFER_SIZE, for writing audio data to the codec
int16_t triple_audio_buffer[3 * BUFFER_SIZE] = {0};
// The write index shows the audio buffer that will be used to write data to the codec
int audio_buffer_write_index = 0;
// The read index shows the audio buffer that will be used to fill data from the data source to the processing buffer
int audio_buffer_read_index = 0;
// Semaphore to synchronize the read and write
static SemaphoreHandle_t sync_read_task;
// Convert input int16_t Q15 values array to the float values array
static void convert_short2float(int16_t *int16_data, float *float_data, int len)
{
float multiplier = 1.0 / (float)(INT16_MAX + 1);
for (int i = 0 ; i < len ; i++) {
float_data[i] = (float)int16_data[i] * multiplier;
}
}
// Convert input float values to the int16_t Q15 values array
static void convert_float2short(float *float_data, int16_t *int16_data, int len)
{
float multiplier = (float)(INT16_MAX + 1);
for (int i = 0 ; i < len ; i++) {
int16_data[i] = (int16_t)((float)multiplier * (float)float_data[i]);
}
}
// In the audio processing the valid output audio values for the floating point format should be in range +/- 1.0,
// because these values will be converted to the 0x8000 and 0x7fff int16_t values, and will be accepted by the codec.
// With additional amplification, for example bass, treble, and for other processing, it is possible that the audio
// signal will reach the maximum values and will make an overflow at the DAC.
// To avoid this situation the digital limiter analyze the output values and control the full amplification gain.
//
void digitalLimiter(float *input_signal, float *output_signal, int signal_length, float threshold, float attack_value, float release_value, float *in_envelope)
{
float envelope = *in_envelope;
for (int i = 0; i < signal_length; i++) {
// Calculate envelope
float abs_input = fabsf(input_signal[i]);
if (abs_input > envelope) {
envelope = envelope * (1 - attack_value) + attack_value * abs_input;
} else {
envelope = envelope * (1 - release_value) + release_value * abs_input;
}
// Apply compression
if (envelope > threshold) {
output_signal[i] = input_signal[i] * (threshold / envelope);
} else {
output_signal[i] = input_signal[i];
}
}
*in_envelope = envelope;
}
static void audio_process_task(void *arg)
{
// Init codeac and apply the initial volume to maximum
spk_codec_dev = bsp_audio_codec_speaker_init();
assert(spk_codec_dev);
esp_codec_dev_set_out_vol(spk_codec_dev, DEFAULT_VOLUME);
// Open file and het the WAV header to set up the sample frequency, amount of channels and resolution
play_file = fopen(play_filename, "rb");
if (play_file == NULL) {
ESP_LOGW(TAG, "%s file does not exist!", play_filename);
}
// Read WAV header
if (fread((void *)&wav_header, 1, sizeof(wav_header), play_file) != sizeof(wav_header)) {
ESP_LOGW(TAG, "Error in reading file");
return;
}
ESP_LOGI(TAG, "Number of channels: %" PRIu16 "", wav_header.num_channels);
ESP_LOGI(TAG, "Bits per sample: %" PRIu16 "", wav_header.bits_per_sample);
ESP_LOGI(TAG, "Sample rate: %" PRIu32 "", wav_header.sample_rate);
ESP_LOGI(TAG, "Data size: %" PRIu32 "", wav_header.data_size);
esp_codec_dev_sample_info_t fs = {
.sample_rate = wav_header.sample_rate,
.channel = wav_header.num_channels,
.bits_per_sample = wav_header.bits_per_sample,
};
if (spk_codec_dev != NULL) {
int result = esp_codec_dev_open(spk_codec_dev, &fs);
}
// Calculate initial volume value
full_volume = exp10f((float)full_volume_db / 20);
// Calculate initial state for LPF
dsps_biquad_gen_lowShelf_f32(iir_coeffs_lpf, lpf_freq, lpf_gain, lpf_qFactor);
// Calculate initial state for HPF
dsps_biquad_gen_highShelf_f32(iir_coeffs_hpf, hpf_freq, hpf_gain, hpf_qFactor);
BaseType_t ret = xTaskCreate(buttons_process_task, "buttons_process_task", 4096, NULL, 4, NULL);
assert(ret == pdPASS);
sync_read_task = xSemaphoreCreateCounting(1, 0);
ret = xTaskCreate(audio_read_task, "audio_read_task", 4096, NULL, 7, NULL);
assert(ret == pdPASS);
vTaskDelay(1);
ESP_LOGW(TAG, "To select volume/bass/treble please use the 'Set' button. And adjust the value with +/- buttons.");
for (;;) {
/* Get data from SPIFFS and send it to codec */
int16_t *wav_bytes = &triple_audio_buffer[audio_buffer_write_index * BUFFER_SIZE];
// Write samples to audio codec
esp_codec_dev_write(spk_codec_dev, wav_bytes, BUFFER_SIZE * sizeof(int16_t));
audio_buffer_write_index++;
if (audio_buffer_write_index >= 3) {
audio_buffer_write_index = 0;
}
// Check the triple buffer overflow
if (audio_buffer_write_index == audio_buffer_read_index) {
// Call delay to switch the task to fill the buffer
vTaskDelay(1);
// Check and indicate overflow status
if (audio_buffer_write_index == audio_buffer_read_index) {
ESP_LOGW(TAG, "Audio buffer overflow!");
}
}
// Generate synt event to read task:
xSemaphoreGive(sync_read_task);
}
}
// The audio_read_task is responsible to read data from the file and fill it to the audio buffer.
// The audio buffer is places inside of triple buffer, to avoid overflow situation in case if
// the processing task busy for a while.
static void audio_read_task(void *arg)
{
while (1) {
// Wait the sync semaphore
if (xSemaphoreTake(sync_read_task, 100)) {
// Get the pointer to the current audio buffer
int16_t *wav_buffer = &triple_audio_buffer[audio_buffer_read_index * BUFFER_SIZE];
// Read the data from the file
uint32_t bytes_read_from_spiffs = fread(wav_buffer, sizeof(int16_t), BUFFER_SIZE, play_file);
// Convert input samples from int16 to float for processing
convert_short2float((int16_t *)wav_buffer, processing_audio_buffer, BUFFER_SIZE);
// Apply bass
dsps_biquad_f32(processing_audio_buffer, processing_audio_buffer, BUFFER_SIZE, iir_coeffs_lpf, iir_w_lpf);
// Apply treble
dsps_biquad_f32(processing_audio_buffer, processing_audio_buffer, BUFFER_SIZE, iir_coeffs_hpf, iir_w_hpf);
// Apply voluve
dsps_mulc_f32_ansi(processing_audio_buffer, processing_audio_buffer, BUFFER_SIZE, full_volume, 1, 1);
// Apply limiter
digitalLimiter(processing_audio_buffer, processing_audio_buffer, BUFFER_SIZE, 0.5, 0.5, 0.0001, &full_envelope);
// Convert from float to int16 for audio codec
convert_float2short(processing_audio_buffer, (int16_t *)wav_buffer, BUFFER_SIZE);
if (bytes_read_from_spiffs != BUFFER_SIZE) {
// Rewind the file and read the WAV header
rewind(play_file);
fread((void *)&wav_header, 1, sizeof(wav_header), play_file);
// Read data to the audio buffer
bytes_read_from_spiffs = fread(wav_buffer, sizeof(int16_t), BUFFER_SIZE, play_file);
}
audio_buffer_read_index++;
if (audio_buffer_read_index >= 3) {
audio_buffer_read_index = 0;
}
} else {
// Error in case of timeout
ESP_LOGE(TAG, "Audio timeout!");
}
}
}
static void buttons_process_task(void *arg)
{
while (1) {
int btn_index = 0;
if (xQueueReceive(audio_button_q, &btn_index, portMAX_DELAY) == pdTRUE) {
switch (btn_index) {
case BSP_BUTTON_SET: {
current_set += 1;
if (current_set > 2) {
current_set = AUDIO_VOLUME;
}
switch (current_set) {
case AUDIO_VOLUME:
ESP_LOGW(TAG, "Select volume");
break;
case AUDIO_BASS:
ESP_LOGW(TAG, "Select bass");
break;
case AUDIO_TREBLE:
ESP_LOGW(TAG, "Select treble");
break;
default:
break;
}
break;
}
case BSP_BUTTON_VOLDOWN: {
switch (current_set) {
case AUDIO_VOLUME:
full_volume_db -= 3;
if (full_volume_db < -36) {
full_volume_db = -36;
}
full_volume = exp10f((float)full_volume_db / 20);
ESP_LOGI(TAG, "Volume Down: %i dB", full_volume_db);
break;
case AUDIO_BASS:
lpf_gain -= 1;
if (lpf_gain < -12) {
lpf_gain = -12;
}
ESP_LOGI(TAG, "Bass Down: %i", (int)lpf_gain);
dsps_biquad_gen_lowShelf_f32(iir_coeffs_lpf, lpf_freq, lpf_gain, lpf_qFactor);
break;
case AUDIO_TREBLE:
hpf_gain -= 1;
if (hpf_gain < -12) {
hpf_gain = -12;
}
ESP_LOGI(TAG, "Treble Down: %i", (int)hpf_gain);
dsps_biquad_gen_highShelf_f32(iir_coeffs_hpf, hpf_freq, hpf_gain, hpf_qFactor);
break;
default:
break;
}
break;
}
case BSP_BUTTON_VOLUP: {
switch (current_set) {
case AUDIO_VOLUME:
full_volume_db += 3;
if (full_volume_db > 0) {
full_volume_db = 0;
}
full_volume = exp10f((float)full_volume_db / 20);
ESP_LOGI(TAG, "Volume Up: %i dB", full_volume_db);
break;
case AUDIO_BASS:
lpf_gain += 1;
if (lpf_gain > 12) {
lpf_gain = 12;
}
ESP_LOGI(TAG, "Bass Up: %i", (int)lpf_gain);
dsps_biquad_gen_lowShelf_f32(iir_coeffs_lpf, lpf_freq, lpf_gain, lpf_qFactor);
break;
case AUDIO_TREBLE:
hpf_gain += 1;
if (hpf_gain > 12) {
hpf_gain = 12;
}
ESP_LOGI(TAG, "Treble Up: %i", (int)hpf_gain);
dsps_biquad_gen_highShelf_f32(iir_coeffs_hpf, hpf_freq, hpf_gain, hpf_qFactor);
break;
default:
break;
}
break;
}
default:
ESP_LOGI(TAG, "No function for this button");
break;
}
}
}
}
void app_main(void)
{
ESP_ERROR_CHECK(bsp_spiffs_mount());
// Create FreeRTOS tasks and queues
audio_button_q = xQueueCreate(10, sizeof(int));
assert (audio_button_q != NULL);
BaseType_t ret = xTaskCreate(audio_process_task, "audio_process_task", 4096, NULL, 6, NULL);
assert(ret == pdPASS);
// Init audio buttons
button_handle_t btns[BSP_BUTTON_NUM];
ESP_ERROR_CHECK(bsp_iot_button_create(btns, NULL, BSP_BUTTON_NUM));
for (int i = 0; i < BSP_BUTTON_NUM; i++) {
ESP_ERROR_CHECK(iot_button_register_cb(btns[i], BUTTON_PRESS_DOWN, btn_handler, (void *) i));
}
}

View File

@@ -0,0 +1,5 @@
dependencies:
espressif/esp32_lyrat: "^1.0.0"
espressif/esp-dsp:
version: '*'
override_path: "../../../../esp-dsp"

View File

@@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage, data, spiffs, , 0x2f0000,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1M,
6 storage, data, spiffs, , 0x2f0000,

View File

@@ -0,0 +1,8 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_USE_MEMMAP=y
CONFIG_SPIFFS_PAGE_SIZE=1024

View File

@@ -0,0 +1,8 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
add_compile_options("-Wno-format")
project(esp-dsp-m5stack-3d-graphics)

View File

@@ -0,0 +1,18 @@
# ESP-DSP M5Stack Core s3 board 3d graphics demo application
The demo is developed for [M5Stack Core S3 board](https://docs.m5stack.com/en/core/CoreS3) development board and is demonstrating the usage of matrices with `ESP-DSP` `Mat` class, Kalman filter and basic 3D graphics.
The 3D Graphics demo displays a 2D graphics, converted to 3D as a 3D rotating object, on the development board's display.
## Running the demo
To start the demo, run the following command:
idf.py build flash monitor
The expected output is the following:
I (2103) gpio: GPIO[35]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (2103) ili9341: LCD panel create success, version: 1.2.0
I (3263) 3D image demo: Showing 3D image

View File

@@ -0,0 +1,133 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "sdkconfig.h"
#include "esp_log.h"
#include "bsp/m5stack_core_s3.h"
#include "esp_dsp.h"
#include "cube_matrix.h"
#include "esp_logo.h"
#include "image_to_3d_matrix.h"
#include "esp_lcd_types.h"
static const char *TAG = "3D image demo";
dspm::Mat perspective_matrix(MATRIX_SIZE, MATRIX_SIZE);
image_3d_matrix_t image;
extern "C" void app_main();
/**
* @brief Initialize 3d image structure
*
* Assigns a 3d image to be displayed to the 3d image structure
*
* @param image: 3d image structure
*/
static void init_3d_matrix_struct(image_3d_matrix_t *image)
{
image->matrix = image_3d_matrix_esp_logo;
image->matrix_len = ((sizeof(image_3d_matrix_esp_logo)) / sizeof(float)) / MATRIX_SIZE;
ESP_LOGI(TAG, "Selected 3D image - ESP Logo");
}
lv_display_t *display = NULL;
lv_color16_t color_data[BSP_LCD_H_RES * BSP_LCD_V_RES];
/**
* @brief Display a 3d image
*
* Fill the display buffer with points from Logo matrix
*
* @param projected_image: 3d matrix from Mat class after projection
*/
static void display_3d_image(dspm::Mat projected_image)
{
for (int i = 0 ; i < projected_image.rows ; i++) {
int x = projected_image(i, 0);
int y = projected_image(i, 1);
for (size_t xx = 0; xx < 4; xx++) {
for (size_t yy = 0; yy < 4; yy++) {
int index = (y + yy) * BSP_LCD_H_RES + (x + xx);
color_data[index].blue = 0x00;
color_data[index].red = 0x1f;
color_data[index].green = 0x00;
}
}
}
}
/**
* @brief RTOS task to draw a 3d image.
*
* Updates 3d matrices, prepares the final 3d matrix to be displayed on the display
*
* @param arg: pointer to RTOS task arguments, 3d image structure in this case
*/
static void draw_3d_image_task(void *arg)
{
float rot_y = 0;
const float angle_increment_y = 4;
image_3d_matrix_t *image = (image_3d_matrix_t *)arg;
dspm::Mat T0 = dspm::Mat::eye(MATRIX_SIZE); // Transformation matrix
dspm::Mat transformed_image(image->matrix_len, MATRIX_SIZE); // 3D image matrix after transformation
dspm::Mat projected_image(image->matrix_len, MATRIX_SIZE); // 3D image matrix after projection
dspm::Mat matrix_3d((float *)image->matrix[0], image->matrix_len, MATRIX_SIZE);
esp_lcd_panel_handle_t panel_handle = (esp_lcd_panel_handle_t)lv_display_get_user_data(display);
int size = BSP_LCD_H_RES * BSP_LCD_V_RES;
while (1) {
rot_y -= angle_increment_y;
if (rot_y <= 0) {
rot_y += 360;
}
// Apply rotation in all the axes to the transformation matrix
update_rotation_matrix(T0, 0, rot_y, 0);
// Scale input matrix to fit the display
update_scaling_matrix(T0, true, 4, 4, 1);
// Apply translation to the transformation matrix
update_translation_matrix(T0, true, ((float)BSP_LCD_H_RES / 2), ((float)BSP_LCD_V_RES / 2), 0);
dspm::Mat result_image = matrix_3d * T0 * perspective_matrix;
// Clear buffer before update
memset(color_data, 0xff, size * 2);
// Fill the display buffer with result matrix data
display_3d_image(result_image);
// Swap colors to the display format
lv_draw_sw_rgb565_swap(color_data, size);
// Update the display
esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, BSP_LCD_H_RES, BSP_LCD_V_RES, color_data);
vTaskDelay(20 / portTICK_PERIOD_MS);
}
}
extern "C" lv_display_t *display_init(void);
void app_main(void)
{
ESP_LOGI(TAG, "Start the 3D graphics application");
ekf_imu13states *ekf13 = new ekf_imu13states();
ekf13->Init();
init_perspective_matrix(perspective_matrix);
init_3d_matrix_struct(&image);
// Init the display
display = display_init();
vTaskDelay(1000 / portTICK_PERIOD_MS);
xTaskCreate(draw_3d_image_task, "draw_3d_image", 16384, &image, 3, NULL);
ESP_LOGI(TAG, "Showing 3D image");
}

View File

@@ -0,0 +1,12 @@
idf_component_register(SRCS "3d_graphics_demo.cpp"
"init_display.c"
"../../../../azure_board_apps/graphics/3d_matrix/3d_matrix_data/esp_logo.c"
"../../../../azure_board_apps/graphics/3d_matrix/3d_matrix_data/esp_text.c"
"../../../../azure_board_apps/graphics/3d_matrix/3d_matrix_data/image_to_3d_matrix.c"
"../../../../azure_board_apps/graphics/3d_matrix/3d_matrix_src/graphics_support.cpp"
INCLUDE_DIRS "."
"../../../../azure_board_apps/graphics/3d_matrix/3d_matrix_data"
"../../../../azure_board_apps/graphics/3d_matrix/3d_matrix_src")
# We add this definition to be compatible with demo
add_compile_definitions(CONFIG_3D_OBJECT_ESP_LOGO=y)

View File

@@ -0,0 +1,8 @@
## IDF Component Manager Manifest File
description: ESP-DSP azure board application 3d graphics
dependencies:
espressif/esp-dsp:
version: '*'
override_path: ../../../../../../esp-dsp
espressif/m5stack_core_s3: '*'

View File

@@ -0,0 +1,301 @@
#include "bsp/m5stack_core_s3.h"
#include "esp_log.h"
#include "esp_dsp.h"
#include "esp_lcd_ili9341.h"
#include "esp_err.h"
static i2c_master_bus_handle_t i2c_handle = NULL;
static bool i2c_initialized = false;
static i2c_master_dev_handle_t axp2101_h = NULL;
static i2c_master_dev_handle_t aw9523_h = NULL;
static bool spi_initialized = false;
static const char *TAG = "3d-graphics";
#define BSP_AXP2101_ADDR 0x34
#define BSP_AW9523_ADDR 0x58
#define BSP_ERROR_CHECK_RETURN_ERR(x) do { \
esp_err_t err_rc_ = (x); \
if (unlikely(err_rc_ != ESP_OK)) { \
return err_rc_; \
} \
} while(0)
#define ESP_RETURN_ON_ERROR(x, log_tag, format, ...) do { \
esp_err_t err_rc_ = (x); \
if (unlikely(err_rc_ != ESP_OK)) { \
ESP_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
return err_rc_; \
} \
} while(0)
#define BSP_ERROR_CHECK_RETURN_NULL(x) do { \
if (unlikely((x) != ESP_OK)) { \
return NULL; \
} \
} while(0)
#define BSP_NULL_CHECK(x, ret) do { \
if ((x) == NULL) { \
return ret; \
} \
} while(0)
#define ESP_GOTO_ON_ERROR(x, goto_tag, log_tag, format, ...) do { \
esp_err_t err_rc_ = (x); \
if (unlikely(err_rc_ != ESP_OK)) { \
ESP_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
ret = err_rc_; \
goto goto_tag; \
} \
} while(0)
esp_err_t bsp_i2c_init(void)
{
/* I2C was initialized before */
if (i2c_initialized) {
return ESP_OK;
}
const i2c_master_bus_config_t i2c_config = {
.i2c_port = BSP_I2C_NUM,
.sda_io_num = BSP_I2C_SDA,
.scl_io_num = BSP_I2C_SCL,
.clk_source = 1,
};
BSP_ERROR_CHECK_RETURN_ERR(i2c_new_master_bus(&i2c_config, &i2c_handle));
// AXP2101 and AW9523 are managed by this BSP
const i2c_device_config_t axp2101_config = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = BSP_AXP2101_ADDR,
.scl_speed_hz = 400000,
};
BSP_ERROR_CHECK_RETURN_ERR(i2c_master_bus_add_device(i2c_handle, &axp2101_config, &axp2101_h));
const i2c_device_config_t aw9523_config = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = BSP_AW9523_ADDR,
.scl_speed_hz = 400000,
};
BSP_ERROR_CHECK_RETURN_ERR(i2c_master_bus_add_device(i2c_handle, &aw9523_config, &aw9523_h));
i2c_initialized = true;
return ESP_OK;
}
static esp_err_t dsp_display_brightness_init(void)
{
/* Initilize I2C */
BSP_ERROR_CHECK_RETURN_ERR(bsp_i2c_init());
const uint8_t lcd_bl_en[] = { 0x90, 0xBF }; // AXP DLDO1 Enable
ESP_RETURN_ON_ERROR(i2c_master_transmit(axp2101_h, lcd_bl_en, sizeof(lcd_bl_en), 1000), TAG, "I2C write failed");
const uint8_t lcd_bl_val[] = { 0x99, 0b00011000 }; // AXP DLDO1 voltage
ESP_RETURN_ON_ERROR(i2c_master_transmit(axp2101_h, lcd_bl_val, sizeof(lcd_bl_val), 1000), TAG, "I2C write failed");
return ESP_OK;
}
static esp_err_t bsp_spi_init(uint32_t max_transfer_sz)
{
/* SPI was initialized before */
if (spi_initialized) {
return ESP_OK;
}
ESP_LOGD(TAG, "Initialize SPI bus");
const spi_bus_config_t buscfg = {
.sclk_io_num = BSP_LCD_PCLK,
.mosi_io_num = BSP_LCD_MOSI,
.miso_io_num = BSP_LCD_MISO,
.quadwp_io_num = GPIO_NUM_NC,
.quadhd_io_num = GPIO_NUM_NC,
.max_transfer_sz = max_transfer_sz,
};
ESP_RETURN_ON_ERROR(spi_bus_initialize(BSP_LCD_SPI_NUM, &buscfg, SPI_DMA_CH_AUTO), TAG, "SPI init failed");
spi_initialized = true;
return ESP_OK;
}
/* Features */
typedef enum {
BSP_FEATURE_LCD,
BSP_FEATURE_TOUCH,
BSP_FEATURE_SD,
BSP_FEATURE_SPEAKER,
BSP_FEATURE_CAMERA,
} bsp_feature_t;
static esp_err_t bsp_enable_feature(bsp_feature_t feature)
{
esp_err_t err = ESP_OK;
static uint8_t aw9523_P0 = 0b10;
static uint8_t aw9523_P1 = 0b10100000;
uint8_t data[2];
/* Initilize I2C */
BSP_ERROR_CHECK_RETURN_ERR(bsp_i2c_init());
switch (feature) {
case BSP_FEATURE_LCD:
/* Enable LCD */
aw9523_P1 |= (1 << 1);
break;
case BSP_FEATURE_TOUCH:
/* Enable Touch */
aw9523_P0 |= (1);
break;
case BSP_FEATURE_SD:
/* AXP ALDO4 voltage / SD Card / 3V3 */
data[0] = 0x95;
data[1] = 0b00011100; //3V3
err |= i2c_master_transmit(axp2101_h, data, sizeof(data), 1000);
/* Enable SD */
aw9523_P0 |= (1 << 4);
break;
case BSP_FEATURE_SPEAKER:
/* AXP ALDO1 voltage / PA PVDD / 1V8 */
data[0] = 0x92;
data[1] = 0b00001101; //1V8
err |= i2c_master_transmit(axp2101_h, data, sizeof(data), 1000);
/* AXP ALDO2 voltage / Codec / 3V3 */
data[0] = 0x93;
data[1] = 0b00011100; //3V3
err |= i2c_master_transmit(axp2101_h, data, sizeof(data), 1000);
/* AXP ALDO3 voltage / Codec+Mic / 3V3 */
data[0] = 0x94;
data[1] = 0b00011100; //3V3
err |= i2c_master_transmit(axp2101_h, data, sizeof(data), 1000);
/* AW9523 P0 is in push-pull mode */
data[0] = 0x11;
data[1] = 0x10;
err |= i2c_master_transmit(aw9523_h, data, sizeof(data), 1000);
/* Enable Codec AW88298 */
aw9523_P0 |= (1 << 2);
break;
case BSP_FEATURE_CAMERA:
/* Enable Camera */
aw9523_P1 |= (1);
break;
}
data[0] = 0x02;
data[1] = aw9523_P0;
err |= i2c_master_transmit(aw9523_h, data, sizeof(data), 1000);
data[0] = 0x03;
data[1] = aw9523_P1;
err |= i2c_master_transmit(aw9523_h, data, sizeof(data), 1000);
return err;
}
#define LCD_CMD_BITS 8
#define LCD_PARAM_BITS 8
#define LCD_LEDC_CH CONFIG_BSP_DISPLAY_BRIGHTNESS_LEDC_CH
esp_err_t dsp_display_new(const bsp_display_config_t *config, esp_lcd_panel_handle_t *ret_panel, esp_lcd_panel_io_handle_t *ret_io)
{
esp_err_t ret = ESP_OK;
assert(config != NULL && config->max_transfer_sz > 0);
BSP_ERROR_CHECK_RETURN_ERR(bsp_enable_feature(BSP_FEATURE_LCD));
/* Initialize SPI */
ESP_RETURN_ON_ERROR(bsp_spi_init(config->max_transfer_sz), TAG, "");
ESP_LOGD(TAG, "Install panel IO");
const esp_lcd_panel_io_spi_config_t io_config = {
.dc_gpio_num = BSP_LCD_DC,
.cs_gpio_num = BSP_LCD_CS,
.pclk_hz = BSP_LCD_PIXEL_CLOCK_HZ,
.lcd_cmd_bits = LCD_CMD_BITS,
.lcd_param_bits = LCD_PARAM_BITS,
.spi_mode = 0,
.trans_queue_depth = 10,
};
ESP_GOTO_ON_ERROR(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)BSP_LCD_SPI_NUM, &io_config, ret_io), err, TAG, "New panel IO failed");
ESP_LOGD(TAG, "Install LCD driver");
const esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = BSP_LCD_RST, // Shared with Touch reset
.color_space = BSP_LCD_COLOR_SPACE,
.bits_per_pixel = BSP_LCD_BITS_PER_PIXEL,
};
ESP_GOTO_ON_ERROR(esp_lcd_new_panel_ili9341(*ret_io, &panel_config, ret_panel), err, TAG, "New panel failed");
esp_lcd_panel_reset(*ret_panel);
esp_lcd_panel_init(*ret_panel);
esp_lcd_panel_invert_color(*ret_panel, true);
return ret;
err:
if (*ret_panel) {
esp_lcd_panel_del(*ret_panel);
}
if (*ret_io) {
esp_lcd_panel_io_del(*ret_io);
}
spi_bus_free(BSP_LCD_SPI_NUM);
return ret;
}
static lv_display_t *bsp_display_lcd_init(const bsp_display_cfg_t *cfg)
{
assert(cfg != NULL);
esp_lcd_panel_io_handle_t io_handle = NULL;
esp_lcd_panel_handle_t panel_handle = NULL;
const bsp_display_config_t bsp_disp_cfg = {
.max_transfer_sz = BSP_LCD_DRAW_BUFF_SIZE * sizeof(uint16_t),
};
BSP_ERROR_CHECK_RETURN_NULL(dsp_display_new(&bsp_disp_cfg, &panel_handle, &io_handle));
esp_lcd_panel_disp_on_off(panel_handle, true);
lv_display_t *display = lv_display_create(BSP_LCD_H_RES, BSP_LCD_V_RES);
lv_display_set_user_data(display, panel_handle);
// set color depth
lv_display_set_color_format(display, LV_COLOR_FORMAT_RGB565);
return display;
}
static lv_display_t *disp;
static lv_display_t *dsp_display_start_with_config(const bsp_display_cfg_t *cfg)
{
assert(cfg != NULL);
BSP_ERROR_CHECK_RETURN_NULL(lvgl_port_init(&cfg->lvgl_port_cfg));
BSP_ERROR_CHECK_RETURN_NULL(dsp_display_brightness_init());
BSP_NULL_CHECK(disp = bsp_display_lcd_init(cfg), NULL);
return disp;
}
lv_display_t *display_init(void)
{
bsp_display_cfg_t cfg = {
.lvgl_port_cfg = ESP_LVGL_PORT_INIT_CONFIG(),
.buffer_size = BSP_LCD_DRAW_BUFF_SIZE,
.double_buffer = BSP_LCD_DRAW_BUFF_DOUBLE,
.flags = {
.buff_dma = true,
.buff_spiram = false,
}
};
cfg.lvgl_port_cfg.task_affinity = 1; /* For camera */
return dsp_display_start_with_config(&cfg);
}

View File

@@ -0,0 +1,56 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Minimal Configuration
#
CONFIG_IDF_TARGET="esp32s3"
CONFIG_COMPILER_OPTIMIZATION_PERF=y
CONFIG_I2C_ENABLE_DEBUG_LOG=y
CONFIG_I2C_ENABLE_SLAVE_DRIVER_VERSION_2=y
CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
CONFIG_SPIRAM=y
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
CONFIG_ESP_MAIN_TASK_STACK_SIZE=4096
CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=4096
CONFIG_ESP_INT_WDT=n
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=3084
CONFIG_CODEC_I2C_BACKWARD_COMPATIBLE=n
CONFIG_LV_CONF_MINIMAL=y
CONFIG_LV_USE_ASSERT_NULL=y
CONFIG_LV_USE_ASSERT_MALLOC=y
CONFIG_LV_FONT_UNSCII_8=n
CONFIG_LV_FONT_DEFAULT_MONTSERRAT_14=y
CONFIG_LV_TXT_ENC_UTF8=y
CONFIG_LV_WIDGETS_HAS_DEFAULT_VALUE=y
CONFIG_LV_USE_ANIMIMG=y
CONFIG_LV_USE_ARC=y
CONFIG_LV_USE_BUTTON=y
CONFIG_LV_USE_BUTTONMATRIX=y
CONFIG_LV_USE_CALENDAR=y
CONFIG_LV_USE_CANVAS=y
CONFIG_LV_USE_CHART=y
CONFIG_LV_USE_CHECKBOX=y
CONFIG_LV_USE_DROPDOWN=y
CONFIG_LV_USE_IMAGEBUTTON=y
CONFIG_LV_USE_KEYBOARD=y
CONFIG_LV_USE_LED=y
CONFIG_LV_USE_LINE=y
CONFIG_LV_USE_LIST=y
CONFIG_LV_USE_MENU=y
CONFIG_LV_USE_MSGBOX=y
CONFIG_LV_USE_ROLLER=y
CONFIG_LV_USE_SCALE=y
CONFIG_LV_USE_SLIDER=y
CONFIG_LV_USE_SPAN=y
CONFIG_LV_USE_SPINBOX=y
CONFIG_LV_USE_SPINNER=y
CONFIG_LV_USE_SWITCH=y
CONFIG_LV_USE_TEXTAREA=y
CONFIG_LV_USE_TABLE=y
CONFIG_LV_USE_TABVIEW=y
CONFIG_LV_USE_TILEVIEW=y
CONFIG_LV_USE_WIN=y
CONFIG_LV_USE_THEME_DEFAULT=y
CONFIG_LV_USE_THEME_SIMPLE=y
CONFIG_LV_USE_FLEX=y
CONFIG_LV_USE_GRID=y
CONFIG_LV_BUILD_EXAMPLES=y

View File

@@ -0,0 +1,8 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
add_compile_options("-Wno-format")
project(esp-dsp-m5stack-3d-kalman)

View File

@@ -0,0 +1,25 @@
# ESP-DSP M5Stack Code S3 3d graphics demo application
The demo is developed for [M5Stack Core S3 board](https://docs.m5stack.com/en/core/CoreS3) development board and is demonstrating the usage of matrices with `ESP-DSP` `Mat` class, Kalman filter and basic 3D graphics.
The demo is showing the basic use case of bmi270 and bmm150 sensors with esp-idf.
The 3D Graphics demo displays a 2D graphics, converted to 3D as a 3D rotating object, on the development board's display.
## Running the demo
To start the demo, run the following command:
idf.py build flash monitor
The expected output is the following:
I (2097) ili9341: LCD panel create success, version: 1.2.0
I (2367) 3d-kalman: bmi270 ChipID = 0x24 (should be 0x24), err = 00
I (2377) 3d-kalman: bmm150 chip ID = 0x32 (should be 0x32), err = 00
I (2387) 3d-kalman: bmi270 status = 01
I (3267) 3d-kalman: bmi270 status = 01
I (3277) 3d-kalman: bmi270 initialization is done
I (4277) 3d-kalman: Showing 3D image
I (4277) main_task: Returned from app_main()
Note, that the first line `Selected 3D image` from the expected output depends on the user's Kconfing menu selection

View File

@@ -0,0 +1,437 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "esp_log.h"
#include "bsp/m5stack_core_s3.h"
#include "esp_dsp.h"
#include "cube_matrix.h"
#include "esp_logo.h"
#include "esp_text.h"
#include "graphics_support.h"
#include "image_to_3d_matrix.h"
static const char *TAG = "3d-kalman";
dspm::Mat perspective_matrix(MATRIX_SIZE, MATRIX_SIZE);
extern "C" void app_main();
#define M5_CUBE_SIDE (BSP_LCD_V_RES / 4)
// X Y Z coordinates of the cube centered to (0, 0, 0)
const float m5_cube_vectors_3d[CUBE_POINTS][MATRIX_SIZE] =
// X Y Z W
{ {-M5_CUBE_SIDE, -M5_CUBE_SIDE, -M5_CUBE_SIDE, 1}, // -1, -1, -1
{-M5_CUBE_SIDE, -M5_CUBE_SIDE, M5_CUBE_SIDE, 1}, // -1, -1, 1
{-M5_CUBE_SIDE, M5_CUBE_SIDE, -M5_CUBE_SIDE, 1}, // -1, 1, -1
{-M5_CUBE_SIDE, M5_CUBE_SIDE, M5_CUBE_SIDE, 1}, // -1, 1, 1
{ M5_CUBE_SIDE, -M5_CUBE_SIDE, -M5_CUBE_SIDE, 1}, // 1, -1, -1
{ M5_CUBE_SIDE, -M5_CUBE_SIDE, M5_CUBE_SIDE, 1}, // 1, -1, 1
{ M5_CUBE_SIDE, M5_CUBE_SIDE, -M5_CUBE_SIDE, 1}, // 1, 1, -1
{ M5_CUBE_SIDE, M5_CUBE_SIDE, M5_CUBE_SIDE, 1} // 1, 1, 1
};
/**
* @brief Initialize 3d image structure
*
* Assigns a 3d image to be displayed to the 3d image structure based on the Kconfig menu result.
* The Kconfig menu is operated by a user
*
* @param image: 3d image structure
*/
static void init_3d_matrix_struct(image_3d_matrix_t *image)
{
image->matrix = m5_cube_vectors_3d;
image->matrix_len = ((sizeof(m5_cube_vectors_3d)) / sizeof(float)) / MATRIX_SIZE;
}
lv_style_t style_red;
lv_style_t style_blue;
lv_display_t *display = NULL;
/**
* @brief Initialize display
*/
lv_obj_t **objs;
lv_point_precise_t *points;
static i2c_master_bus_handle_t i2c_handle;
static i2c_master_dev_handle_t bmi270_h = NULL;
#define BSP_BMI270_ADDR 0x69
#define BSP_BMM150_ADDR 0x10
// i2c read/write buffers
static uint8_t i2c_read_buffer[32];
static uint8_t i2c_write_buffer[32];
// Definitions for bmi270 registers
#define BMI270_IF_CONF 0x6B // Auxiliary I2C
#define BMI270_AUX_DEV_ID 0x4B // Auxiliary I2C Device address
#define BMI270_PWR_CONF 0x7C
#define BMI270_PWR_CTRL 0x7D // Auxiliary I2C Device address
#define BMI270_CMD 0x7E // CMD
#define BMI270_AUX_IF_CONFIG 0x4C // Auxiliary I2C configuration register
#define BMI270_AUX_READ_ADDR 0x4D // Read from auxiliary device
#define BMI270_AUX_WRITE_ADDR 0x4E // Write to auxiliary device
#define BMI270_AUX_WRITE_DATA 0x4F // Write to auxiliary device
#define BMI270_AUX_STATUS 0x03
#define BMI270_AUX_DATA0 0x04
#define BMI270_ACC_DATA0 0x0C
#define BMI270_GYR_DATA0 0x12
#define BMI270_ACC_CONF 0x40
#define BMI270_ACC_RANGE 0x41
#define BMI270_GYR_CONF 0x42
#define BMI270_GYR_RANGE 0x43
#define BMI270_AUX_CONF 0x44
#define BMI270_INIT_CTRL 0x59
#define BMI270_INIT_DATA 0x5e
#define BMI270_INTERNAL_STATUS 0x21
// Definitions for bmi150 registers
#define BMM150_REG_POWER_CONTROL 0x4B
#define BMM150_SHIP_ID 0x40
#define BMM150_DATA0 0x42
// Basic fuctions to access bmi270 and bmm150
esp_err_t read_bmm150_data(uint8_t addr, uint8_t *data, int length)
{
i2c_write_buffer[0] = BMI270_AUX_READ_ADDR;
i2c_write_buffer[1] = addr;
esp_err_t err = i2c_master_transmit(bmi270_h, i2c_write_buffer, 2, 1000);
i2c_write_buffer[0] = BMI270_AUX_STATUS;
err = i2c_master_transmit_receive(bmi270_h, i2c_write_buffer, 1, data, length, 1000);
i2c_write_buffer[0] = BMI270_AUX_DATA0;
err = i2c_master_transmit_receive(bmi270_h, i2c_write_buffer, 1, data, length, 1000);
return err;
}
esp_err_t write_bmm150_data(uint8_t addr, uint8_t *data, int length)
{
i2c_write_buffer[0] = BMI270_AUX_WRITE_DATA;
i2c_write_buffer[1] = data[0];
esp_err_t err = i2c_master_transmit(bmi270_h, i2c_write_buffer, 2, 1000);
i2c_write_buffer[0] = BMI270_AUX_WRITE_ADDR;
i2c_write_buffer[1] = addr;
err = i2c_master_transmit(bmi270_h, i2c_write_buffer, 2, 1000);
return err;
}
esp_err_t write_bmi270_data(uint8_t addr, uint8_t *data, int length)
{
if (length < 32) {
i2c_write_buffer[0] = BMI270_AUX_WRITE_DATA;
for (size_t i = 0; i < length; i++) {
i2c_write_buffer[1 + i] = data[i];
}
esp_err_t err = i2c_master_transmit(bmi270_h, i2c_write_buffer, 1 + length, 1000);
return err;
}
uint8_t *temp_data = (uint8_t *)malloc(length + 4);
for (size_t i = 0; i < length; i++) {
temp_data[1 + i] = data[i];
}
temp_data[0] = addr;
esp_err_t err = i2c_master_transmit(bmi270_h, temp_data, 1 + length, 1000);
free(temp_data);
return err;
}
esp_err_t read_bmi270_data(uint8_t addr, uint8_t *data, int length)
{
i2c_write_buffer[0] = addr;
esp_err_t err = i2c_master_transmit_receive(bmi270_h, i2c_write_buffer, 1, data, length, 1000);
return err;
}
esp_err_t write_bmi270_reg(uint8_t addr, uint8_t data)
{
i2c_write_buffer[0] = addr;
i2c_write_buffer[1] = data;
esp_err_t err = i2c_master_transmit(bmi270_h, i2c_write_buffer, 2, 1000);
return err;
}
uint8_t read_bmi270_reg(uint8_t addr, esp_err_t *err)
{
i2c_write_buffer[0] = addr;
*err = i2c_master_transmit_receive(bmi270_h, i2c_write_buffer, 1, &i2c_write_buffer[16], 1, 1000);
return i2c_write_buffer[16];
}
extern "C" uint8_t bmi270_context_config_file[];
extern "C" const int bmi270_context_config_file_size;
int16_t sensors_data[32];
/**
* @brief Initialize the application.
*
* This function initialize the display 3D points and chips: mbi270 and bmm150
*
*/
static void app_init(void)
{
lv_style_init(&style_red);
lv_style_init(&style_blue);
lv_style_set_line_color(&style_red, lv_palette_main(LV_PALETTE_RED));
lv_style_set_line_width(&style_red, 10);
lv_style_set_line_rounded(&style_red, false);
lv_style_set_line_color(&style_blue, lv_palette_main(LV_PALETTE_BLUE));
lv_style_set_line_width(&style_blue, 10);
lv_style_set_line_rounded(&style_blue, false);
objs = (lv_obj_t **)malloc(CUBE_EDGES * sizeof(lv_obj_t *));
points = (lv_point_precise_t *)malloc(CUBE_EDGES * 2 * sizeof(lv_point_precise_t));
for (uint8_t cube_point = 0; cube_point < CUBE_EDGES / 2; cube_point++) {
objs[cube_point] = lv_line_create(lv_screen_active());
lv_obj_add_style(objs[cube_point], &style_red, 0);
}
for (uint8_t cube_point = CUBE_EDGES / 2; cube_point < CUBE_EDGES; cube_point++) {
objs[cube_point] = lv_line_create(lv_screen_active());
lv_obj_add_style(objs[cube_point], &style_blue, 0);
}
// Init the bmi270 and bmm150 chips
esp_err_t err = i2c_master_get_bus_handle(CONFIG_BSP_I2C_NUM, &i2c_handle);
const i2c_device_config_t bmi270_config = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = BSP_BMI270_ADDR,
.scl_speed_hz = 400000,
};
err = i2c_master_bus_add_device(i2c_handle, &bmi270_config, &bmi270_h);
vTaskDelay(10);
// Read chip ID to check the connection
i2c_write_buffer[0] = 0x00;
err = i2c_master_transmit_receive(bmi270_h, i2c_write_buffer, 1, i2c_read_buffer, 1, 1000);
ESP_LOGI(TAG, "bmi270 ChipID = 0x%2.2x (should be 0x24), err = %2.2x", i2c_read_buffer[0], err);
i2c_write_buffer[0] = BMI270_IF_CONF;
i2c_write_buffer[1] = 0x20;
err = i2c_master_transmit(bmi270_h, i2c_write_buffer, 2, 1000);
i2c_write_buffer[0] = BMI270_IF_CONF;
err = i2c_master_transmit_receive(bmi270_h, i2c_write_buffer, 1, i2c_read_buffer, 1, 1000);
i2c_write_buffer[0] = BMI270_PWR_CTRL;
i2c_write_buffer[1] = 0x0f;
err = i2c_master_transmit(bmi270_h, i2c_write_buffer, 2, 1000);
i2c_write_buffer[0] = BMI270_PWR_CTRL;
err = i2c_master_transmit_receive(bmi270_h, i2c_write_buffer, 1, i2c_read_buffer, 1, 1000);
i2c_write_buffer[0] = BMI270_AUX_IF_CONFIG;
i2c_write_buffer[1] = 0x80;
err = i2c_master_transmit(bmi270_h, i2c_write_buffer, 2, 1000);
i2c_write_buffer[0] = BMI270_AUX_IF_CONFIG;
err = i2c_master_transmit_receive(bmi270_h, i2c_write_buffer, 1, i2c_read_buffer, 1, 1000);
// vTaskDelay(1);
err = read_bmm150_data(BMM150_REG_POWER_CONTROL, i2c_read_buffer, 1);
i2c_read_buffer[0] = 1;
write_bmm150_data(BMM150_REG_POWER_CONTROL, i2c_read_buffer, 1);
read_bmm150_data(BMM150_REG_POWER_CONTROL, i2c_read_buffer, 1);
vTaskDelay(1);
err = read_bmm150_data(BMM150_SHIP_ID, i2c_read_buffer, 1);
ESP_LOGI(TAG, "bmm150 chip ID = 0x%2.2x (should be 0x32), err = %2.2x", i2c_read_buffer[0], err);
err = read_bmm150_data(0x4c, i2c_read_buffer, 1);
i2c_read_buffer[0] = 0x3 << 3;
write_bmm150_data(0x4c, i2c_read_buffer, 1);
err = read_bmm150_data(0x4c, i2c_read_buffer, 1);
vTaskDelay(1);
write_bmi270_reg(BMI270_PWR_CONF, 0);
ESP_LOGI(TAG, "bmi270 status = %2.2x", read_bmi270_reg(BMI270_INTERNAL_STATUS, &err));
vTaskDelay(10 / portTICK_PERIOD_MS);
write_bmi270_reg(BMI270_INIT_CTRL, 0x00);
err = write_bmi270_data(BMI270_INIT_DATA, bmi270_context_config_file, bmi270_context_config_file_size);
write_bmi270_reg(BMI270_INIT_CTRL, 0x01);
ESP_LOGI(TAG, "bmi270 status = %2.2x", read_bmi270_reg(BMI270_INTERNAL_STATUS, &err));
write_bmi270_reg(BMI270_PWR_CTRL, 0x0f);
write_bmi270_reg(BMI270_ACC_CONF, 0xA6);
write_bmi270_reg(BMI270_GYR_CONF, 0xA6);
write_bmi270_reg(BMI270_PWR_CONF, 0x02);
write_bmi270_reg(BMI270_AUX_CONF, 0x07);
write_bmi270_reg(BMI270_ACC_RANGE, 0x03);
write_bmi270_reg(BMI270_GYR_RANGE, 0x00);
i2c_write_buffer[0] = BMI270_IF_CONF;
i2c_write_buffer[1] = 0x00;
err = i2c_master_transmit(bmi270_h, i2c_write_buffer, 2, 1000);
i2c_write_buffer[0] = BMI270_AUX_READ_ADDR;
i2c_write_buffer[1] = BMM150_DATA0;
err = i2c_master_transmit(bmi270_h, i2c_write_buffer, 2, 1000);
i2c_write_buffer[0] = BMI270_IF_CONF;
i2c_write_buffer[1] = 0x20;
err = i2c_master_transmit(bmi270_h, i2c_write_buffer, 2, 1000);
i2c_write_buffer[0] = BMI270_AUX_IF_CONFIG;
i2c_write_buffer[1] = 0x03;
err = i2c_master_transmit(bmi270_h, i2c_write_buffer, 2, 1000);
ESP_LOGI(TAG, "bmi270 initialization is done");
}
/**
* @brief Display a 3d image
*
* If the object is the 3d cube, connect the projected cube points by lines and display the lines
* For any other 3d object lit pixels on the display from provided XY coordinates
*
* @param projected_image: 3d matrix from Mat class after projection
*/
static void display_3d_image(dspm::Mat projected_image)
{
// For the 3D cube, only the 6 points of the cube are transformed
// Cube edges, connecting transformed 3D cube points are connected with lines here
bsp_display_lock(10000);
for (uint8_t cube_point = 0; cube_point < CUBE_EDGES; cube_point++) {
points[cube_point * 2 + 0].x = (int16_t)projected_image(cube_dict_line_begin[cube_point], 0);
points[cube_point * 2 + 0].y = (int16_t)projected_image(cube_dict_line_begin[cube_point], 1);
points[cube_point * 2 + 1].x = (int16_t)projected_image(cube_dict_line_end[cube_point], 0);
points[cube_point * 2 + 1].y = (int16_t)projected_image(cube_dict_line_end[cube_point], 1);
lv_line_set_points(objs[cube_point], &points[cube_point * 2 + 0], 2);
lv_obj_set_pos(objs[cube_point], 0, 0);
}
bsp_display_unlock();
}
ekf_imu13states *ekf13 = NULL;
/**
* @brief RTOS task to draw a 3d image.
*
* Updates 3d matrices, prepares the final 3d matrix to be displayed on the display
*
* @param arg: pointer to RTOS task arguments, 3d image structure in this case
*/
static void draw_3d_image_task(void *arg)
{
image_3d_matrix_t *image = (image_3d_matrix_t *)arg;
dspm::Mat T = dspm::Mat::eye(MATRIX_SIZE); // Transformation matrix
dspm::Mat transformed_image(image->matrix_len, MATRIX_SIZE); // 3D image matrix after transformation
dspm::Mat projected_image(image->matrix_len, MATRIX_SIZE); // 3D image matrix after projection
dspm::Mat matrix_3d((float *)image->matrix[0], image->matrix_len, MATRIX_SIZE);
float dt = 0;
static float prev_time = 0;
float current_time = dsp_get_cpu_cycle_count();
float R_m[6] = {0.01, 0.01, 0.01, 0.01, 0.01, 0.01};
float magn_norm = 1;
while (1) {
esp_err_t err;
// Calculate dt for kalman filter
current_time = dsp_get_cpu_cycle_count();
if (current_time > prev_time) {
dt = current_time - prev_time;
dt = dt / 240000000.0;
}
prev_time = current_time;
// Read and convert data from bmi270 and bmm150 sensors
err = read_bmi270_data(BMI270_AUX_DATA0, (uint8_t *)sensors_data, 20);
float accel[3];
float gyro[3];
float magn[3];
for (size_t i = 0; i < 3; i++) {
magn[i] = sensors_data[i];
accel[i] = sensors_data[4 + i];
gyro[i] = sensors_data[7 + i];
/* code */
}
// We have to apply this because initial direction of sensors
magn[1] = -magn[1];
accel[1] = -accel[1];
gyro[1] = -gyro[1];
magn[2] = -magn[2];
accel[2] = -accel[2];
gyro[2] = -gyro[2];
dspm::Mat gyro_input_mat(gyro, 3, 1);
dspm::Mat accel_input_mat(accel, 3, 1);
dspm::Mat mag_input_mat(magn, 3, 1);
// Accelerometer has 166 max range fit to the int16 value
accel_input_mat = accel_input_mat / 32768 * 16;
if (magn_norm < mag_input_mat.norm()) {
magn_norm = mag_input_mat.norm();
}
mag_input_mat = (1 / magn_norm) * mag_input_mat;
// range 2000 gedree/sec fit to the int16 range
gyro_input_mat *= (2000 * DEG_TO_RAD / 32768);
ekf13->Process(gyro_input_mat.data, dt);
ekf13->UpdateRefMeasurementMagn(accel_input_mat.data, mag_input_mat.data, R_m);
// Convert directin quaternion to rotation matrix
dspm::Mat R1 = ekf::quat2rotm(ekf13->X.data).t(); // matrix(3x1) that holds x, y, z rotation data
// Convert rotation matrix to Euler angels
dspm::Mat eul_angles = ekf::rotm2eul(R1);
// Apply radian to degree
eul_angles *= RAD_TO_DEG;
// Apply rotation in all the axes to the transformation matrix
update_rotation_matrix(T, eul_angles(0, 0), eul_angles(1, 0), eul_angles(2, 0));
// Apply translation to the transformation matrix
update_translation_matrix(T, true, ((float)BSP_LCD_H_RES / 2), ((float)BSP_LCD_V_RES / 2), 0);
// matrix mul cube_matirx(8x4) * transformation_matrix(4x4) = transformed_cube(8x4)
transformed_image = matrix_3d * T;
// matrix mul transformed_cube(8x4) * perspective_matrix(4x4) = projected_cube(8x4)
projected_image = transformed_image * perspective_matrix;
display_3d_image(projected_image);
vTaskDelay(5 / portTICK_PERIOD_MS);
}
}
image_3d_matrix_t image;
void app_main(void)
{
ekf13 = new ekf_imu13states();
ekf13->Init();
// Init all board components
display = bsp_display_start();
init_perspective_matrix(perspective_matrix);
init_3d_matrix_struct(&image);
app_init();
vTaskDelay(1000 / portTICK_PERIOD_MS);
xTaskCreate(draw_3d_image_task, "draw_3d_image", 16384, &image, 4, NULL);
ESP_LOGI(TAG, "Showing 3D image");
}

View File

@@ -0,0 +1,11 @@
idf_component_register(SRCS "3d_kalman_demo.cpp"
"bmi270_context.c"
"../../../../azure_board_apps/graphics/3d_matrix/3d_matrix_data/esp_logo.c"
"../../../../azure_board_apps/graphics/3d_matrix/3d_matrix_data/esp_text.c"
"../../../../azure_board_apps/graphics/3d_matrix/3d_matrix_data/image_to_3d_matrix.c"
"../../../../azure_board_apps/graphics/3d_matrix/3d_matrix_src/graphics_support.cpp"
INCLUDE_DIRS "."
"../../../../azure_board_apps/graphics/3d_matrix/3d_matrix_data"
"../../../../azure_board_apps/graphics/3d_matrix/3d_matrix_src")
add_compile_definitions(CONFIG_3D_OBJECT_CUBE=y)

View File

@@ -0,0 +1,444 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
const uint8_t bmi270_context_config_file[] = {
0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x00, 0xb0, 0xc8, 0x2e, 0x00, 0x2e, 0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0xc9,
0x01, 0x80, 0x2e, 0xe2, 0x00, 0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x77, 0xb0, 0x50, 0x30, 0x21, 0x2e, 0x59, 0xf5,
0x10, 0x30, 0x21, 0x2e, 0x6a, 0xf5, 0x80, 0x2e, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x09, 0x01, 0x00, 0x22,
0x00, 0x76, 0x00, 0x00, 0x10, 0x00, 0x10, 0xd1, 0x00, 0xcb, 0xa7, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0xfd, 0x2d, 0x2c, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x24, 0x22, 0x00, 0x80, 0x2e, 0x48, 0x02, 0x01, 0x2e, 0x49,
0xf1, 0x0b, 0xbc, 0x10, 0x50, 0x0f, 0xb8, 0x00, 0x90, 0xfb, 0x7f, 0x07, 0x2f, 0x03, 0x2e, 0x21, 0xf2, 0x02, 0x31,
0x4a, 0x0a, 0x23, 0x2e, 0x21, 0xf2, 0x09, 0x2c, 0x00, 0x30, 0x98, 0x2e, 0x0e, 0xc7, 0x03, 0x2e, 0x21, 0xf2, 0xf2,
0x3e, 0x4a, 0x08, 0x23, 0x2e, 0x21, 0xf2, 0xfb, 0x6f, 0xf0, 0x5f, 0xb8, 0x2e, 0x13, 0x52, 0x00, 0x2e, 0x60, 0x40,
0x41, 0x40, 0x0d, 0xbc, 0x98, 0xbc, 0xc0, 0x2e, 0x01, 0x0a, 0x0f, 0xb8, 0x43, 0x86, 0x25, 0x40, 0x04, 0x40, 0xd8,
0xbe, 0x2c, 0x0b, 0x22, 0x11, 0x54, 0x42, 0x03, 0x80, 0x4b, 0x0e, 0xf6, 0x2f, 0xb8, 0x2e, 0x20, 0x50, 0xe7, 0x7f,
0xf6, 0x7f, 0x46, 0x30, 0x0f, 0x2e, 0xa4, 0xf1, 0xbe, 0x09, 0x80, 0xb3, 0x06, 0x2f, 0x0d, 0x2e, 0x84, 0x00, 0x84,
0xaf, 0x02, 0x2f, 0x16, 0x30, 0x2d, 0x2e, 0x7b, 0x00, 0x86, 0x30, 0x2d, 0x2e, 0x60, 0xf5, 0xf6, 0x6f, 0xe7, 0x6f,
0xe0, 0x5f, 0xc8, 0x2e, 0x80, 0x2e, 0xfb, 0x00, 0x00, 0x30, 0xc0, 0x2e, 0x21, 0x2e, 0x8d, 0x00, 0x44, 0x47, 0x99,
0x00, 0xff, 0x3f, 0x00, 0x0c, 0xff, 0x0f, 0x00, 0x04, 0xc0, 0x00, 0x5b, 0xf5, 0x90, 0x00, 0x1e, 0xf2, 0xfd, 0xf5,
0x8e, 0x00, 0x96, 0x00, 0x96, 0x00, 0xe0, 0x00, 0x19, 0xf4, 0x66, 0xf5, 0x00, 0x18, 0x64, 0xf5, 0x9d, 0x00, 0x7f,
0x00, 0x81, 0x00, 0xae, 0x00, 0xff, 0xfb, 0x21, 0x02, 0x00, 0x10, 0x00, 0x40, 0xff, 0x00, 0x00, 0x80, 0xff, 0x7f,
0x54, 0x0f, 0xeb, 0x00, 0x7f, 0xff, 0xc2, 0xf5, 0x68, 0xf7, 0xb3, 0xf1, 0x4e, 0x0f, 0x42, 0x0f, 0x48, 0x0f, 0x80,
0x00, 0x67, 0x0f, 0x58, 0xf7, 0x5b, 0xf7, 0x6a, 0x0f, 0x86, 0x00, 0x59, 0x0f, 0x6c, 0x0f, 0xc6, 0xf1, 0x66, 0x0f,
0x6c, 0xf7, 0x00, 0xe0, 0x00, 0xff, 0xd1, 0xf5, 0x6e, 0x0f, 0x71, 0x0f, 0xff, 0x03, 0x00, 0xfc, 0xf0, 0x3f, 0xb9,
0x00, 0x2d, 0xf5, 0xca, 0xf5, 0x8a, 0x00, 0x00, 0x08, 0x71, 0x7d, 0xfe, 0xc0, 0x03, 0x3f, 0x05, 0x3e, 0x49, 0x01,
0x92, 0x02, 0xf5, 0xd6, 0xe8, 0x63, 0xd3, 0xf8, 0x2e, 0x07, 0x5c, 0xce, 0xa5, 0x67, 0x28, 0x02, 0x4e, 0x01, 0x00,
0xf0, 0x33, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x50, 0x10,
0x50, 0x17, 0x52, 0x05, 0x2e, 0x7d, 0x00, 0xfb, 0x7f, 0x00, 0x2e, 0x13, 0x40, 0x93, 0x42, 0x41, 0x0e, 0xfb, 0x2f,
0x98, 0x2e, 0x91, 0x03, 0x98, 0x2e, 0x87, 0xcf, 0x01, 0x2e, 0x89, 0x00, 0x00, 0xb2, 0x08, 0x2f, 0x01, 0x2e, 0x69,
0xf7, 0xb1, 0x3f, 0x01, 0x08, 0x01, 0x30, 0x23, 0x2e, 0x89, 0x00, 0x21, 0x2e, 0x69, 0xf7, 0xfb, 0x6f, 0xf0, 0x5f,
0xb8, 0x2e, 0xa0, 0x50, 0x80, 0x7f, 0xe7, 0x7f, 0xd5, 0x7f, 0xc4, 0x7f, 0xb3, 0x7f, 0xa2, 0x7f, 0x91, 0x7f, 0xf6,
0x7f, 0x7b, 0x7f, 0x00, 0x2e, 0x01, 0x2e, 0x60, 0xf5, 0x60, 0x7f, 0x98, 0x2e, 0xce, 0x00, 0x62, 0x6f, 0x01, 0x32,
0x91, 0x08, 0x80, 0xb2, 0x11, 0x2f, 0x00, 0xb2, 0x03, 0x2f, 0x05, 0x2e, 0x18, 0x00, 0x80, 0x90, 0x09, 0x2f, 0x60,
0x7f, 0x98, 0x2e, 0xf9, 0x00, 0x23, 0x50, 0x01, 0x32, 0x01, 0x42, 0x02, 0x86, 0x60, 0x6f, 0x02, 0x30, 0xc2, 0x42,
0x23, 0x2e, 0x60, 0xf5, 0x00, 0x90, 0x00, 0x30, 0x01, 0x2f, 0x21, 0x2e, 0x7a, 0x00, 0xf6, 0x6f, 0x91, 0x6f, 0xa2,
0x6f, 0xb3, 0x6f, 0xc4, 0x6f, 0xd5, 0x6f, 0xe7, 0x6f, 0x7b, 0x6f, 0x80, 0x6f, 0x60, 0x5f, 0xc8, 0x2e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x01, 0xd4, 0x7b, 0x3b,
0x01, 0xdb, 0x7a, 0x04, 0x00, 0x3f, 0x7b, 0xcd, 0x6c, 0xc3, 0x04, 0x85, 0x09, 0xc3, 0x04, 0xec, 0xe6, 0x0c, 0x46,
0x01, 0x00, 0x27, 0x00, 0x19, 0x00, 0x96, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x0c, 0x00, 0xf0, 0x3c, 0x00, 0x01, 0x01,
0x00, 0x03, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0xe1, 0x06, 0x66, 0x0a, 0x0a, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x50, 0x98, 0x2e, 0xd7, 0x0e, 0x50, 0x32, 0x98, 0x2e,
0x48, 0x03, 0x10, 0x30, 0x21, 0x2e, 0x21, 0xf2, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x2e, 0xd0, 0x2e, 0x00, 0x2e, 0x01,
0x80, 0x06, 0xa2, 0xfb, 0x2f, 0x01, 0x2e, 0x9c, 0x00, 0x00, 0xb2, 0x10, 0x2f, 0x01, 0x2e, 0x18, 0x00, 0x00, 0xb2,
0x0c, 0x2f, 0x01, 0x54, 0x03, 0x52, 0x01, 0x50, 0x98, 0x2e, 0xc2, 0xc0, 0x98, 0x2e, 0xf5, 0xb0, 0x01, 0x50, 0x98,
0x2e, 0xd5, 0xb6, 0x10, 0x30, 0x21, 0x2e, 0x19, 0x00, 0x01, 0x2e, 0x84, 0x00, 0x04, 0xae, 0x0b, 0x2f, 0x01, 0x2e,
0x9c, 0x00, 0x00, 0xb2, 0x07, 0x2f, 0x01, 0x52, 0x98, 0x2e, 0x8e, 0x0e, 0x00, 0xb2, 0x02, 0x2f, 0x10, 0x30, 0x21,
0x2e, 0x79, 0x00, 0x01, 0x2e, 0x79, 0x00, 0x00, 0x90, 0x90, 0x2e, 0x14, 0x03, 0x01, 0x2e, 0x87, 0x00, 0x00, 0xb2,
0x04, 0x2f, 0x98, 0x2e, 0x2f, 0x0e, 0x00, 0x30, 0x21, 0x2e, 0x7b, 0x00, 0x01, 0x2e, 0x7b, 0x00, 0x00, 0xb2, 0x12,
0x2f, 0x01, 0x2e, 0x84, 0x00, 0x00, 0x90, 0x02, 0x2f, 0x98, 0x2e, 0x1f, 0x0e, 0x09, 0x2d, 0x98, 0x2e, 0x81, 0x0d,
0x01, 0x2e, 0x84, 0x00, 0x04, 0x90, 0x02, 0x2f, 0x50, 0x32, 0x98, 0x2e, 0x48, 0x03, 0x00, 0x30, 0x21, 0x2e, 0x7b,
0x00, 0x01, 0x2e, 0x78, 0x00, 0x00, 0xb2, 0x90, 0x2e, 0x2c, 0x03, 0x01, 0x2e, 0x78, 0x00, 0x81, 0x30, 0x01, 0x08,
0x00, 0xb2, 0x61, 0x2f, 0x03, 0x2e, 0x24, 0x02, 0x01, 0x2e, 0x84, 0x00, 0x98, 0xbc, 0x98, 0xb8, 0x05, 0xb2, 0x0d,
0x58, 0x23, 0x2f, 0x07, 0x90, 0x07, 0x54, 0x00, 0x30, 0x37, 0x2f, 0x15, 0x41, 0x04, 0x41, 0xdc, 0xbe, 0x44, 0xbe,
0xdc, 0xba, 0x2c, 0x01, 0x61, 0x00, 0x0d, 0x56, 0x4a, 0x0f, 0x0c, 0x2f, 0xd1, 0x42, 0x94, 0xb8, 0xc1, 0x42, 0x11,
0x30, 0x05, 0x2e, 0x6a, 0xf7, 0x2c, 0xbd, 0x2f, 0xb9, 0x80, 0xb2, 0x08, 0x22, 0x98, 0x2e, 0xaf, 0x03, 0x21, 0x2d,
0x61, 0x30, 0x23, 0x2e, 0x84, 0x00, 0x98, 0x2e, 0xaf, 0x03, 0x00, 0x30, 0x21, 0x2e, 0x5a, 0xf5, 0x18, 0x2d, 0xf1,
0x7f, 0x50, 0x30, 0x98, 0x2e, 0x48, 0x03, 0x0d, 0x52, 0x05, 0x50, 0x50, 0x42, 0x70, 0x30, 0x0b, 0x54, 0x42, 0x42,
0x7e, 0x82, 0xf2, 0x6f, 0x80, 0xb2, 0x42, 0x42, 0x05, 0x2f, 0x21, 0x2e, 0x84, 0x00, 0x10, 0x30, 0x98, 0x2e, 0xaf,
0x03, 0x03, 0x2d, 0x60, 0x30, 0x21, 0x2e, 0x84, 0x00, 0x01, 0x2e, 0x84, 0x00, 0x06, 0x90, 0x18, 0x2f, 0x01, 0x2e,
0x77, 0x00, 0x09, 0x54, 0x05, 0x52, 0xf0, 0x7f, 0x98, 0x2e, 0x7a, 0xc1, 0xf1, 0x6f, 0x08, 0x1a, 0x40, 0x30, 0x08,
0x2f, 0x21, 0x2e, 0x84, 0x00, 0x20, 0x30, 0x98, 0x2e, 0x9b, 0x03, 0x50, 0x32, 0x98, 0x2e, 0x48, 0x03, 0x05, 0x2d,
0x98, 0x2e, 0x38, 0x0e, 0x00, 0x30, 0x21, 0x2e, 0x84, 0x00, 0x00, 0x30, 0x21, 0x2e, 0x78, 0x00, 0x18, 0x2d, 0x01,
0x2e, 0x84, 0x00, 0x03, 0xaa, 0x01, 0x2f, 0x98, 0x2e, 0x45, 0x0e, 0x01, 0x2e, 0x84, 0x00, 0x3f, 0x80, 0x03, 0xa2,
0x01, 0x2f, 0x00, 0x2e, 0x02, 0x2d, 0x98, 0x2e, 0x5b, 0x0e, 0x30, 0x30, 0x98, 0x2e, 0xba, 0x03, 0x00, 0x30, 0x21,
0x2e, 0x79, 0x00, 0x50, 0x32, 0x98, 0x2e, 0x48, 0x03, 0x01, 0x2e, 0x19, 0x00, 0x00, 0xb2, 0x10, 0x2f, 0x01, 0x2e,
0x85, 0x00, 0x21, 0x2e, 0x90, 0x00, 0x0f, 0x52, 0x7e, 0x82, 0x11, 0x50, 0x41, 0x40, 0x18, 0xb9, 0x11, 0x42, 0x02,
0x42, 0x02, 0x80, 0x00, 0x2e, 0x01, 0x40, 0x01, 0x42, 0x98, 0x2e, 0xaa, 0x01, 0x00, 0x30, 0x21, 0x2e, 0x19, 0x00,
0x21, 0x2e, 0x9c, 0x00, 0x80, 0x2e, 0x52, 0x02, 0x21, 0x2e, 0x59, 0xf5, 0x10, 0x30, 0xc0, 0x2e, 0x21, 0x2e, 0x4a,
0xf1, 0x80, 0x2e, 0x00, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x01,
0x34, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0x2e, 0x7d, 0x00, 0x16, 0xb8, 0x02, 0x34, 0x4a, 0x0c, 0x21, 0x2e, 0x2d, 0xf5, 0xc0, 0x2e, 0x23,
0x2e, 0x7d, 0x00, 0x03, 0xbc, 0x21, 0x2e, 0x85, 0x00, 0x03, 0x2e, 0x85, 0x00, 0x40, 0xb2, 0x10, 0x30, 0x21, 0x2e,
0x19, 0x00, 0x01, 0x30, 0x05, 0x2f, 0x05, 0x2e, 0x88, 0x00, 0x80, 0x90, 0x01, 0x2f, 0x23, 0x2e, 0x6f, 0xf5, 0xc0,
0x2e, 0x21, 0x2e, 0x89, 0x00, 0x11, 0x30, 0x81, 0x08, 0x01, 0x2e, 0x6a, 0xf7, 0x71, 0x3f, 0x23, 0xbd, 0x01, 0x08,
0x02, 0x0a, 0xc0, 0x2e, 0x21, 0x2e, 0x6a, 0xf7, 0x30, 0x25, 0x00, 0x30, 0x21, 0x2e, 0x5a, 0xf5, 0x10, 0x50, 0x21,
0x2e, 0x7b, 0x00, 0x21, 0x2e, 0x78, 0x00, 0xfb, 0x7f, 0x98, 0x2e, 0xaf, 0x03, 0x40, 0x30, 0x21, 0x2e, 0x84, 0x00,
0xfb, 0x6f, 0xf0, 0x5f, 0x03, 0x25, 0x80, 0x2e, 0x9b, 0x03, 0x0b, 0x00, 0x94, 0x02, 0x14, 0x24, 0x80, 0x00, 0x04,
0x00, 0x04, 0x30, 0x08, 0xb8, 0x94, 0x02, 0xc0, 0x2e, 0x28, 0xbd, 0x02, 0x0a, 0x0d, 0x82, 0x02, 0x30, 0x12, 0x42,
0x41, 0x0e, 0xfc, 0x2f, 0xb8, 0x2e, 0x95, 0x50, 0xc0, 0x2e, 0x21, 0x2e, 0xa9, 0x01, 0x02, 0x30, 0x02, 0x2c, 0x41,
0x00, 0x12, 0x42, 0x41, 0x0e, 0xfc, 0x2f, 0xb8, 0x2e, 0x13, 0x82, 0x02, 0x30, 0x12, 0x42, 0x41, 0x0e, 0xfc, 0x2f,
0x3f, 0x80, 0xa1, 0x30, 0xc0, 0x2e, 0x01, 0x42, 0x00, 0x2e, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0xc0, 0x50, 0xe7, 0x7f,
0xf6, 0x7f, 0x26, 0x30, 0x0f, 0x2e, 0x61, 0xf5, 0x2f, 0x2e, 0x78, 0x00, 0x0f, 0x2e, 0x78, 0x00, 0xbe, 0x09, 0xa2,
0x7f, 0x80, 0x7f, 0x80, 0xb3, 0xd5, 0x7f, 0xc4, 0x7f, 0xb3, 0x7f, 0x91, 0x7f, 0x7b, 0x7f, 0x0b, 0x2f, 0x19, 0x50,
0x1a, 0x25, 0x12, 0x40, 0x42, 0x7f, 0x74, 0x82, 0x12, 0x40, 0x52, 0x7f, 0x00, 0x2e, 0x00, 0x40, 0x60, 0x7f, 0x98,
0x2e, 0x6a, 0xd6, 0x81, 0x30, 0x01, 0x2e, 0x78, 0x00, 0x01, 0x08, 0x00, 0xb2, 0x42, 0x2f, 0x03, 0x2e, 0x24, 0x02,
0x01, 0x2e, 0x24, 0x02, 0x97, 0xbc, 0x06, 0xbc, 0x9f, 0xb8, 0x0f, 0xb8, 0x00, 0x90, 0x23, 0x2e, 0x88, 0x00, 0x10,
0x30, 0x01, 0x30, 0x2a, 0x2f, 0x03, 0x2e, 0x84, 0x00, 0x44, 0xb2, 0x05, 0x2f, 0x47, 0xb2, 0x00, 0x30, 0x2d, 0x2f,
0x21, 0x2e, 0x78, 0x00, 0x2b, 0x2d, 0x03, 0x2e, 0xfd, 0xf5, 0x9e, 0xbc, 0x9f, 0xb8, 0x40, 0x90, 0x14, 0x2f, 0x03,
0x2e, 0xfc, 0xf5, 0x99, 0xbc, 0x9f, 0xb8, 0x40, 0x90, 0x0e, 0x2f, 0x03, 0x2e, 0x49, 0xf1, 0x1b, 0x54, 0x4a, 0x08,
0x40, 0x90, 0x08, 0x2f, 0x98, 0x2e, 0xce, 0x00, 0x00, 0xb2, 0x10, 0x30, 0x03, 0x2f, 0x50, 0x30, 0x21, 0x2e, 0x84,
0x00, 0x10, 0x2d, 0x98, 0x2e, 0x9b, 0x03, 0x00, 0x30, 0x21, 0x2e, 0x78, 0x00, 0x0a, 0x2d, 0x05, 0x2e, 0x69, 0xf7,
0x2d, 0xbd, 0x2f, 0xb9, 0x80, 0xb2, 0x01, 0x2f, 0x21, 0x2e, 0x79, 0x00, 0x23, 0x2e, 0x78, 0x00, 0xe0, 0x31, 0x21,
0x2e, 0x61, 0xf5, 0xf6, 0x6f, 0xe7, 0x6f, 0x80, 0x6f, 0xa2, 0x6f, 0xb3, 0x6f, 0xc4, 0x6f, 0xd5, 0x6f, 0x7b, 0x6f,
0x91, 0x6f, 0x40, 0x5f, 0xc8, 0x2e, 0x90, 0x50, 0xf7, 0x7f, 0xe6, 0x7f, 0xd5, 0x7f, 0xc4, 0x7f, 0xb3, 0x7f, 0xa1,
0x7f, 0x90, 0x7f, 0x82, 0x7f, 0x7b, 0x7f, 0x98, 0x2e, 0xce, 0x00, 0x00, 0xb2, 0x10, 0x30, 0x49, 0x2f, 0x05, 0x2e,
0x21, 0x02, 0x03, 0x2e, 0x2d, 0x02, 0x21, 0x56, 0x08, 0x08, 0x93, 0x08, 0x90, 0x0a, 0x25, 0x2e, 0x18, 0x00, 0x05,
0x2e, 0xc1, 0xf5, 0x2e, 0xbc, 0x05, 0x2e, 0x84, 0x00, 0x84, 0xa2, 0x0e, 0xb8, 0x31, 0x30, 0x88, 0x04, 0x03, 0x2f,
0x01, 0x2e, 0x18, 0x00, 0x00, 0xb2, 0x0c, 0x2f, 0x1d, 0x50, 0x01, 0x52, 0x98, 0x2e, 0xd7, 0x00, 0x05, 0x2e, 0x7a,
0x00, 0x80, 0x90, 0x02, 0x2f, 0x10, 0x30, 0x21, 0x2e, 0x7a, 0x00, 0x25, 0x2e, 0x9c, 0x00, 0x05, 0x2e, 0x18, 0x00,
0x80, 0xb2, 0x20, 0x2f, 0x01, 0x2e, 0xc0, 0xf5, 0xf2, 0x30, 0x02, 0x08, 0x07, 0xaa, 0x73, 0x30, 0x03, 0x2e, 0x7c,
0x00, 0x18, 0x22, 0x41, 0x1a, 0x05, 0x2f, 0x03, 0x2e, 0x66, 0xf5, 0x9f, 0xbc, 0x9f, 0xb8, 0x40, 0x90, 0x0c, 0x2f,
0x1f, 0x52, 0x03, 0x30, 0x53, 0x42, 0x2b, 0x30, 0x90, 0x04, 0x5b, 0x42, 0x21, 0x2e, 0x7c, 0x00, 0x24, 0xbd, 0x7e,
0x80, 0x81, 0x84, 0x43, 0x42, 0x02, 0x42, 0x02, 0x32, 0x25, 0x2e, 0x62, 0xf5, 0x05, 0x2e, 0x86, 0x00, 0x81, 0x84,
0x25, 0x2e, 0x86, 0x00, 0x02, 0x31, 0x25, 0x2e, 0x60, 0xf5, 0x05, 0x2e, 0x25, 0x02, 0x10, 0x30, 0x90, 0x08, 0x80,
0xb2, 0x0b, 0x2f, 0x05, 0x2e, 0xca, 0xf5, 0xf0, 0x3e, 0x90, 0x08, 0x25, 0x2e, 0xca, 0xf5, 0x05, 0x2e, 0x59, 0xf5,
0xe0, 0x3f, 0x90, 0x08, 0x25, 0x2e, 0x59, 0xf5, 0x90, 0x6f, 0xa1, 0x6f, 0xb3, 0x6f, 0xc4, 0x6f, 0xd5, 0x6f, 0xe6,
0x6f, 0xf7, 0x6f, 0x7b, 0x6f, 0x82, 0x6f, 0x70, 0x5f, 0xc8, 0x2e, 0x2f, 0x52, 0x90, 0x50, 0x53, 0x40, 0x4a, 0x25,
0x40, 0x40, 0x39, 0x8b, 0xfb, 0x7f, 0x0c, 0xbc, 0x21, 0x52, 0x37, 0x89, 0x0b, 0x30, 0x59, 0x08, 0x0c, 0xb8, 0xe0,
0x7f, 0x8b, 0x7f, 0x4b, 0x43, 0x0b, 0x43, 0x40, 0xb2, 0xd1, 0x7f, 0x6e, 0x2f, 0x01, 0x2e, 0x83, 0x00, 0x00, 0xb2,
0x0e, 0x2f, 0x25, 0x52, 0x01, 0x2e, 0x7e, 0x00, 0xc3, 0x7f, 0xb4, 0x7f, 0xa5, 0x7f, 0x98, 0x2e, 0xbb, 0xcc, 0x05,
0x30, 0x2b, 0x2e, 0x83, 0x00, 0xc3, 0x6f, 0xd1, 0x6f, 0xb4, 0x6f, 0xa5, 0x6f, 0x36, 0xbc, 0x06, 0xb9, 0x35, 0xbc,
0x0f, 0xb8, 0x94, 0xb0, 0xc6, 0x7f, 0x00, 0xb2, 0x0c, 0x2f, 0x27, 0x50, 0x29, 0x56, 0x0b, 0x30, 0x05, 0x2e, 0x21,
0x02, 0x2d, 0x5c, 0x1b, 0x42, 0xdb, 0x42, 0x96, 0x08, 0x25, 0x2e, 0x21, 0x02, 0x0b, 0x42, 0xcb, 0x42, 0x00, 0x2e,
0x31, 0x56, 0xcb, 0x08, 0x25, 0x52, 0x01, 0x2e, 0x7e, 0x00, 0x01, 0x54, 0x2b, 0x5c, 0x98, 0x2e, 0x06, 0xcd, 0xd2,
0x6f, 0x27, 0x5a, 0x94, 0x6f, 0xa4, 0xbc, 0x53, 0x41, 0x00, 0xb3, 0x1f, 0xb8, 0x44, 0x41, 0x01, 0x30, 0xd5, 0x7f,
0x05, 0x2f, 0x00, 0xb2, 0x03, 0x2f, 0x29, 0x5c, 0x11, 0x30, 0x93, 0x43, 0x84, 0x43, 0x23, 0xbd, 0x2f, 0xb9, 0x80,
0xb2, 0x1c, 0x2f, 0x72, 0x6f, 0xda, 0x00, 0x82, 0x6f, 0x22, 0x03, 0x44, 0x43, 0x00, 0x90, 0x27, 0x2e, 0x7f, 0x00,
0x29, 0x5a, 0x12, 0x2f, 0x29, 0x54, 0x00, 0x2e, 0x90, 0x40, 0x82, 0x40, 0x18, 0x04, 0xa2, 0x06, 0x80, 0xaa, 0x04,
0x2f, 0x80, 0x90, 0x08, 0x2f, 0xc2, 0x6f, 0x50, 0x0f, 0x05, 0x2f, 0xc0, 0x6f, 0x00, 0xb2, 0x02, 0x2f, 0x53, 0x43,
0x44, 0x43, 0x11, 0x30, 0xe0, 0x6f, 0x98, 0x2e, 0x95, 0xcf, 0xd1, 0x6f, 0x15, 0x5a, 0x09, 0x2e, 0x7f, 0x00, 0x41,
0x40, 0x54, 0x43, 0x08, 0x2c, 0x41, 0x43, 0x15, 0x30, 0x2b, 0x2e, 0x83, 0x00, 0x01, 0x30, 0xe0, 0x6f, 0x98, 0x2e,
0x95, 0xcf, 0x00, 0x2e, 0xfb, 0x6f, 0x70, 0x5f, 0xb8, 0x2e, 0x50, 0x86, 0xcd, 0x88, 0x34, 0x85, 0xc5, 0x40, 0x91,
0x40, 0x8c, 0x80, 0x06, 0x41, 0x13, 0x40, 0x50, 0x50, 0x6e, 0x01, 0x82, 0x40, 0x04, 0x40, 0x34, 0x8c, 0xfb, 0x7f,
0x98, 0x2e, 0xce, 0x03, 0xe0, 0x7f, 0x00, 0x2e, 0x91, 0x41, 0x8c, 0x81, 0x82, 0x41, 0x13, 0x40, 0x04, 0x40, 0x34,
0x8e, 0x98, 0x2e, 0xce, 0x03, 0xc0, 0x7f, 0xd5, 0x7f, 0x13, 0x24, 0xff, 0x00, 0xd6, 0x41, 0xcc, 0x83, 0xc2, 0x41,
0x57, 0x40, 0x74, 0x80, 0x44, 0x40, 0x11, 0x40, 0x0c, 0x8a, 0xf7, 0x01, 0x94, 0x03, 0x12, 0x24, 0x80, 0x00, 0x3a,
0x01, 0x02, 0x30, 0xb2, 0x03, 0xce, 0x17, 0xfb, 0x08, 0x23, 0x01, 0xb2, 0x02, 0x48, 0xbb, 0x28, 0xbd, 0xf2, 0x0b,
0x53, 0x41, 0x02, 0x40, 0x44, 0x41, 0x74, 0x8d, 0xb7, 0x7f, 0x98, 0x2e, 0xce, 0x03, 0x50, 0x25, 0x91, 0x41, 0x8c,
0x81, 0x82, 0x41, 0x13, 0x40, 0x04, 0x40, 0x34, 0x8e, 0x98, 0x2e, 0xce, 0x03, 0x60, 0x25, 0xd1, 0x41, 0xcc, 0x81,
0xc2, 0x41, 0x13, 0x40, 0x04, 0x40, 0x98, 0x2e, 0xce, 0x03, 0x11, 0x24, 0xb3, 0x00, 0x71, 0x0e, 0xd3, 0x6f, 0xe1,
0x6f, 0x33, 0x2f, 0x12, 0x24, 0xdd, 0x00, 0xda, 0x0f, 0x2b, 0x2f, 0x12, 0x24, 0x8c, 0x00, 0x5a, 0x0e, 0x09, 0x2f,
0x10, 0x24, 0x83, 0x05, 0x48, 0x0e, 0x11, 0x24, 0x7f, 0x22, 0x10, 0x24, 0x18, 0x32, 0x08, 0x22, 0x80, 0x2e, 0xd7,
0xb4, 0x13, 0x24, 0xf4, 0x00, 0x73, 0x0e, 0x0f, 0x2f, 0x10, 0x24, 0x11, 0x10, 0x68, 0x0e, 0x10, 0x24, 0xa2, 0x30,
0x13, 0x24, 0x97, 0x23, 0x03, 0x22, 0x13, 0x24, 0x3b, 0x04, 0x4b, 0x0e, 0x11, 0x24, 0x0f, 0x30, 0x01, 0x22, 0x80,
0x2e, 0xd7, 0xb4, 0x11, 0x24, 0x53, 0x02, 0x41, 0x0e, 0x11, 0x24, 0xe7, 0x31, 0x10, 0x24, 0xfc, 0x25, 0x08, 0x22,
0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24, 0xe8, 0x40, 0x80, 0x2e, 0xd7, 0xb4, 0xf2, 0x37, 0x5a, 0x0e, 0x90, 0x2e, 0x50,
0xb3, 0x12, 0x24, 0xea, 0x00, 0x4a, 0x0e, 0x90, 0x2e, 0xc7, 0xb2, 0xc2, 0x6f, 0x14, 0x24, 0x4c, 0x0b, 0x54, 0x0e,
0x90, 0x2e, 0xab, 0xb2, 0x14, 0x24, 0x9b, 0x00, 0x5c, 0x0e, 0x90, 0x2e, 0xa1, 0xb2, 0x14, 0x24, 0x22, 0x01, 0x4c,
0x0e, 0x70, 0x2f, 0x82, 0xa3, 0x5e, 0x2f, 0x11, 0x24, 0xba, 0x0b, 0x51, 0x0e, 0x35, 0x2f, 0x11, 0x24, 0x03, 0x08,
0x69, 0x0e, 0x2d, 0x2f, 0xb1, 0x6f, 0x14, 0x24, 0x90, 0x00, 0x0c, 0x0e, 0x24, 0x2f, 0x11, 0x24, 0x31, 0x08, 0x69,
0x0e, 0x16, 0x2f, 0x11, 0x24, 0x7d, 0x01, 0x59, 0x0e, 0x0e, 0x2f, 0x11, 0x24, 0xd7, 0x0c, 0x51, 0x0e, 0x11, 0x24,
0x9f, 0x44, 0x13, 0x24, 0x41, 0x57, 0x4b, 0x22, 0x93, 0x35, 0x43, 0x0e, 0x10, 0x24, 0xbd, 0x42, 0x08, 0x22, 0x80,
0x2e, 0xd7, 0xb4, 0x10, 0x24, 0x1c, 0x42, 0x80, 0x2e, 0xd7, 0xb4, 0x11, 0x24, 0x47, 0x01, 0x59, 0x0e, 0x11, 0x24,
0xa2, 0x45, 0x10, 0x24, 0x31, 0x51, 0x08, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24, 0x80, 0x41, 0x80, 0x2e, 0xd7,
0xb4, 0x10, 0x24, 0x67, 0x54, 0x80, 0x2e, 0xd7, 0xb4, 0x11, 0x24, 0x8c, 0x08, 0xe9, 0x0f, 0x10, 0x24, 0x0a, 0x48,
0x90, 0x2e, 0xd7, 0xb4, 0xb1, 0x6f, 0x13, 0x24, 0xe8, 0x03, 0x8b, 0x0f, 0x10, 0x24, 0xcd, 0x57, 0x90, 0x2e, 0xd7,
0xb4, 0x73, 0x35, 0x8b, 0x0f, 0x10, 0x24, 0x6f, 0x42, 0x90, 0x2e, 0xd7, 0xb4, 0x10, 0x24, 0xa0, 0xfe, 0x08, 0x0e,
0x10, 0x24, 0x38, 0x54, 0x13, 0x24, 0xa3, 0x46, 0x03, 0x22, 0x13, 0x24, 0x45, 0xfd, 0x0b, 0x0e, 0x11, 0x24, 0x04,
0x43, 0x08, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0xb1, 0x6f, 0x00, 0x3a, 0x08, 0x0e, 0x11, 0x24, 0x3d, 0x45, 0x10, 0x24,
0x52, 0x54, 0x48, 0x22, 0x10, 0x24, 0x8f, 0x01, 0x58, 0x0e, 0x10, 0x24, 0x48, 0x44, 0x01, 0x22, 0x80, 0x2e, 0xd7,
0xb4, 0xb1, 0x6f, 0x13, 0x24, 0xfa, 0x03, 0x0b, 0x0e, 0x11, 0x24, 0x85, 0x43, 0x13, 0x24, 0x35, 0x55, 0x4b, 0x22,
0x11, 0xa2, 0x10, 0x24, 0xf6, 0x57, 0x08, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0x11, 0x24, 0xa4, 0x0a, 0x69, 0x0e, 0x11,
0x24, 0x7b, 0x5a, 0x10, 0x24, 0x5e, 0x20, 0x08, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0x11, 0x24, 0x0f, 0x01, 0x59, 0x0e,
0x0d, 0x2f, 0x18, 0xa2, 0x11, 0x24, 0x2b, 0x47, 0x10, 0x24, 0xf4, 0x55, 0x48, 0x22, 0x10, 0x24, 0x16, 0x0b, 0x50,
0x0e, 0x10, 0x24, 0xc7, 0x51, 0x01, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0x11, 0x24, 0x72, 0x0a, 0x51, 0x0e, 0x11, 0x24,
0x85, 0x55, 0x10, 0x24, 0xb2, 0x47, 0x08, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24, 0x83, 0x00, 0x48, 0x0e, 0x53,
0x2f, 0x11, 0x24, 0xe1, 0x07, 0x69, 0x0e, 0x2d, 0x2f, 0x95, 0xaf, 0x27, 0x2f, 0x82, 0xaf, 0x21, 0x2f, 0x11, 0x24,
0xd7, 0x00, 0x59, 0x0e, 0x19, 0x2f, 0xb1, 0x6f, 0x10, 0x24, 0xcc, 0x03, 0x88, 0x0f, 0x10, 0x2f, 0x10, 0x24, 0xe8,
0xfe, 0x08, 0x0e, 0x11, 0x24, 0x7e, 0x56, 0x10, 0x24, 0x94, 0x45, 0x48, 0x22, 0xc0, 0x6f, 0x13, 0x24, 0x06, 0x0b,
0x43, 0x0e, 0x10, 0x24, 0x2f, 0x51, 0x01, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24, 0xde, 0x51, 0x80, 0x2e, 0xd7,
0xb4, 0x10, 0x24, 0xe8, 0x54, 0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24, 0xa4, 0x52, 0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24,
0xd0, 0x44, 0x80, 0x2e, 0xd7, 0xb4, 0x11, 0x24, 0xb8, 0x00, 0xd9, 0x0f, 0x19, 0x2f, 0xc1, 0x6f, 0x10, 0x24, 0xe7,
0x0c, 0xc8, 0x0f, 0x10, 0x2f, 0x11, 0x24, 0xc7, 0x07, 0x69, 0x0e, 0x11, 0x24, 0xf6, 0x52, 0x10, 0x24, 0x7a, 0x12,
0x48, 0x22, 0xb0, 0x6f, 0x13, 0x24, 0x5d, 0x02, 0x03, 0x0e, 0x10, 0x24, 0x7c, 0x54, 0x01, 0x22, 0x80, 0x2e, 0xd7,
0xb4, 0x10, 0x24, 0x8d, 0x51, 0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24, 0x28, 0x52, 0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24,
0xd2, 0x07, 0xe8, 0x0f, 0x28, 0x2f, 0x10, 0x24, 0xb0, 0x00, 0xd8, 0x0f, 0x20, 0x2f, 0x10, 0x24, 0xc6, 0x07, 0x68,
0x0e, 0x18, 0x2f, 0x50, 0x35, 0x48, 0x0e, 0x11, 0x2f, 0xb1, 0x6f, 0x10, 0x24, 0xf4, 0x01, 0x08, 0x0e, 0x11, 0x24,
0x35, 0x51, 0x10, 0x24, 0x22, 0x12, 0x48, 0x22, 0xc0, 0x6f, 0x13, 0x24, 0xe0, 0x0c, 0x43, 0x0e, 0x10, 0x24, 0x7b,
0x50, 0x08, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24, 0x81, 0x52, 0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24, 0x3b, 0x53,
0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24, 0x63, 0x51, 0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24, 0x27, 0x51, 0x80, 0x2e, 0xd7,
0xb4, 0x18, 0xa2, 0x90, 0x2e, 0xdb, 0xb3, 0x12, 0x24, 0x08, 0x02, 0x4a, 0x0e, 0x37, 0x2f, 0x12, 0x24, 0x2a, 0x09,
0x6a, 0x0e, 0x1d, 0x2f, 0x13, 0x24, 0x8e, 0x00, 0x73, 0x0e, 0x09, 0x2f, 0x11, 0x24, 0xa5, 0x01, 0x41, 0x0e, 0x11,
0x24, 0x76, 0x32, 0x10, 0x24, 0x12, 0x25, 0x08, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24, 0xa9, 0x0d, 0x68, 0x0e,
0x10, 0x24, 0x04, 0x27, 0x13, 0x24, 0x73, 0x20, 0x03, 0x22, 0x13, 0x24, 0x14, 0x04, 0x4b, 0x0e, 0x11, 0x24, 0x15,
0x2c, 0x01, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0x11, 0x24, 0xae, 0x08, 0x69, 0x0e, 0x08, 0x2f, 0xa1, 0x35, 0x71, 0x0e,
0x11, 0x24, 0x8b, 0x2b, 0x10, 0x24, 0x07, 0x35, 0x08, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0x91, 0x34, 0x59, 0x0e, 0x11,
0x24, 0x7b, 0x19, 0x10, 0x24, 0x50, 0x59, 0x08, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0x62, 0x32, 0x42, 0x0e, 0x22, 0x2f,
0xa2, 0x32, 0x5a, 0x0e, 0x1b, 0x2f, 0x12, 0x24, 0x0b, 0x08, 0x6a, 0x0e, 0x0e, 0x2f, 0xa3, 0x34, 0x43, 0x0e, 0x10,
0x24, 0x28, 0x2b, 0x13, 0x24, 0x20, 0x23, 0x03, 0x22, 0x13, 0x24, 0x8d, 0x01, 0x4b, 0x0e, 0x11, 0x24, 0x5c, 0x21,
0x08, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0x31, 0x36, 0x59, 0x0e, 0x11, 0x24, 0x43, 0x25, 0x10, 0x24, 0xfa, 0x49, 0x08,
0x22, 0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24, 0xc7, 0x2a, 0x80, 0x2e, 0xd7, 0xb4, 0x40, 0x36, 0x58, 0x0e, 0x09, 0x2f,
0x11, 0x24, 0x9e, 0x08, 0x69, 0x0e, 0x11, 0x24, 0xe3, 0x54, 0x10, 0x24, 0x73, 0x22, 0x08, 0x22, 0x80, 0x2e, 0xd7,
0xb4, 0x10, 0x24, 0x38, 0x01, 0xc8, 0x0f, 0x10, 0x2f, 0x11, 0x24, 0x11, 0x08, 0x69, 0x0e, 0x11, 0x24, 0x6e, 0x48,
0x10, 0x24, 0x2b, 0x28, 0x48, 0x22, 0xc0, 0x6f, 0x13, 0x24, 0xc1, 0x0a, 0x43, 0x0e, 0x10, 0x24, 0x0f, 0x23, 0x08,
0x22, 0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24, 0xd0, 0x1a, 0x80, 0x2e, 0xd7, 0xb4, 0xe2, 0x33, 0x5a, 0x0e, 0x77, 0x2f,
0x12, 0x24, 0x0c, 0x08, 0x6a, 0x0e, 0x2a, 0x2f, 0x12, 0x24, 0xc5, 0x00, 0x4a, 0x0e, 0x08, 0x2f, 0x11, 0x36, 0x59,
0x0e, 0x11, 0x24, 0xfd, 0x18, 0x10, 0x24, 0x75, 0x58, 0x08, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0xc2, 0x34, 0x5a, 0x0e,
0x0d, 0x2f, 0x11, 0x24, 0x36, 0x08, 0x69, 0x0e, 0x11, 0x24, 0x08, 0x58, 0x13, 0x24, 0x3b, 0x54, 0x4b, 0x22, 0x01,
0xa2, 0x10, 0x24, 0xc6, 0x52, 0x08, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0xb3, 0x36, 0x4b, 0x0e, 0x11, 0x24, 0x0e, 0x24,
0x13, 0x24, 0x7b, 0x50, 0x59, 0x22, 0x0e, 0xa2, 0x10, 0x24, 0xf7, 0x56, 0x01, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0xc2,
0x35, 0x5a, 0x0e, 0x12, 0x2f, 0x01, 0xa2, 0x0c, 0x2f, 0x84, 0xa3, 0x10, 0x24, 0xd4, 0x58, 0x13, 0x24, 0x76, 0x56,
0x03, 0x22, 0x73, 0x36, 0x4b, 0x0e, 0x11, 0x24, 0xeb, 0x52, 0x08, 0x22, 0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24, 0x87,
0x16, 0x80, 0x2e, 0xd7, 0xb4, 0xb0, 0x6f, 0x13, 0x24, 0x02, 0xfd, 0x03, 0x0e, 0x29, 0x2f, 0x84, 0xa3, 0xc0, 0x6f,
0x09, 0x2f, 0x11, 0x24, 0xe4, 0x0a, 0x41, 0x0e, 0x11, 0x24, 0x5d, 0x44, 0x10, 0x24, 0x2f, 0x5a, 0x08, 0x22, 0x80,
0x2e, 0xd7, 0xb4, 0x13, 0x24, 0x96, 0x0c, 0x43, 0x0e, 0x0e, 0x2f, 0x40, 0x33, 0x48, 0x0e, 0x10, 0x24, 0xf2, 0x18,
0x13, 0x24, 0x31, 0x49, 0x03, 0x22, 0x13, 0x24, 0x99, 0x00, 0x4b, 0x0e, 0x11, 0x24, 0xab, 0x18, 0x01, 0x22, 0x80,
0x2e, 0xd7, 0xb4, 0x11, 0x24, 0xc6, 0x07, 0x69, 0x0e, 0x11, 0x24, 0xb0, 0x49, 0x10, 0x24, 0xbf, 0x17, 0x08, 0x22,
0x80, 0x2e, 0xd7, 0xb4, 0x10, 0x24, 0x03, 0x15, 0x80, 0x2e, 0xd7, 0xb4, 0xb0, 0x32, 0x48, 0x0e, 0x57, 0x2f, 0xa0,
0x37, 0x48, 0x0e, 0x13, 0x2f, 0x83, 0xa3, 0x08, 0x2f, 0x10, 0x24, 0xe0, 0x00, 0x48, 0x0e, 0x11, 0x24, 0xf6, 0x25,
0x10, 0x24, 0x75, 0x17, 0x71, 0x2c, 0x08, 0x22, 0x10, 0x24, 0xa0, 0x00, 0x48, 0x0e, 0x11, 0x24, 0x7f, 0x18, 0x10,
0x24, 0xa6, 0x13, 0x68, 0x2c, 0x08, 0x22, 0x11, 0x24, 0xf9, 0x07, 0x69, 0x0e, 0x0d, 0x2f, 0x11, 0x24, 0x10, 0x08,
0x69, 0x0e, 0x11, 0x24, 0xb1, 0x14, 0x10, 0x24, 0x8e, 0x58, 0x48, 0x22, 0x90, 0x32, 0x58, 0x0e, 0x10, 0x24, 0x6d,
0x14, 0x56, 0x2c, 0x01, 0x22, 0xc1, 0x6f, 0x10, 0x24, 0x68, 0x0c, 0x48, 0x0e, 0xb1, 0x6f, 0x0c, 0x2f, 0xcd, 0xa2,
0x10, 0x24, 0x23, 0x14, 0x13, 0x24, 0x8d, 0x42, 0x03, 0x22, 0x13, 0x24, 0x2a, 0xfd, 0x0b, 0x0e, 0x11, 0x24, 0x53,
0x12, 0x43, 0x2c, 0x08, 0x22, 0x10, 0x24, 0xcc, 0x07, 0x68, 0x0e, 0x0e, 0x2f, 0x10, 0x24, 0x08, 0xfd, 0x08, 0x0e,
0x10, 0x24, 0x08, 0x16, 0x13, 0x24, 0x83, 0x45, 0x03, 0x22, 0x13, 0x24, 0xa1, 0xfd, 0x0b, 0x0e, 0x11, 0x24, 0xa6,
0x14, 0x30, 0x2c, 0x01, 0x22, 0x10, 0x24, 0x5b, 0x01, 0x08, 0x0e, 0x11, 0x24, 0x2f, 0x12, 0x10, 0x24, 0xdd, 0x44,
0x27, 0x2c, 0x08, 0x22, 0xdb, 0xa2, 0x0f, 0x2f, 0xc1, 0x6f, 0x10, 0x24, 0xb2, 0x0b, 0x48, 0x0e, 0x11, 0x24, 0x21,
0x55, 0x10, 0x24, 0xc8, 0x14, 0x48, 0x22, 0x10, 0x24, 0x4c, 0x08, 0x68, 0x0e, 0x10, 0x24, 0xe4, 0x57, 0x15, 0x2c,
0x01, 0x22, 0x44, 0xa2, 0x0f, 0x2f, 0xc1, 0x6f, 0x10, 0x24, 0xcb, 0x0b, 0x48, 0x0e, 0x11, 0x24, 0x09, 0x58, 0x10,
0x24, 0xe4, 0x10, 0x48, 0x22, 0x10, 0x24, 0x4d, 0x08, 0x68, 0x0e, 0x10, 0x24, 0x1a, 0x12, 0x03, 0x2c, 0x01, 0x22,
0x10, 0x24, 0x0c, 0x10, 0xfb, 0x6f, 0xb0, 0x5f, 0xb8, 0x2e, 0xa3, 0x32, 0xc3, 0x00, 0x60, 0x51, 0xc2, 0x40, 0x81,
0x84, 0xd3, 0x7f, 0xd2, 0x42, 0xe0, 0x7f, 0x00, 0x30, 0xc4, 0x40, 0x20, 0x02, 0xc3, 0x7f, 0xd0, 0x42, 0x42, 0x3d,
0xc0, 0x40, 0x01, 0x80, 0xc0, 0x42, 0xda, 0x00, 0x93, 0x7f, 0xb1, 0x7f, 0xab, 0x7f, 0x98, 0x2e, 0xb3, 0xc0, 0x91,
0x6f, 0xf3, 0x32, 0x40, 0x42, 0x00, 0xac, 0x8b, 0x00, 0x02, 0x2f, 0xe1, 0x6f, 0x39, 0x56, 0x43, 0x42, 0xa1, 0x82,
0x91, 0x7f, 0x33, 0x33, 0x4b, 0x00, 0x81, 0x7f, 0x13, 0x3c, 0x4b, 0x00, 0x80, 0x40, 0x53, 0x34, 0xb5, 0x6f, 0x8b,
0x00, 0x0d, 0xb0, 0x43, 0x87, 0x76, 0x7f, 0xb2, 0x7f, 0x63, 0x7f, 0x65, 0x25, 0xb5, 0x6f, 0x92, 0x41, 0x63, 0x41,
0x64, 0x41, 0x44, 0x81, 0x56, 0x7f, 0x41, 0x7f, 0x00, 0x2e, 0x26, 0x40, 0x27, 0x40, 0x45, 0x41, 0xf7, 0x7f, 0xb0,
0x7f, 0x98, 0x2e, 0x67, 0xcc, 0x81, 0x6f, 0x0f, 0xa4, 0x43, 0x40, 0x72, 0x6f, 0x94, 0x6f, 0x05, 0x30, 0x01, 0x2f,
0xc0, 0xa0, 0x03, 0x2f, 0x31, 0xac, 0x07, 0x2f, 0xc0, 0xa4, 0x05, 0x2f, 0xa2, 0x00, 0xeb, 0x04, 0x80, 0x40, 0x01,
0x80, 0x43, 0x42, 0x80, 0x42, 0x41, 0x86, 0x56, 0x6f, 0x62, 0x6f, 0x41, 0x6f, 0x42, 0x82, 0x72, 0x0e, 0x83, 0x7f,
0xd5, 0x2f, 0x53, 0x32, 0x8b, 0x00, 0xa1, 0x86, 0x56, 0x25, 0xf0, 0x82, 0x82, 0x40, 0x8d, 0xb0, 0x52, 0x40, 0xde,
0x00, 0x91, 0x7f, 0xb3, 0x7f, 0x85, 0x7f, 0xb3, 0x30, 0x7b, 0x52, 0x98, 0x2e, 0x5a, 0xca, 0x1a, 0x25, 0x83, 0x6f,
0x6d, 0x82, 0xfd, 0x88, 0x50, 0x7f, 0x71, 0x7f, 0x81, 0x7f, 0x05, 0x30, 0x83, 0x30, 0x00, 0x30, 0x11, 0x41, 0x52,
0x6f, 0x25, 0x7f, 0x30, 0x7f, 0x44, 0x7f, 0x98, 0x2e, 0x0f, 0xca, 0x73, 0x6f, 0x20, 0x25, 0x90, 0x6f, 0x7d, 0x52,
0xd2, 0x42, 0x73, 0x7f, 0x12, 0x7f, 0x98, 0x2e, 0x86, 0xb7, 0x93, 0x6f, 0x11, 0x6f, 0xd2, 0x40, 0x0a, 0x18, 0x31,
0x6f, 0x0e, 0x00, 0x93, 0x7f, 0x83, 0x30, 0x44, 0x6f, 0x21, 0x6f, 0x62, 0x6f, 0x62, 0x0e, 0x4f, 0x03, 0xe1, 0x2f,
0x33, 0x52, 0x01, 0x00, 0x01, 0x30, 0x69, 0x03, 0x3a, 0x25, 0xea, 0x82, 0x92, 0x6f, 0xf0, 0x86, 0xd1, 0xbe, 0x0f,
0xb8, 0xbd, 0x84, 0x94, 0x7f, 0x05, 0x0a, 0x23, 0x7f, 0x52, 0x7f, 0x40, 0x7f, 0x31, 0x7f, 0x71, 0x7f, 0xd3, 0x30,
0x84, 0x6f, 0x55, 0x6f, 0x10, 0x41, 0x52, 0x41, 0x41, 0x6f, 0x55, 0x7f, 0x10, 0x7f, 0x04, 0x7f, 0x98, 0x2e, 0x0f,
0xca, 0x11, 0x6f, 0x20, 0x25, 0x98, 0x2e, 0xfe, 0xc9, 0x31, 0x6f, 0x04, 0x6f, 0x50, 0x42, 0x31, 0x7f, 0xd3, 0x30,
0x21, 0x6f, 0x61, 0x0e, 0xea, 0x2f, 0xb1, 0x6f, 0x41, 0x84, 0x32, 0x25, 0x90, 0x40, 0x84, 0x40, 0x71, 0x6f, 0xb4,
0x7f, 0x72, 0x7f, 0x40, 0x7f, 0x33, 0x7f, 0x98, 0x2e, 0xb3, 0xc0, 0x53, 0x6f, 0xb1, 0x32, 0x99, 0x00, 0x83, 0xb9,
0x41, 0x6f, 0x4b, 0x00, 0xb0, 0x6f, 0x03, 0x30, 0xc3, 0x02, 0x84, 0x40, 0xb2, 0x7f, 0xa1, 0x84, 0x0d, 0xb1, 0x52,
0x7f, 0x56, 0x01, 0x74, 0x6f, 0x30, 0x6f, 0x92, 0x6f, 0x43, 0x8b, 0x03, 0x43, 0x01, 0x42, 0x95, 0x7f, 0xbd, 0x86,
0x51, 0x41, 0x41, 0x7f, 0x75, 0x7f, 0x00, 0x2e, 0xd1, 0x40, 0x42, 0x41, 0x32, 0x7f, 0x23, 0x7f, 0x98, 0x2e, 0x74,
0xc0, 0x41, 0x6f, 0xc8, 0x00, 0x90, 0x6f, 0x01, 0x30, 0x75, 0x6f, 0x32, 0x6f, 0x03, 0x42, 0x91, 0x02, 0x23, 0x6f,
0x61, 0x6f, 0x59, 0x0e, 0x62, 0x43, 0x95, 0x7f, 0xe7, 0x2f, 0xb2, 0x6f, 0x51, 0x6f, 0x82, 0x40, 0x8d, 0xb0, 0x8e,
0x00, 0xfd, 0x8a, 0xb2, 0x7f, 0x02, 0x30, 0x79, 0x52, 0x05, 0x25, 0x03, 0x30, 0x54, 0x40, 0xec, 0x01, 0x16, 0x40,
0x43, 0x89, 0xc7, 0x41, 0x37, 0x18, 0x3d, 0x8b, 0x96, 0x00, 0x44, 0x0e, 0xdf, 0x02, 0xf4, 0x2f, 0x09, 0x52, 0x51,
0x00, 0x02, 0x30, 0x9a, 0x02, 0xb5, 0x6f, 0x45, 0x87, 0x1b, 0xba, 0x25, 0xbc, 0x51, 0x6f, 0x4d, 0x8b, 0x7a, 0x82,
0xc6, 0x40, 0x20, 0x0a, 0x30, 0x00, 0xd0, 0x42, 0x2b, 0xb5, 0xc0, 0x40, 0x82, 0x02, 0x40, 0x34, 0x08, 0x00, 0xd2,
0x42, 0xb0, 0x7f, 0x75, 0x7f, 0x93, 0x7f, 0x00, 0x2e, 0xb5, 0x6f, 0xe2, 0x6f, 0x63, 0x41, 0x64, 0x41, 0x44, 0x8f,
0x82, 0x40, 0xe6, 0x41, 0xc0, 0x41, 0xc4, 0x8f, 0x45, 0x41, 0xf0, 0x7f, 0xb7, 0x7f, 0x61, 0x7f, 0x98, 0x2e, 0x67,
0xcc, 0x00, 0x18, 0x09, 0x52, 0x71, 0x00, 0x03, 0x30, 0xbb, 0x02, 0x1b, 0xba, 0x93, 0x6f, 0x25, 0xbc, 0x61, 0x6f,
0xc5, 0x40, 0x42, 0x82, 0x20, 0x0a, 0x28, 0x00, 0xd0, 0x42, 0x2b, 0xb9, 0xc0, 0x40, 0x82, 0x02, 0xd2, 0x42, 0x93,
0x7f, 0x00, 0x2e, 0x72, 0x6f, 0x5a, 0x0e, 0xd9, 0x2f, 0xb1, 0x6f, 0xf3, 0x3c, 0xcb, 0x00, 0xda, 0x82, 0xc3, 0x40,
0x41, 0x40, 0x59, 0x0e, 0x50, 0x2f, 0xe1, 0x6f, 0xe3, 0x32, 0xcb, 0x00, 0xb3, 0x7f, 0x22, 0x30, 0xc0, 0x40, 0x01,
0x80, 0xc0, 0x42, 0x02, 0xa2, 0x30, 0x2f, 0xc2, 0x42, 0x98, 0x2e, 0x83, 0xb1, 0xe1, 0x6f, 0xb3, 0x35, 0xcb, 0x00,
0x24, 0x3d, 0xc2, 0x40, 0xdc, 0x00, 0x84, 0x40, 0x00, 0x91, 0x93, 0x7f, 0x02, 0x2f, 0x00, 0x2e, 0x06, 0x2c, 0x0c,
0xb8, 0x30, 0x25, 0x00, 0x33, 0x48, 0x00, 0x98, 0x2e, 0xf6, 0xb6, 0x91, 0x6f, 0x90, 0x7f, 0x00, 0x2e, 0x44, 0x40,
0x20, 0x1a, 0x15, 0x2f, 0xd3, 0x6f, 0xc1, 0x6f, 0xc3, 0x40, 0x35, 0x5a, 0x42, 0x40, 0xd3, 0x7e, 0x08, 0xbc, 0x25,
0x09, 0xe2, 0x7e, 0xc4, 0x0a, 0x42, 0x82, 0xf3, 0x7e, 0xd1, 0x7f, 0x34, 0x30, 0x83, 0x6f, 0x82, 0x30, 0x31, 0x30,
0x98, 0x2e, 0xb3, 0x00, 0xd1, 0x6f, 0x93, 0x6f, 0x43, 0x42, 0xf0, 0x32, 0xb1, 0x6f, 0x41, 0x82, 0xe2, 0x6f, 0x43,
0x40, 0xc1, 0x86, 0xc2, 0xa2, 0x43, 0x42, 0x03, 0x30, 0x02, 0x2f, 0x90, 0x00, 0x00, 0x2e, 0x83, 0x42, 0x61, 0x88,
0x42, 0x40, 0x8d, 0xb0, 0x26, 0x00, 0x98, 0x2e, 0xd9, 0x03, 0x1c, 0x83, 0x00, 0x2e, 0x43, 0x42, 0x00, 0x2e, 0xab,
0x6f, 0xa0, 0x5e, 0xb8, 0x2e, 0xb1, 0x35, 0x40, 0x51, 0x41, 0x01, 0x02, 0x30, 0x1a, 0x25, 0x13, 0x30, 0x40, 0x25,
0x12, 0x42, 0x45, 0x0e, 0xfc, 0x2f, 0x65, 0x34, 0x28, 0x80, 0x25, 0x01, 0x13, 0x42, 0x44, 0x0e, 0xfc, 0x2f, 0x27,
0x80, 0x65, 0x56, 0x03, 0x42, 0x15, 0x80, 0xa3, 0x30, 0x03, 0x42, 0x04, 0x80, 0x4d, 0x56, 0x7f, 0x58, 0x13, 0x42,
0xd4, 0x7e, 0xc2, 0x7e, 0xf2, 0x7e, 0x6c, 0x8c, 0x81, 0x56, 0x83, 0x58, 0xe3, 0x7e, 0x04, 0x7f, 0x71, 0x8a, 0x97,
0x41, 0x17, 0x42, 0x75, 0x0e, 0xfb, 0x2f, 0x85, 0x5c, 0x87, 0x5e, 0x16, 0x7f, 0x36, 0x7f, 0x27, 0x7f, 0x00, 0x2e,
0x89, 0x5c, 0x8b, 0x5e, 0x46, 0x7f, 0x57, 0x7f, 0x76, 0x8c, 0x57, 0x41, 0x17, 0x42, 0x6e, 0x0e, 0xfb, 0x2f, 0x8d,
0x5a, 0x8f, 0x5e, 0x65, 0x7f, 0x87, 0x7f, 0x72, 0x7f, 0x00, 0x2e, 0x91, 0x5a, 0x93, 0x5e, 0x95, 0x7f, 0xa7, 0x7f,
0x7b, 0x8a, 0x97, 0x41, 0x17, 0x42, 0x75, 0x0e, 0xfb, 0x2f, 0x7f, 0x5c, 0xb2, 0x7f, 0xc6, 0x7f, 0xd3, 0x7f, 0xe2,
0x7f, 0xf4, 0x7f, 0x40, 0x82, 0x52, 0x41, 0x12, 0x42, 0x69, 0x0e, 0xfb, 0x2f, 0xc0, 0x5e, 0xb8, 0x2e, 0x03, 0x2e,
0x2d, 0x02, 0x9f, 0xbc, 0x9f, 0xb8, 0x20, 0x50, 0x40, 0xb2, 0x14, 0x2f, 0x10, 0x25, 0x01, 0x2e, 0x8d, 0x00, 0x00,
0x90, 0x0b, 0x2f, 0x97, 0x50, 0xf1, 0x7f, 0xeb, 0x7f, 0x98, 0x2e, 0x83, 0xb6, 0x01, 0x2e, 0x8d, 0x00, 0x01, 0x80,
0x21, 0x2e, 0x8d, 0x00, 0xf1, 0x6f, 0xeb, 0x6f, 0xe0, 0x5f, 0x97, 0x50, 0x80, 0x2e, 0xda, 0xb4, 0x00, 0x30, 0x21,
0x2e, 0x8d, 0x00, 0xe0, 0x5f, 0xb8, 0x2e, 0x41, 0x25, 0x42, 0x8a, 0x50, 0x50, 0x99, 0x52, 0x81, 0x80, 0x99, 0x09,
0xf5, 0x7f, 0x52, 0x25, 0x07, 0x52, 0x03, 0x8e, 0xd9, 0x08, 0x02, 0x40, 0x03, 0x81, 0x44, 0x83, 0x6c, 0xbb, 0xda,
0x0e, 0xe7, 0x7f, 0xdb, 0x7f, 0x20, 0x2f, 0x02, 0x41, 0x32, 0x1a, 0x1d, 0x2f, 0x42, 0x85, 0x00, 0x2e, 0x82, 0x40,
0xda, 0x0e, 0x03, 0x30, 0x05, 0x2f, 0xf1, 0x6f, 0x06, 0x30, 0x42, 0x40, 0x81, 0x84, 0x18, 0x2c, 0x42, 0x42, 0xbf,
0x85, 0x82, 0x00, 0x41, 0x40, 0x86, 0x40, 0x81, 0x8d, 0x86, 0x42, 0x20, 0x25, 0x13, 0x30, 0x06, 0x30, 0x97, 0x40,
0x81, 0x8d, 0xf9, 0x0f, 0x09, 0x2f, 0x85, 0xa3, 0xf9, 0x2f, 0x03, 0x30, 0x06, 0x2c, 0x06, 0x30, 0x9b, 0x52, 0xd9,
0x0e, 0x13, 0x30, 0x01, 0x30, 0xd9, 0x22, 0xc0, 0xb2, 0x12, 0x83, 0xc1, 0x7f, 0x03, 0x30, 0xb4, 0x7f, 0x06, 0x2f,
0x51, 0x30, 0x70, 0x25, 0x98, 0x2e, 0xe3, 0x03, 0xff, 0x81, 0x00, 0x2e, 0x03, 0x42, 0x43, 0x8b, 0xe0, 0x6f, 0xf1,
0x6f, 0x00, 0x40, 0x41, 0x40, 0xc8, 0x0f, 0x37, 0x2f, 0x00, 0x41, 0x80, 0xa7, 0x3c, 0x2f, 0x01, 0x83, 0x47, 0x8e,
0x42, 0x40, 0xfa, 0x01, 0x81, 0x84, 0x08, 0x89, 0x45, 0x41, 0x55, 0x0e, 0xc6, 0x43, 0x42, 0x42, 0xf4, 0x7f, 0x00,
0x2f, 0x43, 0x42, 0x51, 0x82, 0x70, 0x1a, 0x41, 0x40, 0x06, 0x2f, 0xc3, 0x6f, 0x41, 0x82, 0xc1, 0x42, 0xcd, 0x0e,
0x26, 0x2f, 0xc5, 0x42, 0x25, 0x2d, 0x7f, 0x82, 0x51, 0xbb, 0xa5, 0x00, 0xce, 0x0f, 0x12, 0x2f, 0x14, 0x30, 0x05,
0x30, 0xf7, 0x6f, 0x06, 0x30, 0x05, 0x2c, 0xe0, 0x7f, 0xd0, 0x41, 0x05, 0x1a, 0x23, 0x22, 0xb0, 0x01, 0x7a, 0x0e,
0xf9, 0x2f, 0x71, 0x0f, 0xe0, 0x6f, 0x28, 0x22, 0x41, 0x8b, 0x71, 0x22, 0x45, 0xa7, 0xee, 0x2f, 0xb3, 0x6f, 0xc2,
0x6f, 0xc0, 0x42, 0x81, 0x42, 0x08, 0x2d, 0x04, 0x25, 0xc4, 0x6f, 0x98, 0x2e, 0xea, 0x03, 0x00, 0x2e, 0x40, 0x41,
0x00, 0x43, 0x00, 0x30, 0xdb, 0x6f, 0xb0, 0x5f, 0xb8, 0x2e, 0x10, 0x50, 0x03, 0x40, 0x19, 0x18, 0x37, 0x56, 0x19,
0x05, 0x36, 0x25, 0xf7, 0x7f, 0x4a, 0x17, 0x54, 0x18, 0xec, 0x18, 0x09, 0x17, 0x01, 0x30, 0x0c, 0x07, 0xe2, 0x18,
0xde, 0x00, 0xf2, 0x6f, 0x97, 0x02, 0x33, 0x58, 0xdc, 0x00, 0x91, 0x02, 0xbf, 0xb8, 0x21, 0xbd, 0x8a, 0x0a, 0xc0,
0x2e, 0x02, 0x42, 0xf0, 0x5f, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x01, 0x2e, 0x5d, 0xf7, 0x08, 0xbc, 0x80, 0xac, 0x0e, 0xbb, 0x02, 0x2f,
0x00, 0x30, 0x41, 0x04, 0x82, 0x06, 0xc0, 0xa4, 0x00, 0x30, 0x11, 0x2f, 0x40, 0xa9, 0x03, 0x2f, 0x40, 0x91, 0x0d,
0x2f, 0x00, 0xa7, 0x0b, 0x2f, 0x80, 0xb3, 0x33, 0x58, 0x02, 0x2f, 0x90, 0xa1, 0x26, 0x13, 0x20, 0x23, 0x80, 0x90,
0x10, 0x30, 0x01, 0x2f, 0xcc, 0x0e, 0x00, 0x2f, 0x00, 0x30, 0xb8, 0x2e, 0x35, 0x50, 0x18, 0x08, 0x08, 0xbc, 0x88,
0xb6, 0x0d, 0x17, 0xc6, 0xbd, 0x56, 0xbc, 0x37, 0x58, 0xda, 0xba, 0x04, 0x01, 0x1d, 0x0a, 0x10, 0x50, 0x05, 0x30,
0x32, 0x25, 0x45, 0x03, 0xfb, 0x7f, 0xf6, 0x30, 0x21, 0x25, 0x98, 0x2e, 0x37, 0xca, 0x16, 0xb5, 0x9a, 0xbc, 0x06,
0xb8, 0x80, 0xa8, 0x41, 0x0a, 0x0e, 0x2f, 0x80, 0x90, 0x02, 0x2f, 0x39, 0x50, 0x48, 0x0f, 0x09, 0x2f, 0xbf, 0xa0,
0x04, 0x2f, 0xbf, 0x90, 0x06, 0x2f, 0x37, 0x54, 0xca, 0x0f, 0x03, 0x2f, 0x00, 0x2e, 0x02, 0x2c, 0x37, 0x52, 0x39,
0x52, 0xf2, 0x33, 0x98, 0x2e, 0xd9, 0xc0, 0xfb, 0x6f, 0xf1, 0x37, 0xc0, 0x2e, 0x01, 0x08, 0xf0, 0x5f, 0x41, 0x56,
0x3b, 0x54, 0xd0, 0x40, 0xc4, 0x40, 0x0b, 0x2e, 0xfd, 0xf3, 0x41, 0x52, 0x90, 0x42, 0x94, 0x42, 0x95, 0x42, 0x05,
0x30, 0x43, 0x50, 0x0f, 0x88, 0x06, 0x40, 0x04, 0x41, 0x96, 0x42, 0xc5, 0x42, 0x48, 0xbe, 0x73, 0x30, 0x0d, 0x2e,
0x88, 0x00, 0x4f, 0xba, 0x84, 0x42, 0x03, 0x42, 0x81, 0xb3, 0x02, 0x2f, 0x2b, 0x2e, 0x6f, 0xf5, 0x06, 0x2d, 0x05,
0x2e, 0x77, 0xf7, 0x3f, 0x56, 0x93, 0x08, 0x25, 0x2e, 0x77, 0xf7, 0x3d, 0x54, 0x25, 0x2e, 0xc2, 0xf5, 0x07, 0x2e,
0xfd, 0xf3, 0x42, 0x30, 0xb4, 0x33, 0xda, 0x0a, 0x4c, 0x00, 0x27, 0x2e, 0xfd, 0xf3, 0x43, 0x40, 0xd4, 0x3f, 0xdc,
0x08, 0x43, 0x42, 0x00, 0x2e, 0x00, 0x2e, 0x43, 0x40, 0x24, 0x30, 0xdc, 0x0a, 0x43, 0x42, 0x04, 0x80, 0x03, 0x2e,
0xfd, 0xf3, 0x4a, 0x0a, 0x23, 0x2e, 0xfd, 0xf3, 0x61, 0x34, 0xc0, 0x2e, 0x01, 0x42, 0x00, 0x2e, 0x60, 0x50, 0x1a,
0x25, 0x7a, 0x86, 0xe0, 0x7f, 0xf3, 0x7f, 0x03, 0x25, 0x45, 0x52, 0x41, 0x84, 0xdb, 0x7f, 0x33, 0x30, 0x98, 0x2e,
0x16, 0xc2, 0x1a, 0x25, 0x7d, 0x82, 0xf0, 0x6f, 0xe2, 0x6f, 0x32, 0x25, 0x16, 0x40, 0x94, 0x40, 0x26, 0x01, 0x85,
0x40, 0x8e, 0x17, 0xc4, 0x42, 0x6e, 0x03, 0x95, 0x42, 0x41, 0x0e, 0xf4, 0x2f, 0xdb, 0x6f, 0xa0, 0x5f, 0xb8, 0x2e,
0xb0, 0x51, 0xfb, 0x7f, 0x98, 0x2e, 0xe8, 0x0d, 0x5a, 0x25, 0x98, 0x2e, 0x0f, 0x0e, 0x4f, 0x58, 0x32, 0x87, 0xc4,
0x7f, 0x65, 0x89, 0x6b, 0x8d, 0x47, 0x5a, 0x65, 0x7f, 0xe1, 0x7f, 0x83, 0x7f, 0xa6, 0x7f, 0x74, 0x7f, 0xd0, 0x7f,
0xb6, 0x7f, 0x94, 0x7f, 0x17, 0x30, 0x49, 0x52, 0x4b, 0x54, 0x51, 0x7f, 0x00, 0x2e, 0x85, 0x6f, 0x42, 0x7f, 0x00,
0x2e, 0x51, 0x41, 0x45, 0x81, 0x42, 0x41, 0x13, 0x40, 0x3b, 0x8a, 0x00, 0x40, 0x4b, 0x04, 0xd0, 0x06, 0xc0, 0xac,
0x85, 0x7f, 0x02, 0x2f, 0x02, 0x30, 0x51, 0x04, 0xd3, 0x06, 0x41, 0x84, 0x05, 0x30, 0x5d, 0x02, 0xc9, 0x16, 0xdf,
0x08, 0xd3, 0x00, 0x8d, 0x02, 0xaf, 0xbc, 0xb1, 0xb9, 0x59, 0x0a, 0x65, 0x6f, 0x11, 0x43, 0xa1, 0xb4, 0x52, 0x41,
0x53, 0x41, 0x01, 0x43, 0x34, 0x7f, 0x65, 0x7f, 0x26, 0x31, 0xe5, 0x6f, 0xd4, 0x6f, 0x98, 0x2e, 0x37, 0xca, 0x32,
0x6f, 0x75, 0x6f, 0x83, 0x40, 0x42, 0x41, 0x23, 0x7f, 0x12, 0x7f, 0xf6, 0x30, 0x40, 0x25, 0x51, 0x25, 0x98, 0x2e,
0x37, 0xca, 0x14, 0x6f, 0x20, 0x05, 0x70, 0x6f, 0x25, 0x6f, 0x69, 0x07, 0xa2, 0x6f, 0x31, 0x6f, 0x0b, 0x30, 0x04,
0x42, 0x9b, 0x42, 0x8b, 0x42, 0x55, 0x42, 0x32, 0x7f, 0x40, 0xa9, 0xc3, 0x6f, 0x71, 0x7f, 0x02, 0x30, 0xd0, 0x40,
0xc3, 0x7f, 0x03, 0x2f, 0x40, 0x91, 0x15, 0x2f, 0x00, 0xa7, 0x13, 0x2f, 0x00, 0xa4, 0x11, 0x2f, 0x84, 0xbd, 0x98,
0x2e, 0x79, 0xca, 0x55, 0x6f, 0x37, 0x54, 0x54, 0x41, 0x82, 0x00, 0xf3, 0x3f, 0x45, 0x41, 0xcb, 0x02, 0xf6, 0x30,
0x98, 0x2e, 0x37, 0xca, 0x35, 0x6f, 0xa4, 0x6f, 0x41, 0x43, 0x03, 0x2c, 0x00, 0x43, 0xa4, 0x6f, 0x35, 0x6f, 0x17,
0x30, 0x42, 0x6f, 0x51, 0x6f, 0x93, 0x40, 0x42, 0x82, 0x00, 0x41, 0xc3, 0x00, 0x03, 0x43, 0x51, 0x7f, 0x00, 0x2e,
0x94, 0x40, 0x41, 0x41, 0x4c, 0x02, 0xc4, 0x6f, 0x55, 0x56, 0x63, 0x0e, 0x74, 0x6f, 0x51, 0x43, 0xa5, 0x7f, 0x8a,
0x2f, 0x09, 0x2e, 0x88, 0x00, 0x01, 0xb3, 0x21, 0x2f, 0x4f, 0x58, 0x90, 0x6f, 0x13, 0x41, 0xb6, 0x6f, 0xe4, 0x7f,
0x00, 0x2e, 0x91, 0x41, 0x14, 0x40, 0x92, 0x41, 0x15, 0x40, 0x17, 0x2e, 0x6f, 0xf5, 0xb6, 0x7f, 0xd0, 0x7f, 0xcb,
0x7f, 0x98, 0x2e, 0x00, 0x0c, 0x07, 0x15, 0xc2, 0x6f, 0x14, 0x0b, 0x29, 0x2e, 0x6f, 0xf5, 0xc3, 0xa3, 0xc1, 0x8f,
0xe4, 0x6f, 0xd0, 0x6f, 0xe6, 0x2f, 0x14, 0x30, 0x05, 0x2e, 0x6f, 0xf5, 0x14, 0x0b, 0x29, 0x2e, 0x6f, 0xf5, 0x18,
0x2d, 0x51, 0x56, 0x04, 0x32, 0xb5, 0x6f, 0x1c, 0x01, 0x51, 0x41, 0x52, 0x41, 0xc3, 0x40, 0xb5, 0x7f, 0xe4, 0x7f,
0x98, 0x2e, 0x1f, 0x0c, 0xe4, 0x6f, 0x21, 0x87, 0x00, 0x43, 0x04, 0x32, 0x53, 0x54, 0x5a, 0x0e, 0xef, 0x2f, 0x4d,
0x54, 0x09, 0x2e, 0x77, 0xf7, 0x22, 0x0b, 0x29, 0x2e, 0x77, 0xf7, 0xfb, 0x6f, 0x50, 0x5e, 0xb8, 0x2e, 0x10, 0x50,
0x01, 0x2e, 0x84, 0x00, 0x00, 0xb2, 0xfb, 0x7f, 0x51, 0x2f, 0x01, 0xb2, 0x48, 0x2f, 0x02, 0xb2, 0x42, 0x2f, 0x03,
0x90, 0x56, 0x2f, 0x5b, 0x52, 0x79, 0x80, 0x42, 0x40, 0x81, 0x84, 0x00, 0x40, 0x42, 0x42, 0x98, 0x2e, 0x93, 0x0c,
0x5d, 0x54, 0x5b, 0x50, 0xa1, 0x40, 0x98, 0xbd, 0x82, 0x40, 0x3e, 0x82, 0xda, 0x0a, 0x44, 0x40, 0x8b, 0x16, 0xe3,
0x00, 0x53, 0x42, 0x00, 0x2e, 0x43, 0x40, 0x9a, 0x02, 0x52, 0x42, 0x00, 0x2e, 0x41, 0x40, 0x4d, 0x54, 0x4a, 0x0e,
0x3a, 0x2f, 0x3a, 0x82, 0x00, 0x30, 0x41, 0x40, 0x21, 0x2e, 0x6c, 0x0f, 0x40, 0xb2, 0x0a, 0x2f, 0x98, 0x2e, 0xb1,
0x0c, 0x98, 0x2e, 0x45, 0x0e, 0x98, 0x2e, 0x5b, 0x0e, 0xfb, 0x6f, 0xf0, 0x5f, 0x00, 0x30, 0x80, 0x2e, 0xba, 0x03,
0x61, 0x52, 0x57, 0x54, 0x42, 0x42, 0x4f, 0x84, 0x73, 0x30, 0x5f, 0x52, 0x83, 0x42, 0x1b, 0x30, 0x6b, 0x42, 0x23,
0x30, 0x27, 0x2e, 0x87, 0x00, 0x37, 0x2e, 0x84, 0x00, 0x21, 0x2e, 0x86, 0x00, 0x7a, 0x84, 0x17, 0x2c, 0x42, 0x42,
0x30, 0x30, 0x21, 0x2e, 0x84, 0x00, 0x12, 0x2d, 0x21, 0x30, 0x00, 0x30, 0x23, 0x2e, 0x84, 0x00, 0x21, 0x2e, 0x7b,
0xf7, 0x0b, 0x2d, 0x17, 0x30, 0x98, 0x2e, 0x51, 0x0c, 0x59, 0x50, 0x0c, 0x82, 0x72, 0x30, 0x2f, 0x2e, 0x84, 0x00,
0x25, 0x2e, 0x7b, 0xf7, 0x40, 0x42, 0x00, 0x2e, 0xfb, 0x6f, 0xf0, 0x5f, 0xb8, 0x2e, 0x70, 0x50, 0x0a, 0x25, 0x39,
0x86, 0xfb, 0x7f, 0xe1, 0x32, 0x62, 0x30, 0x98, 0x2e, 0xc2, 0xc4, 0x35, 0x56, 0xa5, 0x6f, 0xab, 0x08, 0x91, 0x6f,
0x4b, 0x08, 0x63, 0x56, 0xc4, 0x6f, 0x23, 0x09, 0x4d, 0xba, 0x93, 0xbc, 0x8c, 0x0b, 0xd1, 0x6f, 0x0b, 0x09, 0x4f,
0x52, 0x65, 0x5e, 0x56, 0x42, 0xaf, 0x09, 0x4d, 0xba, 0x23, 0xbd, 0x94, 0x0a, 0xe5, 0x6f, 0x68, 0xbb, 0xeb, 0x08,
0xbd, 0xb9, 0x63, 0xbe, 0xfb, 0x6f, 0x52, 0x42, 0xe3, 0x0a, 0xc0, 0x2e, 0x43, 0x42, 0x90, 0x5f, 0x55, 0x50, 0x03,
0x2e, 0x25, 0xf3, 0x13, 0x40, 0x00, 0x40, 0x9b, 0xbc, 0x9b, 0xb4, 0x08, 0xbd, 0xb8, 0xb9, 0x98, 0xbc, 0xda, 0x0a,
0x08, 0xb6, 0x89, 0x16, 0xc0, 0x2e, 0x19, 0x00, 0x62, 0x02, 0x10, 0x50, 0xfb, 0x7f, 0x98, 0x2e, 0x81, 0x0d, 0x01,
0x2e, 0x84, 0x00, 0x31, 0x30, 0x08, 0x04, 0xfb, 0x6f, 0x01, 0x30, 0xf0, 0x5f, 0x23, 0x2e, 0x86, 0x00, 0x21, 0x2e,
0x87, 0x00, 0xb8, 0x2e, 0x01, 0x2e, 0x87, 0x00, 0x03, 0x2e, 0x86, 0x00, 0x48, 0x0e, 0x01, 0x2f, 0x80, 0x2e, 0x1f,
0x0e, 0xb8, 0x2e, 0x67, 0x50, 0x21, 0x34, 0x01, 0x42, 0x82, 0x30, 0xc1, 0x32, 0x25, 0x2e, 0x62, 0xf5, 0x01, 0x00,
0x22, 0x30, 0x01, 0x40, 0x4a, 0x0a, 0x01, 0x42, 0xb8, 0x2e, 0x67, 0x54, 0xf0, 0x3b, 0x83, 0x40, 0xd8, 0x08, 0x69,
0x52, 0x83, 0x42, 0x00, 0x30, 0x83, 0x30, 0x50, 0x42, 0xc4, 0x32, 0x27, 0x2e, 0x64, 0xf5, 0x94, 0x00, 0x50, 0x42,
0x40, 0x42, 0xd3, 0x3f, 0x84, 0x40, 0x7d, 0x82, 0xe3, 0x08, 0x40, 0x42, 0x83, 0x42, 0xb8, 0x2e, 0x61, 0x52, 0x00,
0x30, 0x40, 0x42, 0x7c, 0x86, 0x3b, 0x52, 0x09, 0x2e, 0x57, 0x0f, 0x41, 0x54, 0xc4, 0x42, 0xd3, 0x86, 0x54, 0x40,
0x55, 0x40, 0x94, 0x42, 0x85, 0x42, 0x21, 0x2e, 0x87, 0x00, 0x42, 0x40, 0x25, 0x2e, 0xfd, 0xf3, 0xc0, 0x42, 0x7e,
0x82, 0x05, 0x2e, 0x79, 0x00, 0x80, 0xb2, 0x14, 0x2f, 0x05, 0x2e, 0x24, 0x02, 0x27, 0xbd, 0x2f, 0xb9, 0x80, 0x90,
0x02, 0x2f, 0x21, 0x2e, 0x6f, 0xf5, 0x0c, 0x2d, 0x07, 0x2e, 0x58, 0x0f, 0x14, 0x30, 0x1c, 0x09, 0x05, 0x2e, 0x77,
0xf7, 0x3f, 0x56, 0x47, 0xbe, 0x93, 0x08, 0x94, 0x0a, 0x25, 0x2e, 0x77, 0xf7, 0x6b, 0x54, 0x50, 0x42, 0x4a, 0x0e,
0xfc, 0x2f, 0xb8, 0x2e, 0x50, 0x50, 0x02, 0x30, 0x43, 0x86, 0x69, 0x50, 0xfb, 0x7f, 0xe3, 0x7f, 0xd2, 0x7f, 0xc0,
0x7f, 0xb1, 0x7f, 0x00, 0x2e, 0x41, 0x40, 0x00, 0x40, 0x48, 0x04, 0x98, 0x2e, 0x74, 0xc0, 0x1e, 0xaa, 0xd3, 0x6f,
0x14, 0x30, 0xb1, 0x6f, 0xe3, 0x22, 0xc0, 0x6f, 0x52, 0x40, 0xe4, 0x6f, 0x4c, 0x0e, 0x12, 0x42, 0xd3, 0x7f, 0xeb,
0x2f, 0x03, 0x2e, 0x6d, 0x0f, 0x40, 0x90, 0x11, 0x30, 0x03, 0x2f, 0x23, 0x2e, 0x6d, 0x0f, 0x02, 0x2c, 0x00, 0x30,
0xd0, 0x6f, 0xfb, 0x6f, 0xb0, 0x5f, 0xb8, 0x2e, 0x40, 0x50, 0xf1, 0x7f, 0x0a, 0x25, 0x3c, 0x86, 0xeb, 0x7f, 0x41,
0x33, 0x22, 0x30, 0x98, 0x2e, 0xc2, 0xc4, 0xd3, 0x6f, 0xf4, 0x30, 0xdc, 0x09, 0x6f, 0x58, 0xc2, 0x6f, 0x94, 0x09,
0x71, 0x58, 0x6a, 0xbb, 0xdc, 0x08, 0xb4, 0xb9, 0xb1, 0xbd, 0x6d, 0x5a, 0x95, 0x08, 0x21, 0xbd, 0xf6, 0xbf, 0x77,
0x0b, 0x51, 0xbe, 0xf1, 0x6f, 0xeb, 0x6f, 0x52, 0x42, 0x54, 0x42, 0xc0, 0x2e, 0x43, 0x42, 0xc0, 0x5f, 0x50, 0x50,
0x75, 0x52, 0x93, 0x30, 0x53, 0x42, 0xfb, 0x7f, 0x7b, 0x30, 0x4b, 0x42, 0x13, 0x30, 0x42, 0x82, 0x20, 0x33, 0x43,
0x42, 0xc8, 0x00, 0x01, 0x2e, 0x80, 0x03, 0x05, 0x2e, 0x7d, 0x00, 0x19, 0x52, 0xe2, 0x7f, 0xd0, 0x7f, 0xc3, 0x7f,
0x98, 0x2e, 0xb6, 0x0e, 0xd1, 0x6f, 0x48, 0x0a, 0xd1, 0x7f, 0x3a, 0x25, 0xfb, 0x86, 0x01, 0x33, 0x12, 0x30, 0x98,
0x2e, 0xc2, 0xc4, 0xd1, 0x6f, 0x48, 0x0a, 0x40, 0xb2, 0x0d, 0x2f, 0xe0, 0x6f, 0x03, 0x2e, 0x80, 0x03, 0x53, 0x30,
0x07, 0x80, 0x27, 0x2e, 0x21, 0xf2, 0x98, 0xbc, 0x01, 0x42, 0x98, 0x2e, 0x91, 0x03, 0x00, 0x2e, 0x00, 0x2e, 0xd0,
0x2e, 0xb1, 0x6f, 0x9b, 0xb8, 0x07, 0x2e, 0x1b, 0x00, 0x19, 0x1a, 0xb1, 0x7f, 0x71, 0x30, 0x04, 0x2f, 0x23, 0x2e,
0x21, 0xf2, 0x00, 0x2e, 0x00, 0x2e, 0xd0, 0x2e, 0x98, 0x2e, 0x6d, 0xc0, 0x98, 0x2e, 0x5d, 0xc0, 0x98, 0x2e, 0xdf,
0x03, 0x20, 0x26, 0xc1, 0x6f, 0x02, 0x31, 0x52, 0x42, 0xab, 0x30, 0x4b, 0x42, 0x20, 0x33, 0x77, 0x56, 0xf1, 0x37,
0xc4, 0x40, 0xa2, 0x0a, 0xc2, 0x42, 0xd8, 0x00, 0x01, 0x2e, 0x5e, 0xf7, 0x41, 0x08, 0x23, 0x2e, 0x94, 0x00, 0xe3,
0x7f, 0x98, 0x2e, 0xaa, 0x01, 0xe1, 0x6f, 0x83, 0x30, 0x43, 0x42, 0x03, 0x30, 0xfb, 0x6f, 0x73, 0x50, 0x02, 0x30,
0x00, 0x2e, 0x00, 0x2e, 0x81, 0x84, 0x50, 0x0e, 0xfa, 0x2f, 0x43, 0x42, 0x11, 0x30, 0xb0, 0x5f, 0x23, 0x2e, 0x21,
0xf2, 0xb8, 0x2e, 0xc1, 0x4a, 0x00, 0x00, 0x6d, 0x57, 0x00, 0x00, 0x77, 0x8e, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff,
0xd3, 0xff, 0xff, 0xff, 0xe5, 0xff, 0xff, 0xff, 0xee, 0xe1, 0xff, 0xff, 0x7c, 0x13, 0x00, 0x00, 0x46, 0xe6, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
0xc1, 0xfd, 0x2d
};
const int bmi270_context_config_file_size = sizeof(bmi270_context_config_file);

View File

@@ -0,0 +1,8 @@
## IDF Component Manager Manifest File
description: ESP-DSP azure board application 3d graphics
dependencies:
espressif/esp-dsp:
version: '*'
override_path: ../../../../../../esp-dsp
espressif/m5stack_core_s3: '*'

View File

@@ -0,0 +1,56 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Minimal Configuration
#
CONFIG_IDF_TARGET="esp32s3"
CONFIG_COMPILER_OPTIMIZATION_PERF=y
CONFIG_I2C_ENABLE_DEBUG_LOG=y
CONFIG_I2C_ENABLE_SLAVE_DRIVER_VERSION_2=y
CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
CONFIG_SPIRAM=y
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
CONFIG_ESP_MAIN_TASK_STACK_SIZE=4096
CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=4096
CONFIG_ESP_INT_WDT=n
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=3084
CONFIG_CODEC_I2C_BACKWARD_COMPATIBLE=n
CONFIG_LV_CONF_MINIMAL=y
CONFIG_LV_USE_ASSERT_NULL=y
CONFIG_LV_USE_ASSERT_MALLOC=y
CONFIG_LV_FONT_UNSCII_8=n
CONFIG_LV_FONT_DEFAULT_MONTSERRAT_14=y
CONFIG_LV_TXT_ENC_UTF8=y
CONFIG_LV_WIDGETS_HAS_DEFAULT_VALUE=y
CONFIG_LV_USE_ANIMIMG=y
CONFIG_LV_USE_ARC=y
CONFIG_LV_USE_BUTTON=y
CONFIG_LV_USE_BUTTONMATRIX=y
CONFIG_LV_USE_CALENDAR=y
CONFIG_LV_USE_CANVAS=y
CONFIG_LV_USE_CHART=y
CONFIG_LV_USE_CHECKBOX=y
CONFIG_LV_USE_DROPDOWN=y
CONFIG_LV_USE_IMAGEBUTTON=y
CONFIG_LV_USE_KEYBOARD=y
CONFIG_LV_USE_LED=y
CONFIG_LV_USE_LINE=y
CONFIG_LV_USE_LIST=y
CONFIG_LV_USE_MENU=y
CONFIG_LV_USE_MSGBOX=y
CONFIG_LV_USE_ROLLER=y
CONFIG_LV_USE_SCALE=y
CONFIG_LV_USE_SLIDER=y
CONFIG_LV_USE_SPAN=y
CONFIG_LV_USE_SPINBOX=y
CONFIG_LV_USE_SPINNER=y
CONFIG_LV_USE_SWITCH=y
CONFIG_LV_USE_TEXTAREA=y
CONFIG_LV_USE_TABLE=y
CONFIG_LV_USE_TABVIEW=y
CONFIG_LV_USE_TILEVIEW=y
CONFIG_LV_USE_WIN=y
CONFIG_LV_USE_THEME_DEFAULT=y
CONFIG_LV_USE_THEME_SIMPLE=y
CONFIG_LV_USE_FLEX=y
CONFIG_LV_USE_GRID=y
CONFIG_LV_BUILD_EXAMPLES=y

View File

@@ -0,0 +1,8 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(spectrum_box_lite)

View File

@@ -0,0 +1,45 @@
# ESP-DSP ESP32-S3-BOX-Lite Board demo application
The demo applications are developed for the ESP32-S3-BOX-Lite development board and demonstrate the usage of FFT functions from the ESP-DSP library.
This example showcases how to use FFT functionality to process audio stream data.
The application record sound from two microphones and show the spectrum from them at display as 2D plot.
## Audio Processing Flow
The audio processing flow contains next blocks:
1. Audio processing task
* Read left and right channel data from the microphone
* Apply window multiplication to both channels
* Process FFT and apply bit reverse
* Split complex spectrum from two channels to two spectrums of two real channels
* Calculate absolute spectrum and convert it to dB
* Calculate moving average of the spectrum
2. Image Display Task
* Read data from the
* Write data from triple buffer to audio codec
## How to use the example
Just flash the application to the ESP32-S3-BOX-Lite development board, and play some music around or start to speak to the board microphones.
The display will show the real-time spectrum.
The microphone sensitivity could be adjusted in the code.
### Hardware required
This example does not require any special hardware, and can be run on any common development board.
### Configure the project
Under Component Config ---> DSP Library ---> DSP Optimization, it's possible to choose either the optimized or ANSI implementation, to compare them.
### Build and flash
Build the project and flash it to the board, then run monitor tool to view serial output (replace PORT with serial port name):
```
idf.py flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

View File

@@ -0,0 +1,2 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")

View File

@@ -0,0 +1,6 @@
dependencies:
espressif/esp-box-lite: "^2.0.3"
lvgl/lvgl: "^8.3.10"
espressif/esp-dsp:
version: '*'
override_path: "../../../../esp-dsp"

View File

@@ -0,0 +1,269 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#include <dirent.h>
#include <math.h>
#include "bsp/esp-bsp.h"
#include "esp_log.h"
#include "esp_dsp.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_system.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_timer.h"
#include <malloc.h>
// Amount of audio channels
#define I2S_CHANNEL_NUM (2)
// Microphone Sample rate
#define SAMPLE_RATE (10000)
#define BITS_PER_CHANNEL 16
// Input buffer size
#define BUFFER_PROCESS_SIZE 512
static const char *TAG = "main";
// Buffer to process output spectrum
static float result_data[BUFFER_PROCESS_SIZE];
// Microphone read task
static void microphone_read_task(void *arg)
{
esp_codec_dev_handle_t mic_codec_dev = NULL;
// Init board microphone
mic_codec_dev = bsp_audio_codec_microphone_init();
if (mic_codec_dev == NULL) {
ESP_LOGE(TAG, "Not possible to initialize microphone!");
return;
}
// Init esp-dsp library to use fft functionality
esp_err_t ret = dsps_fft2r_init_sc16(NULL, CONFIG_DSP_MAX_FFT_SIZE);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Not possible to initialize FFT esp-dsp from library!");
return;
}
esp_codec_dev_sample_info_t fs = {
.sample_rate = SAMPLE_RATE,
.channel = I2S_CHANNEL_NUM,
.channel_mask = 0,
.bits_per_sample = BITS_PER_CHANNEL,
};
int result = esp_codec_dev_open(mic_codec_dev, &fs);
if (result != ESP_OK) {
ESP_LOGE(TAG, "Not possible to open microphone!");
return;
}
// Set input microphone gain (from 1 to 100)
ESP_LOGI(TAG, "Adjust microphone input volume in the code here...");
result |= esp_codec_dev_set_in_gain(mic_codec_dev, 20.0);
if (result != ESP_OK) {
ESP_LOGE(TAG, "Not possible to set up microphone gain!");
return;
}
int audio_chunksize = BUFFER_PROCESS_SIZE;
// Allocate audio buffer and check for result
int16_t *audio_buffer = (int16_t *)memalign(16, (audio_chunksize + 16) * sizeof(int16_t) * I2S_CHANNEL_NUM);
// Allocate buffer for window
int16_t *wind_buffer = (int16_t *)memalign(16, (audio_chunksize + 16) * sizeof(int16_t) * I2S_CHANNEL_NUM);
// Generate window and convert it to int16_t
dsps_wind_blackman_harris_f32(result_data, audio_chunksize);
for (int i = 0 ; i < audio_chunksize; i++) {
wind_buffer[i * 2 + 0] = (int16_t)(result_data[i] * 32767);
wind_buffer[i * 2 + 1] = wind_buffer[i * 2 + 0];
}
while (true) {
// Read audio data from I2S bus
result = esp_codec_dev_read(mic_codec_dev, audio_buffer, audio_chunksize * sizeof(int16_t) * I2S_CHANNEL_NUM);
// Multiply input stream with window coefficients
dsps_mul_s16_ansi(audio_buffer, wind_buffer, audio_buffer, audio_chunksize * 2, 1, 1, 1, 15);
// Call FFT bit reverse
dsps_fft2r_sc16_ae32(audio_buffer, audio_chunksize);
dsps_bit_rev_sc16_ansi(audio_buffer, audio_chunksize);
// Convert spectrum from two input channels to two
// spectrums for two channels.
dsps_cplx2reC_sc16(audio_buffer, audio_chunksize);
// The output data array presented as moving average for input in dB
for (int i = 0 ; i < audio_chunksize ; i++) {
float spectrum_sqr = audio_buffer[i * 2 + 0] * audio_buffer[i * 2 + 0] + audio_buffer[i * 2 + 1] * audio_buffer[i * 2 + 1];
float spectrum_dB = 10 * log10f(0.1 + spectrum_sqr);
// Multiply with sime coefficient for better view data on screen
spectrum_dB = 4 * spectrum_dB;
// Apply moving average of spectrum
result_data[i] = 0.8 * result_data[i] + 0.2 * spectrum_dB;
}
vTaskDelay(10);
}
}
// Screen image width
#define X_AXIS_SIZE (320)
// Screen image height
#define Y_AXIS_SIZE (240)
static uint8_t screen_rgb_data[X_AXIS_SIZE * Y_AXIS_SIZE * LV_IMG_PX_SIZE_ALPHA_BYTE];
static const lv_img_dsc_t img_screen_rgb = {
.header.always_zero = 0,
.header.w = X_AXIS_SIZE,
.header.h = Y_AXIS_SIZE,
.data_size = X_AXIS_SIZE * Y_AXIS_SIZE * LV_IMG_PX_SIZE_ALPHA_BYTE,
.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA,
.data = screen_rgb_data,
};
// The function convert value to RGB565 color value
static int8_t colors[3][3] = { {0, 0, 31}, {0, 63, 0}, {31, 0, 0} };
static uint16_t convert_to_rgb(uint8_t minval, uint8_t maxval, int8_t val)
{
uint16_t result;
float i_f = (float)(val - minval) / (float)(maxval - minval) * 2;
int Ii = i_f;
float If = i_f - Ii;
int8_t *c1 = colors[Ii];
int8_t *c2 = colors[Ii + 1];
uint16_t res_colors[3];
res_colors[0] = c1[0] + If * (c2[0] - c1[0]);
res_colors[1] = c1[1] + If * (c2[1] - c1[1]);
res_colors[2] = c1[2] + If * (c2[2] - c1[2]);
result = res_colors[2] | (res_colors[1] << 5) | (res_colors[0] << 11);
return result;
}
// Init screen with blue values
static void spectrum2d_picture_init()
{
for (int y = 0 ; y < img_screen_rgb.header.h ; y++) {
for (int x = 0 ; x < img_screen_rgb.header.w ; x++) {
screen_rgb_data[(y * img_screen_rgb.header.w + x)*LV_IMG_PX_SIZE_ALPHA_BYTE + 0] = 0x0;
screen_rgb_data[(y * img_screen_rgb.header.w + x)*LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = 0x1f;
screen_rgb_data[(y * img_screen_rgb.header.w + x)*LV_IMG_PX_SIZE_ALPHA_BYTE + 2] = 0xff;
}
}
}
// Add spectrum data to the screen
static void spectrum2d_picture()
{
for (int y = 0 ; y < (img_screen_rgb.header.h - 1) ; y++) {
for (int x = 0 ; x < img_screen_rgb.header.w ; x++) {
for (int i = 0 ; i < LV_IMG_PX_SIZE_ALPHA_BYTE ; i++) {
screen_rgb_data[(y * img_screen_rgb.header.w + x)*LV_IMG_PX_SIZE_ALPHA_BYTE + i] = screen_rgb_data[((y + 1) * img_screen_rgb.header.w + x) * LV_IMG_PX_SIZE_ALPHA_BYTE + i];
}
}
}
// Add left channel to the screen
// The order of the values inverted
for (int x = 0 ; x < img_screen_rgb.header.w / 2 ; x++) {
// Get inverted index value
int in_index = img_screen_rgb.header.w / 2 - x - 1;
float data = result_data[in_index];
// Limit input data
if (data > 127) {
data = 127;
}
if (data < 0) {
data = 0;
}
// Convert input value in dB to the color
uint16_t color_val = convert_to_rgb(0, 128, data);
// Split 16 bit value to two bytes, to change the bytes order
uint8_t *ref_val = (uint8_t *)&color_val;
int out_index = x;
screen_rgb_data[((img_screen_rgb.header.h - 1)*img_screen_rgb.header.w + out_index)*LV_IMG_PX_SIZE_ALPHA_BYTE + 0] = ref_val[1];
screen_rgb_data[((img_screen_rgb.header.h - 1)*img_screen_rgb.header.w + out_index)*LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = ref_val[0];
// Set alpha value
screen_rgb_data[((img_screen_rgb.header.h - 1)*img_screen_rgb.header.w + out_index)*LV_IMG_PX_SIZE_ALPHA_BYTE + 2] = 0xff;
}
// Add right channel to the screen
for (int x = 0 ; x < img_screen_rgb.header.w / 2 ; x++) {
// Get index of right channel
int in_index = BUFFER_PROCESS_SIZE / 2 + x;
float data = result_data[in_index];
// Limit input data
if (data > 127) {
data = 127;
}
if (data < 0) {
data = 0;
}
// Convert input value in dB to the color
uint16_t color_val = convert_to_rgb(0, 128, data);
// Split 16 bit value to two bytes, to change the bytes order
uint8_t *ref_val = (uint8_t *)&color_val;
int out_index = img_screen_rgb.header.w / 2 + x;
screen_rgb_data[((img_screen_rgb.header.h - 1)*img_screen_rgb.header.w + out_index)*LV_IMG_PX_SIZE_ALPHA_BYTE + 0] = ref_val[1];
screen_rgb_data[((img_screen_rgb.header.h - 1)*img_screen_rgb.header.w + out_index)*LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = ref_val[0];
// Set alpha value
screen_rgb_data[((img_screen_rgb.header.h - 1)*img_screen_rgb.header.w + out_index)*LV_IMG_PX_SIZE_ALPHA_BYTE + 2] = 0xff;
}
}
static void image_display_task(void *arg)
{
// LV_IMG_DECLARE(img_screen_rgb);
lv_obj_t *img1 = lv_img_create(lv_scr_act());
lv_img_set_src(img1, &img_screen_rgb);
spectrum2d_picture_init();
lv_obj_align(img1, LV_ALIGN_CENTER, 0, 0);
for (;;) {
// Update image with new spectrum values
spectrum2d_picture();
// Update screen with new image
lv_obj_align(img1, LV_ALIGN_CENTER, 0, 0);
// Free CPU for a while
vTaskDelay(1);
}
}
void app_main(void)
{
/* Initialize I2C (for touch and audio) */
bsp_i2c_init();
/* Initialize display and LVGL */
bsp_display_start();
/* Set display brightness to 100% */
bsp_display_backlight_on();
int ret_val = xTaskCreatePinnedToCore(&microphone_read_task, "Microphone read Task", 8 * 1024, NULL, 3, NULL, 0);
if (ret_val != pdPASS) {
ESP_LOGE(TAG, "Not possible to allocate microphone task, ret_val = %i", ret_val);
return;
}
ret_val = xTaskCreatePinnedToCore(&image_display_task, "Draw task", 10 * 1024, NULL, 5, NULL, 1);
if (ret_val != pdPASS) {
ESP_LOGE(TAG, "Not possible to allocate microphone task, ret_val= %i", ret_val);
return;
}
}

View File

@@ -0,0 +1,66 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) 5.3.0 Project Minimal Configuration
#
CONFIG_IDF_TARGET="esp32s3"
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB=y
CONFIG_ESP32S3_DATA_CACHE_64KB=y
CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y
CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
CONFIG_ESP_INT_WDT=n
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_BSP_LCD_DRAW_BUF_HEIGHT=10
CONFIG_LV_CONF_MINIMAL=y
CONFIG_LV_MEM_CUSTOM=y
CONFIG_LV_USE_ASSERT_NULL=y
CONFIG_LV_USE_ASSERT_MALLOC=y
CONFIG_LV_USE_PERF_MONITOR=y
CONFIG_LV_FONT_UNSCII_8=n
CONFIG_LV_FONT_DEFAULT_MONTSERRAT_14=y
CONFIG_LV_TXT_ENC_UTF8=y
CONFIG_LV_USE_ARC=y
CONFIG_LV_USE_BTN=y
CONFIG_LV_USE_BTNMATRIX=y
CONFIG_LV_USE_CANVAS=y
CONFIG_LV_USE_CHECKBOX=y
CONFIG_LV_USE_DROPDOWN=y
CONFIG_LV_USE_LINE=y
CONFIG_LV_USE_ROLLER=y
CONFIG_LV_USE_SLIDER=y
CONFIG_LV_USE_SWITCH=y
CONFIG_LV_USE_TEXTAREA=y
CONFIG_LV_USE_TABLE=y
CONFIG_LV_USE_ANIMIMG=y
CONFIG_LV_USE_CALENDAR=y
CONFIG_LV_USE_CHART=y
CONFIG_LV_USE_COLORWHEEL=y
CONFIG_LV_USE_IMGBTN=y
CONFIG_LV_USE_KEYBOARD=y
CONFIG_LV_USE_LED=y
CONFIG_LV_USE_LIST=y
CONFIG_LV_USE_MENU=y
CONFIG_LV_USE_METER=y
CONFIG_LV_USE_MSGBOX=y
CONFIG_LV_USE_SPAN=y
CONFIG_LV_USE_SPINBOX=y
CONFIG_LV_USE_SPINNER=y
CONFIG_LV_USE_TABVIEW=y
CONFIG_LV_USE_TILEVIEW=y
CONFIG_LV_USE_WIN=y
CONFIG_LV_USE_THEME_DEFAULT=y
CONFIG_LV_USE_THEME_BASIC=y
CONFIG_LV_USE_FLEX=y
CONFIG_LV_USE_GRID=y
CONFIG_LV_USE_FS_POSIX=y
CONFIG_LV_FS_POSIX_LETTER=83
CONFIG_LV_USE_PNG=y
CONFIG_LV_USE_BMP=y
CONFIG_LV_USE_SJPG=y
CONFIG_LV_USE_GIF=y
CONFIG_LV_USE_SNAPSHOT=y
CONFIG_LV_BUILD_EXAMPLES=y

View File

@@ -0,0 +1,91 @@
#!/bin/bash
#
# Build the test app and all examples from the examples directory.
# Expects EXAMPLE_TARGETS, TEST_TARGETS and IDF_TOOLCHAIN environment variables to be set.
# EXAMPLE_TARGETS and TEST_TARGETS variable are the lists of IDF_TARGET values to build the examples and
# the test app for, respectively.
# IDF_TOOLCHAIN compiler toolchain used to build the test app (clang or gcc)
# -----------------------------------------------------------------------------
# Safety settings (see https://gist.github.com/ilg-ul/383869cbb01f61a51c4d).
if [[ -n "${DEBUG_SHELL}" ]]
then
set -x # Activate the expand mode if DEBUG is anything but empty.
fi
if [[ -z "${EXAMPLE_TARGETS}" || -z "${TEST_TARGETS}" || -z "${IDF_TOOLCHAIN}" ]]
then
echo "EXAMPLE_TARGETS, TEST_TARGETS and IDF_TOOLCHAIN environment variables must be set before calling this script"
exit 1
fi
if [[ -z "${SKIP_GNU_MAKE_BUILD}" ]]
then
echo "SKIP_GNU_MAKE_BUILD not set, will build with GNU Make based build system as well."
export SKIP_GNU_MAKE_BUILD=0
fi
set -o errexit # Exit if command failed.
set -o pipefail # Exit if pipe failed.
set -o nounset # Exit if variable not set.
STARS='***************************************************'
# -----------------------------------------------------------------------------
die() {
echo "${1:-"Unknown Error"}" 1>&2
exit 1
}
# build_for_targets <target list>
# call this in the project directory
function build_for_targets
{
target_list="$1"
toolchain="$2"
for IDF_TARGET in ${target_list}
do
export IDF_TARGET
if [[ "${IDF_TARGET}" = "esp32" ]] && [[ "${SKIP_GNU_MAKE_BUILD}" = "0" ]]
then
echo "${STARS}"
echo "Building in $PWD with Make"
# -j option will be set via MAKEFLAGS in .gitlab-ci.yml
# shellcheck disable=SC2015
make defconfig && make || die "Make build in ${PWD} has failed"
rm -rf build
fi
echo "${STARS}"
echo "Building in $PWD with CMake for ${IDF_TARGET}"
rm -f sdkconfig
idf.py set-target "${IDF_TARGET}"
idf.py build || die "CMake build in ${PWD} has failed for ${IDF_TARGET}"
if [[ "${toolchain}" = "clang" ]]
then
idf.py clang-check --run-clang-tidy-py run-clang-tidy
fi
idf.py fullclean || true
done
}
# Build the test app
echo "${STARS}"
pushd test_app
build_for_targets "${TEST_TARGETS}" "${IDF_TOOLCHAIN}"
popd
# Build the examples
pushd examples
EXAMPLES=$(find . -maxdepth 1 -mindepth 1 -type d | cut -d '/' -f 2)
for NAME in ${EXAMPLES}
do
pushd "${NAME}"
build_for_targets "${EXAMPLE_TARGETS}" "${IDF_TOOLCHAIN}"
popd
done
popd

View File

@@ -0,0 +1,21 @@
# ESP-DSP Examples
This directory contains a range of examples for ESP-DSP library.
These examples are intended to demonstrate part of ESP-DSP functionality (e.g. initialization, execution) and to provide code that you can copy and adapt into your own projects.
See the [README.md](../README.md) file in the upper level directory for more information about ESP-DSP.
# Example Layout
The examples are grouped into subdirectories by category. Each category directory contains one or more example projects:
* [Dot Product Calculation](./dotprod/README.md) Example
* [Basic Math Operations](./basic_math/README.md) Example
* [FFT](./fft/README.md) Example
* [Matrix](./matrix/README.md) Example
* [FFT Window](./fft_window/README.md) Example
* [IIR Filter](./iir/README.md) Example
* [Kalman Filter](./kalman/README.md) Example
* [FIR Filter](.fir/README.md) Example
* [2D Convolution](./conv2d//README.md) Example

View File

@@ -0,0 +1,20 @@
# ESP-DSP Applications
This directory contains a range of applications for ESP-DSP library.
These applications are intended to demonstrate part of ESP-DSP functionality (e.g. initialization, execution) and to provide examples of fully working projects built using ESP-DSP component
See the [README.md](../README.md) file in the upper level directory for more information about ESP-DSP.
# Applications Layout
The applications are grouped into subdirectories by category. Each category directory contains one or more projects:
* [ESP32-Azure IoT kit](./azure_board_apps/README.md) applications
* [3d graphics](./azure_board_apps/apps/3d_graphics/README.md) application
* [Kalman filter](./azure_board_apps/apps/kalman_filter/README.md) application
* [LyraT Board](./lyrat_board_app/README.md) application
* [ESP32-S3-BOX-Lite](./spectrum_box_lite/README.md) application

View File

@@ -0,0 +1,5 @@
**/build/
**/sdkconfig
**/sdkconfig.old
**/dependencies.lock
**/managed_components/**

View File

@@ -0,0 +1,29 @@
# ESP-DSP ESP32-Azure IoT kit demo applications
The demo applications are developed for ESP32-Azure IoT kit development board and are demonstrating usage of matrices with ESP-DPS Mat class, Kalman filter and basic
3D projection with matrices
### [3D Graphics demo](apps/3d_graphics)
* a simple rotation of a selected 3D objects is shown on the display
* demonstrating usage the Mat class, matrices and operations with matrices
<div align="center">
<img src= "apps/3d_graphics/3d_graphics.gif">
</div>
### [Kalman filter demo](apps/kalman_filter/)
* a selected 3D object is following movements of the development board with IMU sensors
* the sensors outputs are processed by the Kalman filter
* demonstrating usage the Mat class, matrices, operations with matrices and Kalman filter
<div align="center">
<img src= "apps/kalman_filter/kalman_filter.gif">
</div>
### [3D graphics](graphics/img_to_3d_matrix/example/)
Simple 3D graphics is used in the both demos, to display the 3D on the monochromatic display. The Graphics is using transformation matrices to rotate, scale and translate (move) 3D objects, to show the matrix calculation capabilities of the ESP-DSP repository.
## Used components
* [ESP-DSP](https://github.com/espressif/esp-dsp): matrices, Mat class, Kalman filter
* [ESP-BSP](https://github.com/espressif/esp-bsp): ESP32-Azure IoT kit

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

View File

@@ -0,0 +1,8 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
add_compile_options("-Wno-format")
project(esp-dsp-azure-board-app-3d-graphics)

View File

@@ -0,0 +1,27 @@
# ESP-DSP ESP32-Azure IoT kit 3d graphics demo application
The demo is developed for [ESP32-Azure IoT kit](https://github.com/espressif/esp-bsp/tree/master/esp32_azure_iot_kit) development board and is demonstrating the usage of matrices with `ESP-DSP` `Mat` class, Kalman filter and basic 3D graphics.
The 3D Graphics demo displays a 2D graphics, converted to 3D as a 3D rotating object, on the development board's display. Button press changes the rotation direction of the 3D object. Run the menuconfig using the following command:
idf.py mencuonfig
In the menuconfig's menu item `Demo user configuration` select which 3D object to display. It's either a 3D cube, or ESP logo, or a user-defined graphics. Getting the user-defined graphics is described in an [example](../../graphics/img_to_3d_matrix/example/)
## Running the demo
To start the demo, run the following command:
idf.py build flash monitor
The expected output is the following:
I (570) 3D image demo: Selected 3D image - ESP Logo
I (570) 3D image demo: Showing ESP text
I (6730) 3D image demo: Showing 3D image
Note, that the first line `Selected 3D image` from the expected output depends on the user's Kconfing menu selection
<div align="center">
<img src= "applications/azure_board_apps/apps/3d_graphics/3d_graphics.gif">
</div>

View File

@@ -0,0 +1,240 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "esp_log.h"
#include "ssd1306.h"
#include "bsp/esp-bsp.h"
#include "esp_dsp.h"
#include "cube_matrix.h"
#include "esp_logo.h"
#include "esp_text.h"
#include "graphics_support.h"
#include "image_to_3d_matrix.h"
static ssd1306_handle_t ssd1306_dev = NULL;
static bool button_pressed = true;
dspm::Mat perspective_matrix(MATRIX_SIZE, MATRIX_SIZE);
extern "C" void app_main();
/**
* @brief Initialize 3d image structure
*
* Assigns a 3d image to be displayed to the 3d image structure based on the Kconfig menu result.
* The Kconfig menu is operated by a user
*
* @param image: 3d image structure
*/
static void init_3d_matrix_struct(image_3d_matrix_t *image)
{
#ifdef CONFIG_3D_OBJECT_ESP_LOGO
image->matrix = image_3d_matrix_esp_logo;
image->matrix_len = ((sizeof(image_3d_matrix_esp_logo)) / sizeof(float)) / MATRIX_SIZE;
ESP_LOGI("3D image demo", "Selected 3D image - ESP Logo");
#elif CONFIG_3D_OBJECT_CUSTOM
image->matrix = image_to_3d_matrix_custom;
image->matrix_len = ((sizeof(image_to_3d_matrix_custom)) / sizeof(float)) / MATRIX_SIZE;
ESP_LOGI("3D image demo", "Selected 3D image - User's custom image");
#elif CONFIG_3D_OBJECT_CUBE
image->matrix = cube_vectors_3d;
image->matrix_len = ((sizeof(cube_vectors_3d)) / sizeof(float)) / MATRIX_SIZE;
ESP_LOGI("3D image demo", "Selected 3D image - 3D cube");
#endif
}
/**
* @brief Initialize display
*/
static void app_ssd1306_init(void)
{
ssd1306_dev = ssd1306_create((i2c_port_t)BSP_I2C_NUM, SSD1306_I2C_ADDRESS);
ssd1306_clear_screen(ssd1306_dev, 0x00);
ssd1306_refresh_gram(ssd1306_dev);
}
/**
* @brief Display a 3d image
*
* If the object is the 3d cube, connect the projected cube points by lines and display the lines
* For any other 3d object lit pixels on the display from provided XY coordinates
*
* @param projected_image: 3d matrix from Mat class after projection
*/
static void display_3d_image(dspm::Mat projected_image)
{
ssd1306_clear_screen(ssd1306_dev, 0);
if (OBJECT_3D_CUBE) {
// For the 3D cube, only the 6 points of the cube are transformed
// Cube edges, connecting transformed 3D cube points are connected with lines here
for (uint8_t cube_point = 0; cube_point < CUBE_EDGES; cube_point++) {
ssd1306_draw_line(ssd1306_dev,
(int16_t)projected_image(cube_dict_line_begin[cube_point], 0),
(int16_t)projected_image(cube_dict_line_begin[cube_point], 1),
(int16_t)projected_image(cube_dict_line_end[cube_point], 0),
(int16_t)projected_image(cube_dict_line_end[cube_point], 1));
}
} else {
// Every other 3D image is drawn here pixel by pixel
for (uint32_t pixel = 0; pixel < projected_image.rows; pixel++ ) {
ssd1306_fill_point(ssd1306_dev, projected_image(pixel, 0), projected_image(pixel, 1), 1);
}
}
ssd1306_refresh_gram(ssd1306_dev);
}
/**
* @brief Display ESPRESSIF text
*
* To demonstrate usage of the translation and scaling matrices
*/
static void dispaly_esp_text(void)
{
image_3d_matrix_t esp_text;
esp_text.matrix = image_3d_array_esp_text;
esp_text.matrix_len = ((sizeof(image_3d_array_esp_text)) / sizeof(float)) / MATRIX_SIZE;
int16_t shift_x = -SSD1606_X_CENTER;
dspm::Mat T = dspm::Mat::eye(MATRIX_SIZE); // Transformation matrix
dspm::Mat transformed_image(esp_text.matrix_len, MATRIX_SIZE); // 3D image matrix after transformation
dspm::Mat matrix_3d((float *)esp_text.matrix[0], esp_text.matrix_len, MATRIX_SIZE);
ESP_LOGI("3D image demo", "Showing ESP text");
for (int i = 0; i < 52; i++) {
update_translation_matrix(T, true, (float)shift_x, (float)SSD1606_Y_CENTER, 0);
transformed_image = matrix_3d * T;
ssd1306_clear_screen(ssd1306_dev, 0);
for (uint32_t point = 0; point < transformed_image.rows; point++ ) {
ssd1306_fill_point(ssd1306_dev, transformed_image(point, 0), transformed_image(point, 1), 1);
}
ssd1306_refresh_gram(ssd1306_dev);
vTaskDelay(50 / portTICK_PERIOD_MS);
shift_x += 5;
}
ssd1306_clear_screen(ssd1306_dev, 0);
ssd1306_draw_bitmap(ssd1306_dev, 0, 24, &image_bmp_array_esp_text[0], 128, 24);
ssd1306_refresh_gram(ssd1306_dev);
update_translation_matrix(T, true, (float)SSD1606_X_CENTER, (float)SSD1606_Y_CENTER, 0);
vTaskDelay(100 / portTICK_PERIOD_MS);
float scale = 1;
for (int i = 0; i < 20; i++) {
update_scaling_matrix(T, false, scale, scale, 1);
transformed_image = matrix_3d * T;
ssd1306_clear_screen(ssd1306_dev, 0);
for (uint32_t point = 0; point < transformed_image.rows; point++ ) {
ssd1306_fill_point(ssd1306_dev, transformed_image(point, 0), transformed_image(point, 1), 1);
}
ssd1306_refresh_gram(ssd1306_dev);
vTaskDelay(50 / portTICK_PERIOD_MS);
if (i < 10) {
scale -= 0.05;
} else {
scale += 0.05;
}
}
}
/**
* @brief RTOS task to draw a 3d image.
*
* Updates 3d matrices, prepares the final 3d matrix to be displayed on the display
*
* @param arg: pointer to RTOS task arguments, 3d image structure in this case
*/
static void draw_3d_image_task(void *arg)
{
float rot_y = 0, rot_x = 0;
const float angle_increment = 4;
image_3d_matrix_t *image = (image_3d_matrix_t *)arg;
dspm::Mat T = dspm::Mat::eye(MATRIX_SIZE); // Transformation matrix
dspm::Mat transformed_image(image->matrix_len, MATRIX_SIZE); // 3D image matrix after transformation
dspm::Mat projected_image(image->matrix_len, MATRIX_SIZE); // 3D image matrix after projection
dspm::Mat matrix_3d((float *)image->matrix[0], image->matrix_len, MATRIX_SIZE);
if (OBJECT_3D_CUBE) {
rot_x = 45;
}
while (1) {
if (button_pressed) {
rot_y += angle_increment;
if (rot_y >= 360) {
rot_y -= 360;
}
} else {
rot_y -= angle_increment;
if (rot_y <= 0) {
rot_y += 360;
}
}
// Apply rotation in all the axes to the transformation matrix
update_rotation_matrix(T, rot_x, rot_y, 0);
// Apply translation to the transformation matrix
update_translation_matrix(T, true, ((float)SSD1606_X_CENTER), ((float)SSD1606_Y_CENTER), 0);
// explanation for the matrix multiplication is for the 3D cube scenario, applies for all of the objects
// where matrix rows for the transformed image and the projected image are set according to the specific 3d object
// matrix mul cube_matirx(8x4) * transformation_matrix(4x4) = transformed_cube(8x4)
transformed_image = matrix_3d * T;
// matrix mul transformed_cube(8x4) * perspective_matrix(4x4) = projected_cube(8x4)
projected_image = transformed_image * perspective_matrix;
display_3d_image(projected_image);
vTaskDelay(20 / portTICK_PERIOD_MS);
}
}
void app_main(void)
{
static bool button_prev_val = false;
image_3d_matrix_t image;
ekf_imu13states *ekf13 = new ekf_imu13states();
ekf13->Init();
// Init all board components
bsp_i2c_init();
app_ssd1306_init(); // display init
bsp_leds_init(); // LEDs init
bsp_i2c_set_clk_speed(I2C_CLK_600KHZ); // Set I2C to 600kHz
init_perspective_matrix(perspective_matrix);
init_3d_matrix_struct(&image);
dispaly_esp_text();
vTaskDelay(1000 / portTICK_PERIOD_MS);
xTaskCreate(draw_3d_image_task, "draw_3d_image", 2048, &image, 4, NULL);
ESP_LOGI("3D image demo", "Showing 3D image");
while (1) {
if (bsp_button_get()) {
button_pressed = !button_pressed;
}
if (button_prev_val != button_pressed) {
button_prev_val = button_pressed;
if (button_pressed) {
bsp_led_set(BSP_LED_AZURE, true);
} else {
bsp_led_set(BSP_LED_AZURE, false);
}
}
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}

View File

@@ -0,0 +1,8 @@
idf_component_register(SRCS "3d_graphics_demo.cpp"
"../../../graphics/3d_matrix/3d_matrix_data/esp_logo.c"
"../../../graphics/3d_matrix/3d_matrix_data/esp_text.c"
"../../../graphics/3d_matrix/3d_matrix_data/image_to_3d_matrix.c"
"../../../graphics/3d_matrix/3d_matrix_src/graphics_support.cpp"
INCLUDE_DIRS "."
"../../../graphics/3d_matrix/3d_matrix_data"
"../../../graphics/3d_matrix/3d_matrix_src")

View File

@@ -0,0 +1,19 @@
menu "Demo user configuration"
choice
prompt "Select 3D object"
config 3D_OBJECT_CUBE
bool "3D cube"
help
3D graphics to be displayed is cube
config 3D_OBJECT_ESP_LOGO
bool "3D ESP Logo"
help
3D graphics to be displayed is ESP Logo
config 3D_OBJECT_CUSTOM
bool "User-defined graphics"
help
3D graphics to be displayed is a user-defined graphics
endchoice
endmenu

View File

@@ -0,0 +1,8 @@
## IDF Component Manager Manifest File
description: ESP-DSP azure board application 3d graphics
dependencies:
espressif/esp32_azure_iot_kit: "*"
espressif/esp-dsp:
version: "*"
override_path: "../../../../../../esp-dsp"

View File

@@ -0,0 +1,8 @@
# For more information about build system see
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
add_compile_options("-Wno-format")
project(esp-dsp-azure-board-app-kalman-filter)

View File

@@ -0,0 +1,59 @@
# ESP-DSP ESP32-Azure IoT kit Kalman filter demo application
The demo is developed for [ESP32-Azure IoT kit](https://github.com/espressif/esp-bsp/tree/master/esp32_azure_iot_kit) development board and is demonstrating the usage of matrices with `ESP-DSP` `Mat` class, Kalman filter and basic 3D graphics.
The Kalman filter demo displays a 2D graphics, converted to 3D as a 3D object, on the development board's display. The 3D object follows the movements of the development board, where the Kalman filter is used for processing the output signals of the IMU sensors accommodated on the development board. The 3D object rotation is calculated by the Kalman filter class methods. All 3 IMU sensors present on the dev board (accelerometer, gyroscope and magnetometer) are used for sensing the development board's position.
If the board is inactive (no, or very low rotation is detected) for a set period of time, the demo enters an "Idle" state, in which a 3D rotating object is displayed. Once a certain set level of the board's rotation is detected, the demo enters a normal, "Active", state.
For the project settings, run the menuconfig using the following command:
idf.py mencuonfig
In the menuconfig's menu item `Demo user configuration` select which 3D object to display. It's either 3D cube, or ESP logo, or a user-defined graphics. Getting the user-defined 3D object is described in the [3D Graphics demo](../3d_graphics)
## Kalman filter
#### Calibration
The filter must be calibrated before the first run, which takes several minutes. But the calibration process before each run can be omitted by calibrating the filter once, saving Kalman's filter state vectors to the NVS, and loading those vectors back into the Kalman filter before the run. In addition, every 5 minutes a current state vectors are saved into the flash memory.
## Running the demo
To start the demo, run the following command:
idf.py build flash monitor
The expected output is the following:
I (589) Kalman filter demo: Selected 3D image - 3D cube
I (590) Kalman filter demo: Filter state vectors present in the NVS
I (592) Kalman filter demo: Loading state vectors into the filter structure
I (604) Kalman filter demo: State vectors loaded from the NVS
I (606) Barometer: disabled
I (619) Board status: board put to active mode
I (95780) Board status: board put to idle mode
I (300619) Kalman filter demo: State vectors saved to NVS
Note, that the first line `Selected 3D image` from the expected output depends on the user's Kconfing menu selection
To start the demo and run the initial Kalman filter calibration, one must erase the flash memory, to remove the previously stored Kalman filter's state vectors. To do so, run the following command:
idf.py erase_flash build flash monitor
The expected output is the following:
I (592) Kalman filter demo: Selected 3D image - 3D cube
I (595) Kalman filter demo: Filter state vectors not present in the NVS
I (595) Kalman filter demo: Starting Kalman filter calibration loop
I (100699) Kalman filter demo: Exiting Kalman filter calibration loop
I (100894) Kalman filter demo: Estimated gyroscope bias error [deg/sec]: -0.020715 -0.000431 -0.022452
I (100900) Kalman filter demo: State vectors saved to the NVS
I (100900) Barometer: disabled
I (100911) Board status: board put to active mode
I (196072) Board status: board put to idle mode
I (400912) Kalman filter demo: State vectors saved to NVS
<div align="center">
<img src= "applications/azure_board_apps/apps/kalman_filter/kalman_filter.gif">
</div>

View File

@@ -0,0 +1,7 @@
idf_component_register(SRCS "kalman_filter_demo.cpp"
"../../../graphics/3d_matrix/3d_matrix_data/esp_logo.c"
"../../../graphics/3d_matrix/3d_matrix_data/image_to_3d_matrix.c"
"../../../graphics/3d_matrix/3d_matrix_src/graphics_support.cpp"
INCLUDE_DIRS "."
"../../../graphics/3d_matrix/3d_matrix_data"
"../../../graphics/3d_matrix/3d_matrix_src")

View File

@@ -0,0 +1,19 @@
menu "Demo user configuration"
choice
prompt "Select 3D object"
config 3D_OBJECT_CUBE
bool "3D cube"
help
3D graphics to be displayed is cube
config 3D_OBJECT_ESP_LOGO
bool "3D ESP Logo"
help
3D graphics to be displayed is ESP Logo
config 3D_OBJECT_CUSTOM
bool "User-defined graphics"
help
3D graphics to be displayed is a user-defined graphics
endchoice
endmenu

View File

@@ -0,0 +1,8 @@
## IDF Component Manager Manifest File
description: ESP-DSP azure board application Kalman filter
dependencies:
espressif/esp32_azure_iot_kit: "*"
espressif/esp-dsp:
version: "*"
override_path: "../../../../../../esp-dsp"

View File

@@ -0,0 +1,608 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <malloc.h>
#include "mpu6050.h"
#include "ssd1306.h"
#include "mag3110.h"
#include "fbm320.h"
#include "bsp/esp-bsp.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "esp_idf_version.h" // for backward compatibility of esp-timer
#include "nvs.h"
#include "nvs_flash.h"
#include "graphics_support.h"
#include "cube_matrix.h"
#include "esp_dsp.h"
#include "ekf_imu13states.h"
#include "esp_logo.h"
#include "image_to_3d_matrix.h"
#define STORAGE_NAMESPACE "kalman_filter"
#define USE_BAROMETER 0
static ssd1306_handle_t ssd1306_dev = NULL;
static mpu6050_handle_t mpu6050_dev = NULL;
static mag3110_handle_t mag3110_dev = NULL;
static fbm320_handle_t fbm320_dev = NULL;
static bool kalman_filter_calibrated = false;
static bool board_inactive = true;
dspm::Mat perspective_matrix(MATRIX_SIZE, MATRIX_SIZE);
extern "C" void app_main();
/**
* @brief Initialize magnetometer
*/
static void app_mag3110_init(void)
{
esp_err_t ret;
mag3110_dev = mag3110_create((i2c_port_t)BSP_I2C_NUM);
mag3110_start_raw(mag3110_dev, MAG3110_DR_OS_80_16);
assert(ESP_OK == ret);
}
/**
* @brief Initialize display
*/
static void app_ssd1306_init(void)
{
ssd1306_dev = ssd1306_create((i2c_port_t)BSP_I2C_NUM, SSD1306_I2C_ADDRESS);
ssd1306_clear_screen(ssd1306_dev, 0x00);
ssd1306_refresh_gram(ssd1306_dev);
}
/**
* @brief Initialize accelerometer and gyroscope
*/
static void mpu6050_init(void)
{
esp_err_t ret;
mpu6050_dev = mpu6050_create((i2c_port_t)BSP_I2C_NUM, MPU6050_I2C_ADDRESS);
ret = mpu6050_config(mpu6050_dev, ACCE_FS_8G, GYRO_FS_2000DPS);
assert(ESP_OK == ret);
ret = mpu6050_wake_up(mpu6050_dev);
assert(ESP_OK == ret);
}
/**
* @brief Initialize pressure sensor
*/
static void app_fbm320_init(void)
{
esp_err_t ret;
fbm320_dev = fbm320_create((i2c_port_t)BSP_I2C_NUM, FBM320_I2C_ADDRESS_1);
ret = fbm320_init(fbm320_dev);
assert(ESP_OK == ret);
}
/**
* @brief Initialize NVS flash memory
*/
static void init_nvs_flash_memory(void)
{
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
// NVS partition was truncated and needs to be erased
// Retry nvs_flash_init
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK( err );
}
/**
* @brief Initialize 3d image structure
*
* Assigns a 3d image to be displayed to the 3d image structure based on the Kconfig menu result.
* The Kconfig menu is operated by a user
*
* @param image: pointer to 3d image structure
* @param ekf13: kalman filter object
*/
static void init_3d_matrix_struct(image_3d_matrix_kalman_t *image, ekf_imu13states *ekf13)
{
#ifdef CONFIG_3D_OBJECT_ESP_LOGO
image->matrix = image_3d_matrix_esp_logo;
image->matrix_len = ((sizeof(image_3d_matrix_esp_logo)) / sizeof(float)) / MATRIX_SIZE;
ESP_LOGI("Kalman filter demo", "Selected 3D image - ESP Logo");
#elif CONFIG_3D_OBJECT_CUSTOM
image->matrix = image_to_3d_matrix_custom;
image->matrix_len = ((sizeof(image_to_3d_matrix_custom)) / sizeof(float)) / MATRIX_SIZE;
ESP_LOGI("Kalman filter demo", "Selected 3D image - User's custom image");
#elif CONFIG_3D_OBJECT_CUBE
image->matrix = cube_vectors_3d;
image->matrix_len = ((sizeof(cube_vectors_3d)) / sizeof(float)) / MATRIX_SIZE;
ESP_LOGI("Kalman filter demo", "Selected 3D image - 3D cube");
#endif
image->ekf13 = ekf13;
}
/**
* @brief Display a 3d image
*
* If the object is the 3d cube, connect the projected cube points by lines and display the lines
* For any other 3d object lit pixels on the display from provided XY coordinates
*
* @param projected_image: 3d matrix from Mat class after projection
*/
static void display_3d_image(dspm::Mat projected_image)
{
ssd1306_clear_screen(ssd1306_dev, 0);
if (OBJECT_3D_CUBE) {
// For the 3D cube, only the 6 points of the cube are transformed
// Cube edges, connecting transformed 3D cube points are connected with lines here
for (uint8_t cube_point = 0; cube_point < CUBE_EDGES; cube_point++) {
ssd1306_draw_line(ssd1306_dev,
(int16_t)projected_image(cube_dict_line_begin[cube_point], 0),
(int16_t)projected_image(cube_dict_line_begin[cube_point], 1),
(int16_t)projected_image(cube_dict_line_end[cube_point], 0),
(int16_t)projected_image(cube_dict_line_end[cube_point], 1));
}
} else {
// Every other 3D image is drawn here pixel by pixel
for (uint32_t pixel = 0; pixel < projected_image.rows; pixel++ ) {
ssd1306_fill_point(ssd1306_dev, projected_image(pixel, 0), projected_image(pixel, 1), 1);
}
}
ssd1306_refresh_gram(ssd1306_dev);
}
/**
* @brief Draw a 3d image
*
* Updates 3d matrices and prepares the final 3d matrix to be displayed on the display.
* Board inactivity check - decides which board mode to display (active or inactive), based on the board movements.
*
* @param ekf13: kalman filter object
* @param transformed_image: 3d matrix holding a 3d image after transformation
* @param projected_image: 3d matrix holding a 3d image after projection
* @param matrix_3d: 3d matrix holding the original 3d image, without any transformation
*/
static void draw_3d_image(ekf_imu13states *ekf13, dspm::Mat &transformed_image, dspm::Mat &projected_image, dspm::Mat &matrix_3d)
{
static const float movement_treshold = 0.0001; // threshold to decide between Idle and Active state of the board
static float inactive_rotation = 0; // rotation angle (in degrees) for Idle state
static unsigned int inactivity_count = 0;
static const unsigned int inactivity_count_treshold = 75;
static unsigned int inactivity_check = 0; // activity of the board is being checked once in N calls of the function
static float prev_state_arr[3] = {0, 0, 0}; // holds the previous state of the Euler angles, to compare the diff
dspm::Mat T = dspm::Mat::eye(MATRIX_SIZE); // Transformation matrix
dspm::Mat R1 = ekf::quat2rotm(ekf13->X.data); // matrix(3x1) that holds x, y, z rotation data
dspm::Mat eul_angles = ekf::rotm2eul(R1);
// check if the board is active or not every N calls of the function
if (!(inactivity_check++ % 10)) {
dspm::Mat prev_state_mat(prev_state_arr, 3, 1);
dspm::Mat diff = eul_angles - prev_state_mat;
prev_state_mat = eul_angles;
float max_diff = fabs(diff(0, 0) * diff(1, 0) * diff(2, 0));
// wake-up the board if the current board movement crosses the threshold
if (board_inactive && (max_diff > movement_treshold)) {
board_inactive = false;
ESP_LOGI("Board status", "board put to active mode");
}
// if the board is awake, and the current movement of the board is lower than the threshold - the board is
// being moved with - run the inactivity_counter
// after some time (if the movement of the board has been lower than the threshold) put the board to idle mode
else if (!board_inactive && (max_diff < movement_treshold)) {
if (inactivity_count > inactivity_count_treshold) {
board_inactive = true;
inactivity_count = 0;
ESP_LOGI("Board status", "board put to idle mode");
update_perspective_matrix(perspective_matrix, 90);
}
inactivity_count++;
}
// if the board is awake and the current movement of the board is higher than the threshold clear the inactivity_counter
else if (!board_inactive && (max_diff >= movement_treshold)) {
inactivity_count = 0;
}
}
if (board_inactive) {
// board idle state - display a rotating cube
update_rotation_matrix(T, inactive_rotation += 3.0, 10.0, 10.0);
} else {
// board active state - 3D object follows movements of the board
eul_angles(2, 0) = -eul_angles(2, 0);
dspm::Mat R = ekf::eul2rotm(eul_angles.data);
// Enlarge rotation matrix from 3x3 to 4x4
// Copy rotation matrix R(3x3) to transformation matrix T_m(4x4)
for (int row = 0; row < R.rows; row++) {
for (int col = 0; col < R.cols; col++) {
T(row, col) = R(row, col);
}
}
}
// explanation for the matrix multiplication is for the 3D cube scenario, applies for all of the objects
// where matrix rows for the transformed image and the projected image are set according to the specific 3d object
// matrix mul cube_matirx(8x4) * transformation_matrix(4x4) = transformed_cube(8x4)
transformed_image = matrix_3d * T;
// matrix mul transformed_cube(8x4) * perspective_matrix(4x4) = projected_cube(8x4)
projected_image = transformed_image * perspective_matrix;
display_3d_image(projected_image);
}
/**
* @brief Kalman filter RTOS task (or ESP timer callback)
*
* Takes IMU sensors measurements to be processed by the Kalman filter
* Function is used as:
* RTOS task - during normal Kalman filter operation
* ESP Timer callback function - during Kalman filter calibration process
*
* @param arg: pointer to RTOS task arguments, 3d image structure in this case
*/
static void kalman_filter_task(void *arg)
{
mpu6050_acce_value_t acce_sample;
mpu6050_gyro_value_t gyro_sample;
mag3110_result_t mag_sample;
image_3d_matrix_kalman_t *kalman_filter_args = (image_3d_matrix_kalman_t *)arg;
ekf_imu13states *ekf13 = kalman_filter_args->ekf13;
dspm::Mat transformed_image(kalman_filter_args->matrix_len, MATRIX_SIZE); // 3D image matrix after transformation
dspm::Mat projected_image(kalman_filter_args->matrix_len, MATRIX_SIZE); // 3D image matrix after projection
dspm::Mat matrix_3d((float *)kalman_filter_args->matrix[0], kalman_filter_args->matrix_len, MATRIX_SIZE);
// Covariance matrix for Kalman filter, set specifically for this development board IMU sensors
float R_m[10] = {0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.0001, 0.000001, 0.000001, 0.000001, 0.000001};
update_perspective_matrix(perspective_matrix, 90);
while (1) {
// dt calculation
static float prev_time = 0;
const float current_time = dsp_get_cpu_cycle_count();
float dt = 0;
// Crystal count difference conversion to Dt time constant
if (current_time > prev_time) {
dt = current_time - prev_time;
dt = dt / 240000000.0;
}
prev_time = current_time;
// Get all the sensors values
mpu6050_get_acce(mpu6050_dev, &acce_sample);
mpu6050_get_gyro(mpu6050_dev, &gyro_sample);
mag3110_get_magnetic_induction(mag3110_dev, &mag_sample);
// Make arrays from the sensors values
float gyro_input_arr[3] = {gyro_sample.gyro_x, gyro_sample.gyro_y, gyro_sample.gyro_z};
float accel_input_arr[3] = {acce_sample.acce_x, acce_sample.acce_y, acce_sample.acce_z};
float mag_input_arr[3] = {(float)mag_sample.x, (float)mag_sample.y, (float)mag_sample.z};
// Accel and Mag data to Mat class
dspm::Mat gyro_input_mat(gyro_input_arr, 3, 1);
dspm::Mat accel_input_mat(accel_input_arr, 3, 1);
dspm::Mat mag_input_mat(mag_input_arr, 3, 1);
// Normalize vectors
dspm::Mat accel_norm = accel_input_mat / accel_input_mat.norm();
dspm::Mat magn_norm = mag_input_mat / mag_input_mat.norm();
gyro_input_mat *= DEG_TO_RAD;
ekf13->Process(gyro_input_mat.data, dt);
ekf13->UpdateRefMeasurementMagn(accel_norm.data, magn_norm.data, R_m);
if (kalman_filter_calibrated) {
// Use the function as RTOS task for the filter calculation
draw_3d_image(ekf13, transformed_image, projected_image, matrix_3d);
vTaskDelay(20 / portTICK_PERIOD_MS);
} else {
// Use the function as a callback for kalman_filter_calibration_timer
break;
}
}
}
/**
* @brief Kalman filter calibration procedure
*
* The Kalman filter must be calibrated before the very first run. The state of the Kalman filter is saved
* into NVS after the calibration.
* The calibration is run, only if no Kalman filter state is saved in the NVS. Which occurs after erasing
* the flash memory. Power cycling the board does not remove the Kalman filter state from the NVS.
*
* @param image: pointer to 3d image structure
*/
static void kalman_filter_calibration(image_3d_matrix_kalman_t *image)
{
ekf_imu13states *ekf13 = image->ekf13;
esp_err_t ret;
nvs_handle_t nvs_handle_kalman;
size_t state_vectors_size = 13 * 14;
float *state_vectors = (float *)malloc(state_vectors_size * sizeof(float));
ret = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &nvs_handle_kalman);
if (ret != ESP_OK) {
ESP_LOGE("NVS error", "(%s) opening NVS!\n", esp_err_to_name(ret));
assert(ESP_OK == ret);
}
// Read previously saved blob, if available
size_t required_size = 0; // value will default to 0, if not set yet in NVS
ret = nvs_get_blob(nvs_handle_kalman, "state_vectors", NULL, &required_size);
if (ret != ESP_OK && ret != ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGE("NVS error", "(%s) reading data from NVS!\n", esp_err_to_name(ret));
assert(ESP_OK == ret);
}
if (required_size > 0) {
ESP_LOGI("Kalman filter demo", "Filter state vectors present in the NVS");
ESP_LOGI("Kalman filter demo", "Loading state vectors into the filter structure");
size_t state_vectors_size_addr = state_vectors_size * sizeof(float);
ret = nvs_get_blob(nvs_handle_kalman, "state_vectors", state_vectors, &state_vectors_size_addr);
if (ret != ESP_OK) {
ESP_LOGE("NVS error", "(%s) reading data from NVS!\n", esp_err_to_name(ret));
assert(ESP_OK == ret);
}
for (int i = 0; i < state_vectors_size; i++) {
if (i < state_vectors_size - 13) {
ekf13->P.data[i] = state_vectors[i];
} else {
ekf13->X.data[i - (state_vectors_size - 13)] = state_vectors[i];
}
}
ESP_LOGI("Kalman filter demo", "State vectors loaded from the NVS");
nvs_close(nvs_handle_kalman);
} else {
ESP_LOGI("Kalman filter demo", "Filter state vectors not present in the NVS");
const float kalman_timer_period_us = 100000;
// ESP timer for the Kalman filter calibration
const esp_timer_create_args_t kalman_calibration_timer_config = {
.callback = kalman_filter_task,
.arg = image,
.dispatch_method = ESP_TIMER_TASK,
.name = "kalman_filter_calibration_timer",
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0)
.skip_unhandled_events = true,
#endif
};
esp_timer_handle_t kalman_calibration_timer = NULL;
ret = esp_timer_create(&kalman_calibration_timer_config, &kalman_calibration_timer);
assert(ESP_OK == ret);
ssd1306_clear_screen(ssd1306_dev, 0x00);
ESP_LOGI("Kalman filter demo", "Starting Kalman filter calibration loop");
ssd1306_clear_screen(ssd1306_dev, 0x00);
ssd1306_draw_string(ssd1306_dev, 0, 16, (const uint8_t *)"Kalman filter", 16, 1);
ssd1306_draw_string(ssd1306_dev, 0, 32, (const uint8_t *)"calibration", 16, 1);
ssd1306_refresh_gram(ssd1306_dev);
ret = esp_timer_start_periodic(kalman_calibration_timer, kalman_timer_period_us);
assert(ESP_OK == ret);
vTaskDelay(100000 / portTICK_PERIOD_MS);
ret = esp_timer_stop(kalman_calibration_timer);
assert(ESP_OK == ret);
ret = esp_timer_delete(kalman_calibration_timer);
assert(ESP_OK == ret);
ESP_LOGI("Kalman filter demo", "Exiting Kalman filter calibration loop");
ssd1306_draw_string(ssd1306_dev, 0, 48, (const uint8_t *)"Done!", 16, 1);
ssd1306_refresh_gram(ssd1306_dev);
vTaskDelay(100 / portTICK_PERIOD_MS);
dspm::Mat estimated_error(&ekf13->X.data[4], 3, 1);
ESP_LOGI("Kalman filter demo", "Estimated gyroscope bias error [deg/sec]: %.6f\t%.6f\t%.6f",
estimated_error.data[0], estimated_error.data[1], estimated_error.data[2]);
for (int i = 0; i < state_vectors_size; i++) {
if (i < state_vectors_size - 13) {
state_vectors[i] = ekf13->P.data[i];
} else {
state_vectors[i] = ekf13->X.data[i - (state_vectors_size - 13)];
}
}
ret = nvs_set_blob(nvs_handle_kalman, "state_vectors", state_vectors, state_vectors_size * sizeof(float));
assert(ESP_OK == ret);
ret = nvs_commit(nvs_handle_kalman);
assert(ESP_OK == ret);
nvs_close(nvs_handle_kalman);
ESP_LOGI("Kalman filter demo", "State vectors saved to the NVS");
}
// Set the initial state of the X vector
ekf13->X(0, 0) = 1;
ekf13->X(0, 1) = 0;
ekf13->X(0, 2) = 0;
ekf13->X(0, 3) = 0;
free(state_vectors);
kalman_filter_calibrated = true;
}
/**
* @brief RTOS task to periodically save the filter state
*
* The Kalman filter state is periodically saved into the NVS, each 5 min. So a recent Kalman filter state
* could be loaded into the Kalman filter object after a power cycle.
*
* @param arg: pointer to RTOS task arguments, Kalman filter object in this case
*/
static void save_state_vectors_task(void *arg)
{
esp_err_t ret;
size_t state_vectors_size = 13 * 14;
nvs_handle_t nvs_handle_kalman;
ekf_imu13states *ekf13 = (ekf_imu13states *)arg;
vTaskDelay((60000 * 5) / portTICK_PERIOD_MS); // 5min
while (1) {
float *state_vectors = (float *)malloc(state_vectors_size * sizeof(float));
ret = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &nvs_handle_kalman);
if (ret != ESP_OK) {
ESP_LOGE("NVS error", "(%s) opening NVS!\n", esp_err_to_name(ret));
assert(ESP_OK == ret);
}
for (int i = 0; i < state_vectors_size; i++) {
if (i < state_vectors_size - 13) {
state_vectors[i] = ekf13->P.data[i];
} else {
state_vectors[i] = ekf13->X.data[i - (state_vectors_size - 13)];
}
}
ret = nvs_set_blob(nvs_handle_kalman, "state_vectors", state_vectors, state_vectors_size * sizeof(float));
if (ret != ESP_OK && ret != ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGE("NVS error", "(%s) writing data to NVS!\n", esp_err_to_name(ret));
assert(ESP_OK == ret);
}
ret = nvs_commit(nvs_handle_kalman);
if (ret != ESP_OK && ret != ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGE("NVS error", "(%s) commiting data to NVS!\n", esp_err_to_name(ret));
assert(ESP_OK == ret);
}
nvs_close(nvs_handle_kalman);
ESP_LOGI("Kalman filter demo", "State vectors saved to NVS");
free(state_vectors);
vTaskDelay((60000 * 5) / portTICK_PERIOD_MS); // Save the State vectors each 5 min
}
}
/**
* @brief ROTS task to read a pressure
*
* Pressure is measured periodically to better average out a stable value of pressure
*
* @param arg: pointer to RTOS task arguments, pointer to the pressure variable in this case
*/
static void get_pressure_task(void *arg)
{
int32_t real_p, real_t;
float *pressure_ptr = (float *)arg;
float pressure_global = *pressure_ptr;
int call_count = 0;
int call_count1 = 0;
float pressure_initial = pressure_global;
float last_pressure = pressure_global;
float baro_image = pressure_global;
bool changed = false;
while (1) {
if (ESP_OK == fbm320_get_data(fbm320_dev, FBM320_MEAS_PRESS_OSR_4096, &real_t, &real_p)) {
pressure_global = (0.999 * pressure_global) + (0.001 * ((float)real_p) / 1000.0);
call_count1++;
}
if (board_inactive) {
pressure_initial = pressure_global;
last_pressure = pressure_global;
baro_image = pressure_global;
} else {
call_count++;
if (fabs(pressure_global - last_pressure) > 0.0005) { // cahnge more than 0.5 Pa
last_pressure = pressure_global;
baro_image = (0.9 * baro_image) + (0.1 * last_pressure);
changed = true;
}
if ((!(call_count % 10)) && changed) {
float fov = 90 + (1000.0 * ((float)(pressure_initial - baro_image)));
update_perspective_matrix(perspective_matrix, fov);
changed = false;
}
}
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
/**
* @brief read the initial value of pressure
*/
float get_initial_pressure(void)
{
float pressure;
int32_t real_p, real_t;
int averagning_loop_count = 500;
ESP_LOGI("Barometer", "Averagining initial barometer pressure");
ssd1306_clear_screen(ssd1306_dev, 0x00);
ssd1306_draw_string(ssd1306_dev, 0, 16, (const uint8_t *)"Barometer", 16, 1);
ssd1306_draw_string(ssd1306_dev, 0, 32, (const uint8_t *)"averaging", 16, 1);
ssd1306_refresh_gram(ssd1306_dev);
// take the first pressure measurement
while (1) {
if (ESP_OK == fbm320_get_data(fbm320_dev, FBM320_MEAS_PRESS_OSR_4096, &real_t, &real_p)) {
pressure = ((float)real_p) / 1000.0; // pressure in kPa
break;
}
}
// average first N measurements
while (averagning_loop_count--) {
if (ESP_OK == fbm320_get_data(fbm320_dev, FBM320_MEAS_PRESS_OSR_4096, &real_t, &real_p)) {
pressure = (0.999 * pressure) + (0.001 * ((float)real_p) / 1000.0);
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
ESP_LOGI("Barometer", "Initial value set");
ssd1306_draw_string(ssd1306_dev, 0, 48, (const uint8_t *)"Done!", 16, 1);
ssd1306_refresh_gram(ssd1306_dev);
return (pressure);
}
void app_main(void)
{
image_3d_matrix_kalman_t image;
ekf_imu13states *ekf13 = new ekf_imu13states();
ekf13->Init();
// Init all board components
bsp_i2c_init();
app_ssd1306_init(); // display init
mpu6050_init(); // gyro, acc init
app_mag3110_init(); // magnetometer init
app_fbm320_init(); // barometer init
bsp_leds_init(); // LEDs init
init_nvs_flash_memory(); // Non-Volatile Storage
init_perspective_matrix(perspective_matrix);
init_3d_matrix_struct(&image, ekf13);
kalman_filter_calibration(&image);
// Use a barometer for measuring the altitude
if (USE_BAROMETER) {
float init_pressure = get_initial_pressure();
xTaskCreate(get_pressure_task, "get_pressure_task", 2048 * 4, &init_pressure, 4, NULL);
} else {
ESP_LOGI("Barometer", "disabled");
}
xTaskCreate(kalman_filter_task, "kalman_filter_task", 2048 * 4, &image, 5, NULL);
xTaskCreate(save_state_vectors_task, "save_state_vectors", 2048, ekf13, 6, NULL);
while (1) {
vTaskDelay(10000 / portTICK_PERIOD_MS);
}
}

View File

@@ -0,0 +1,3 @@
img_to_3d_matrix/converted_image/**
img_to_3d_matrix/example/*.c
img_to_3d_matrix/example/*.h

View File

@@ -0,0 +1,51 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "graphics_support.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C"
{
#endif
#define CUBE_POINTS 8
#define CUBE_EDGES 12
#define CUBE_SIDE (SSD1606_Y_CENTER / 2)
// X Y Z coordinates of the cube centered to (0, 0, 0)
const float cube_vectors_3d[CUBE_POINTS][MATRIX_SIZE] =
// X Y Z W
{ {-CUBE_SIDE, -CUBE_SIDE, -CUBE_SIDE, 1}, // -1, -1, -1
{-CUBE_SIDE, -CUBE_SIDE, CUBE_SIDE, 1}, // -1, -1, 1
{-CUBE_SIDE, CUBE_SIDE, -CUBE_SIDE, 1}, // -1, 1, -1
{-CUBE_SIDE, CUBE_SIDE, CUBE_SIDE, 1}, // -1, 1, 1
{ CUBE_SIDE, -CUBE_SIDE, -CUBE_SIDE, 1}, // 1, -1, -1
{ CUBE_SIDE, -CUBE_SIDE, CUBE_SIDE, 1}, // 1, -1, 1
{ CUBE_SIDE, CUBE_SIDE, -CUBE_SIDE, 1}, // 1, 1, -1
{ CUBE_SIDE, CUBE_SIDE, CUBE_SIDE, 1} // 1, 1, 1
};
// Dictionary for 3d cube edges displaying
// Cube edges cube_vectors_3d[3] <-> cube_vectors_3d[1]
// cube_vectors_3d[3] <-> cube_vectors_3d[7]
// cube_vectors_3d[5] <-> cube_vectors_3d[7]
// cube_vectors_3d[5] <-> cube_vectors_3d[1]....
const uint8_t cube_dict_line_begin[CUBE_EDGES] = {3, 3, 5, 5, 2, 2, 4, 4, 3, 7, 1, 5};
const uint8_t cube_dict_line_end[CUBE_EDGES] = {1, 7, 7, 1, 0, 6, 6, 0, 2, 6, 0, 4};
#ifdef CONFIG_3D_OBJECT_CUBE
#define OBJECT_3D_CUBE 1
#else
#define OBJECT_3D_CUBE 0
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,290 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_logo.h"
#ifdef CONFIG_3D_OBJECT_ESP_LOGO
const uint8_t image_bmp_array_esp_logo[512] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00,
0x00, 0x00, 0x0f, 0xc0, 0x1f, 0xfc, 0x00, 0x00, 0x00, 0x0c, 0x1f, 0xfc, 0x07, 0xfe, 0x00, 0x00,
0x00, 0x0c, 0x3f, 0xff, 0x03, 0xff, 0x00, 0x00, 0x00, 0x18, 0x7f, 0xff, 0xc0, 0xff, 0xc0, 0x00,
0x00, 0x38, 0x7f, 0xff, 0xf0, 0x7f, 0xe0, 0x00, 0x00, 0x70, 0x7f, 0xff, 0xf8, 0x3f, 0xe0, 0x00,
0x00, 0x60, 0x7f, 0xff, 0xfe, 0x0f, 0xf0, 0x00, 0x00, 0xe0, 0x01, 0xff, 0xff, 0x07, 0xf8, 0x00,
0x00, 0xc0, 0x00, 0x3f, 0xff, 0x83, 0xfc, 0x00, 0x01, 0xc0, 0x00, 0x07, 0xff, 0xe1, 0xfc, 0x00,
0x01, 0x81, 0xfc, 0x01, 0xff, 0xf0, 0xfe, 0x00, 0x01, 0x87, 0xff, 0xc0, 0x7f, 0xf8, 0xfe, 0x00,
0x03, 0x0f, 0xff, 0xf0, 0x3f, 0xf8, 0x7e, 0x00, 0x03, 0x1f, 0xff, 0xfc, 0x1f, 0xfc, 0x3f, 0x00,
0x03, 0x1f, 0xff, 0xff, 0x07, 0xfe, 0x1f, 0x00, 0x03, 0x3f, 0xff, 0xff, 0x83, 0xff, 0x1f, 0x00,
0x06, 0x3f, 0xff, 0xff, 0xc1, 0xff, 0x0f, 0x00, 0x06, 0x3f, 0xff, 0xff, 0xe0, 0xff, 0x8f, 0x80,
0x06, 0x7f, 0x83, 0xff, 0xf0, 0xff, 0xc7, 0x80, 0x06, 0x7f, 0x80, 0x7f, 0xf8, 0x7f, 0xc7, 0x80,
0x06, 0x7f, 0xc0, 0x1f, 0xfc, 0x3f, 0xe3, 0x80, 0x06, 0x3f, 0xfc, 0x0f, 0xfe, 0x3f, 0xe3, 0x80,
0x06, 0x3f, 0xff, 0x07, 0xff, 0x1f, 0xf1, 0x80, 0x06, 0x3f, 0xff, 0xc3, 0xff, 0x0f, 0xf0, 0x00,
0x06, 0x1f, 0xff, 0xe1, 0xff, 0x8f, 0xf0, 0x00, 0x07, 0x0f, 0xff, 0xf0, 0xff, 0x8f, 0xf8, 0x00,
0x03, 0x07, 0xff, 0xf8, 0x7f, 0xc7, 0xf8, 0x00, 0x03, 0x01, 0xff, 0xfc, 0x3f, 0xc7, 0xf8, 0x00,
0x03, 0x00, 0x3f, 0xfe, 0x3f, 0xc7, 0xf8, 0x00, 0x01, 0x80, 0x07, 0xfe, 0x1f, 0xe3, 0xfc, 0x00,
0x01, 0x80, 0x03, 0xff, 0x1f, 0xe3, 0xfc, 0x00, 0x01, 0xc0, 0x01, 0xff, 0x1f, 0xe3, 0xfc, 0x00,
0x00, 0xc0, 0x78, 0xff, 0x0f, 0xe3, 0xfc, 0x00, 0x00, 0xe0, 0xfc, 0x7f, 0x8f, 0xf1, 0xf8, 0x00,
0x00, 0x61, 0xfc, 0x7f, 0x8f, 0xf1, 0xf0, 0x00, 0x00, 0x71, 0xfc, 0x7f, 0x8f, 0xf1, 0xf0, 0x00,
0x00, 0x39, 0xfc, 0x7f, 0x8f, 0xf1, 0xe0, 0x00, 0x00, 0x19, 0xfc, 0x7f, 0x8f, 0xf0, 0x00, 0x00,
0x00, 0x1c, 0xf8, 0x7f, 0x8f, 0xf0, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x7f, 0x8f, 0xf0, 0x10, 0x00,
0x00, 0x07, 0x00, 0x7f, 0x8f, 0xf0, 0x38, 0x00, 0x00, 0x03, 0xc0, 0xff, 0x0f, 0xe0, 0x70, 0x00,
0x00, 0x01, 0xe0, 0x7f, 0x0f, 0xc0, 0xe0, 0x00, 0x00, 0x00, 0x78, 0x1f, 0x00, 0x03, 0xc0, 0x00,
0x00, 0x00, 0x3e, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x7e, 0x00, 0x00,
0x00, 0x00, 0x03, 0xfc, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x07, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const float image_3d_matrix_esp_logo[1427][4] = {
{-2.0, -25.0, 0, 1}, {-1.0, -25.0, 0, 1}, {0.0, -25.0, 0, 1}, {1.0, -25.0, 0, 1}, {2.0, -25.0, 0, 1}, {3.0, -25.0, 0, 1},
{4.0, -25.0, 0, 1}, {5.0, -25.0, 0, 1}, {6.0, -25.0, 0, 1}, {-2.0, -24.0, 0, 1}, {-1.0, -24.0, 0, 1}, {0.0, -24.0, 0, 1},
{1.0, -24.0, 0, 1}, {2.0, -24.0, 0, 1}, {3.0, -24.0, 0, 1}, {4.0, -24.0, 0, 1}, {5.0, -24.0, 0, 1}, {6.0, -24.0, 0, 1},
{7.0, -24.0, 0, 1}, {8.0, -24.0, 0, 1}, {9.0, -24.0, 0, 1}, {1.0, -23.0, 0, 1}, {2.0, -23.0, 0, 1}, {3.0, -23.0, 0, 1},
{4.0, -23.0, 0, 1}, {5.0, -23.0, 0, 1}, {6.0, -23.0, 0, 1}, {7.0, -23.0, 0, 1}, {8.0, -23.0, 0, 1}, {9.0, -23.0, 0, 1},
{10.0, -23.0, 0, 1}, {11.0, -23.0, 0, 1}, {-12.0, -22.0, 0, 1}, {-11.0, -22.0, 0, 1}, {-10.0, -22.0, 0, 1}, {-9.0, -22.0, 0, 1},
{-8.0, -22.0, 0, 1}, {-7.0, -22.0, 0, 1}, {3.0, -22.0, 0, 1}, {4.0, -22.0, 0, 1}, {5.0, -22.0, 0, 1}, {6.0, -22.0, 0, 1},
{7.0, -22.0, 0, 1}, {8.0, -22.0, 0, 1}, {9.0, -22.0, 0, 1}, {10.0, -22.0, 0, 1}, {11.0, -22.0, 0, 1}, {12.0, -22.0, 0, 1},
{13.0, -22.0, 0, 1}, {-20.0, -21.0, 0, 1}, {-19.0, -21.0, 0, 1}, {-13.0, -21.0, 0, 1}, {-12.0, -21.0, 0, 1}, {-11.0, -21.0, 0, 1},
{-10.0, -21.0, 0, 1}, {-9.0, -21.0, 0, 1}, {-8.0, -21.0, 0, 1}, {-7.0, -21.0, 0, 1}, {-6.0, -21.0, 0, 1}, {-5.0, -21.0, 0, 1},
{-4.0, -21.0, 0, 1}, {-3.0, -21.0, 0, 1}, {5.0, -21.0, 0, 1}, {6.0, -21.0, 0, 1}, {7.0, -21.0, 0, 1}, {8.0, -21.0, 0, 1},
{9.0, -21.0, 0, 1}, {10.0, -21.0, 0, 1}, {11.0, -21.0, 0, 1}, {12.0, -21.0, 0, 1}, {13.0, -21.0, 0, 1}, {14.0, -21.0, 0, 1},
{-20.0, -20.0, 0, 1}, {-19.0, -20.0, 0, 1}, {-14.0, -20.0, 0, 1}, {-13.0, -20.0, 0, 1}, {-12.0, -20.0, 0, 1}, {-11.0, -20.0, 0, 1},
{-10.0, -20.0, 0, 1}, {-9.0, -20.0, 0, 1}, {-8.0, -20.0, 0, 1}, {-7.0, -20.0, 0, 1}, {-6.0, -20.0, 0, 1}, {-5.0, -20.0, 0, 1},
{-4.0, -20.0, 0, 1}, {-3.0, -20.0, 0, 1}, {-2.0, -20.0, 0, 1}, {-1.0, -20.0, 0, 1}, {6.0, -20.0, 0, 1}, {7.0, -20.0, 0, 1},
{8.0, -20.0, 0, 1}, {9.0, -20.0, 0, 1}, {10.0, -20.0, 0, 1}, {11.0, -20.0, 0, 1}, {12.0, -20.0, 0, 1}, {13.0, -20.0, 0, 1},
{14.0, -20.0, 0, 1}, {15.0, -20.0, 0, 1}, {-21.0, -19.0, 0, 1}, {-20.0, -19.0, 0, 1}, {-15.0, -19.0, 0, 1}, {-14.0, -19.0, 0, 1},
{-13.0, -19.0, 0, 1}, {-12.0, -19.0, 0, 1}, {-11.0, -19.0, 0, 1}, {-10.0, -19.0, 0, 1}, {-9.0, -19.0, 0, 1}, {-8.0, -19.0, 0, 1},
{-7.0, -19.0, 0, 1}, {-6.0, -19.0, 0, 1}, {-5.0, -19.0, 0, 1}, {-4.0, -19.0, 0, 1}, {-3.0, -19.0, 0, 1}, {-2.0, -19.0, 0, 1},
{-1.0, -19.0, 0, 1}, {0.0, -19.0, 0, 1}, {1.0, -19.0, 0, 1}, {8.0, -19.0, 0, 1}, {9.0, -19.0, 0, 1}, {10.0, -19.0, 0, 1},
{11.0, -19.0, 0, 1}, {12.0, -19.0, 0, 1}, {13.0, -19.0, 0, 1}, {14.0, -19.0, 0, 1}, {15.0, -19.0, 0, 1}, {16.0, -19.0, 0, 1},
{17.0, -19.0, 0, 1}, {-22.0, -18.0, 0, 1}, {-21.0, -18.0, 0, 1}, {-20.0, -18.0, 0, 1}, {-15.0, -18.0, 0, 1}, {-14.0, -18.0, 0, 1},
{-13.0, -18.0, 0, 1}, {-12.0, -18.0, 0, 1}, {-11.0, -18.0, 0, 1}, {-10.0, -18.0, 0, 1}, {-9.0, -18.0, 0, 1}, {-8.0, -18.0, 0, 1},
{-7.0, -18.0, 0, 1}, {-6.0, -18.0, 0, 1}, {-5.0, -18.0, 0, 1}, {-4.0, -18.0, 0, 1}, {-3.0, -18.0, 0, 1}, {-2.0, -18.0, 0, 1},
{-1.0, -18.0, 0, 1}, {0.0, -18.0, 0, 1}, {1.0, -18.0, 0, 1}, {2.0, -18.0, 0, 1}, {3.0, -18.0, 0, 1}, {9.0, -18.0, 0, 1},
{10.0, -18.0, 0, 1}, {11.0, -18.0, 0, 1}, {12.0, -18.0, 0, 1}, {13.0, -18.0, 0, 1}, {14.0, -18.0, 0, 1}, {15.0, -18.0, 0, 1},
{16.0, -18.0, 0, 1}, {17.0, -18.0, 0, 1}, {18.0, -18.0, 0, 1}, {-23.0, -17.0, 0, 1}, {-22.0, -17.0, 0, 1}, {-21.0, -17.0, 0, 1},
{-15.0, -17.0, 0, 1}, {-14.0, -17.0, 0, 1}, {-13.0, -17.0, 0, 1}, {-12.0, -17.0, 0, 1}, {-11.0, -17.0, 0, 1}, {-10.0, -17.0, 0, 1},
{-9.0, -17.0, 0, 1}, {-8.0, -17.0, 0, 1}, {-7.0, -17.0, 0, 1}, {-6.0, -17.0, 0, 1}, {-5.0, -17.0, 0, 1}, {-4.0, -17.0, 0, 1},
{-3.0, -17.0, 0, 1}, {-2.0, -17.0, 0, 1}, {-1.0, -17.0, 0, 1}, {0.0, -17.0, 0, 1}, {1.0, -17.0, 0, 1}, {2.0, -17.0, 0, 1},
{3.0, -17.0, 0, 1}, {4.0, -17.0, 0, 1}, {10.0, -17.0, 0, 1}, {11.0, -17.0, 0, 1}, {12.0, -17.0, 0, 1}, {13.0, -17.0, 0, 1},
{14.0, -17.0, 0, 1}, {15.0, -17.0, 0, 1}, {16.0, -17.0, 0, 1}, {17.0, -17.0, 0, 1}, {18.0, -17.0, 0, 1}, {-23.0, -16.0, 0, 1},
{-22.0, -16.0, 0, 1}, {-15.0, -16.0, 0, 1}, {-14.0, -16.0, 0, 1}, {-13.0, -16.0, 0, 1}, {-12.0, -16.0, 0, 1}, {-11.0, -16.0, 0, 1},
{-10.0, -16.0, 0, 1}, {-9.0, -16.0, 0, 1}, {-8.0, -16.0, 0, 1}, {-7.0, -16.0, 0, 1}, {-6.0, -16.0, 0, 1}, {-5.0, -16.0, 0, 1},
{-4.0, -16.0, 0, 1}, {-3.0, -16.0, 0, 1}, {-2.0, -16.0, 0, 1}, {-1.0, -16.0, 0, 1}, {0.0, -16.0, 0, 1}, {1.0, -16.0, 0, 1},
{2.0, -16.0, 0, 1}, {3.0, -16.0, 0, 1}, {4.0, -16.0, 0, 1}, {5.0, -16.0, 0, 1}, {6.0, -16.0, 0, 1}, {12.0, -16.0, 0, 1},
{13.0, -16.0, 0, 1}, {14.0, -16.0, 0, 1}, {15.0, -16.0, 0, 1}, {16.0, -16.0, 0, 1}, {17.0, -16.0, 0, 1}, {18.0, -16.0, 0, 1},
{19.0, -16.0, 0, 1}, {-24.0, -15.0, 0, 1}, {-23.0, -15.0, 0, 1}, {-22.0, -15.0, 0, 1}, {-9.0, -15.0, 0, 1}, {-8.0, -15.0, 0, 1},
{-7.0, -15.0, 0, 1}, {-6.0, -15.0, 0, 1}, {-5.0, -15.0, 0, 1}, {-4.0, -15.0, 0, 1}, {-3.0, -15.0, 0, 1}, {-2.0, -15.0, 0, 1},
{-1.0, -15.0, 0, 1}, {0.0, -15.0, 0, 1}, {1.0, -15.0, 0, 1}, {2.0, -15.0, 0, 1}, {3.0, -15.0, 0, 1}, {4.0, -15.0, 0, 1},
{5.0, -15.0, 0, 1}, {6.0, -15.0, 0, 1}, {7.0, -15.0, 0, 1}, {13.0, -15.0, 0, 1}, {14.0, -15.0, 0, 1}, {15.0, -15.0, 0, 1},
{16.0, -15.0, 0, 1}, {17.0, -15.0, 0, 1}, {18.0, -15.0, 0, 1}, {19.0, -15.0, 0, 1}, {20.0, -15.0, 0, 1}, {-24.0, -14.0, 0, 1},
{-23.0, -14.0, 0, 1}, {-6.0, -14.0, 0, 1}, {-5.0, -14.0, 0, 1}, {-4.0, -14.0, 0, 1}, {-3.0, -14.0, 0, 1}, {-2.0, -14.0, 0, 1},
{-1.0, -14.0, 0, 1}, {0.0, -14.0, 0, 1}, {1.0, -14.0, 0, 1}, {2.0, -14.0, 0, 1}, {3.0, -14.0, 0, 1}, {4.0, -14.0, 0, 1},
{5.0, -14.0, 0, 1}, {6.0, -14.0, 0, 1}, {7.0, -14.0, 0, 1}, {8.0, -14.0, 0, 1}, {14.0, -14.0, 0, 1}, {15.0, -14.0, 0, 1},
{16.0, -14.0, 0, 1}, {17.0, -14.0, 0, 1}, {18.0, -14.0, 0, 1}, {19.0, -14.0, 0, 1}, {20.0, -14.0, 0, 1}, {21.0, -14.0, 0, 1},
{-25.0, -13.0, 0, 1}, {-24.0, -13.0, 0, 1}, {-23.0, -13.0, 0, 1}, {-3.0, -13.0, 0, 1}, {-2.0, -13.0, 0, 1}, {-1.0, -13.0, 0, 1},
{0.0, -13.0, 0, 1}, {1.0, -13.0, 0, 1}, {2.0, -13.0, 0, 1}, {3.0, -13.0, 0, 1}, {4.0, -13.0, 0, 1}, {5.0, -13.0, 0, 1},
{6.0, -13.0, 0, 1}, {7.0, -13.0, 0, 1}, {8.0, -13.0, 0, 1}, {9.0, -13.0, 0, 1}, {10.0, -13.0, 0, 1}, {15.0, -13.0, 0, 1},
{16.0, -13.0, 0, 1}, {17.0, -13.0, 0, 1}, {18.0, -13.0, 0, 1}, {19.0, -13.0, 0, 1}, {20.0, -13.0, 0, 1}, {21.0, -13.0, 0, 1},
{-25.0, -12.0, 0, 1}, {-24.0, -12.0, 0, 1}, {-17.0, -12.0, 0, 1}, {-16.0, -12.0, 0, 1}, {-15.0, -12.0, 0, 1}, {-14.0, -12.0, 0, 1},
{-13.0, -12.0, 0, 1}, {-12.0, -12.0, 0, 1}, {-11.0, -12.0, 0, 1}, {-1.0, -12.0, 0, 1}, {0.0, -12.0, 0, 1}, {1.0, -12.0, 0, 1},
{2.0, -12.0, 0, 1}, {3.0, -12.0, 0, 1}, {4.0, -12.0, 0, 1}, {5.0, -12.0, 0, 1}, {6.0, -12.0, 0, 1}, {7.0, -12.0, 0, 1},
{8.0, -12.0, 0, 1}, {9.0, -12.0, 0, 1}, {10.0, -12.0, 0, 1}, {11.0, -12.0, 0, 1}, {16.0, -12.0, 0, 1}, {17.0, -12.0, 0, 1},
{18.0, -12.0, 0, 1}, {19.0, -12.0, 0, 1}, {20.0, -12.0, 0, 1}, {21.0, -12.0, 0, 1}, {22.0, -12.0, 0, 1}, {-25.0, -11.0, 0, 1},
{-24.0, -11.0, 0, 1}, {-19.0, -11.0, 0, 1}, {-18.0, -11.0, 0, 1}, {-17.0, -11.0, 0, 1}, {-16.0, -11.0, 0, 1}, {-15.0, -11.0, 0, 1},
{-14.0, -11.0, 0, 1}, {-13.0, -11.0, 0, 1}, {-12.0, -11.0, 0, 1}, {-11.0, -11.0, 0, 1}, {-10.0, -11.0, 0, 1}, {-9.0, -11.0, 0, 1},
{-8.0, -11.0, 0, 1}, {-7.0, -11.0, 0, 1}, {1.0, -11.0, 0, 1}, {2.0, -11.0, 0, 1}, {3.0, -11.0, 0, 1}, {4.0, -11.0, 0, 1},
{5.0, -11.0, 0, 1}, {6.0, -11.0, 0, 1}, {7.0, -11.0, 0, 1}, {8.0, -11.0, 0, 1}, {9.0, -11.0, 0, 1}, {10.0, -11.0, 0, 1},
{11.0, -11.0, 0, 1}, {12.0, -11.0, 0, 1}, {16.0, -11.0, 0, 1}, {17.0, -11.0, 0, 1}, {18.0, -11.0, 0, 1}, {19.0, -11.0, 0, 1},
{20.0, -11.0, 0, 1}, {21.0, -11.0, 0, 1}, {22.0, -11.0, 0, 1}, {-26.0, -10.0, 0, 1}, {-25.0, -10.0, 0, 1}, {-20.0, -10.0, 0, 1},
{-19.0, -10.0, 0, 1}, {-18.0, -10.0, 0, 1}, {-17.0, -10.0, 0, 1}, {-16.0, -10.0, 0, 1}, {-15.0, -10.0, 0, 1}, {-14.0, -10.0, 0, 1},
{-13.0, -10.0, 0, 1}, {-12.0, -10.0, 0, 1}, {-11.0, -10.0, 0, 1}, {-10.0, -10.0, 0, 1}, {-9.0, -10.0, 0, 1}, {-8.0, -10.0, 0, 1},
{-7.0, -10.0, 0, 1}, {-6.0, -10.0, 0, 1}, {-5.0, -10.0, 0, 1}, {2.0, -10.0, 0, 1}, {3.0, -10.0, 0, 1}, {4.0, -10.0, 0, 1},
{5.0, -10.0, 0, 1}, {6.0, -10.0, 0, 1}, {7.0, -10.0, 0, 1}, {8.0, -10.0, 0, 1}, {9.0, -10.0, 0, 1}, {10.0, -10.0, 0, 1},
{11.0, -10.0, 0, 1}, {12.0, -10.0, 0, 1}, {17.0, -10.0, 0, 1}, {18.0, -10.0, 0, 1}, {19.0, -10.0, 0, 1}, {20.0, -10.0, 0, 1},
{21.0, -10.0, 0, 1}, {22.0, -10.0, 0, 1}, {-26.0, -9.0, 0, 1}, {-25.0, -9.0, 0, 1}, {-21.0, -9.0, 0, 1}, {-20.0, -9.0, 0, 1},
{-19.0, -9.0, 0, 1}, {-18.0, -9.0, 0, 1}, {-17.0, -9.0, 0, 1}, {-16.0, -9.0, 0, 1}, {-15.0, -9.0, 0, 1}, {-14.0, -9.0, 0, 1},
{-13.0, -9.0, 0, 1}, {-12.0, -9.0, 0, 1}, {-11.0, -9.0, 0, 1}, {-10.0, -9.0, 0, 1}, {-9.0, -9.0, 0, 1}, {-8.0, -9.0, 0, 1},
{-7.0, -9.0, 0, 1}, {-6.0, -9.0, 0, 1}, {-5.0, -9.0, 0, 1}, {-4.0, -9.0, 0, 1}, {-3.0, -9.0, 0, 1}, {3.0, -9.0, 0, 1},
{4.0, -9.0, 0, 1}, {5.0, -9.0, 0, 1}, {6.0, -9.0, 0, 1}, {7.0, -9.0, 0, 1}, {8.0, -9.0, 0, 1}, {9.0, -9.0, 0, 1},
{10.0, -9.0, 0, 1}, {11.0, -9.0, 0, 1}, {12.0, -9.0, 0, 1}, {13.0, -9.0, 0, 1}, {18.0, -9.0, 0, 1}, {19.0, -9.0, 0, 1},
{20.0, -9.0, 0, 1}, {21.0, -9.0, 0, 1}, {22.0, -9.0, 0, 1}, {23.0, -9.0, 0, 1}, {-26.0, -8.0, 0, 1}, {-25.0, -8.0, 0, 1},
{-21.0, -8.0, 0, 1}, {-20.0, -8.0, 0, 1}, {-19.0, -8.0, 0, 1}, {-18.0, -8.0, 0, 1}, {-17.0, -8.0, 0, 1}, {-16.0, -8.0, 0, 1},
{-15.0, -8.0, 0, 1}, {-14.0, -8.0, 0, 1}, {-13.0, -8.0, 0, 1}, {-12.0, -8.0, 0, 1}, {-11.0, -8.0, 0, 1}, {-10.0, -8.0, 0, 1},
{-9.0, -8.0, 0, 1}, {-8.0, -8.0, 0, 1}, {-7.0, -8.0, 0, 1}, {-6.0, -8.0, 0, 1}, {-5.0, -8.0, 0, 1}, {-4.0, -8.0, 0, 1},
{-3.0, -8.0, 0, 1}, {-2.0, -8.0, 0, 1}, {-1.0, -8.0, 0, 1}, {5.0, -8.0, 0, 1}, {6.0, -8.0, 0, 1}, {7.0, -8.0, 0, 1},
{8.0, -8.0, 0, 1}, {9.0, -8.0, 0, 1}, {10.0, -8.0, 0, 1}, {11.0, -8.0, 0, 1}, {12.0, -8.0, 0, 1}, {13.0, -8.0, 0, 1},
{14.0, -8.0, 0, 1}, {19.0, -8.0, 0, 1}, {20.0, -8.0, 0, 1}, {21.0, -8.0, 0, 1}, {22.0, -8.0, 0, 1}, {23.0, -8.0, 0, 1},
{-26.0, -7.0, 0, 1}, {-25.0, -7.0, 0, 1}, {-22.0, -7.0, 0, 1}, {-21.0, -7.0, 0, 1}, {-20.0, -7.0, 0, 1}, {-19.0, -7.0, 0, 1},
{-18.0, -7.0, 0, 1}, {-17.0, -7.0, 0, 1}, {-16.0, -7.0, 0, 1}, {-15.0, -7.0, 0, 1}, {-14.0, -7.0, 0, 1}, {-13.0, -7.0, 0, 1},
{-12.0, -7.0, 0, 1}, {-11.0, -7.0, 0, 1}, {-10.0, -7.0, 0, 1}, {-9.0, -7.0, 0, 1}, {-8.0, -7.0, 0, 1}, {-7.0, -7.0, 0, 1},
{-6.0, -7.0, 0, 1}, {-5.0, -7.0, 0, 1}, {-4.0, -7.0, 0, 1}, {-3.0, -7.0, 0, 1}, {-2.0, -7.0, 0, 1}, {-1.0, -7.0, 0, 1},
{0.0, -7.0, 0, 1}, {6.0, -7.0, 0, 1}, {7.0, -7.0, 0, 1}, {8.0, -7.0, 0, 1}, {9.0, -7.0, 0, 1}, {10.0, -7.0, 0, 1},
{11.0, -7.0, 0, 1}, {12.0, -7.0, 0, 1}, {13.0, -7.0, 0, 1}, {14.0, -7.0, 0, 1}, {15.0, -7.0, 0, 1}, {19.0, -7.0, 0, 1},
{20.0, -7.0, 0, 1}, {21.0, -7.0, 0, 1}, {22.0, -7.0, 0, 1}, {23.0, -7.0, 0, 1}, {-27.0, -6.0, 0, 1}, {-26.0, -6.0, 0, 1},
{-22.0, -6.0, 0, 1}, {-21.0, -6.0, 0, 1}, {-20.0, -6.0, 0, 1}, {-19.0, -6.0, 0, 1}, {-18.0, -6.0, 0, 1}, {-17.0, -6.0, 0, 1},
{-16.0, -6.0, 0, 1}, {-15.0, -6.0, 0, 1}, {-14.0, -6.0, 0, 1}, {-13.0, -6.0, 0, 1}, {-12.0, -6.0, 0, 1}, {-11.0, -6.0, 0, 1},
{-10.0, -6.0, 0, 1}, {-9.0, -6.0, 0, 1}, {-8.0, -6.0, 0, 1}, {-7.0, -6.0, 0, 1}, {-6.0, -6.0, 0, 1}, {-5.0, -6.0, 0, 1},
{-4.0, -6.0, 0, 1}, {-3.0, -6.0, 0, 1}, {-2.0, -6.0, 0, 1}, {-1.0, -6.0, 0, 1}, {0.0, -6.0, 0, 1}, {1.0, -6.0, 0, 1},
{7.0, -6.0, 0, 1}, {8.0, -6.0, 0, 1}, {9.0, -6.0, 0, 1}, {10.0, -6.0, 0, 1}, {11.0, -6.0, 0, 1}, {12.0, -6.0, 0, 1},
{13.0, -6.0, 0, 1}, {14.0, -6.0, 0, 1}, {15.0, -6.0, 0, 1}, {20.0, -6.0, 0, 1}, {21.0, -6.0, 0, 1}, {22.0, -6.0, 0, 1},
{23.0, -6.0, 0, 1}, {-27.0, -5.0, 0, 1}, {-26.0, -5.0, 0, 1}, {-22.0, -5.0, 0, 1}, {-21.0, -5.0, 0, 1}, {-20.0, -5.0, 0, 1},
{-19.0, -5.0, 0, 1}, {-18.0, -5.0, 0, 1}, {-17.0, -5.0, 0, 1}, {-16.0, -5.0, 0, 1}, {-15.0, -5.0, 0, 1}, {-14.0, -5.0, 0, 1},
{-13.0, -5.0, 0, 1}, {-12.0, -5.0, 0, 1}, {-11.0, -5.0, 0, 1}, {-10.0, -5.0, 0, 1}, {-9.0, -5.0, 0, 1}, {-8.0, -5.0, 0, 1},
{-7.0, -5.0, 0, 1}, {-6.0, -5.0, 0, 1}, {-5.0, -5.0, 0, 1}, {-4.0, -5.0, 0, 1}, {-3.0, -5.0, 0, 1}, {-2.0, -5.0, 0, 1},
{-1.0, -5.0, 0, 1}, {0.0, -5.0, 0, 1}, {1.0, -5.0, 0, 1}, {2.0, -5.0, 0, 1}, {8.0, -5.0, 0, 1}, {9.0, -5.0, 0, 1},
{10.0, -5.0, 0, 1}, {11.0, -5.0, 0, 1}, {12.0, -5.0, 0, 1}, {13.0, -5.0, 0, 1}, {14.0, -5.0, 0, 1}, {15.0, -5.0, 0, 1},
{16.0, -5.0, 0, 1}, {20.0, -5.0, 0, 1}, {21.0, -5.0, 0, 1}, {22.0, -5.0, 0, 1}, {23.0, -5.0, 0, 1}, {24.0, -5.0, 0, 1},
{-27.0, -4.0, 0, 1}, {-26.0, -4.0, 0, 1}, {-23.0, -4.0, 0, 1}, {-22.0, -4.0, 0, 1}, {-21.0, -4.0, 0, 1}, {-20.0, -4.0, 0, 1},
{-19.0, -4.0, 0, 1}, {-18.0, -4.0, 0, 1}, {-17.0, -4.0, 0, 1}, {-16.0, -4.0, 0, 1}, {-10.0, -4.0, 0, 1}, {-9.0, -4.0, 0, 1},
{-8.0, -4.0, 0, 1}, {-7.0, -4.0, 0, 1}, {-6.0, -4.0, 0, 1}, {-5.0, -4.0, 0, 1}, {-4.0, -4.0, 0, 1}, {-3.0, -4.0, 0, 1},
{-2.0, -4.0, 0, 1}, {-1.0, -4.0, 0, 1}, {0.0, -4.0, 0, 1}, {1.0, -4.0, 0, 1}, {2.0, -4.0, 0, 1}, {3.0, -4.0, 0, 1},
{8.0, -4.0, 0, 1}, {9.0, -4.0, 0, 1}, {10.0, -4.0, 0, 1}, {11.0, -4.0, 0, 1}, {12.0, -4.0, 0, 1}, {13.0, -4.0, 0, 1},
{14.0, -4.0, 0, 1}, {15.0, -4.0, 0, 1}, {16.0, -4.0, 0, 1}, {17.0, -4.0, 0, 1}, {21.0, -4.0, 0, 1}, {22.0, -4.0, 0, 1},
{23.0, -4.0, 0, 1}, {24.0, -4.0, 0, 1}, {-27.0, -3.0, 0, 1}, {-26.0, -3.0, 0, 1}, {-23.0, -3.0, 0, 1}, {-22.0, -3.0, 0, 1},
{-21.0, -3.0, 0, 1}, {-20.0, -3.0, 0, 1}, {-19.0, -3.0, 0, 1}, {-18.0, -3.0, 0, 1}, {-17.0, -3.0, 0, 1}, {-16.0, -3.0, 0, 1},
{-7.0, -3.0, 0, 1}, {-6.0, -3.0, 0, 1}, {-5.0, -3.0, 0, 1}, {-4.0, -3.0, 0, 1}, {-3.0, -3.0, 0, 1}, {-2.0, -3.0, 0, 1},
{-1.0, -3.0, 0, 1}, {0.0, -3.0, 0, 1}, {1.0, -3.0, 0, 1}, {2.0, -3.0, 0, 1}, {3.0, -3.0, 0, 1}, {4.0, -3.0, 0, 1},
{9.0, -3.0, 0, 1}, {10.0, -3.0, 0, 1}, {11.0, -3.0, 0, 1}, {12.0, -3.0, 0, 1}, {13.0, -3.0, 0, 1}, {14.0, -3.0, 0, 1},
{15.0, -3.0, 0, 1}, {16.0, -3.0, 0, 1}, {17.0, -3.0, 0, 1}, {21.0, -3.0, 0, 1}, {22.0, -3.0, 0, 1}, {23.0, -3.0, 0, 1},
{24.0, -3.0, 0, 1}, {-27.0, -2.0, 0, 1}, {-26.0, -2.0, 0, 1}, {-23.0, -2.0, 0, 1}, {-22.0, -2.0, 0, 1}, {-21.0, -2.0, 0, 1},
{-20.0, -2.0, 0, 1}, {-19.0, -2.0, 0, 1}, {-18.0, -2.0, 0, 1}, {-17.0, -2.0, 0, 1}, {-16.0, -2.0, 0, 1}, {-15.0, -2.0, 0, 1},
{-5.0, -2.0, 0, 1}, {-4.0, -2.0, 0, 1}, {-3.0, -2.0, 0, 1}, {-2.0, -2.0, 0, 1}, {-1.0, -2.0, 0, 1}, {0.0, -2.0, 0, 1},
{1.0, -2.0, 0, 1}, {2.0, -2.0, 0, 1}, {3.0, -2.0, 0, 1}, {4.0, -2.0, 0, 1}, {5.0, -2.0, 0, 1}, {10.0, -2.0, 0, 1},
{11.0, -2.0, 0, 1}, {12.0, -2.0, 0, 1}, {13.0, -2.0, 0, 1}, {14.0, -2.0, 0, 1}, {15.0, -2.0, 0, 1}, {16.0, -2.0, 0, 1},
{17.0, -2.0, 0, 1}, {18.0, -2.0, 0, 1}, {22.0, -2.0, 0, 1}, {23.0, -2.0, 0, 1}, {24.0, -2.0, 0, 1}, {-27.0, -1.0, 0, 1},
{-26.0, -1.0, 0, 1}, {-22.0, -1.0, 0, 1}, {-21.0, -1.0, 0, 1}, {-20.0, -1.0, 0, 1}, {-19.0, -1.0, 0, 1}, {-18.0, -1.0, 0, 1},
{-17.0, -1.0, 0, 1}, {-16.0, -1.0, 0, 1}, {-15.0, -1.0, 0, 1}, {-14.0, -1.0, 0, 1}, {-13.0, -1.0, 0, 1}, {-12.0, -1.0, 0, 1},
{-11.0, -1.0, 0, 1}, {-4.0, -1.0, 0, 1}, {-3.0, -1.0, 0, 1}, {-2.0, -1.0, 0, 1}, {-1.0, -1.0, 0, 1}, {0.0, -1.0, 0, 1},
{1.0, -1.0, 0, 1}, {2.0, -1.0, 0, 1}, {3.0, -1.0, 0, 1}, {4.0, -1.0, 0, 1}, {5.0, -1.0, 0, 1}, {6.0, -1.0, 0, 1},
{10.0, -1.0, 0, 1}, {11.0, -1.0, 0, 1}, {12.0, -1.0, 0, 1}, {13.0, -1.0, 0, 1}, {14.0, -1.0, 0, 1}, {15.0, -1.0, 0, 1},
{16.0, -1.0, 0, 1}, {17.0, -1.0, 0, 1}, {18.0, -1.0, 0, 1}, {22.0, -1.0, 0, 1}, {23.0, -1.0, 0, 1}, {24.0, -1.0, 0, 1},
{-27.0, 0.0, 0, 1}, {-26.0, 0.0, 0, 1}, {-22.0, 0.0, 0, 1}, {-21.0, 0.0, 0, 1}, {-20.0, 0.0, 0, 1}, {-19.0, 0.0, 0, 1},
{-18.0, 0.0, 0, 1}, {-17.0, 0.0, 0, 1}, {-16.0, 0.0, 0, 1}, {-15.0, 0.0, 0, 1}, {-14.0, 0.0, 0, 1}, {-13.0, 0.0, 0, 1},
{-12.0, 0.0, 0, 1}, {-11.0, 0.0, 0, 1}, {-10.0, 0.0, 0, 1}, {-9.0, 0.0, 0, 1}, {-3.0, 0.0, 0, 1}, {-2.0, 0.0, 0, 1},
{-1.0, 0.0, 0, 1}, {0.0, 0.0, 0, 1}, {1.0, 0.0, 0, 1}, {2.0, 0.0, 0, 1}, {3.0, 0.0, 0, 1}, {4.0, 0.0, 0, 1},
{5.0, 0.0, 0, 1}, {6.0, 0.0, 0, 1}, {7.0, 0.0, 0, 1}, {11.0, 0.0, 0, 1}, {12.0, 0.0, 0, 1}, {13.0, 0.0, 0, 1},
{14.0, 0.0, 0, 1}, {15.0, 0.0, 0, 1}, {16.0, 0.0, 0, 1}, {17.0, 0.0, 0, 1}, {18.0, 0.0, 0, 1}, {19.0, 0.0, 0, 1},
{23.0, 0.0, 0, 1}, {24.0, 0.0, 0, 1}, {-27.0, 1.0, 0, 1}, {-26.0, 1.0, 0, 1}, {-22.0, 1.0, 0, 1}, {-21.0, 1.0, 0, 1},
{-20.0, 1.0, 0, 1}, {-19.0, 1.0, 0, 1}, {-18.0, 1.0, 0, 1}, {-17.0, 1.0, 0, 1}, {-16.0, 1.0, 0, 1}, {-15.0, 1.0, 0, 1},
{-14.0, 1.0, 0, 1}, {-13.0, 1.0, 0, 1}, {-12.0, 1.0, 0, 1}, {-11.0, 1.0, 0, 1}, {-10.0, 1.0, 0, 1}, {-9.0, 1.0, 0, 1},
{-8.0, 1.0, 0, 1}, {-7.0, 1.0, 0, 1}, {-2.0, 1.0, 0, 1}, {-1.0, 1.0, 0, 1}, {0.0, 1.0, 0, 1}, {1.0, 1.0, 0, 1},
{2.0, 1.0, 0, 1}, {3.0, 1.0, 0, 1}, {4.0, 1.0, 0, 1}, {5.0, 1.0, 0, 1}, {6.0, 1.0, 0, 1}, {7.0, 1.0, 0, 1},
{12.0, 1.0, 0, 1}, {13.0, 1.0, 0, 1}, {14.0, 1.0, 0, 1}, {15.0, 1.0, 0, 1}, {16.0, 1.0, 0, 1}, {17.0, 1.0, 0, 1},
{18.0, 1.0, 0, 1}, {19.0, 1.0, 0, 1}, {-27.0, 2.0, 0, 1}, {-26.0, 2.0, 0, 1}, {-21.0, 2.0, 0, 1}, {-20.0, 2.0, 0, 1},
{-19.0, 2.0, 0, 1}, {-18.0, 2.0, 0, 1}, {-17.0, 2.0, 0, 1}, {-16.0, 2.0, 0, 1}, {-15.0, 2.0, 0, 1}, {-14.0, 2.0, 0, 1},
{-13.0, 2.0, 0, 1}, {-12.0, 2.0, 0, 1}, {-11.0, 2.0, 0, 1}, {-10.0, 2.0, 0, 1}, {-9.0, 2.0, 0, 1}, {-8.0, 2.0, 0, 1},
{-7.0, 2.0, 0, 1}, {-6.0, 2.0, 0, 1}, {-1.0, 2.0, 0, 1}, {0.0, 2.0, 0, 1}, {1.0, 2.0, 0, 1}, {2.0, 2.0, 0, 1},
{3.0, 2.0, 0, 1}, {4.0, 2.0, 0, 1}, {5.0, 2.0, 0, 1}, {6.0, 2.0, 0, 1}, {7.0, 2.0, 0, 1}, {8.0, 2.0, 0, 1},
{12.0, 2.0, 0, 1}, {13.0, 2.0, 0, 1}, {14.0, 2.0, 0, 1}, {15.0, 2.0, 0, 1}, {16.0, 2.0, 0, 1}, {17.0, 2.0, 0, 1},
{18.0, 2.0, 0, 1}, {19.0, 2.0, 0, 1}, {-27.0, 3.0, 0, 1}, {-26.0, 3.0, 0, 1}, {-25.0, 3.0, 0, 1}, {-20.0, 3.0, 0, 1},
{-19.0, 3.0, 0, 1}, {-18.0, 3.0, 0, 1}, {-17.0, 3.0, 0, 1}, {-16.0, 3.0, 0, 1}, {-15.0, 3.0, 0, 1}, {-14.0, 3.0, 0, 1},
{-13.0, 3.0, 0, 1}, {-12.0, 3.0, 0, 1}, {-11.0, 3.0, 0, 1}, {-10.0, 3.0, 0, 1}, {-9.0, 3.0, 0, 1}, {-8.0, 3.0, 0, 1},
{-7.0, 3.0, 0, 1}, {-6.0, 3.0, 0, 1}, {-5.0, 3.0, 0, 1}, {0.0, 3.0, 0, 1}, {1.0, 3.0, 0, 1}, {2.0, 3.0, 0, 1},
{3.0, 3.0, 0, 1}, {4.0, 3.0, 0, 1}, {5.0, 3.0, 0, 1}, {6.0, 3.0, 0, 1}, {7.0, 3.0, 0, 1}, {8.0, 3.0, 0, 1},
{12.0, 3.0, 0, 1}, {13.0, 3.0, 0, 1}, {14.0, 3.0, 0, 1}, {15.0, 3.0, 0, 1}, {16.0, 3.0, 0, 1}, {17.0, 3.0, 0, 1},
{18.0, 3.0, 0, 1}, {19.0, 3.0, 0, 1}, {20.0, 3.0, 0, 1}, {-26.0, 4.0, 0, 1}, {-25.0, 4.0, 0, 1}, {-19.0, 4.0, 0, 1},
{-18.0, 4.0, 0, 1}, {-17.0, 4.0, 0, 1}, {-16.0, 4.0, 0, 1}, {-15.0, 4.0, 0, 1}, {-14.0, 4.0, 0, 1}, {-13.0, 4.0, 0, 1},
{-12.0, 4.0, 0, 1}, {-11.0, 4.0, 0, 1}, {-10.0, 4.0, 0, 1}, {-9.0, 4.0, 0, 1}, {-8.0, 4.0, 0, 1}, {-7.0, 4.0, 0, 1},
{-6.0, 4.0, 0, 1}, {-5.0, 4.0, 0, 1}, {-4.0, 4.0, 0, 1}, {1.0, 4.0, 0, 1}, {2.0, 4.0, 0, 1}, {3.0, 4.0, 0, 1},
{4.0, 4.0, 0, 1}, {5.0, 4.0, 0, 1}, {6.0, 4.0, 0, 1}, {7.0, 4.0, 0, 1}, {8.0, 4.0, 0, 1}, {9.0, 4.0, 0, 1},
{13.0, 4.0, 0, 1}, {14.0, 4.0, 0, 1}, {15.0, 4.0, 0, 1}, {16.0, 4.0, 0, 1}, {17.0, 4.0, 0, 1}, {18.0, 4.0, 0, 1},
{19.0, 4.0, 0, 1}, {20.0, 4.0, 0, 1}, {-26.0, 5.0, 0, 1}, {-25.0, 5.0, 0, 1}, {-17.0, 5.0, 0, 1}, {-16.0, 5.0, 0, 1},
{-15.0, 5.0, 0, 1}, {-14.0, 5.0, 0, 1}, {-13.0, 5.0, 0, 1}, {-12.0, 5.0, 0, 1}, {-11.0, 5.0, 0, 1}, {-10.0, 5.0, 0, 1},
{-9.0, 5.0, 0, 1}, {-8.0, 5.0, 0, 1}, {-7.0, 5.0, 0, 1}, {-6.0, 5.0, 0, 1}, {-5.0, 5.0, 0, 1}, {-4.0, 5.0, 0, 1},
{-3.0, 5.0, 0, 1}, {2.0, 5.0, 0, 1}, {3.0, 5.0, 0, 1}, {4.0, 5.0, 0, 1}, {5.0, 5.0, 0, 1}, {6.0, 5.0, 0, 1},
{7.0, 5.0, 0, 1}, {8.0, 5.0, 0, 1}, {9.0, 5.0, 0, 1}, {13.0, 5.0, 0, 1}, {14.0, 5.0, 0, 1}, {15.0, 5.0, 0, 1},
{16.0, 5.0, 0, 1}, {17.0, 5.0, 0, 1}, {18.0, 5.0, 0, 1}, {19.0, 5.0, 0, 1}, {20.0, 5.0, 0, 1}, {-26.0, 6.0, 0, 1},
{-25.0, 6.0, 0, 1}, {-14.0, 6.0, 0, 1}, {-13.0, 6.0, 0, 1}, {-12.0, 6.0, 0, 1}, {-11.0, 6.0, 0, 1}, {-10.0, 6.0, 0, 1},
{-9.0, 6.0, 0, 1}, {-8.0, 6.0, 0, 1}, {-7.0, 6.0, 0, 1}, {-6.0, 6.0, 0, 1}, {-5.0, 6.0, 0, 1}, {-4.0, 6.0, 0, 1},
{-3.0, 6.0, 0, 1}, {-2.0, 6.0, 0, 1}, {2.0, 6.0, 0, 1}, {3.0, 6.0, 0, 1}, {4.0, 6.0, 0, 1}, {5.0, 6.0, 0, 1},
{6.0, 6.0, 0, 1}, {7.0, 6.0, 0, 1}, {8.0, 6.0, 0, 1}, {9.0, 6.0, 0, 1}, {13.0, 6.0, 0, 1}, {14.0, 6.0, 0, 1},
{15.0, 6.0, 0, 1}, {16.0, 6.0, 0, 1}, {17.0, 6.0, 0, 1}, {18.0, 6.0, 0, 1}, {19.0, 6.0, 0, 1}, {20.0, 6.0, 0, 1},
{-25.0, 7.0, 0, 1}, {-24.0, 7.0, 0, 1}, {-11.0, 7.0, 0, 1}, {-10.0, 7.0, 0, 1}, {-9.0, 7.0, 0, 1}, {-8.0, 7.0, 0, 1},
{-7.0, 7.0, 0, 1}, {-6.0, 7.0, 0, 1}, {-5.0, 7.0, 0, 1}, {-4.0, 7.0, 0, 1}, {-3.0, 7.0, 0, 1}, {-2.0, 7.0, 0, 1},
{3.0, 7.0, 0, 1}, {4.0, 7.0, 0, 1}, {5.0, 7.0, 0, 1}, {6.0, 7.0, 0, 1}, {7.0, 7.0, 0, 1}, {8.0, 7.0, 0, 1},
{9.0, 7.0, 0, 1}, {10.0, 7.0, 0, 1}, {14.0, 7.0, 0, 1}, {15.0, 7.0, 0, 1}, {16.0, 7.0, 0, 1}, {17.0, 7.0, 0, 1},
{18.0, 7.0, 0, 1}, {19.0, 7.0, 0, 1}, {20.0, 7.0, 0, 1}, {21.0, 7.0, 0, 1}, {-25.0, 8.0, 0, 1}, {-24.0, 8.0, 0, 1},
{-10.0, 8.0, 0, 1}, {-9.0, 8.0, 0, 1}, {-8.0, 8.0, 0, 1}, {-7.0, 8.0, 0, 1}, {-6.0, 8.0, 0, 1}, {-5.0, 8.0, 0, 1},
{-4.0, 8.0, 0, 1}, {-3.0, 8.0, 0, 1}, {-2.0, 8.0, 0, 1}, {-1.0, 8.0, 0, 1}, {3.0, 8.0, 0, 1}, {4.0, 8.0, 0, 1},
{5.0, 8.0, 0, 1}, {6.0, 8.0, 0, 1}, {7.0, 8.0, 0, 1}, {8.0, 8.0, 0, 1}, {9.0, 8.0, 0, 1}, {10.0, 8.0, 0, 1},
{14.0, 8.0, 0, 1}, {15.0, 8.0, 0, 1}, {16.0, 8.0, 0, 1}, {17.0, 8.0, 0, 1}, {18.0, 8.0, 0, 1}, {19.0, 8.0, 0, 1},
{20.0, 8.0, 0, 1}, {21.0, 8.0, 0, 1}, {-25.0, 9.0, 0, 1}, {-24.0, 9.0, 0, 1}, {-23.0, 9.0, 0, 1}, {-9.0, 9.0, 0, 1},
{-8.0, 9.0, 0, 1}, {-7.0, 9.0, 0, 1}, {-6.0, 9.0, 0, 1}, {-5.0, 9.0, 0, 1}, {-4.0, 9.0, 0, 1}, {-3.0, 9.0, 0, 1},
{-2.0, 9.0, 0, 1}, {-1.0, 9.0, 0, 1}, {3.0, 9.0, 0, 1}, {4.0, 9.0, 0, 1}, {5.0, 9.0, 0, 1}, {6.0, 9.0, 0, 1},
{7.0, 9.0, 0, 1}, {8.0, 9.0, 0, 1}, {9.0, 9.0, 0, 1}, {10.0, 9.0, 0, 1}, {14.0, 9.0, 0, 1}, {15.0, 9.0, 0, 1},
{16.0, 9.0, 0, 1}, {17.0, 9.0, 0, 1}, {18.0, 9.0, 0, 1}, {19.0, 9.0, 0, 1}, {20.0, 9.0, 0, 1}, {21.0, 9.0, 0, 1},
{-24.0, 10.0, 0, 1}, {-23.0, 10.0, 0, 1}, {-15.0, 10.0, 0, 1}, {-14.0, 10.0, 0, 1}, {-13.0, 10.0, 0, 1}, {-12.0, 10.0, 0, 1},
{-8.0, 10.0, 0, 1}, {-7.0, 10.0, 0, 1}, {-6.0, 10.0, 0, 1}, {-5.0, 10.0, 0, 1}, {-4.0, 10.0, 0, 1}, {-3.0, 10.0, 0, 1},
{-2.0, 10.0, 0, 1}, {-1.0, 10.0, 0, 1}, {4.0, 10.0, 0, 1}, {5.0, 10.0, 0, 1}, {6.0, 10.0, 0, 1}, {7.0, 10.0, 0, 1},
{8.0, 10.0, 0, 1}, {9.0, 10.0, 0, 1}, {10.0, 10.0, 0, 1}, {14.0, 10.0, 0, 1}, {15.0, 10.0, 0, 1}, {16.0, 10.0, 0, 1},
{17.0, 10.0, 0, 1}, {18.0, 10.0, 0, 1}, {19.0, 10.0, 0, 1}, {20.0, 10.0, 0, 1}, {21.0, 10.0, 0, 1}, {-24.0, 11.0, 0, 1},
{-23.0, 11.0, 0, 1}, {-22.0, 11.0, 0, 1}, {-16.0, 11.0, 0, 1}, {-15.0, 11.0, 0, 1}, {-14.0, 11.0, 0, 1}, {-13.0, 11.0, 0, 1},
{-12.0, 11.0, 0, 1}, {-11.0, 11.0, 0, 1}, {-7.0, 11.0, 0, 1}, {-6.0, 11.0, 0, 1}, {-5.0, 11.0, 0, 1}, {-4.0, 11.0, 0, 1},
{-3.0, 11.0, 0, 1}, {-2.0, 11.0, 0, 1}, {-1.0, 11.0, 0, 1}, {0.0, 11.0, 0, 1}, {4.0, 11.0, 0, 1}, {5.0, 11.0, 0, 1},
{6.0, 11.0, 0, 1}, {7.0, 11.0, 0, 1}, {8.0, 11.0, 0, 1}, {9.0, 11.0, 0, 1}, {10.0, 11.0, 0, 1}, {11.0, 11.0, 0, 1},
{15.0, 11.0, 0, 1}, {16.0, 11.0, 0, 1}, {17.0, 11.0, 0, 1}, {18.0, 11.0, 0, 1}, {19.0, 11.0, 0, 1}, {20.0, 11.0, 0, 1},
{-23.0, 12.0, 0, 1}, {-22.0, 12.0, 0, 1}, {-17.0, 12.0, 0, 1}, {-16.0, 12.0, 0, 1}, {-15.0, 12.0, 0, 1}, {-14.0, 12.0, 0, 1},
{-13.0, 12.0, 0, 1}, {-12.0, 12.0, 0, 1}, {-11.0, 12.0, 0, 1}, {-7.0, 12.0, 0, 1}, {-6.0, 12.0, 0, 1}, {-5.0, 12.0, 0, 1},
{-4.0, 12.0, 0, 1}, {-3.0, 12.0, 0, 1}, {-2.0, 12.0, 0, 1}, {-1.0, 12.0, 0, 1}, {0.0, 12.0, 0, 1}, {4.0, 12.0, 0, 1},
{5.0, 12.0, 0, 1}, {6.0, 12.0, 0, 1}, {7.0, 12.0, 0, 1}, {8.0, 12.0, 0, 1}, {9.0, 12.0, 0, 1}, {10.0, 12.0, 0, 1},
{11.0, 12.0, 0, 1}, {15.0, 12.0, 0, 1}, {16.0, 12.0, 0, 1}, {17.0, 12.0, 0, 1}, {18.0, 12.0, 0, 1}, {19.0, 12.0, 0, 1},
{-23.0, 13.0, 0, 1}, {-22.0, 13.0, 0, 1}, {-21.0, 13.0, 0, 1}, {-17.0, 13.0, 0, 1}, {-16.0, 13.0, 0, 1}, {-15.0, 13.0, 0, 1},
{-14.0, 13.0, 0, 1}, {-13.0, 13.0, 0, 1}, {-12.0, 13.0, 0, 1}, {-11.0, 13.0, 0, 1}, {-7.0, 13.0, 0, 1}, {-6.0, 13.0, 0, 1},
{-5.0, 13.0, 0, 1}, {-4.0, 13.0, 0, 1}, {-3.0, 13.0, 0, 1}, {-2.0, 13.0, 0, 1}, {-1.0, 13.0, 0, 1}, {0.0, 13.0, 0, 1},
{4.0, 13.0, 0, 1}, {5.0, 13.0, 0, 1}, {6.0, 13.0, 0, 1}, {7.0, 13.0, 0, 1}, {8.0, 13.0, 0, 1}, {9.0, 13.0, 0, 1},
{10.0, 13.0, 0, 1}, {11.0, 13.0, 0, 1}, {15.0, 13.0, 0, 1}, {16.0, 13.0, 0, 1}, {17.0, 13.0, 0, 1}, {18.0, 13.0, 0, 1},
{19.0, 13.0, 0, 1}, {-22.0, 14.0, 0, 1}, {-21.0, 14.0, 0, 1}, {-20.0, 14.0, 0, 1}, {-17.0, 14.0, 0, 1}, {-16.0, 14.0, 0, 1},
{-15.0, 14.0, 0, 1}, {-14.0, 14.0, 0, 1}, {-13.0, 14.0, 0, 1}, {-12.0, 14.0, 0, 1}, {-11.0, 14.0, 0, 1}, {-7.0, 14.0, 0, 1},
{-6.0, 14.0, 0, 1}, {-5.0, 14.0, 0, 1}, {-4.0, 14.0, 0, 1}, {-3.0, 14.0, 0, 1}, {-2.0, 14.0, 0, 1}, {-1.0, 14.0, 0, 1},
{0.0, 14.0, 0, 1}, {4.0, 14.0, 0, 1}, {5.0, 14.0, 0, 1}, {6.0, 14.0, 0, 1}, {7.0, 14.0, 0, 1}, {8.0, 14.0, 0, 1},
{9.0, 14.0, 0, 1}, {10.0, 14.0, 0, 1}, {11.0, 14.0, 0, 1}, {15.0, 14.0, 0, 1}, {16.0, 14.0, 0, 1}, {17.0, 14.0, 0, 1},
{18.0, 14.0, 0, 1}, {-21.0, 15.0, 0, 1}, {-20.0, 15.0, 0, 1}, {-17.0, 15.0, 0, 1}, {-16.0, 15.0, 0, 1}, {-15.0, 15.0, 0, 1},
{-14.0, 15.0, 0, 1}, {-13.0, 15.0, 0, 1}, {-12.0, 15.0, 0, 1}, {-11.0, 15.0, 0, 1}, {-7.0, 15.0, 0, 1}, {-6.0, 15.0, 0, 1},
{-5.0, 15.0, 0, 1}, {-4.0, 15.0, 0, 1}, {-3.0, 15.0, 0, 1}, {-2.0, 15.0, 0, 1}, {-1.0, 15.0, 0, 1}, {0.0, 15.0, 0, 1},
{4.0, 15.0, 0, 1}, {5.0, 15.0, 0, 1}, {6.0, 15.0, 0, 1}, {7.0, 15.0, 0, 1}, {8.0, 15.0, 0, 1}, {9.0, 15.0, 0, 1},
{10.0, 15.0, 0, 1}, {11.0, 15.0, 0, 1}, {-21.0, 16.0, 0, 1}, {-20.0, 16.0, 0, 1}, {-19.0, 16.0, 0, 1}, {-16.0, 16.0, 0, 1},
{-15.0, 16.0, 0, 1}, {-14.0, 16.0, 0, 1}, {-13.0, 16.0, 0, 1}, {-12.0, 16.0, 0, 1}, {-7.0, 16.0, 0, 1}, {-6.0, 16.0, 0, 1},
{-5.0, 16.0, 0, 1}, {-4.0, 16.0, 0, 1}, {-3.0, 16.0, 0, 1}, {-2.0, 16.0, 0, 1}, {-1.0, 16.0, 0, 1}, {0.0, 16.0, 0, 1},
{4.0, 16.0, 0, 1}, {5.0, 16.0, 0, 1}, {6.0, 16.0, 0, 1}, {7.0, 16.0, 0, 1}, {8.0, 16.0, 0, 1}, {9.0, 16.0, 0, 1},
{10.0, 16.0, 0, 1}, {11.0, 16.0, 0, 1}, {-20.0, 17.0, 0, 1}, {-19.0, 17.0, 0, 1}, {-18.0, 17.0, 0, 1}, {-7.0, 17.0, 0, 1},
{-6.0, 17.0, 0, 1}, {-5.0, 17.0, 0, 1}, {-4.0, 17.0, 0, 1}, {-3.0, 17.0, 0, 1}, {-2.0, 17.0, 0, 1}, {-1.0, 17.0, 0, 1},
{0.0, 17.0, 0, 1}, {4.0, 17.0, 0, 1}, {5.0, 17.0, 0, 1}, {6.0, 17.0, 0, 1}, {7.0, 17.0, 0, 1}, {8.0, 17.0, 0, 1},
{9.0, 17.0, 0, 1}, {10.0, 17.0, 0, 1}, {11.0, 17.0, 0, 1}, {19.0, 17.0, 0, 1}, {-19.0, 18.0, 0, 1}, {-18.0, 18.0, 0, 1},
{-17.0, 18.0, 0, 1}, {-7.0, 18.0, 0, 1}, {-6.0, 18.0, 0, 1}, {-5.0, 18.0, 0, 1}, {-4.0, 18.0, 0, 1}, {-3.0, 18.0, 0, 1},
{-2.0, 18.0, 0, 1}, {-1.0, 18.0, 0, 1}, {0.0, 18.0, 0, 1}, {4.0, 18.0, 0, 1}, {5.0, 18.0, 0, 1}, {6.0, 18.0, 0, 1},
{7.0, 18.0, 0, 1}, {8.0, 18.0, 0, 1}, {9.0, 18.0, 0, 1}, {10.0, 18.0, 0, 1}, {11.0, 18.0, 0, 1}, {18.0, 18.0, 0, 1},
{19.0, 18.0, 0, 1}, {20.0, 18.0, 0, 1}, {-18.0, 19.0, 0, 1}, {-17.0, 19.0, 0, 1}, {-16.0, 19.0, 0, 1}, {-15.0, 19.0, 0, 1},
{-8.0, 19.0, 0, 1}, {-7.0, 19.0, 0, 1}, {-6.0, 19.0, 0, 1}, {-5.0, 19.0, 0, 1}, {-4.0, 19.0, 0, 1}, {-3.0, 19.0, 0, 1},
{-2.0, 19.0, 0, 1}, {-1.0, 19.0, 0, 1}, {4.0, 19.0, 0, 1}, {5.0, 19.0, 0, 1}, {6.0, 19.0, 0, 1}, {7.0, 19.0, 0, 1},
{8.0, 19.0, 0, 1}, {9.0, 19.0, 0, 1}, {10.0, 19.0, 0, 1}, {17.0, 19.0, 0, 1}, {18.0, 19.0, 0, 1}, {19.0, 19.0, 0, 1},
{-17.0, 20.0, 0, 1}, {-16.0, 20.0, 0, 1}, {-15.0, 20.0, 0, 1}, {-14.0, 20.0, 0, 1}, {-7.0, 20.0, 0, 1}, {-6.0, 20.0, 0, 1},
{-5.0, 20.0, 0, 1}, {-4.0, 20.0, 0, 1}, {-3.0, 20.0, 0, 1}, {-2.0, 20.0, 0, 1}, {-1.0, 20.0, 0, 1}, {4.0, 20.0, 0, 1},
{5.0, 20.0, 0, 1}, {6.0, 20.0, 0, 1}, {7.0, 20.0, 0, 1}, {8.0, 20.0, 0, 1}, {9.0, 20.0, 0, 1}, {16.0, 20.0, 0, 1},
{17.0, 20.0, 0, 1}, {18.0, 20.0, 0, 1}, {-15.0, 21.0, 0, 1}, {-14.0, 21.0, 0, 1}, {-13.0, 21.0, 0, 1}, {-12.0, 21.0, 0, 1},
{-5.0, 21.0, 0, 1}, {-4.0, 21.0, 0, 1}, {-3.0, 21.0, 0, 1}, {-2.0, 21.0, 0, 1}, {-1.0, 21.0, 0, 1}, {14.0, 21.0, 0, 1},
{15.0, 21.0, 0, 1}, {16.0, 21.0, 0, 1}, {17.0, 21.0, 0, 1}, {-14.0, 22.0, 0, 1}, {-13.0, 22.0, 0, 1}, {-12.0, 22.0, 0, 1},
{-11.0, 22.0, 0, 1}, {-10.0, 22.0, 0, 1}, {12.0, 22.0, 0, 1}, {13.0, 22.0, 0, 1}, {14.0, 22.0, 0, 1}, {15.0, 22.0, 0, 1},
{-12.0, 23.0, 0, 1}, {-11.0, 23.0, 0, 1}, {-10.0, 23.0, 0, 1}, {-9.0, 23.0, 0, 1}, {-8.0, 23.0, 0, 1}, {9.0, 23.0, 0, 1},
{10.0, 23.0, 0, 1}, {11.0, 23.0, 0, 1}, {12.0, 23.0, 0, 1}, {13.0, 23.0, 0, 1}, {14.0, 23.0, 0, 1}, {-10.0, 24.0, 0, 1},
{-9.0, 24.0, 0, 1}, {-8.0, 24.0, 0, 1}, {-7.0, 24.0, 0, 1}, {-6.0, 24.0, 0, 1}, {-5.0, 24.0, 0, 1}, {-4.0, 24.0, 0, 1},
{-3.0, 24.0, 0, 1}, {5.0, 24.0, 0, 1}, {6.0, 24.0, 0, 1}, {7.0, 24.0, 0, 1}, {8.0, 24.0, 0, 1}, {9.0, 24.0, 0, 1},
{10.0, 24.0, 0, 1}, {11.0, 24.0, 0, 1}, {12.0, 24.0, 0, 1}, {-7.0, 25.0, 0, 1}, {-6.0, 25.0, 0, 1}, {-5.0, 25.0, 0, 1},
{-4.0, 25.0, 0, 1}, {-3.0, 25.0, 0, 1}, {-2.0, 25.0, 0, 1}, {-1.0, 25.0, 0, 1}, {0.0, 25.0, 0, 1}, {1.0, 25.0, 0, 1},
{2.0, 25.0, 0, 1}, {3.0, 25.0, 0, 1}, {4.0, 25.0, 0, 1}, {5.0, 25.0, 0, 1}, {6.0, 25.0, 0, 1}, {7.0, 25.0, 0, 1},
{8.0, 25.0, 0, 1}, {9.0, 25.0, 0, 1}, {-3.0, 26.0, 0, 1}, {-2.0, 26.0, 0, 1}, {-1.0, 26.0, 0, 1}, {0.0, 26.0, 0, 1},
{1.0, 26.0, 0, 1}, {2.0, 26.0, 0, 1}, {3.0, 26.0, 0, 1}, {4.0, 26.0, 0, 1}, {5.0, 26.0, 0, 1}
};
#endif // CONFIG_3D_OBJECT_ESP_LOGO

View File

@@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
extern const uint8_t image_bmp_array_esp_logo[512];
extern const float image_3d_matrix_esp_logo[1427][4];
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,252 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_text.h"
const uint8_t image_bmp_array_esp_text[384] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3f, 0xf8, 0x7f, 0xf1, 0xff, 0xe1, 0xff, 0xe0, 0x7f, 0xe0, 0xff, 0xc1, 0xff, 0xc7, 0x07, 0xfe,
0x7f, 0xf8, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xf0, 0xff, 0xe1, 0xff, 0xc3, 0xff, 0xc7, 0x0f, 0xfe,
0x7f, 0xf8, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xe3, 0xff, 0xc3, 0xff, 0xc7, 0x1f, 0xfe,
0x70, 0x00, 0xe0, 0x01, 0xe0, 0x79, 0xe0, 0x71, 0xc0, 0x03, 0x80, 0x07, 0x80, 0x07, 0x1e, 0x00,
0x70, 0x00, 0xe0, 0x01, 0xe0, 0x39, 0xe0, 0x71, 0xc0, 0x03, 0x80, 0x07, 0x80, 0x07, 0x1c, 0x00,
0x70, 0x00, 0xe0, 0x01, 0xe0, 0x39, 0xe0, 0x71, 0xc0, 0x03, 0x80, 0x07, 0x80, 0x07, 0x1c, 0x00,
0x70, 0x00, 0xe0, 0x01, 0xe0, 0x39, 0xe0, 0x71, 0xc0, 0x03, 0x80, 0x07, 0x80, 0x07, 0x1c, 0x00,
0x70, 0x00, 0xe0, 0x01, 0xe0, 0x39, 0xe0, 0x71, 0xc0, 0x03, 0x80, 0x07, 0x80, 0x07, 0x1c, 0x00,
0x70, 0x00, 0xe0, 0x01, 0xe0, 0x39, 0xe0, 0x71, 0xc0, 0x03, 0x80, 0x07, 0x80, 0x07, 0x1c, 0x00,
0x7f, 0xf0, 0xff, 0xe1, 0xe0, 0x79, 0xe0, 0x71, 0xff, 0xc3, 0xff, 0x83, 0xff, 0x87, 0x1f, 0xfc,
0x7f, 0xf0, 0xff, 0xf1, 0xff, 0xf9, 0xff, 0xf1, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xc7, 0x1f, 0xfc,
0x7f, 0xf0, 0x7f, 0xf1, 0xff, 0xf1, 0xff, 0xf1, 0xff, 0xc1, 0xff, 0xe1, 0xff, 0xc7, 0x1f, 0xfc,
0x70, 0x00, 0x00, 0x79, 0xff, 0xf1, 0xff, 0xe1, 0xc0, 0x00, 0x01, 0xe0, 0x03, 0xc7, 0x1c, 0x00,
0x70, 0x00, 0x00, 0x79, 0xff, 0xc1, 0xe1, 0xe1, 0xc0, 0x00, 0x00, 0xe0, 0x01, 0xc7, 0x1c, 0x00,
0x70, 0x00, 0x00, 0x79, 0xe0, 0x01, 0xe0, 0xe1, 0xc0, 0x00, 0x00, 0xe0, 0x01, 0xc7, 0x1c, 0x00,
0x70, 0x00, 0x00, 0x79, 0xe0, 0x01, 0xe0, 0x71, 0xc0, 0x00, 0x00, 0xe0, 0x01, 0xc7, 0x1c, 0x00,
0x70, 0x00, 0x00, 0x79, 0xe0, 0x01, 0xe0, 0x71, 0xc0, 0x00, 0x00, 0xe0, 0x01, 0xc7, 0x1c, 0x00,
0x70, 0x00, 0x00, 0x79, 0xe0, 0x01, 0xe0, 0x71, 0xc0, 0x00, 0x00, 0xe0, 0x01, 0xc7, 0x1c, 0x00,
0x70, 0x00, 0x00, 0x79, 0xe0, 0x01, 0xe0, 0x71, 0xc0, 0x00, 0x00, 0xe0, 0x01, 0xc7, 0x1c, 0x00,
0x7f, 0xf8, 0xff, 0xf1, 0xe0, 0x01, 0xe0, 0x79, 0xff, 0xe3, 0xff, 0xe7, 0xff, 0xc7, 0x1c, 0x00,
0x7f, 0xf8, 0xff, 0xf1, 0xe0, 0x01, 0xe0, 0x38, 0xff, 0xe3, 0xff, 0xc7, 0xff, 0xc7, 0x1c, 0x00,
0x3f, 0xf8, 0xff, 0xe1, 0xe0, 0x01, 0xe0, 0x38, 0xff, 0xe3, 0xff, 0x87, 0xff, 0x87, 0x1c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const float image_3d_array_esp_text[1271][4] = {
{-62.0, -11.0, 0, 1}, {-61.0, -11.0, 0, 1}, {-60.0, -11.0, 0, 1}, {-59.0, -11.0, 0, 1}, {-58.0, -11.0, 0, 1}, {-57.0, -11.0, 0, 1},
{-56.0, -11.0, 0, 1}, {-55.0, -11.0, 0, 1}, {-54.0, -11.0, 0, 1}, {-53.0, -11.0, 0, 1}, {-52.0, -11.0, 0, 1}, {-47.0, -11.0, 0, 1},
{-46.0, -11.0, 0, 1}, {-45.0, -11.0, 0, 1}, {-44.0, -11.0, 0, 1}, {-43.0, -11.0, 0, 1}, {-42.0, -11.0, 0, 1}, {-41.0, -11.0, 0, 1},
{-40.0, -11.0, 0, 1}, {-39.0, -11.0, 0, 1}, {-38.0, -11.0, 0, 1}, {-37.0, -11.0, 0, 1}, {-33.0, -11.0, 0, 1}, {-32.0, -11.0, 0, 1},
{-31.0, -11.0, 0, 1}, {-30.0, -11.0, 0, 1}, {-29.0, -11.0, 0, 1}, {-28.0, -11.0, 0, 1}, {-27.0, -11.0, 0, 1}, {-26.0, -11.0, 0, 1},
{-25.0, -11.0, 0, 1}, {-24.0, -11.0, 0, 1}, {-23.0, -11.0, 0, 1}, {-22.0, -11.0, 0, 1}, {-17.0, -11.0, 0, 1}, {-16.0, -11.0, 0, 1},
{-15.0, -11.0, 0, 1}, {-14.0, -11.0, 0, 1}, {-13.0, -11.0, 0, 1}, {-12.0, -11.0, 0, 1}, {-11.0, -11.0, 0, 1}, {-10.0, -11.0, 0, 1},
{-9.0, -11.0, 0, 1}, {-8.0, -11.0, 0, 1}, {-7.0, -11.0, 0, 1}, {-6.0, -11.0, 0, 1}, {1.0, -11.0, 0, 1}, {2.0, -11.0, 0, 1},
{3.0, -11.0, 0, 1}, {4.0, -11.0, 0, 1}, {5.0, -11.0, 0, 1}, {6.0, -11.0, 0, 1}, {7.0, -11.0, 0, 1}, {8.0, -11.0, 0, 1},
{9.0, -11.0, 0, 1}, {10.0, -11.0, 0, 1}, {16.0, -11.0, 0, 1}, {17.0, -11.0, 0, 1}, {18.0, -11.0, 0, 1}, {19.0, -11.0, 0, 1},
{20.0, -11.0, 0, 1}, {21.0, -11.0, 0, 1}, {22.0, -11.0, 0, 1}, {23.0, -11.0, 0, 1}, {24.0, -11.0, 0, 1}, {25.0, -11.0, 0, 1},
{31.0, -11.0, 0, 1}, {32.0, -11.0, 0, 1}, {33.0, -11.0, 0, 1}, {34.0, -11.0, 0, 1}, {35.0, -11.0, 0, 1}, {36.0, -11.0, 0, 1},
{37.0, -11.0, 0, 1}, {38.0, -11.0, 0, 1}, {39.0, -11.0, 0, 1}, {40.0, -11.0, 0, 1}, {41.0, -11.0, 0, 1}, {45.0, -11.0, 0, 1},
{46.0, -11.0, 0, 1}, {47.0, -11.0, 0, 1}, {53.0, -11.0, 0, 1}, {54.0, -11.0, 0, 1}, {55.0, -11.0, 0, 1}, {56.0, -11.0, 0, 1},
{57.0, -11.0, 0, 1}, {58.0, -11.0, 0, 1}, {59.0, -11.0, 0, 1}, {60.0, -11.0, 0, 1}, {61.0, -11.0, 0, 1}, {62.0, -11.0, 0, 1},
{-63.0, -10.0, 0, 1}, {-62.0, -10.0, 0, 1}, {-61.0, -10.0, 0, 1}, {-60.0, -10.0, 0, 1}, {-59.0, -10.0, 0, 1}, {-58.0, -10.0, 0, 1},
{-57.0, -10.0, 0, 1}, {-56.0, -10.0, 0, 1}, {-55.0, -10.0, 0, 1}, {-54.0, -10.0, 0, 1}, {-53.0, -10.0, 0, 1}, {-52.0, -10.0, 0, 1},
{-48.0, -10.0, 0, 1}, {-47.0, -10.0, 0, 1}, {-46.0, -10.0, 0, 1}, {-45.0, -10.0, 0, 1}, {-44.0, -10.0, 0, 1}, {-43.0, -10.0, 0, 1},
{-42.0, -10.0, 0, 1}, {-41.0, -10.0, 0, 1}, {-40.0, -10.0, 0, 1}, {-39.0, -10.0, 0, 1}, {-38.0, -10.0, 0, 1}, {-37.0, -10.0, 0, 1},
{-33.0, -10.0, 0, 1}, {-32.0, -10.0, 0, 1}, {-31.0, -10.0, 0, 1}, {-30.0, -10.0, 0, 1}, {-29.0, -10.0, 0, 1}, {-28.0, -10.0, 0, 1},
{-27.0, -10.0, 0, 1}, {-26.0, -10.0, 0, 1}, {-25.0, -10.0, 0, 1}, {-24.0, -10.0, 0, 1}, {-23.0, -10.0, 0, 1}, {-22.0, -10.0, 0, 1},
{-21.0, -10.0, 0, 1}, {-17.0, -10.0, 0, 1}, {-16.0, -10.0, 0, 1}, {-15.0, -10.0, 0, 1}, {-14.0, -10.0, 0, 1}, {-13.0, -10.0, 0, 1},
{-12.0, -10.0, 0, 1}, {-11.0, -10.0, 0, 1}, {-10.0, -10.0, 0, 1}, {-9.0, -10.0, 0, 1}, {-8.0, -10.0, 0, 1}, {-7.0, -10.0, 0, 1},
{-6.0, -10.0, 0, 1}, {-5.0, -10.0, 0, 1}, {0.0, -10.0, 0, 1}, {1.0, -10.0, 0, 1}, {2.0, -10.0, 0, 1}, {3.0, -10.0, 0, 1},
{4.0, -10.0, 0, 1}, {5.0, -10.0, 0, 1}, {6.0, -10.0, 0, 1}, {7.0, -10.0, 0, 1}, {8.0, -10.0, 0, 1}, {9.0, -10.0, 0, 1},
{10.0, -10.0, 0, 1}, {15.0, -10.0, 0, 1}, {16.0, -10.0, 0, 1}, {17.0, -10.0, 0, 1}, {18.0, -10.0, 0, 1}, {19.0, -10.0, 0, 1},
{20.0, -10.0, 0, 1}, {21.0, -10.0, 0, 1}, {22.0, -10.0, 0, 1}, {23.0, -10.0, 0, 1}, {24.0, -10.0, 0, 1}, {25.0, -10.0, 0, 1},
{30.0, -10.0, 0, 1}, {31.0, -10.0, 0, 1}, {32.0, -10.0, 0, 1}, {33.0, -10.0, 0, 1}, {34.0, -10.0, 0, 1}, {35.0, -10.0, 0, 1},
{36.0, -10.0, 0, 1}, {37.0, -10.0, 0, 1}, {38.0, -10.0, 0, 1}, {39.0, -10.0, 0, 1}, {40.0, -10.0, 0, 1}, {41.0, -10.0, 0, 1},
{45.0, -10.0, 0, 1}, {46.0, -10.0, 0, 1}, {47.0, -10.0, 0, 1}, {52.0, -10.0, 0, 1}, {53.0, -10.0, 0, 1}, {54.0, -10.0, 0, 1},
{55.0, -10.0, 0, 1}, {56.0, -10.0, 0, 1}, {57.0, -10.0, 0, 1}, {58.0, -10.0, 0, 1}, {59.0, -10.0, 0, 1}, {60.0, -10.0, 0, 1},
{61.0, -10.0, 0, 1}, {62.0, -10.0, 0, 1}, {-63.0, -9.0, 0, 1}, {-62.0, -9.0, 0, 1}, {-61.0, -9.0, 0, 1}, {-60.0, -9.0, 0, 1},
{-59.0, -9.0, 0, 1}, {-58.0, -9.0, 0, 1}, {-57.0, -9.0, 0, 1}, {-56.0, -9.0, 0, 1}, {-55.0, -9.0, 0, 1}, {-54.0, -9.0, 0, 1},
{-53.0, -9.0, 0, 1}, {-52.0, -9.0, 0, 1}, {-48.0, -9.0, 0, 1}, {-47.0, -9.0, 0, 1}, {-46.0, -9.0, 0, 1}, {-45.0, -9.0, 0, 1},
{-44.0, -9.0, 0, 1}, {-43.0, -9.0, 0, 1}, {-42.0, -9.0, 0, 1}, {-41.0, -9.0, 0, 1}, {-40.0, -9.0, 0, 1}, {-39.0, -9.0, 0, 1},
{-38.0, -9.0, 0, 1}, {-37.0, -9.0, 0, 1}, {-33.0, -9.0, 0, 1}, {-32.0, -9.0, 0, 1}, {-31.0, -9.0, 0, 1}, {-30.0, -9.0, 0, 1},
{-29.0, -9.0, 0, 1}, {-28.0, -9.0, 0, 1}, {-27.0, -9.0, 0, 1}, {-26.0, -9.0, 0, 1}, {-25.0, -9.0, 0, 1}, {-24.0, -9.0, 0, 1},
{-23.0, -9.0, 0, 1}, {-22.0, -9.0, 0, 1}, {-21.0, -9.0, 0, 1}, {-17.0, -9.0, 0, 1}, {-16.0, -9.0, 0, 1}, {-15.0, -9.0, 0, 1},
{-14.0, -9.0, 0, 1}, {-13.0, -9.0, 0, 1}, {-12.0, -9.0, 0, 1}, {-11.0, -9.0, 0, 1}, {-10.0, -9.0, 0, 1}, {-9.0, -9.0, 0, 1},
{-8.0, -9.0, 0, 1}, {-7.0, -9.0, 0, 1}, {-6.0, -9.0, 0, 1}, {-5.0, -9.0, 0, 1}, {-1.0, -9.0, 0, 1}, {0.0, -9.0, 0, 1},
{1.0, -9.0, 0, 1}, {2.0, -9.0, 0, 1}, {3.0, -9.0, 0, 1}, {4.0, -9.0, 0, 1}, {5.0, -9.0, 0, 1}, {6.0, -9.0, 0, 1},
{7.0, -9.0, 0, 1}, {8.0, -9.0, 0, 1}, {9.0, -9.0, 0, 1}, {10.0, -9.0, 0, 1}, {14.0, -9.0, 0, 1}, {15.0, -9.0, 0, 1},
{16.0, -9.0, 0, 1}, {17.0, -9.0, 0, 1}, {18.0, -9.0, 0, 1}, {19.0, -9.0, 0, 1}, {20.0, -9.0, 0, 1}, {21.0, -9.0, 0, 1},
{22.0, -9.0, 0, 1}, {23.0, -9.0, 0, 1}, {24.0, -9.0, 0, 1}, {25.0, -9.0, 0, 1}, {30.0, -9.0, 0, 1}, {31.0, -9.0, 0, 1},
{32.0, -9.0, 0, 1}, {33.0, -9.0, 0, 1}, {34.0, -9.0, 0, 1}, {35.0, -9.0, 0, 1}, {36.0, -9.0, 0, 1}, {37.0, -9.0, 0, 1},
{38.0, -9.0, 0, 1}, {39.0, -9.0, 0, 1}, {40.0, -9.0, 0, 1}, {41.0, -9.0, 0, 1}, {45.0, -9.0, 0, 1}, {46.0, -9.0, 0, 1},
{47.0, -9.0, 0, 1}, {51.0, -9.0, 0, 1}, {52.0, -9.0, 0, 1}, {53.0, -9.0, 0, 1}, {54.0, -9.0, 0, 1}, {55.0, -9.0, 0, 1},
{56.0, -9.0, 0, 1}, {57.0, -9.0, 0, 1}, {58.0, -9.0, 0, 1}, {59.0, -9.0, 0, 1}, {60.0, -9.0, 0, 1}, {61.0, -9.0, 0, 1},
{62.0, -9.0, 0, 1}, {-63.0, -8.0, 0, 1}, {-62.0, -8.0, 0, 1}, {-61.0, -8.0, 0, 1}, {-48.0, -8.0, 0, 1}, {-47.0, -8.0, 0, 1},
{-46.0, -8.0, 0, 1}, {-33.0, -8.0, 0, 1}, {-32.0, -8.0, 0, 1}, {-31.0, -8.0, 0, 1}, {-30.0, -8.0, 0, 1}, {-23.0, -8.0, 0, 1},
{-22.0, -8.0, 0, 1}, {-21.0, -8.0, 0, 1}, {-20.0, -8.0, 0, 1}, {-17.0, -8.0, 0, 1}, {-16.0, -8.0, 0, 1}, {-15.0, -8.0, 0, 1},
{-14.0, -8.0, 0, 1}, {-7.0, -8.0, 0, 1}, {-6.0, -8.0, 0, 1}, {-5.0, -8.0, 0, 1}, {-1.0, -8.0, 0, 1}, {0.0, -8.0, 0, 1},
{1.0, -8.0, 0, 1}, {14.0, -8.0, 0, 1}, {15.0, -8.0, 0, 1}, {16.0, -8.0, 0, 1}, {29.0, -8.0, 0, 1}, {30.0, -8.0, 0, 1},
{31.0, -8.0, 0, 1}, {32.0, -8.0, 0, 1}, {45.0, -8.0, 0, 1}, {46.0, -8.0, 0, 1}, {47.0, -8.0, 0, 1}, {51.0, -8.0, 0, 1},
{52.0, -8.0, 0, 1}, {53.0, -8.0, 0, 1}, {54.0, -8.0, 0, 1}, {-63.0, -7.0, 0, 1}, {-62.0, -7.0, 0, 1}, {-61.0, -7.0, 0, 1},
{-48.0, -7.0, 0, 1}, {-47.0, -7.0, 0, 1}, {-46.0, -7.0, 0, 1}, {-33.0, -7.0, 0, 1}, {-32.0, -7.0, 0, 1}, {-31.0, -7.0, 0, 1},
{-30.0, -7.0, 0, 1}, {-22.0, -7.0, 0, 1}, {-21.0, -7.0, 0, 1}, {-20.0, -7.0, 0, 1}, {-17.0, -7.0, 0, 1}, {-16.0, -7.0, 0, 1},
{-15.0, -7.0, 0, 1}, {-14.0, -7.0, 0, 1}, {-7.0, -7.0, 0, 1}, {-6.0, -7.0, 0, 1}, {-5.0, -7.0, 0, 1}, {-1.0, -7.0, 0, 1},
{0.0, -7.0, 0, 1}, {1.0, -7.0, 0, 1}, {14.0, -7.0, 0, 1}, {15.0, -7.0, 0, 1}, {16.0, -7.0, 0, 1}, {29.0, -7.0, 0, 1},
{30.0, -7.0, 0, 1}, {31.0, -7.0, 0, 1}, {32.0, -7.0, 0, 1}, {45.0, -7.0, 0, 1}, {46.0, -7.0, 0, 1}, {47.0, -7.0, 0, 1},
{51.0, -7.0, 0, 1}, {52.0, -7.0, 0, 1}, {53.0, -7.0, 0, 1}, {-63.0, -6.0, 0, 1}, {-62.0, -6.0, 0, 1}, {-61.0, -6.0, 0, 1},
{-48.0, -6.0, 0, 1}, {-47.0, -6.0, 0, 1}, {-46.0, -6.0, 0, 1}, {-33.0, -6.0, 0, 1}, {-32.0, -6.0, 0, 1}, {-31.0, -6.0, 0, 1},
{-30.0, -6.0, 0, 1}, {-22.0, -6.0, 0, 1}, {-21.0, -6.0, 0, 1}, {-20.0, -6.0, 0, 1}, {-17.0, -6.0, 0, 1}, {-16.0, -6.0, 0, 1},
{-15.0, -6.0, 0, 1}, {-14.0, -6.0, 0, 1}, {-7.0, -6.0, 0, 1}, {-6.0, -6.0, 0, 1}, {-5.0, -6.0, 0, 1}, {-1.0, -6.0, 0, 1},
{0.0, -6.0, 0, 1}, {1.0, -6.0, 0, 1}, {14.0, -6.0, 0, 1}, {15.0, -6.0, 0, 1}, {16.0, -6.0, 0, 1}, {29.0, -6.0, 0, 1},
{30.0, -6.0, 0, 1}, {31.0, -6.0, 0, 1}, {32.0, -6.0, 0, 1}, {45.0, -6.0, 0, 1}, {46.0, -6.0, 0, 1}, {47.0, -6.0, 0, 1},
{51.0, -6.0, 0, 1}, {52.0, -6.0, 0, 1}, {53.0, -6.0, 0, 1}, {-63.0, -5.0, 0, 1}, {-62.0, -5.0, 0, 1}, {-61.0, -5.0, 0, 1},
{-48.0, -5.0, 0, 1}, {-47.0, -5.0, 0, 1}, {-46.0, -5.0, 0, 1}, {-33.0, -5.0, 0, 1}, {-32.0, -5.0, 0, 1}, {-31.0, -5.0, 0, 1},
{-30.0, -5.0, 0, 1}, {-22.0, -5.0, 0, 1}, {-21.0, -5.0, 0, 1}, {-20.0, -5.0, 0, 1}, {-17.0, -5.0, 0, 1}, {-16.0, -5.0, 0, 1},
{-15.0, -5.0, 0, 1}, {-14.0, -5.0, 0, 1}, {-7.0, -5.0, 0, 1}, {-6.0, -5.0, 0, 1}, {-5.0, -5.0, 0, 1}, {-1.0, -5.0, 0, 1},
{0.0, -5.0, 0, 1}, {1.0, -5.0, 0, 1}, {14.0, -5.0, 0, 1}, {15.0, -5.0, 0, 1}, {16.0, -5.0, 0, 1}, {29.0, -5.0, 0, 1},
{30.0, -5.0, 0, 1}, {31.0, -5.0, 0, 1}, {32.0, -5.0, 0, 1}, {45.0, -5.0, 0, 1}, {46.0, -5.0, 0, 1}, {47.0, -5.0, 0, 1},
{51.0, -5.0, 0, 1}, {52.0, -5.0, 0, 1}, {53.0, -5.0, 0, 1}, {-63.0, -4.0, 0, 1}, {-62.0, -4.0, 0, 1}, {-61.0, -4.0, 0, 1},
{-48.0, -4.0, 0, 1}, {-47.0, -4.0, 0, 1}, {-46.0, -4.0, 0, 1}, {-33.0, -4.0, 0, 1}, {-32.0, -4.0, 0, 1}, {-31.0, -4.0, 0, 1},
{-30.0, -4.0, 0, 1}, {-22.0, -4.0, 0, 1}, {-21.0, -4.0, 0, 1}, {-20.0, -4.0, 0, 1}, {-17.0, -4.0, 0, 1}, {-16.0, -4.0, 0, 1},
{-15.0, -4.0, 0, 1}, {-14.0, -4.0, 0, 1}, {-7.0, -4.0, 0, 1}, {-6.0, -4.0, 0, 1}, {-5.0, -4.0, 0, 1}, {-1.0, -4.0, 0, 1},
{0.0, -4.0, 0, 1}, {1.0, -4.0, 0, 1}, {14.0, -4.0, 0, 1}, {15.0, -4.0, 0, 1}, {16.0, -4.0, 0, 1}, {29.0, -4.0, 0, 1},
{30.0, -4.0, 0, 1}, {31.0, -4.0, 0, 1}, {32.0, -4.0, 0, 1}, {45.0, -4.0, 0, 1}, {46.0, -4.0, 0, 1}, {47.0, -4.0, 0, 1},
{51.0, -4.0, 0, 1}, {52.0, -4.0, 0, 1}, {53.0, -4.0, 0, 1}, {-63.0, -3.0, 0, 1}, {-62.0, -3.0, 0, 1}, {-61.0, -3.0, 0, 1},
{-48.0, -3.0, 0, 1}, {-47.0, -3.0, 0, 1}, {-46.0, -3.0, 0, 1}, {-33.0, -3.0, 0, 1}, {-32.0, -3.0, 0, 1}, {-31.0, -3.0, 0, 1},
{-30.0, -3.0, 0, 1}, {-22.0, -3.0, 0, 1}, {-21.0, -3.0, 0, 1}, {-20.0, -3.0, 0, 1}, {-17.0, -3.0, 0, 1}, {-16.0, -3.0, 0, 1},
{-15.0, -3.0, 0, 1}, {-14.0, -3.0, 0, 1}, {-7.0, -3.0, 0, 1}, {-6.0, -3.0, 0, 1}, {-5.0, -3.0, 0, 1}, {-1.0, -3.0, 0, 1},
{0.0, -3.0, 0, 1}, {1.0, -3.0, 0, 1}, {14.0, -3.0, 0, 1}, {15.0, -3.0, 0, 1}, {16.0, -3.0, 0, 1}, {29.0, -3.0, 0, 1},
{30.0, -3.0, 0, 1}, {31.0, -3.0, 0, 1}, {32.0, -3.0, 0, 1}, {45.0, -3.0, 0, 1}, {46.0, -3.0, 0, 1}, {47.0, -3.0, 0, 1},
{51.0, -3.0, 0, 1}, {52.0, -3.0, 0, 1}, {53.0, -3.0, 0, 1}, {-63.0, -2.0, 0, 1}, {-62.0, -2.0, 0, 1}, {-61.0, -2.0, 0, 1},
{-60.0, -2.0, 0, 1}, {-59.0, -2.0, 0, 1}, {-58.0, -2.0, 0, 1}, {-57.0, -2.0, 0, 1}, {-56.0, -2.0, 0, 1}, {-55.0, -2.0, 0, 1},
{-54.0, -2.0, 0, 1}, {-53.0, -2.0, 0, 1}, {-48.0, -2.0, 0, 1}, {-47.0, -2.0, 0, 1}, {-46.0, -2.0, 0, 1}, {-45.0, -2.0, 0, 1},
{-44.0, -2.0, 0, 1}, {-43.0, -2.0, 0, 1}, {-42.0, -2.0, 0, 1}, {-41.0, -2.0, 0, 1}, {-40.0, -2.0, 0, 1}, {-39.0, -2.0, 0, 1},
{-38.0, -2.0, 0, 1}, {-33.0, -2.0, 0, 1}, {-32.0, -2.0, 0, 1}, {-31.0, -2.0, 0, 1}, {-30.0, -2.0, 0, 1}, {-23.0, -2.0, 0, 1},
{-22.0, -2.0, 0, 1}, {-21.0, -2.0, 0, 1}, {-20.0, -2.0, 0, 1}, {-17.0, -2.0, 0, 1}, {-16.0, -2.0, 0, 1}, {-15.0, -2.0, 0, 1},
{-14.0, -2.0, 0, 1}, {-7.0, -2.0, 0, 1}, {-6.0, -2.0, 0, 1}, {-5.0, -2.0, 0, 1}, {-1.0, -2.0, 0, 1}, {0.0, -2.0, 0, 1},
{1.0, -2.0, 0, 1}, {2.0, -2.0, 0, 1}, {3.0, -2.0, 0, 1}, {4.0, -2.0, 0, 1}, {5.0, -2.0, 0, 1}, {6.0, -2.0, 0, 1},
{7.0, -2.0, 0, 1}, {8.0, -2.0, 0, 1}, {9.0, -2.0, 0, 1}, {14.0, -2.0, 0, 1}, {15.0, -2.0, 0, 1}, {16.0, -2.0, 0, 1},
{17.0, -2.0, 0, 1}, {18.0, -2.0, 0, 1}, {19.0, -2.0, 0, 1}, {20.0, -2.0, 0, 1}, {21.0, -2.0, 0, 1}, {22.0, -2.0, 0, 1},
{23.0, -2.0, 0, 1}, {24.0, -2.0, 0, 1}, {30.0, -2.0, 0, 1}, {31.0, -2.0, 0, 1}, {32.0, -2.0, 0, 1}, {33.0, -2.0, 0, 1},
{34.0, -2.0, 0, 1}, {35.0, -2.0, 0, 1}, {36.0, -2.0, 0, 1}, {37.0, -2.0, 0, 1}, {38.0, -2.0, 0, 1}, {39.0, -2.0, 0, 1},
{40.0, -2.0, 0, 1}, {45.0, -2.0, 0, 1}, {46.0, -2.0, 0, 1}, {47.0, -2.0, 0, 1}, {51.0, -2.0, 0, 1}, {52.0, -2.0, 0, 1},
{53.0, -2.0, 0, 1}, {54.0, -2.0, 0, 1}, {55.0, -2.0, 0, 1}, {56.0, -2.0, 0, 1}, {57.0, -2.0, 0, 1}, {58.0, -2.0, 0, 1},
{59.0, -2.0, 0, 1}, {60.0, -2.0, 0, 1}, {61.0, -2.0, 0, 1}, {-63.0, -1.0, 0, 1}, {-62.0, -1.0, 0, 1}, {-61.0, -1.0, 0, 1},
{-60.0, -1.0, 0, 1}, {-59.0, -1.0, 0, 1}, {-58.0, -1.0, 0, 1}, {-57.0, -1.0, 0, 1}, {-56.0, -1.0, 0, 1}, {-55.0, -1.0, 0, 1},
{-54.0, -1.0, 0, 1}, {-53.0, -1.0, 0, 1}, {-48.0, -1.0, 0, 1}, {-47.0, -1.0, 0, 1}, {-46.0, -1.0, 0, 1}, {-45.0, -1.0, 0, 1},
{-44.0, -1.0, 0, 1}, {-43.0, -1.0, 0, 1}, {-42.0, -1.0, 0, 1}, {-41.0, -1.0, 0, 1}, {-40.0, -1.0, 0, 1}, {-39.0, -1.0, 0, 1},
{-38.0, -1.0, 0, 1}, {-37.0, -1.0, 0, 1}, {-33.0, -1.0, 0, 1}, {-32.0, -1.0, 0, 1}, {-31.0, -1.0, 0, 1}, {-30.0, -1.0, 0, 1},
{-29.0, -1.0, 0, 1}, {-28.0, -1.0, 0, 1}, {-27.0, -1.0, 0, 1}, {-26.0, -1.0, 0, 1}, {-25.0, -1.0, 0, 1}, {-24.0, -1.0, 0, 1},
{-23.0, -1.0, 0, 1}, {-22.0, -1.0, 0, 1}, {-21.0, -1.0, 0, 1}, {-20.0, -1.0, 0, 1}, {-17.0, -1.0, 0, 1}, {-16.0, -1.0, 0, 1},
{-15.0, -1.0, 0, 1}, {-14.0, -1.0, 0, 1}, {-13.0, -1.0, 0, 1}, {-12.0, -1.0, 0, 1}, {-11.0, -1.0, 0, 1}, {-10.0, -1.0, 0, 1},
{-9.0, -1.0, 0, 1}, {-8.0, -1.0, 0, 1}, {-7.0, -1.0, 0, 1}, {-6.0, -1.0, 0, 1}, {-5.0, -1.0, 0, 1}, {-1.0, -1.0, 0, 1},
{0.0, -1.0, 0, 1}, {1.0, -1.0, 0, 1}, {2.0, -1.0, 0, 1}, {3.0, -1.0, 0, 1}, {4.0, -1.0, 0, 1}, {5.0, -1.0, 0, 1},
{6.0, -1.0, 0, 1}, {7.0, -1.0, 0, 1}, {8.0, -1.0, 0, 1}, {9.0, -1.0, 0, 1}, {14.0, -1.0, 0, 1}, {15.0, -1.0, 0, 1},
{16.0, -1.0, 0, 1}, {17.0, -1.0, 0, 1}, {18.0, -1.0, 0, 1}, {19.0, -1.0, 0, 1}, {20.0, -1.0, 0, 1}, {21.0, -1.0, 0, 1},
{22.0, -1.0, 0, 1}, {23.0, -1.0, 0, 1}, {24.0, -1.0, 0, 1}, {25.0, -1.0, 0, 1}, {30.0, -1.0, 0, 1}, {31.0, -1.0, 0, 1},
{32.0, -1.0, 0, 1}, {33.0, -1.0, 0, 1}, {34.0, -1.0, 0, 1}, {35.0, -1.0, 0, 1}, {36.0, -1.0, 0, 1}, {37.0, -1.0, 0, 1},
{38.0, -1.0, 0, 1}, {39.0, -1.0, 0, 1}, {40.0, -1.0, 0, 1}, {41.0, -1.0, 0, 1}, {45.0, -1.0, 0, 1}, {46.0, -1.0, 0, 1},
{47.0, -1.0, 0, 1}, {51.0, -1.0, 0, 1}, {52.0, -1.0, 0, 1}, {53.0, -1.0, 0, 1}, {54.0, -1.0, 0, 1}, {55.0, -1.0, 0, 1},
{56.0, -1.0, 0, 1}, {57.0, -1.0, 0, 1}, {58.0, -1.0, 0, 1}, {59.0, -1.0, 0, 1}, {60.0, -1.0, 0, 1}, {61.0, -1.0, 0, 1},
{-63.0, 0.0, 0, 1}, {-62.0, 0.0, 0, 1}, {-61.0, 0.0, 0, 1}, {-60.0, 0.0, 0, 1}, {-59.0, 0.0, 0, 1}, {-58.0, 0.0, 0, 1},
{-57.0, 0.0, 0, 1}, {-56.0, 0.0, 0, 1}, {-55.0, 0.0, 0, 1}, {-54.0, 0.0, 0, 1}, {-53.0, 0.0, 0, 1}, {-47.0, 0.0, 0, 1},
{-46.0, 0.0, 0, 1}, {-45.0, 0.0, 0, 1}, {-44.0, 0.0, 0, 1}, {-43.0, 0.0, 0, 1}, {-42.0, 0.0, 0, 1}, {-41.0, 0.0, 0, 1},
{-40.0, 0.0, 0, 1}, {-39.0, 0.0, 0, 1}, {-38.0, 0.0, 0, 1}, {-37.0, 0.0, 0, 1}, {-33.0, 0.0, 0, 1}, {-32.0, 0.0, 0, 1},
{-31.0, 0.0, 0, 1}, {-30.0, 0.0, 0, 1}, {-29.0, 0.0, 0, 1}, {-28.0, 0.0, 0, 1}, {-27.0, 0.0, 0, 1}, {-26.0, 0.0, 0, 1},
{-25.0, 0.0, 0, 1}, {-24.0, 0.0, 0, 1}, {-23.0, 0.0, 0, 1}, {-22.0, 0.0, 0, 1}, {-21.0, 0.0, 0, 1}, {-17.0, 0.0, 0, 1},
{-16.0, 0.0, 0, 1}, {-15.0, 0.0, 0, 1}, {-14.0, 0.0, 0, 1}, {-13.0, 0.0, 0, 1}, {-12.0, 0.0, 0, 1}, {-11.0, 0.0, 0, 1},
{-10.0, 0.0, 0, 1}, {-9.0, 0.0, 0, 1}, {-8.0, 0.0, 0, 1}, {-7.0, 0.0, 0, 1}, {-6.0, 0.0, 0, 1}, {-5.0, 0.0, 0, 1},
{-1.0, 0.0, 0, 1}, {0.0, 0.0, 0, 1}, {1.0, 0.0, 0, 1}, {2.0, 0.0, 0, 1}, {3.0, 0.0, 0, 1}, {4.0, 0.0, 0, 1},
{5.0, 0.0, 0, 1}, {6.0, 0.0, 0, 1}, {7.0, 0.0, 0, 1}, {8.0, 0.0, 0, 1}, {9.0, 0.0, 0, 1}, {15.0, 0.0, 0, 1},
{16.0, 0.0, 0, 1}, {17.0, 0.0, 0, 1}, {18.0, 0.0, 0, 1}, {19.0, 0.0, 0, 1}, {20.0, 0.0, 0, 1}, {21.0, 0.0, 0, 1},
{22.0, 0.0, 0, 1}, {23.0, 0.0, 0, 1}, {24.0, 0.0, 0, 1}, {25.0, 0.0, 0, 1}, {26.0, 0.0, 0, 1}, {31.0, 0.0, 0, 1},
{32.0, 0.0, 0, 1}, {33.0, 0.0, 0, 1}, {34.0, 0.0, 0, 1}, {35.0, 0.0, 0, 1}, {36.0, 0.0, 0, 1}, {37.0, 0.0, 0, 1},
{38.0, 0.0, 0, 1}, {39.0, 0.0, 0, 1}, {40.0, 0.0, 0, 1}, {41.0, 0.0, 0, 1}, {45.0, 0.0, 0, 1}, {46.0, 0.0, 0, 1},
{47.0, 0.0, 0, 1}, {51.0, 0.0, 0, 1}, {52.0, 0.0, 0, 1}, {53.0, 0.0, 0, 1}, {54.0, 0.0, 0, 1}, {55.0, 0.0, 0, 1},
{56.0, 0.0, 0, 1}, {57.0, 0.0, 0, 1}, {58.0, 0.0, 0, 1}, {59.0, 0.0, 0, 1}, {60.0, 0.0, 0, 1}, {61.0, 0.0, 0, 1},
{-63.0, 1.0, 0, 1}, {-62.0, 1.0, 0, 1}, {-61.0, 1.0, 0, 1}, {-39.0, 1.0, 0, 1}, {-38.0, 1.0, 0, 1}, {-37.0, 1.0, 0, 1},
{-36.0, 1.0, 0, 1}, {-33.0, 1.0, 0, 1}, {-32.0, 1.0, 0, 1}, {-31.0, 1.0, 0, 1}, {-30.0, 1.0, 0, 1}, {-29.0, 1.0, 0, 1},
{-28.0, 1.0, 0, 1}, {-27.0, 1.0, 0, 1}, {-26.0, 1.0, 0, 1}, {-25.0, 1.0, 0, 1}, {-24.0, 1.0, 0, 1}, {-23.0, 1.0, 0, 1},
{-22.0, 1.0, 0, 1}, {-21.0, 1.0, 0, 1}, {-17.0, 1.0, 0, 1}, {-16.0, 1.0, 0, 1}, {-15.0, 1.0, 0, 1}, {-14.0, 1.0, 0, 1},
{-13.0, 1.0, 0, 1}, {-12.0, 1.0, 0, 1}, {-11.0, 1.0, 0, 1}, {-10.0, 1.0, 0, 1}, {-9.0, 1.0, 0, 1}, {-8.0, 1.0, 0, 1},
{-7.0, 1.0, 0, 1}, {-6.0, 1.0, 0, 1}, {-1.0, 1.0, 0, 1}, {0.0, 1.0, 0, 1}, {1.0, 1.0, 0, 1}, {23.0, 1.0, 0, 1},
{24.0, 1.0, 0, 1}, {25.0, 1.0, 0, 1}, {26.0, 1.0, 0, 1}, {38.0, 1.0, 0, 1}, {39.0, 1.0, 0, 1}, {40.0, 1.0, 0, 1},
{41.0, 1.0, 0, 1}, {45.0, 1.0, 0, 1}, {46.0, 1.0, 0, 1}, {47.0, 1.0, 0, 1}, {51.0, 1.0, 0, 1}, {52.0, 1.0, 0, 1},
{53.0, 1.0, 0, 1}, {-63.0, 2.0, 0, 1}, {-62.0, 2.0, 0, 1}, {-61.0, 2.0, 0, 1}, {-39.0, 2.0, 0, 1}, {-38.0, 2.0, 0, 1},
{-37.0, 2.0, 0, 1}, {-36.0, 2.0, 0, 1}, {-33.0, 2.0, 0, 1}, {-32.0, 2.0, 0, 1}, {-31.0, 2.0, 0, 1}, {-30.0, 2.0, 0, 1},
{-29.0, 2.0, 0, 1}, {-28.0, 2.0, 0, 1}, {-27.0, 2.0, 0, 1}, {-26.0, 2.0, 0, 1}, {-25.0, 2.0, 0, 1}, {-24.0, 2.0, 0, 1},
{-23.0, 2.0, 0, 1}, {-17.0, 2.0, 0, 1}, {-16.0, 2.0, 0, 1}, {-15.0, 2.0, 0, 1}, {-14.0, 2.0, 0, 1}, {-9.0, 2.0, 0, 1},
{-8.0, 2.0, 0, 1}, {-7.0, 2.0, 0, 1}, {-6.0, 2.0, 0, 1}, {-1.0, 2.0, 0, 1}, {0.0, 2.0, 0, 1}, {1.0, 2.0, 0, 1},
{24.0, 2.0, 0, 1}, {25.0, 2.0, 0, 1}, {26.0, 2.0, 0, 1}, {39.0, 2.0, 0, 1}, {40.0, 2.0, 0, 1}, {41.0, 2.0, 0, 1},
{45.0, 2.0, 0, 1}, {46.0, 2.0, 0, 1}, {47.0, 2.0, 0, 1}, {51.0, 2.0, 0, 1}, {52.0, 2.0, 0, 1}, {53.0, 2.0, 0, 1},
{-63.0, 3.0, 0, 1}, {-62.0, 3.0, 0, 1}, {-61.0, 3.0, 0, 1}, {-39.0, 3.0, 0, 1}, {-38.0, 3.0, 0, 1}, {-37.0, 3.0, 0, 1},
{-36.0, 3.0, 0, 1}, {-33.0, 3.0, 0, 1}, {-32.0, 3.0, 0, 1}, {-31.0, 3.0, 0, 1}, {-30.0, 3.0, 0, 1}, {-17.0, 3.0, 0, 1},
{-16.0, 3.0, 0, 1}, {-15.0, 3.0, 0, 1}, {-14.0, 3.0, 0, 1}, {-8.0, 3.0, 0, 1}, {-7.0, 3.0, 0, 1}, {-6.0, 3.0, 0, 1},
{-1.0, 3.0, 0, 1}, {0.0, 3.0, 0, 1}, {1.0, 3.0, 0, 1}, {24.0, 3.0, 0, 1}, {25.0, 3.0, 0, 1}, {26.0, 3.0, 0, 1},
{39.0, 3.0, 0, 1}, {40.0, 3.0, 0, 1}, {41.0, 3.0, 0, 1}, {45.0, 3.0, 0, 1}, {46.0, 3.0, 0, 1}, {47.0, 3.0, 0, 1},
{51.0, 3.0, 0, 1}, {52.0, 3.0, 0, 1}, {53.0, 3.0, 0, 1}, {-63.0, 4.0, 0, 1}, {-62.0, 4.0, 0, 1}, {-61.0, 4.0, 0, 1},
{-39.0, 4.0, 0, 1}, {-38.0, 4.0, 0, 1}, {-37.0, 4.0, 0, 1}, {-36.0, 4.0, 0, 1}, {-33.0, 4.0, 0, 1}, {-32.0, 4.0, 0, 1},
{-31.0, 4.0, 0, 1}, {-30.0, 4.0, 0, 1}, {-17.0, 4.0, 0, 1}, {-16.0, 4.0, 0, 1}, {-15.0, 4.0, 0, 1}, {-14.0, 4.0, 0, 1},
{-7.0, 4.0, 0, 1}, {-6.0, 4.0, 0, 1}, {-5.0, 4.0, 0, 1}, {-1.0, 4.0, 0, 1}, {0.0, 4.0, 0, 1}, {1.0, 4.0, 0, 1},
{24.0, 4.0, 0, 1}, {25.0, 4.0, 0, 1}, {26.0, 4.0, 0, 1}, {39.0, 4.0, 0, 1}, {40.0, 4.0, 0, 1}, {41.0, 4.0, 0, 1},
{45.0, 4.0, 0, 1}, {46.0, 4.0, 0, 1}, {47.0, 4.0, 0, 1}, {51.0, 4.0, 0, 1}, {52.0, 4.0, 0, 1}, {53.0, 4.0, 0, 1},
{-63.0, 5.0, 0, 1}, {-62.0, 5.0, 0, 1}, {-61.0, 5.0, 0, 1}, {-39.0, 5.0, 0, 1}, {-38.0, 5.0, 0, 1}, {-37.0, 5.0, 0, 1},
{-36.0, 5.0, 0, 1}, {-33.0, 5.0, 0, 1}, {-32.0, 5.0, 0, 1}, {-31.0, 5.0, 0, 1}, {-30.0, 5.0, 0, 1}, {-17.0, 5.0, 0, 1},
{-16.0, 5.0, 0, 1}, {-15.0, 5.0, 0, 1}, {-14.0, 5.0, 0, 1}, {-7.0, 5.0, 0, 1}, {-6.0, 5.0, 0, 1}, {-5.0, 5.0, 0, 1},
{-1.0, 5.0, 0, 1}, {0.0, 5.0, 0, 1}, {1.0, 5.0, 0, 1}, {24.0, 5.0, 0, 1}, {25.0, 5.0, 0, 1}, {26.0, 5.0, 0, 1},
{39.0, 5.0, 0, 1}, {40.0, 5.0, 0, 1}, {41.0, 5.0, 0, 1}, {45.0, 5.0, 0, 1}, {46.0, 5.0, 0, 1}, {47.0, 5.0, 0, 1},
{51.0, 5.0, 0, 1}, {52.0, 5.0, 0, 1}, {53.0, 5.0, 0, 1}, {-63.0, 6.0, 0, 1}, {-62.0, 6.0, 0, 1}, {-61.0, 6.0, 0, 1},
{-39.0, 6.0, 0, 1}, {-38.0, 6.0, 0, 1}, {-37.0, 6.0, 0, 1}, {-36.0, 6.0, 0, 1}, {-33.0, 6.0, 0, 1}, {-32.0, 6.0, 0, 1},
{-31.0, 6.0, 0, 1}, {-30.0, 6.0, 0, 1}, {-17.0, 6.0, 0, 1}, {-16.0, 6.0, 0, 1}, {-15.0, 6.0, 0, 1}, {-14.0, 6.0, 0, 1},
{-7.0, 6.0, 0, 1}, {-6.0, 6.0, 0, 1}, {-5.0, 6.0, 0, 1}, {-1.0, 6.0, 0, 1}, {0.0, 6.0, 0, 1}, {1.0, 6.0, 0, 1},
{24.0, 6.0, 0, 1}, {25.0, 6.0, 0, 1}, {26.0, 6.0, 0, 1}, {39.0, 6.0, 0, 1}, {40.0, 6.0, 0, 1}, {41.0, 6.0, 0, 1},
{45.0, 6.0, 0, 1}, {46.0, 6.0, 0, 1}, {47.0, 6.0, 0, 1}, {51.0, 6.0, 0, 1}, {52.0, 6.0, 0, 1}, {53.0, 6.0, 0, 1},
{-63.0, 7.0, 0, 1}, {-62.0, 7.0, 0, 1}, {-61.0, 7.0, 0, 1}, {-39.0, 7.0, 0, 1}, {-38.0, 7.0, 0, 1}, {-37.0, 7.0, 0, 1},
{-36.0, 7.0, 0, 1}, {-33.0, 7.0, 0, 1}, {-32.0, 7.0, 0, 1}, {-31.0, 7.0, 0, 1}, {-30.0, 7.0, 0, 1}, {-17.0, 7.0, 0, 1},
{-16.0, 7.0, 0, 1}, {-15.0, 7.0, 0, 1}, {-14.0, 7.0, 0, 1}, {-7.0, 7.0, 0, 1}, {-6.0, 7.0, 0, 1}, {-5.0, 7.0, 0, 1},
{-1.0, 7.0, 0, 1}, {0.0, 7.0, 0, 1}, {1.0, 7.0, 0, 1}, {24.0, 7.0, 0, 1}, {25.0, 7.0, 0, 1}, {26.0, 7.0, 0, 1},
{39.0, 7.0, 0, 1}, {40.0, 7.0, 0, 1}, {41.0, 7.0, 0, 1}, {45.0, 7.0, 0, 1}, {46.0, 7.0, 0, 1}, {47.0, 7.0, 0, 1},
{51.0, 7.0, 0, 1}, {52.0, 7.0, 0, 1}, {53.0, 7.0, 0, 1}, {-63.0, 8.0, 0, 1}, {-62.0, 8.0, 0, 1}, {-61.0, 8.0, 0, 1},
{-60.0, 8.0, 0, 1}, {-59.0, 8.0, 0, 1}, {-58.0, 8.0, 0, 1}, {-57.0, 8.0, 0, 1}, {-56.0, 8.0, 0, 1}, {-55.0, 8.0, 0, 1},
{-54.0, 8.0, 0, 1}, {-53.0, 8.0, 0, 1}, {-52.0, 8.0, 0, 1}, {-48.0, 8.0, 0, 1}, {-47.0, 8.0, 0, 1}, {-46.0, 8.0, 0, 1},
{-45.0, 8.0, 0, 1}, {-44.0, 8.0, 0, 1}, {-43.0, 8.0, 0, 1}, {-42.0, 8.0, 0, 1}, {-41.0, 8.0, 0, 1}, {-40.0, 8.0, 0, 1},
{-39.0, 8.0, 0, 1}, {-38.0, 8.0, 0, 1}, {-37.0, 8.0, 0, 1}, {-33.0, 8.0, 0, 1}, {-32.0, 8.0, 0, 1}, {-31.0, 8.0, 0, 1},
{-30.0, 8.0, 0, 1}, {-17.0, 8.0, 0, 1}, {-16.0, 8.0, 0, 1}, {-15.0, 8.0, 0, 1}, {-14.0, 8.0, 0, 1}, {-7.0, 8.0, 0, 1},
{-6.0, 8.0, 0, 1}, {-5.0, 8.0, 0, 1}, {-4.0, 8.0, 0, 1}, {-1.0, 8.0, 0, 1}, {0.0, 8.0, 0, 1}, {1.0, 8.0, 0, 1},
{2.0, 8.0, 0, 1}, {3.0, 8.0, 0, 1}, {4.0, 8.0, 0, 1}, {5.0, 8.0, 0, 1}, {6.0, 8.0, 0, 1}, {7.0, 8.0, 0, 1},
{8.0, 8.0, 0, 1}, {9.0, 8.0, 0, 1}, {10.0, 8.0, 0, 1}, {14.0, 8.0, 0, 1}, {15.0, 8.0, 0, 1}, {16.0, 8.0, 0, 1},
{17.0, 8.0, 0, 1}, {18.0, 8.0, 0, 1}, {19.0, 8.0, 0, 1}, {20.0, 8.0, 0, 1}, {21.0, 8.0, 0, 1}, {22.0, 8.0, 0, 1},
{23.0, 8.0, 0, 1}, {24.0, 8.0, 0, 1}, {25.0, 8.0, 0, 1}, {26.0, 8.0, 0, 1}, {29.0, 8.0, 0, 1}, {30.0, 8.0, 0, 1},
{31.0, 8.0, 0, 1}, {32.0, 8.0, 0, 1}, {33.0, 8.0, 0, 1}, {34.0, 8.0, 0, 1}, {35.0, 8.0, 0, 1}, {36.0, 8.0, 0, 1},
{37.0, 8.0, 0, 1}, {38.0, 8.0, 0, 1}, {39.0, 8.0, 0, 1}, {40.0, 8.0, 0, 1}, {41.0, 8.0, 0, 1}, {45.0, 8.0, 0, 1},
{46.0, 8.0, 0, 1}, {47.0, 8.0, 0, 1}, {51.0, 8.0, 0, 1}, {52.0, 8.0, 0, 1}, {53.0, 8.0, 0, 1}, {-63.0, 9.0, 0, 1},
{-62.0, 9.0, 0, 1}, {-61.0, 9.0, 0, 1}, {-60.0, 9.0, 0, 1}, {-59.0, 9.0, 0, 1}, {-58.0, 9.0, 0, 1}, {-57.0, 9.0, 0, 1},
{-56.0, 9.0, 0, 1}, {-55.0, 9.0, 0, 1}, {-54.0, 9.0, 0, 1}, {-53.0, 9.0, 0, 1}, {-52.0, 9.0, 0, 1}, {-48.0, 9.0, 0, 1},
{-47.0, 9.0, 0, 1}, {-46.0, 9.0, 0, 1}, {-45.0, 9.0, 0, 1}, {-44.0, 9.0, 0, 1}, {-43.0, 9.0, 0, 1}, {-42.0, 9.0, 0, 1},
{-41.0, 9.0, 0, 1}, {-40.0, 9.0, 0, 1}, {-39.0, 9.0, 0, 1}, {-38.0, 9.0, 0, 1}, {-37.0, 9.0, 0, 1}, {-33.0, 9.0, 0, 1},
{-32.0, 9.0, 0, 1}, {-31.0, 9.0, 0, 1}, {-30.0, 9.0, 0, 1}, {-17.0, 9.0, 0, 1}, {-16.0, 9.0, 0, 1}, {-15.0, 9.0, 0, 1},
{-14.0, 9.0, 0, 1}, {-6.0, 9.0, 0, 1}, {-5.0, 9.0, 0, 1}, {-4.0, 9.0, 0, 1}, {0.0, 9.0, 0, 1}, {1.0, 9.0, 0, 1},
{2.0, 9.0, 0, 1}, {3.0, 9.0, 0, 1}, {4.0, 9.0, 0, 1}, {5.0, 9.0, 0, 1}, {6.0, 9.0, 0, 1}, {7.0, 9.0, 0, 1},
{8.0, 9.0, 0, 1}, {9.0, 9.0, 0, 1}, {10.0, 9.0, 0, 1}, {14.0, 9.0, 0, 1}, {15.0, 9.0, 0, 1}, {16.0, 9.0, 0, 1},
{17.0, 9.0, 0, 1}, {18.0, 9.0, 0, 1}, {19.0, 9.0, 0, 1}, {20.0, 9.0, 0, 1}, {21.0, 9.0, 0, 1}, {22.0, 9.0, 0, 1},
{23.0, 9.0, 0, 1}, {24.0, 9.0, 0, 1}, {25.0, 9.0, 0, 1}, {29.0, 9.0, 0, 1}, {30.0, 9.0, 0, 1}, {31.0, 9.0, 0, 1},
{32.0, 9.0, 0, 1}, {33.0, 9.0, 0, 1}, {34.0, 9.0, 0, 1}, {35.0, 9.0, 0, 1}, {36.0, 9.0, 0, 1}, {37.0, 9.0, 0, 1},
{38.0, 9.0, 0, 1}, {39.0, 9.0, 0, 1}, {40.0, 9.0, 0, 1}, {41.0, 9.0, 0, 1}, {45.0, 9.0, 0, 1}, {46.0, 9.0, 0, 1},
{47.0, 9.0, 0, 1}, {51.0, 9.0, 0, 1}, {52.0, 9.0, 0, 1}, {53.0, 9.0, 0, 1}, {-62.0, 10.0, 0, 1}, {-61.0, 10.0, 0, 1},
{-60.0, 10.0, 0, 1}, {-59.0, 10.0, 0, 1}, {-58.0, 10.0, 0, 1}, {-57.0, 10.0, 0, 1}, {-56.0, 10.0, 0, 1}, {-55.0, 10.0, 0, 1},
{-54.0, 10.0, 0, 1}, {-53.0, 10.0, 0, 1}, {-52.0, 10.0, 0, 1}, {-48.0, 10.0, 0, 1}, {-47.0, 10.0, 0, 1}, {-46.0, 10.0, 0, 1},
{-45.0, 10.0, 0, 1}, {-44.0, 10.0, 0, 1}, {-43.0, 10.0, 0, 1}, {-42.0, 10.0, 0, 1}, {-41.0, 10.0, 0, 1}, {-40.0, 10.0, 0, 1},
{-39.0, 10.0, 0, 1}, {-38.0, 10.0, 0, 1}, {-33.0, 10.0, 0, 1}, {-32.0, 10.0, 0, 1}, {-31.0, 10.0, 0, 1}, {-30.0, 10.0, 0, 1},
{-17.0, 10.0, 0, 1}, {-16.0, 10.0, 0, 1}, {-15.0, 10.0, 0, 1}, {-14.0, 10.0, 0, 1}, {-6.0, 10.0, 0, 1}, {-5.0, 10.0, 0, 1},
{-4.0, 10.0, 0, 1}, {0.0, 10.0, 0, 1}, {1.0, 10.0, 0, 1}, {2.0, 10.0, 0, 1}, {3.0, 10.0, 0, 1}, {4.0, 10.0, 0, 1},
{5.0, 10.0, 0, 1}, {6.0, 10.0, 0, 1}, {7.0, 10.0, 0, 1}, {8.0, 10.0, 0, 1}, {9.0, 10.0, 0, 1}, {10.0, 10.0, 0, 1},
{14.0, 10.0, 0, 1}, {15.0, 10.0, 0, 1}, {16.0, 10.0, 0, 1}, {17.0, 10.0, 0, 1}, {18.0, 10.0, 0, 1}, {19.0, 10.0, 0, 1},
{20.0, 10.0, 0, 1}, {21.0, 10.0, 0, 1}, {22.0, 10.0, 0, 1}, {23.0, 10.0, 0, 1}, {24.0, 10.0, 0, 1}, {29.0, 10.0, 0, 1},
{30.0, 10.0, 0, 1}, {31.0, 10.0, 0, 1}, {32.0, 10.0, 0, 1}, {33.0, 10.0, 0, 1}, {34.0, 10.0, 0, 1}, {35.0, 10.0, 0, 1},
{36.0, 10.0, 0, 1}, {37.0, 10.0, 0, 1}, {38.0, 10.0, 0, 1}, {39.0, 10.0, 0, 1}, {40.0, 10.0, 0, 1}, {45.0, 10.0, 0, 1},
{46.0, 10.0, 0, 1}, {47.0, 10.0, 0, 1}, {51.0, 10.0, 0, 1}, {52.0, 10.0, 0, 1}, {53.0, 10.0, 0, 1}
};

View File

@@ -0,0 +1,16 @@
// File generated by image_to_3d_array.py
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern const uint8_t image_bmp_array_esp_text[384];
extern const float image_3d_array_esp_text[1271][4];
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,338 @@
// File generated by ImgTo3D.py
// Image file converted to 3D matrix cpu_logo.png
#include "image_to_3d_matrix.h"
#ifdef CONFIG_3D_OBJECT_CUSTOM
const uint8_t image_to_bmp_array_custom[512] = {
0x00, 0x00, 0x0e, 0x1c, 0x38, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00,
0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00,
0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00,
0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00,
0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe,
0xff, 0xfe, 0x0f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xf0, 0x7f, 0xff,
0xff, 0xfe, 0x0f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0x00, 0x1e, 0x0f, 0xff, 0xff, 0xf0, 0x78, 0x00,
0x00, 0x1e, 0x0f, 0x00, 0x00, 0xf0, 0x78, 0x00, 0x00, 0x1e, 0x0f, 0x00, 0x00, 0xf0, 0x78, 0x00,
0x7f, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xfe, 0xff, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xff,
0xff, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xff, 0xff, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xff,
0x7f, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xfc, 0x00, 0x1e, 0x0f, 0x00, 0x00, 0xf0, 0x78, 0x00,
0x00, 0x1e, 0x0f, 0x00, 0x00, 0xf0, 0x78, 0x00, 0x7f, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xfe,
0xff, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xff, 0xff, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xff,
0xff, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xff, 0x7f, 0xfe, 0x0f, 0x00, 0x00, 0xf0, 0x7f, 0xfe,
0x00, 0x1e, 0x0f, 0x00, 0x00, 0xf0, 0x78, 0x00, 0x00, 0x1e, 0x0f, 0x00, 0x00, 0xf0, 0x78, 0x00,
0x7f, 0xfe, 0x0f, 0xff, 0xff, 0xf0, 0x7f, 0xfc, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xf0, 0x7f, 0xff,
0xff, 0xfe, 0x0f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xf0, 0x7f, 0xff,
0x7f, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00,
0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00,
0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00,
0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00,
0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x3e, 0x7c, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x3c, 0x7c, 0x78, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1c, 0x38, 0x70, 0x00, 0x00
};
const float image_to_3d_matrix_custom[1732][4] = {
{-12.0, -32.0, 0, 1}, {-11.0, -32.0, 0, 1}, {-10.0, -32.0, 0, 1}, {-5.0, -32.0, 0, 1}, {-4.0, -32.0, 0, 1}, {-3.0, -32.0, 0, 1},
{2.0, -32.0, 0, 1}, {3.0, -32.0, 0, 1}, {4.0, -32.0, 0, 1}, {9.0, -32.0, 0, 1}, {10.0, -32.0, 0, 1}, {11.0, -32.0, 0, 1},
{-13.0, -31.0, 0, 1}, {-12.0, -31.0, 0, 1}, {-11.0, -31.0, 0, 1}, {-10.0, -31.0, 0, 1}, {-6.0, -31.0, 0, 1}, {-5.0, -31.0, 0, 1},
{-4.0, -31.0, 0, 1}, {-3.0, -31.0, 0, 1}, {-2.0, -31.0, 0, 1}, {1.0, -31.0, 0, 1}, {2.0, -31.0, 0, 1}, {3.0, -31.0, 0, 1},
{4.0, -31.0, 0, 1}, {5.0, -31.0, 0, 1}, {8.0, -31.0, 0, 1}, {9.0, -31.0, 0, 1}, {10.0, -31.0, 0, 1}, {11.0, -31.0, 0, 1},
{12.0, -31.0, 0, 1}, {-13.0, -30.0, 0, 1}, {-12.0, -30.0, 0, 1}, {-11.0, -30.0, 0, 1}, {-10.0, -30.0, 0, 1}, {-6.0, -30.0, 0, 1},
{-5.0, -30.0, 0, 1}, {-4.0, -30.0, 0, 1}, {-3.0, -30.0, 0, 1}, {-2.0, -30.0, 0, 1}, {1.0, -30.0, 0, 1}, {2.0, -30.0, 0, 1},
{3.0, -30.0, 0, 1}, {4.0, -30.0, 0, 1}, {5.0, -30.0, 0, 1}, {8.0, -30.0, 0, 1}, {9.0, -30.0, 0, 1}, {10.0, -30.0, 0, 1},
{11.0, -30.0, 0, 1}, {12.0, -30.0, 0, 1}, {-13.0, -29.0, 0, 1}, {-12.0, -29.0, 0, 1}, {-11.0, -29.0, 0, 1}, {-10.0, -29.0, 0, 1},
{-6.0, -29.0, 0, 1}, {-5.0, -29.0, 0, 1}, {-4.0, -29.0, 0, 1}, {-3.0, -29.0, 0, 1}, {-2.0, -29.0, 0, 1}, {1.0, -29.0, 0, 1},
{2.0, -29.0, 0, 1}, {3.0, -29.0, 0, 1}, {4.0, -29.0, 0, 1}, {5.0, -29.0, 0, 1}, {8.0, -29.0, 0, 1}, {9.0, -29.0, 0, 1},
{10.0, -29.0, 0, 1}, {11.0, -29.0, 0, 1}, {12.0, -29.0, 0, 1}, {-13.0, -28.0, 0, 1}, {-12.0, -28.0, 0, 1}, {-11.0, -28.0, 0, 1},
{-10.0, -28.0, 0, 1}, {-6.0, -28.0, 0, 1}, {-5.0, -28.0, 0, 1}, {-4.0, -28.0, 0, 1}, {-3.0, -28.0, 0, 1}, {-2.0, -28.0, 0, 1},
{1.0, -28.0, 0, 1}, {2.0, -28.0, 0, 1}, {3.0, -28.0, 0, 1}, {4.0, -28.0, 0, 1}, {5.0, -28.0, 0, 1}, {8.0, -28.0, 0, 1},
{9.0, -28.0, 0, 1}, {10.0, -28.0, 0, 1}, {11.0, -28.0, 0, 1}, {12.0, -28.0, 0, 1}, {-13.0, -27.0, 0, 1}, {-12.0, -27.0, 0, 1},
{-11.0, -27.0, 0, 1}, {-10.0, -27.0, 0, 1}, {-6.0, -27.0, 0, 1}, {-5.0, -27.0, 0, 1}, {-4.0, -27.0, 0, 1}, {-3.0, -27.0, 0, 1},
{-2.0, -27.0, 0, 1}, {1.0, -27.0, 0, 1}, {2.0, -27.0, 0, 1}, {3.0, -27.0, 0, 1}, {4.0, -27.0, 0, 1}, {5.0, -27.0, 0, 1},
{8.0, -27.0, 0, 1}, {9.0, -27.0, 0, 1}, {10.0, -27.0, 0, 1}, {11.0, -27.0, 0, 1}, {12.0, -27.0, 0, 1}, {-13.0, -26.0, 0, 1},
{-12.0, -26.0, 0, 1}, {-11.0, -26.0, 0, 1}, {-10.0, -26.0, 0, 1}, {-6.0, -26.0, 0, 1}, {-5.0, -26.0, 0, 1}, {-4.0, -26.0, 0, 1},
{-3.0, -26.0, 0, 1}, {-2.0, -26.0, 0, 1}, {1.0, -26.0, 0, 1}, {2.0, -26.0, 0, 1}, {3.0, -26.0, 0, 1}, {4.0, -26.0, 0, 1},
{5.0, -26.0, 0, 1}, {8.0, -26.0, 0, 1}, {9.0, -26.0, 0, 1}, {10.0, -26.0, 0, 1}, {11.0, -26.0, 0, 1}, {12.0, -26.0, 0, 1},
{-13.0, -25.0, 0, 1}, {-12.0, -25.0, 0, 1}, {-11.0, -25.0, 0, 1}, {-10.0, -25.0, 0, 1}, {-6.0, -25.0, 0, 1}, {-5.0, -25.0, 0, 1},
{-4.0, -25.0, 0, 1}, {-3.0, -25.0, 0, 1}, {-2.0, -25.0, 0, 1}, {1.0, -25.0, 0, 1}, {2.0, -25.0, 0, 1}, {3.0, -25.0, 0, 1},
{4.0, -25.0, 0, 1}, {5.0, -25.0, 0, 1}, {8.0, -25.0, 0, 1}, {9.0, -25.0, 0, 1}, {10.0, -25.0, 0, 1}, {11.0, -25.0, 0, 1},
{12.0, -25.0, 0, 1}, {-13.0, -24.0, 0, 1}, {-12.0, -24.0, 0, 1}, {-11.0, -24.0, 0, 1}, {-10.0, -24.0, 0, 1}, {-6.0, -24.0, 0, 1},
{-5.0, -24.0, 0, 1}, {-4.0, -24.0, 0, 1}, {-3.0, -24.0, 0, 1}, {-2.0, -24.0, 0, 1}, {1.0, -24.0, 0, 1}, {2.0, -24.0, 0, 1},
{3.0, -24.0, 0, 1}, {4.0, -24.0, 0, 1}, {5.0, -24.0, 0, 1}, {8.0, -24.0, 0, 1}, {9.0, -24.0, 0, 1}, {10.0, -24.0, 0, 1},
{11.0, -24.0, 0, 1}, {12.0, -24.0, 0, 1}, {-13.0, -23.0, 0, 1}, {-12.0, -23.0, 0, 1}, {-11.0, -23.0, 0, 1}, {-10.0, -23.0, 0, 1},
{-6.0, -23.0, 0, 1}, {-5.0, -23.0, 0, 1}, {-4.0, -23.0, 0, 1}, {-3.0, -23.0, 0, 1}, {-2.0, -23.0, 0, 1}, {1.0, -23.0, 0, 1},
{2.0, -23.0, 0, 1}, {3.0, -23.0, 0, 1}, {4.0, -23.0, 0, 1}, {5.0, -23.0, 0, 1}, {8.0, -23.0, 0, 1}, {9.0, -23.0, 0, 1},
{10.0, -23.0, 0, 1}, {11.0, -23.0, 0, 1}, {12.0, -23.0, 0, 1}, {-13.0, -22.0, 0, 1}, {-12.0, -22.0, 0, 1}, {-11.0, -22.0, 0, 1},
{-10.0, -22.0, 0, 1}, {-6.0, -22.0, 0, 1}, {-5.0, -22.0, 0, 1}, {-4.0, -22.0, 0, 1}, {-3.0, -22.0, 0, 1}, {-2.0, -22.0, 0, 1},
{1.0, -22.0, 0, 1}, {2.0, -22.0, 0, 1}, {3.0, -22.0, 0, 1}, {4.0, -22.0, 0, 1}, {5.0, -22.0, 0, 1}, {8.0, -22.0, 0, 1},
{9.0, -22.0, 0, 1}, {10.0, -22.0, 0, 1}, {11.0, -22.0, 0, 1}, {12.0, -22.0, 0, 1}, {-21.0, -21.0, 0, 1}, {-20.0, -21.0, 0, 1},
{-19.0, -21.0, 0, 1}, {-18.0, -21.0, 0, 1}, {-17.0, -21.0, 0, 1}, {-16.0, -21.0, 0, 1}, {-15.0, -21.0, 0, 1}, {-14.0, -21.0, 0, 1},
{-13.0, -21.0, 0, 1}, {-12.0, -21.0, 0, 1}, {-11.0, -21.0, 0, 1}, {-10.0, -21.0, 0, 1}, {-9.0, -21.0, 0, 1}, {-8.0, -21.0, 0, 1},
{-7.0, -21.0, 0, 1}, {-6.0, -21.0, 0, 1}, {-5.0, -21.0, 0, 1}, {-4.0, -21.0, 0, 1}, {-3.0, -21.0, 0, 1}, {-2.0, -21.0, 0, 1},
{-1.0, -21.0, 0, 1}, {0.0, -21.0, 0, 1}, {1.0, -21.0, 0, 1}, {2.0, -21.0, 0, 1}, {3.0, -21.0, 0, 1}, {4.0, -21.0, 0, 1},
{5.0, -21.0, 0, 1}, {6.0, -21.0, 0, 1}, {7.0, -21.0, 0, 1}, {8.0, -21.0, 0, 1}, {9.0, -21.0, 0, 1}, {10.0, -21.0, 0, 1},
{11.0, -21.0, 0, 1}, {12.0, -21.0, 0, 1}, {13.0, -21.0, 0, 1}, {14.0, -21.0, 0, 1}, {15.0, -21.0, 0, 1}, {16.0, -21.0, 0, 1},
{17.0, -21.0, 0, 1}, {18.0, -21.0, 0, 1}, {19.0, -21.0, 0, 1}, {20.0, -21.0, 0, 1}, {-21.0, -20.0, 0, 1}, {-20.0, -20.0, 0, 1},
{-19.0, -20.0, 0, 1}, {-18.0, -20.0, 0, 1}, {-17.0, -20.0, 0, 1}, {-16.0, -20.0, 0, 1}, {-15.0, -20.0, 0, 1}, {-14.0, -20.0, 0, 1},
{-13.0, -20.0, 0, 1}, {-12.0, -20.0, 0, 1}, {-11.0, -20.0, 0, 1}, {-10.0, -20.0, 0, 1}, {-9.0, -20.0, 0, 1}, {-8.0, -20.0, 0, 1},
{-7.0, -20.0, 0, 1}, {-6.0, -20.0, 0, 1}, {-5.0, -20.0, 0, 1}, {-4.0, -20.0, 0, 1}, {-3.0, -20.0, 0, 1}, {-2.0, -20.0, 0, 1},
{-1.0, -20.0, 0, 1}, {0.0, -20.0, 0, 1}, {1.0, -20.0, 0, 1}, {2.0, -20.0, 0, 1}, {3.0, -20.0, 0, 1}, {4.0, -20.0, 0, 1},
{5.0, -20.0, 0, 1}, {6.0, -20.0, 0, 1}, {7.0, -20.0, 0, 1}, {8.0, -20.0, 0, 1}, {9.0, -20.0, 0, 1}, {10.0, -20.0, 0, 1},
{11.0, -20.0, 0, 1}, {12.0, -20.0, 0, 1}, {13.0, -20.0, 0, 1}, {14.0, -20.0, 0, 1}, {15.0, -20.0, 0, 1}, {16.0, -20.0, 0, 1},
{17.0, -20.0, 0, 1}, {18.0, -20.0, 0, 1}, {19.0, -20.0, 0, 1}, {20.0, -20.0, 0, 1}, {-21.0, -19.0, 0, 1}, {-20.0, -19.0, 0, 1},
{-19.0, -19.0, 0, 1}, {-18.0, -19.0, 0, 1}, {-17.0, -19.0, 0, 1}, {-16.0, -19.0, 0, 1}, {-15.0, -19.0, 0, 1}, {-14.0, -19.0, 0, 1},
{-13.0, -19.0, 0, 1}, {-12.0, -19.0, 0, 1}, {-11.0, -19.0, 0, 1}, {-10.0, -19.0, 0, 1}, {-9.0, -19.0, 0, 1}, {-8.0, -19.0, 0, 1},
{-7.0, -19.0, 0, 1}, {-6.0, -19.0, 0, 1}, {-5.0, -19.0, 0, 1}, {-4.0, -19.0, 0, 1}, {-3.0, -19.0, 0, 1}, {-2.0, -19.0, 0, 1},
{-1.0, -19.0, 0, 1}, {0.0, -19.0, 0, 1}, {1.0, -19.0, 0, 1}, {2.0, -19.0, 0, 1}, {3.0, -19.0, 0, 1}, {4.0, -19.0, 0, 1},
{5.0, -19.0, 0, 1}, {6.0, -19.0, 0, 1}, {7.0, -19.0, 0, 1}, {8.0, -19.0, 0, 1}, {9.0, -19.0, 0, 1}, {10.0, -19.0, 0, 1},
{11.0, -19.0, 0, 1}, {12.0, -19.0, 0, 1}, {13.0, -19.0, 0, 1}, {14.0, -19.0, 0, 1}, {15.0, -19.0, 0, 1}, {16.0, -19.0, 0, 1},
{17.0, -19.0, 0, 1}, {18.0, -19.0, 0, 1}, {19.0, -19.0, 0, 1}, {20.0, -19.0, 0, 1}, {-21.0, -18.0, 0, 1}, {-20.0, -18.0, 0, 1},
{-19.0, -18.0, 0, 1}, {-18.0, -18.0, 0, 1}, {-17.0, -18.0, 0, 1}, {-16.0, -18.0, 0, 1}, {-15.0, -18.0, 0, 1}, {-14.0, -18.0, 0, 1},
{-13.0, -18.0, 0, 1}, {-12.0, -18.0, 0, 1}, {-11.0, -18.0, 0, 1}, {-10.0, -18.0, 0, 1}, {-9.0, -18.0, 0, 1}, {-8.0, -18.0, 0, 1},
{-7.0, -18.0, 0, 1}, {-6.0, -18.0, 0, 1}, {-5.0, -18.0, 0, 1}, {-4.0, -18.0, 0, 1}, {-3.0, -18.0, 0, 1}, {-2.0, -18.0, 0, 1},
{-1.0, -18.0, 0, 1}, {0.0, -18.0, 0, 1}, {1.0, -18.0, 0, 1}, {2.0, -18.0, 0, 1}, {3.0, -18.0, 0, 1}, {4.0, -18.0, 0, 1},
{5.0, -18.0, 0, 1}, {6.0, -18.0, 0, 1}, {7.0, -18.0, 0, 1}, {8.0, -18.0, 0, 1}, {9.0, -18.0, 0, 1}, {10.0, -18.0, 0, 1},
{11.0, -18.0, 0, 1}, {12.0, -18.0, 0, 1}, {13.0, -18.0, 0, 1}, {14.0, -18.0, 0, 1}, {15.0, -18.0, 0, 1}, {16.0, -18.0, 0, 1},
{17.0, -18.0, 0, 1}, {18.0, -18.0, 0, 1}, {19.0, -18.0, 0, 1}, {20.0, -18.0, 0, 1}, {-21.0, -17.0, 0, 1}, {-20.0, -17.0, 0, 1},
{-19.0, -17.0, 0, 1}, {-18.0, -17.0, 0, 1}, {17.0, -17.0, 0, 1}, {18.0, -17.0, 0, 1}, {19.0, -17.0, 0, 1}, {20.0, -17.0, 0, 1},
{-21.0, -16.0, 0, 1}, {-20.0, -16.0, 0, 1}, {-19.0, -16.0, 0, 1}, {-18.0, -16.0, 0, 1}, {17.0, -16.0, 0, 1}, {18.0, -16.0, 0, 1},
{19.0, -16.0, 0, 1}, {20.0, -16.0, 0, 1}, {-21.0, -15.0, 0, 1}, {-20.0, -15.0, 0, 1}, {-19.0, -15.0, 0, 1}, {-18.0, -15.0, 0, 1},
{17.0, -15.0, 0, 1}, {18.0, -15.0, 0, 1}, {19.0, -15.0, 0, 1}, {20.0, -15.0, 0, 1}, {-21.0, -14.0, 0, 1}, {-20.0, -14.0, 0, 1},
{-19.0, -14.0, 0, 1}, {-18.0, -14.0, 0, 1}, {17.0, -14.0, 0, 1}, {18.0, -14.0, 0, 1}, {19.0, -14.0, 0, 1}, {20.0, -14.0, 0, 1},
{-31.0, -13.0, 0, 1}, {-30.0, -13.0, 0, 1}, {-29.0, -13.0, 0, 1}, {-28.0, -13.0, 0, 1}, {-27.0, -13.0, 0, 1}, {-26.0, -13.0, 0, 1},
{-25.0, -13.0, 0, 1}, {-24.0, -13.0, 0, 1}, {-23.0, -13.0, 0, 1}, {-22.0, -13.0, 0, 1}, {-21.0, -13.0, 0, 1}, {-20.0, -13.0, 0, 1},
{-19.0, -13.0, 0, 1}, {-18.0, -13.0, 0, 1}, {17.0, -13.0, 0, 1}, {18.0, -13.0, 0, 1}, {19.0, -13.0, 0, 1}, {20.0, -13.0, 0, 1},
{21.0, -13.0, 0, 1}, {22.0, -13.0, 0, 1}, {23.0, -13.0, 0, 1}, {24.0, -13.0, 0, 1}, {25.0, -13.0, 0, 1}, {26.0, -13.0, 0, 1},
{27.0, -13.0, 0, 1}, {28.0, -13.0, 0, 1}, {29.0, -13.0, 0, 1}, {30.0, -13.0, 0, 1}, {-32.0, -12.0, 0, 1}, {-31.0, -12.0, 0, 1},
{-30.0, -12.0, 0, 1}, {-29.0, -12.0, 0, 1}, {-28.0, -12.0, 0, 1}, {-27.0, -12.0, 0, 1}, {-26.0, -12.0, 0, 1}, {-25.0, -12.0, 0, 1},
{-24.0, -12.0, 0, 1}, {-23.0, -12.0, 0, 1}, {-22.0, -12.0, 0, 1}, {-21.0, -12.0, 0, 1}, {-20.0, -12.0, 0, 1}, {-19.0, -12.0, 0, 1},
{-18.0, -12.0, 0, 1}, {-12.0, -12.0, 0, 1}, {-11.0, -12.0, 0, 1}, {-10.0, -12.0, 0, 1}, {-9.0, -12.0, 0, 1}, {-8.0, -12.0, 0, 1},
{-7.0, -12.0, 0, 1}, {-6.0, -12.0, 0, 1}, {-5.0, -12.0, 0, 1}, {-4.0, -12.0, 0, 1}, {-3.0, -12.0, 0, 1}, {-2.0, -12.0, 0, 1},
{-1.0, -12.0, 0, 1}, {0.0, -12.0, 0, 1}, {1.0, -12.0, 0, 1}, {2.0, -12.0, 0, 1}, {3.0, -12.0, 0, 1}, {4.0, -12.0, 0, 1},
{5.0, -12.0, 0, 1}, {6.0, -12.0, 0, 1}, {7.0, -12.0, 0, 1}, {8.0, -12.0, 0, 1}, {9.0, -12.0, 0, 1}, {10.0, -12.0, 0, 1},
{11.0, -12.0, 0, 1}, {17.0, -12.0, 0, 1}, {18.0, -12.0, 0, 1}, {19.0, -12.0, 0, 1}, {20.0, -12.0, 0, 1}, {21.0, -12.0, 0, 1},
{22.0, -12.0, 0, 1}, {23.0, -12.0, 0, 1}, {24.0, -12.0, 0, 1}, {25.0, -12.0, 0, 1}, {26.0, -12.0, 0, 1}, {27.0, -12.0, 0, 1},
{28.0, -12.0, 0, 1}, {29.0, -12.0, 0, 1}, {30.0, -12.0, 0, 1}, {31.0, -12.0, 0, 1}, {-32.0, -11.0, 0, 1}, {-31.0, -11.0, 0, 1},
{-30.0, -11.0, 0, 1}, {-29.0, -11.0, 0, 1}, {-28.0, -11.0, 0, 1}, {-27.0, -11.0, 0, 1}, {-26.0, -11.0, 0, 1}, {-25.0, -11.0, 0, 1},
{-24.0, -11.0, 0, 1}, {-23.0, -11.0, 0, 1}, {-22.0, -11.0, 0, 1}, {-21.0, -11.0, 0, 1}, {-20.0, -11.0, 0, 1}, {-19.0, -11.0, 0, 1},
{-18.0, -11.0, 0, 1}, {-12.0, -11.0, 0, 1}, {-11.0, -11.0, 0, 1}, {-10.0, -11.0, 0, 1}, {-9.0, -11.0, 0, 1}, {-8.0, -11.0, 0, 1},
{-7.0, -11.0, 0, 1}, {-6.0, -11.0, 0, 1}, {-5.0, -11.0, 0, 1}, {-4.0, -11.0, 0, 1}, {-3.0, -11.0, 0, 1}, {-2.0, -11.0, 0, 1},
{-1.0, -11.0, 0, 1}, {0.0, -11.0, 0, 1}, {1.0, -11.0, 0, 1}, {2.0, -11.0, 0, 1}, {3.0, -11.0, 0, 1}, {4.0, -11.0, 0, 1},
{5.0, -11.0, 0, 1}, {6.0, -11.0, 0, 1}, {7.0, -11.0, 0, 1}, {8.0, -11.0, 0, 1}, {9.0, -11.0, 0, 1}, {10.0, -11.0, 0, 1},
{11.0, -11.0, 0, 1}, {17.0, -11.0, 0, 1}, {18.0, -11.0, 0, 1}, {19.0, -11.0, 0, 1}, {20.0, -11.0, 0, 1}, {21.0, -11.0, 0, 1},
{22.0, -11.0, 0, 1}, {23.0, -11.0, 0, 1}, {24.0, -11.0, 0, 1}, {25.0, -11.0, 0, 1}, {26.0, -11.0, 0, 1}, {27.0, -11.0, 0, 1},
{28.0, -11.0, 0, 1}, {29.0, -11.0, 0, 1}, {30.0, -11.0, 0, 1}, {31.0, -11.0, 0, 1}, {-32.0, -10.0, 0, 1}, {-31.0, -10.0, 0, 1},
{-30.0, -10.0, 0, 1}, {-29.0, -10.0, 0, 1}, {-28.0, -10.0, 0, 1}, {-27.0, -10.0, 0, 1}, {-26.0, -10.0, 0, 1}, {-25.0, -10.0, 0, 1},
{-24.0, -10.0, 0, 1}, {-23.0, -10.0, 0, 1}, {-22.0, -10.0, 0, 1}, {-21.0, -10.0, 0, 1}, {-20.0, -10.0, 0, 1}, {-19.0, -10.0, 0, 1},
{-18.0, -10.0, 0, 1}, {-12.0, -10.0, 0, 1}, {-11.0, -10.0, 0, 1}, {-10.0, -10.0, 0, 1}, {-9.0, -10.0, 0, 1}, {-8.0, -10.0, 0, 1},
{-7.0, -10.0, 0, 1}, {-6.0, -10.0, 0, 1}, {-5.0, -10.0, 0, 1}, {-4.0, -10.0, 0, 1}, {-3.0, -10.0, 0, 1}, {-2.0, -10.0, 0, 1},
{-1.0, -10.0, 0, 1}, {0.0, -10.0, 0, 1}, {1.0, -10.0, 0, 1}, {2.0, -10.0, 0, 1}, {3.0, -10.0, 0, 1}, {4.0, -10.0, 0, 1},
{5.0, -10.0, 0, 1}, {6.0, -10.0, 0, 1}, {7.0, -10.0, 0, 1}, {8.0, -10.0, 0, 1}, {9.0, -10.0, 0, 1}, {10.0, -10.0, 0, 1},
{11.0, -10.0, 0, 1}, {17.0, -10.0, 0, 1}, {18.0, -10.0, 0, 1}, {19.0, -10.0, 0, 1}, {20.0, -10.0, 0, 1}, {21.0, -10.0, 0, 1},
{22.0, -10.0, 0, 1}, {23.0, -10.0, 0, 1}, {24.0, -10.0, 0, 1}, {25.0, -10.0, 0, 1}, {26.0, -10.0, 0, 1}, {27.0, -10.0, 0, 1},
{28.0, -10.0, 0, 1}, {29.0, -10.0, 0, 1}, {30.0, -10.0, 0, 1}, {31.0, -10.0, 0, 1}, {-21.0, -9.0, 0, 1}, {-20.0, -9.0, 0, 1},
{-19.0, -9.0, 0, 1}, {-18.0, -9.0, 0, 1}, {-12.0, -9.0, 0, 1}, {-11.0, -9.0, 0, 1}, {-10.0, -9.0, 0, 1}, {-9.0, -9.0, 0, 1},
{-8.0, -9.0, 0, 1}, {-7.0, -9.0, 0, 1}, {-6.0, -9.0, 0, 1}, {-5.0, -9.0, 0, 1}, {-4.0, -9.0, 0, 1}, {-3.0, -9.0, 0, 1},
{-2.0, -9.0, 0, 1}, {-1.0, -9.0, 0, 1}, {0.0, -9.0, 0, 1}, {1.0, -9.0, 0, 1}, {2.0, -9.0, 0, 1}, {3.0, -9.0, 0, 1},
{4.0, -9.0, 0, 1}, {5.0, -9.0, 0, 1}, {6.0, -9.0, 0, 1}, {7.0, -9.0, 0, 1}, {8.0, -9.0, 0, 1}, {9.0, -9.0, 0, 1},
{10.0, -9.0, 0, 1}, {11.0, -9.0, 0, 1}, {17.0, -9.0, 0, 1}, {18.0, -9.0, 0, 1}, {19.0, -9.0, 0, 1}, {20.0, -9.0, 0, 1},
{-21.0, -8.0, 0, 1}, {-20.0, -8.0, 0, 1}, {-19.0, -8.0, 0, 1}, {-18.0, -8.0, 0, 1}, {-12.0, -8.0, 0, 1}, {-11.0, -8.0, 0, 1},
{-10.0, -8.0, 0, 1}, {-9.0, -8.0, 0, 1}, {8.0, -8.0, 0, 1}, {9.0, -8.0, 0, 1}, {10.0, -8.0, 0, 1}, {11.0, -8.0, 0, 1},
{17.0, -8.0, 0, 1}, {18.0, -8.0, 0, 1}, {19.0, -8.0, 0, 1}, {20.0, -8.0, 0, 1}, {-21.0, -7.0, 0, 1}, {-20.0, -7.0, 0, 1},
{-19.0, -7.0, 0, 1}, {-18.0, -7.0, 0, 1}, {-12.0, -7.0, 0, 1}, {-11.0, -7.0, 0, 1}, {-10.0, -7.0, 0, 1}, {-9.0, -7.0, 0, 1},
{8.0, -7.0, 0, 1}, {9.0, -7.0, 0, 1}, {10.0, -7.0, 0, 1}, {11.0, -7.0, 0, 1}, {17.0, -7.0, 0, 1}, {18.0, -7.0, 0, 1},
{19.0, -7.0, 0, 1}, {20.0, -7.0, 0, 1}, {-31.0, -6.0, 0, 1}, {-30.0, -6.0, 0, 1}, {-29.0, -6.0, 0, 1}, {-28.0, -6.0, 0, 1},
{-27.0, -6.0, 0, 1}, {-26.0, -6.0, 0, 1}, {-25.0, -6.0, 0, 1}, {-24.0, -6.0, 0, 1}, {-23.0, -6.0, 0, 1}, {-22.0, -6.0, 0, 1},
{-21.0, -6.0, 0, 1}, {-20.0, -6.0, 0, 1}, {-19.0, -6.0, 0, 1}, {-18.0, -6.0, 0, 1}, {-12.0, -6.0, 0, 1}, {-11.0, -6.0, 0, 1},
{-10.0, -6.0, 0, 1}, {-9.0, -6.0, 0, 1}, {8.0, -6.0, 0, 1}, {9.0, -6.0, 0, 1}, {10.0, -6.0, 0, 1}, {11.0, -6.0, 0, 1},
{17.0, -6.0, 0, 1}, {18.0, -6.0, 0, 1}, {19.0, -6.0, 0, 1}, {20.0, -6.0, 0, 1}, {21.0, -6.0, 0, 1}, {22.0, -6.0, 0, 1},
{23.0, -6.0, 0, 1}, {24.0, -6.0, 0, 1}, {25.0, -6.0, 0, 1}, {26.0, -6.0, 0, 1}, {27.0, -6.0, 0, 1}, {28.0, -6.0, 0, 1},
{29.0, -6.0, 0, 1}, {30.0, -6.0, 0, 1}, {-32.0, -5.0, 0, 1}, {-31.0, -5.0, 0, 1}, {-30.0, -5.0, 0, 1}, {-29.0, -5.0, 0, 1},
{-28.0, -5.0, 0, 1}, {-27.0, -5.0, 0, 1}, {-26.0, -5.0, 0, 1}, {-25.0, -5.0, 0, 1}, {-24.0, -5.0, 0, 1}, {-23.0, -5.0, 0, 1},
{-22.0, -5.0, 0, 1}, {-21.0, -5.0, 0, 1}, {-20.0, -5.0, 0, 1}, {-19.0, -5.0, 0, 1}, {-18.0, -5.0, 0, 1}, {-12.0, -5.0, 0, 1},
{-11.0, -5.0, 0, 1}, {-10.0, -5.0, 0, 1}, {-9.0, -5.0, 0, 1}, {8.0, -5.0, 0, 1}, {9.0, -5.0, 0, 1}, {10.0, -5.0, 0, 1},
{11.0, -5.0, 0, 1}, {17.0, -5.0, 0, 1}, {18.0, -5.0, 0, 1}, {19.0, -5.0, 0, 1}, {20.0, -5.0, 0, 1}, {21.0, -5.0, 0, 1},
{22.0, -5.0, 0, 1}, {23.0, -5.0, 0, 1}, {24.0, -5.0, 0, 1}, {25.0, -5.0, 0, 1}, {26.0, -5.0, 0, 1}, {27.0, -5.0, 0, 1},
{28.0, -5.0, 0, 1}, {29.0, -5.0, 0, 1}, {30.0, -5.0, 0, 1}, {31.0, -5.0, 0, 1}, {-32.0, -4.0, 0, 1}, {-31.0, -4.0, 0, 1},
{-30.0, -4.0, 0, 1}, {-29.0, -4.0, 0, 1}, {-28.0, -4.0, 0, 1}, {-27.0, -4.0, 0, 1}, {-26.0, -4.0, 0, 1}, {-25.0, -4.0, 0, 1},
{-24.0, -4.0, 0, 1}, {-23.0, -4.0, 0, 1}, {-22.0, -4.0, 0, 1}, {-21.0, -4.0, 0, 1}, {-20.0, -4.0, 0, 1}, {-19.0, -4.0, 0, 1},
{-18.0, -4.0, 0, 1}, {-12.0, -4.0, 0, 1}, {-11.0, -4.0, 0, 1}, {-10.0, -4.0, 0, 1}, {-9.0, -4.0, 0, 1}, {8.0, -4.0, 0, 1},
{9.0, -4.0, 0, 1}, {10.0, -4.0, 0, 1}, {11.0, -4.0, 0, 1}, {17.0, -4.0, 0, 1}, {18.0, -4.0, 0, 1}, {19.0, -4.0, 0, 1},
{20.0, -4.0, 0, 1}, {21.0, -4.0, 0, 1}, {22.0, -4.0, 0, 1}, {23.0, -4.0, 0, 1}, {24.0, -4.0, 0, 1}, {25.0, -4.0, 0, 1},
{26.0, -4.0, 0, 1}, {27.0, -4.0, 0, 1}, {28.0, -4.0, 0, 1}, {29.0, -4.0, 0, 1}, {30.0, -4.0, 0, 1}, {31.0, -4.0, 0, 1},
{-32.0, -3.0, 0, 1}, {-31.0, -3.0, 0, 1}, {-30.0, -3.0, 0, 1}, {-29.0, -3.0, 0, 1}, {-28.0, -3.0, 0, 1}, {-27.0, -3.0, 0, 1},
{-26.0, -3.0, 0, 1}, {-25.0, -3.0, 0, 1}, {-24.0, -3.0, 0, 1}, {-23.0, -3.0, 0, 1}, {-22.0, -3.0, 0, 1}, {-21.0, -3.0, 0, 1},
{-20.0, -3.0, 0, 1}, {-19.0, -3.0, 0, 1}, {-18.0, -3.0, 0, 1}, {-12.0, -3.0, 0, 1}, {-11.0, -3.0, 0, 1}, {-10.0, -3.0, 0, 1},
{-9.0, -3.0, 0, 1}, {8.0, -3.0, 0, 1}, {9.0, -3.0, 0, 1}, {10.0, -3.0, 0, 1}, {11.0, -3.0, 0, 1}, {17.0, -3.0, 0, 1},
{18.0, -3.0, 0, 1}, {19.0, -3.0, 0, 1}, {20.0, -3.0, 0, 1}, {21.0, -3.0, 0, 1}, {22.0, -3.0, 0, 1}, {23.0, -3.0, 0, 1},
{24.0, -3.0, 0, 1}, {25.0, -3.0, 0, 1}, {26.0, -3.0, 0, 1}, {27.0, -3.0, 0, 1}, {28.0, -3.0, 0, 1}, {29.0, -3.0, 0, 1},
{30.0, -3.0, 0, 1}, {31.0, -3.0, 0, 1}, {-31.0, -2.0, 0, 1}, {-30.0, -2.0, 0, 1}, {-29.0, -2.0, 0, 1}, {-28.0, -2.0, 0, 1},
{-27.0, -2.0, 0, 1}, {-26.0, -2.0, 0, 1}, {-25.0, -2.0, 0, 1}, {-24.0, -2.0, 0, 1}, {-23.0, -2.0, 0, 1}, {-22.0, -2.0, 0, 1},
{-21.0, -2.0, 0, 1}, {-20.0, -2.0, 0, 1}, {-19.0, -2.0, 0, 1}, {-18.0, -2.0, 0, 1}, {-12.0, -2.0, 0, 1}, {-11.0, -2.0, 0, 1},
{-10.0, -2.0, 0, 1}, {-9.0, -2.0, 0, 1}, {8.0, -2.0, 0, 1}, {9.0, -2.0, 0, 1}, {10.0, -2.0, 0, 1}, {11.0, -2.0, 0, 1},
{17.0, -2.0, 0, 1}, {18.0, -2.0, 0, 1}, {19.0, -2.0, 0, 1}, {20.0, -2.0, 0, 1}, {21.0, -2.0, 0, 1}, {22.0, -2.0, 0, 1},
{23.0, -2.0, 0, 1}, {24.0, -2.0, 0, 1}, {25.0, -2.0, 0, 1}, {26.0, -2.0, 0, 1}, {27.0, -2.0, 0, 1}, {28.0, -2.0, 0, 1},
{29.0, -2.0, 0, 1}, {-21.0, -1.0, 0, 1}, {-20.0, -1.0, 0, 1}, {-19.0, -1.0, 0, 1}, {-18.0, -1.0, 0, 1}, {-12.0, -1.0, 0, 1},
{-11.0, -1.0, 0, 1}, {-10.0, -1.0, 0, 1}, {-9.0, -1.0, 0, 1}, {8.0, -1.0, 0, 1}, {9.0, -1.0, 0, 1}, {10.0, -1.0, 0, 1},
{11.0, -1.0, 0, 1}, {17.0, -1.0, 0, 1}, {18.0, -1.0, 0, 1}, {19.0, -1.0, 0, 1}, {20.0, -1.0, 0, 1}, {-21.0, 0.0, 0, 1},
{-20.0, 0.0, 0, 1}, {-19.0, 0.0, 0, 1}, {-18.0, 0.0, 0, 1}, {-12.0, 0.0, 0, 1}, {-11.0, 0.0, 0, 1}, {-10.0, 0.0, 0, 1},
{-9.0, 0.0, 0, 1}, {8.0, 0.0, 0, 1}, {9.0, 0.0, 0, 1}, {10.0, 0.0, 0, 1}, {11.0, 0.0, 0, 1}, {17.0, 0.0, 0, 1},
{18.0, 0.0, 0, 1}, {19.0, 0.0, 0, 1}, {20.0, 0.0, 0, 1}, {-31.0, 1.0, 0, 1}, {-30.0, 1.0, 0, 1}, {-29.0, 1.0, 0, 1},
{-28.0, 1.0, 0, 1}, {-27.0, 1.0, 0, 1}, {-26.0, 1.0, 0, 1}, {-25.0, 1.0, 0, 1}, {-24.0, 1.0, 0, 1}, {-23.0, 1.0, 0, 1},
{-22.0, 1.0, 0, 1}, {-21.0, 1.0, 0, 1}, {-20.0, 1.0, 0, 1}, {-19.0, 1.0, 0, 1}, {-18.0, 1.0, 0, 1}, {-12.0, 1.0, 0, 1},
{-11.0, 1.0, 0, 1}, {-10.0, 1.0, 0, 1}, {-9.0, 1.0, 0, 1}, {8.0, 1.0, 0, 1}, {9.0, 1.0, 0, 1}, {10.0, 1.0, 0, 1},
{11.0, 1.0, 0, 1}, {17.0, 1.0, 0, 1}, {18.0, 1.0, 0, 1}, {19.0, 1.0, 0, 1}, {20.0, 1.0, 0, 1}, {21.0, 1.0, 0, 1},
{22.0, 1.0, 0, 1}, {23.0, 1.0, 0, 1}, {24.0, 1.0, 0, 1}, {25.0, 1.0, 0, 1}, {26.0, 1.0, 0, 1}, {27.0, 1.0, 0, 1},
{28.0, 1.0, 0, 1}, {29.0, 1.0, 0, 1}, {30.0, 1.0, 0, 1}, {-32.0, 2.0, 0, 1}, {-31.0, 2.0, 0, 1}, {-30.0, 2.0, 0, 1},
{-29.0, 2.0, 0, 1}, {-28.0, 2.0, 0, 1}, {-27.0, 2.0, 0, 1}, {-26.0, 2.0, 0, 1}, {-25.0, 2.0, 0, 1}, {-24.0, 2.0, 0, 1},
{-23.0, 2.0, 0, 1}, {-22.0, 2.0, 0, 1}, {-21.0, 2.0, 0, 1}, {-20.0, 2.0, 0, 1}, {-19.0, 2.0, 0, 1}, {-18.0, 2.0, 0, 1},
{-12.0, 2.0, 0, 1}, {-11.0, 2.0, 0, 1}, {-10.0, 2.0, 0, 1}, {-9.0, 2.0, 0, 1}, {8.0, 2.0, 0, 1}, {9.0, 2.0, 0, 1},
{10.0, 2.0, 0, 1}, {11.0, 2.0, 0, 1}, {17.0, 2.0, 0, 1}, {18.0, 2.0, 0, 1}, {19.0, 2.0, 0, 1}, {20.0, 2.0, 0, 1},
{21.0, 2.0, 0, 1}, {22.0, 2.0, 0, 1}, {23.0, 2.0, 0, 1}, {24.0, 2.0, 0, 1}, {25.0, 2.0, 0, 1}, {26.0, 2.0, 0, 1},
{27.0, 2.0, 0, 1}, {28.0, 2.0, 0, 1}, {29.0, 2.0, 0, 1}, {30.0, 2.0, 0, 1}, {31.0, 2.0, 0, 1}, {-32.0, 3.0, 0, 1},
{-31.0, 3.0, 0, 1}, {-30.0, 3.0, 0, 1}, {-29.0, 3.0, 0, 1}, {-28.0, 3.0, 0, 1}, {-27.0, 3.0, 0, 1}, {-26.0, 3.0, 0, 1},
{-25.0, 3.0, 0, 1}, {-24.0, 3.0, 0, 1}, {-23.0, 3.0, 0, 1}, {-22.0, 3.0, 0, 1}, {-21.0, 3.0, 0, 1}, {-20.0, 3.0, 0, 1},
{-19.0, 3.0, 0, 1}, {-18.0, 3.0, 0, 1}, {-12.0, 3.0, 0, 1}, {-11.0, 3.0, 0, 1}, {-10.0, 3.0, 0, 1}, {-9.0, 3.0, 0, 1},
{8.0, 3.0, 0, 1}, {9.0, 3.0, 0, 1}, {10.0, 3.0, 0, 1}, {11.0, 3.0, 0, 1}, {17.0, 3.0, 0, 1}, {18.0, 3.0, 0, 1},
{19.0, 3.0, 0, 1}, {20.0, 3.0, 0, 1}, {21.0, 3.0, 0, 1}, {22.0, 3.0, 0, 1}, {23.0, 3.0, 0, 1}, {24.0, 3.0, 0, 1},
{25.0, 3.0, 0, 1}, {26.0, 3.0, 0, 1}, {27.0, 3.0, 0, 1}, {28.0, 3.0, 0, 1}, {29.0, 3.0, 0, 1}, {30.0, 3.0, 0, 1},
{31.0, 3.0, 0, 1}, {-32.0, 4.0, 0, 1}, {-31.0, 4.0, 0, 1}, {-30.0, 4.0, 0, 1}, {-29.0, 4.0, 0, 1}, {-28.0, 4.0, 0, 1},
{-27.0, 4.0, 0, 1}, {-26.0, 4.0, 0, 1}, {-25.0, 4.0, 0, 1}, {-24.0, 4.0, 0, 1}, {-23.0, 4.0, 0, 1}, {-22.0, 4.0, 0, 1},
{-21.0, 4.0, 0, 1}, {-20.0, 4.0, 0, 1}, {-19.0, 4.0, 0, 1}, {-18.0, 4.0, 0, 1}, {-12.0, 4.0, 0, 1}, {-11.0, 4.0, 0, 1},
{-10.0, 4.0, 0, 1}, {-9.0, 4.0, 0, 1}, {8.0, 4.0, 0, 1}, {9.0, 4.0, 0, 1}, {10.0, 4.0, 0, 1}, {11.0, 4.0, 0, 1},
{17.0, 4.0, 0, 1}, {18.0, 4.0, 0, 1}, {19.0, 4.0, 0, 1}, {20.0, 4.0, 0, 1}, {21.0, 4.0, 0, 1}, {22.0, 4.0, 0, 1},
{23.0, 4.0, 0, 1}, {24.0, 4.0, 0, 1}, {25.0, 4.0, 0, 1}, {26.0, 4.0, 0, 1}, {27.0, 4.0, 0, 1}, {28.0, 4.0, 0, 1},
{29.0, 4.0, 0, 1}, {30.0, 4.0, 0, 1}, {31.0, 4.0, 0, 1}, {-31.0, 5.0, 0, 1}, {-30.0, 5.0, 0, 1}, {-29.0, 5.0, 0, 1},
{-28.0, 5.0, 0, 1}, {-27.0, 5.0, 0, 1}, {-26.0, 5.0, 0, 1}, {-25.0, 5.0, 0, 1}, {-24.0, 5.0, 0, 1}, {-23.0, 5.0, 0, 1},
{-22.0, 5.0, 0, 1}, {-21.0, 5.0, 0, 1}, {-20.0, 5.0, 0, 1}, {-19.0, 5.0, 0, 1}, {-18.0, 5.0, 0, 1}, {-12.0, 5.0, 0, 1},
{-11.0, 5.0, 0, 1}, {-10.0, 5.0, 0, 1}, {-9.0, 5.0, 0, 1}, {8.0, 5.0, 0, 1}, {9.0, 5.0, 0, 1}, {10.0, 5.0, 0, 1},
{11.0, 5.0, 0, 1}, {17.0, 5.0, 0, 1}, {18.0, 5.0, 0, 1}, {19.0, 5.0, 0, 1}, {20.0, 5.0, 0, 1}, {21.0, 5.0, 0, 1},
{22.0, 5.0, 0, 1}, {23.0, 5.0, 0, 1}, {24.0, 5.0, 0, 1}, {25.0, 5.0, 0, 1}, {26.0, 5.0, 0, 1}, {27.0, 5.0, 0, 1},
{28.0, 5.0, 0, 1}, {29.0, 5.0, 0, 1}, {30.0, 5.0, 0, 1}, {-21.0, 6.0, 0, 1}, {-20.0, 6.0, 0, 1}, {-19.0, 6.0, 0, 1},
{-18.0, 6.0, 0, 1}, {-12.0, 6.0, 0, 1}, {-11.0, 6.0, 0, 1}, {-10.0, 6.0, 0, 1}, {-9.0, 6.0, 0, 1}, {8.0, 6.0, 0, 1},
{9.0, 6.0, 0, 1}, {10.0, 6.0, 0, 1}, {11.0, 6.0, 0, 1}, {17.0, 6.0, 0, 1}, {18.0, 6.0, 0, 1}, {19.0, 6.0, 0, 1},
{20.0, 6.0, 0, 1}, {-21.0, 7.0, 0, 1}, {-20.0, 7.0, 0, 1}, {-19.0, 7.0, 0, 1}, {-18.0, 7.0, 0, 1}, {-12.0, 7.0, 0, 1},
{-11.0, 7.0, 0, 1}, {-10.0, 7.0, 0, 1}, {-9.0, 7.0, 0, 1}, {8.0, 7.0, 0, 1}, {9.0, 7.0, 0, 1}, {10.0, 7.0, 0, 1},
{11.0, 7.0, 0, 1}, {17.0, 7.0, 0, 1}, {18.0, 7.0, 0, 1}, {19.0, 7.0, 0, 1}, {20.0, 7.0, 0, 1}, {-31.0, 8.0, 0, 1},
{-30.0, 8.0, 0, 1}, {-29.0, 8.0, 0, 1}, {-28.0, 8.0, 0, 1}, {-27.0, 8.0, 0, 1}, {-26.0, 8.0, 0, 1}, {-25.0, 8.0, 0, 1},
{-24.0, 8.0, 0, 1}, {-23.0, 8.0, 0, 1}, {-22.0, 8.0, 0, 1}, {-21.0, 8.0, 0, 1}, {-20.0, 8.0, 0, 1}, {-19.0, 8.0, 0, 1},
{-18.0, 8.0, 0, 1}, {-12.0, 8.0, 0, 1}, {-11.0, 8.0, 0, 1}, {-10.0, 8.0, 0, 1}, {-9.0, 8.0, 0, 1}, {-8.0, 8.0, 0, 1},
{-7.0, 8.0, 0, 1}, {-6.0, 8.0, 0, 1}, {-5.0, 8.0, 0, 1}, {-4.0, 8.0, 0, 1}, {-3.0, 8.0, 0, 1}, {-2.0, 8.0, 0, 1},
{-1.0, 8.0, 0, 1}, {0.0, 8.0, 0, 1}, {1.0, 8.0, 0, 1}, {2.0, 8.0, 0, 1}, {3.0, 8.0, 0, 1}, {4.0, 8.0, 0, 1},
{5.0, 8.0, 0, 1}, {6.0, 8.0, 0, 1}, {7.0, 8.0, 0, 1}, {8.0, 8.0, 0, 1}, {9.0, 8.0, 0, 1}, {10.0, 8.0, 0, 1},
{11.0, 8.0, 0, 1}, {17.0, 8.0, 0, 1}, {18.0, 8.0, 0, 1}, {19.0, 8.0, 0, 1}, {20.0, 8.0, 0, 1}, {21.0, 8.0, 0, 1},
{22.0, 8.0, 0, 1}, {23.0, 8.0, 0, 1}, {24.0, 8.0, 0, 1}, {25.0, 8.0, 0, 1}, {26.0, 8.0, 0, 1}, {27.0, 8.0, 0, 1},
{28.0, 8.0, 0, 1}, {29.0, 8.0, 0, 1}, {-32.0, 9.0, 0, 1}, {-31.0, 9.0, 0, 1}, {-30.0, 9.0, 0, 1}, {-29.0, 9.0, 0, 1},
{-28.0, 9.0, 0, 1}, {-27.0, 9.0, 0, 1}, {-26.0, 9.0, 0, 1}, {-25.0, 9.0, 0, 1}, {-24.0, 9.0, 0, 1}, {-23.0, 9.0, 0, 1},
{-22.0, 9.0, 0, 1}, {-21.0, 9.0, 0, 1}, {-20.0, 9.0, 0, 1}, {-19.0, 9.0, 0, 1}, {-18.0, 9.0, 0, 1}, {-12.0, 9.0, 0, 1},
{-11.0, 9.0, 0, 1}, {-10.0, 9.0, 0, 1}, {-9.0, 9.0, 0, 1}, {-8.0, 9.0, 0, 1}, {-7.0, 9.0, 0, 1}, {-6.0, 9.0, 0, 1},
{-5.0, 9.0, 0, 1}, {-4.0, 9.0, 0, 1}, {-3.0, 9.0, 0, 1}, {-2.0, 9.0, 0, 1}, {-1.0, 9.0, 0, 1}, {0.0, 9.0, 0, 1},
{1.0, 9.0, 0, 1}, {2.0, 9.0, 0, 1}, {3.0, 9.0, 0, 1}, {4.0, 9.0, 0, 1}, {5.0, 9.0, 0, 1}, {6.0, 9.0, 0, 1},
{7.0, 9.0, 0, 1}, {8.0, 9.0, 0, 1}, {9.0, 9.0, 0, 1}, {10.0, 9.0, 0, 1}, {11.0, 9.0, 0, 1}, {17.0, 9.0, 0, 1},
{18.0, 9.0, 0, 1}, {19.0, 9.0, 0, 1}, {20.0, 9.0, 0, 1}, {21.0, 9.0, 0, 1}, {22.0, 9.0, 0, 1}, {23.0, 9.0, 0, 1},
{24.0, 9.0, 0, 1}, {25.0, 9.0, 0, 1}, {26.0, 9.0, 0, 1}, {27.0, 9.0, 0, 1}, {28.0, 9.0, 0, 1}, {29.0, 9.0, 0, 1},
{30.0, 9.0, 0, 1}, {31.0, 9.0, 0, 1}, {-32.0, 10.0, 0, 1}, {-31.0, 10.0, 0, 1}, {-30.0, 10.0, 0, 1}, {-29.0, 10.0, 0, 1},
{-28.0, 10.0, 0, 1}, {-27.0, 10.0, 0, 1}, {-26.0, 10.0, 0, 1}, {-25.0, 10.0, 0, 1}, {-24.0, 10.0, 0, 1}, {-23.0, 10.0, 0, 1},
{-22.0, 10.0, 0, 1}, {-21.0, 10.0, 0, 1}, {-20.0, 10.0, 0, 1}, {-19.0, 10.0, 0, 1}, {-18.0, 10.0, 0, 1}, {-12.0, 10.0, 0, 1},
{-11.0, 10.0, 0, 1}, {-10.0, 10.0, 0, 1}, {-9.0, 10.0, 0, 1}, {-8.0, 10.0, 0, 1}, {-7.0, 10.0, 0, 1}, {-6.0, 10.0, 0, 1},
{-5.0, 10.0, 0, 1}, {-4.0, 10.0, 0, 1}, {-3.0, 10.0, 0, 1}, {-2.0, 10.0, 0, 1}, {-1.0, 10.0, 0, 1}, {0.0, 10.0, 0, 1},
{1.0, 10.0, 0, 1}, {2.0, 10.0, 0, 1}, {3.0, 10.0, 0, 1}, {4.0, 10.0, 0, 1}, {5.0, 10.0, 0, 1}, {6.0, 10.0, 0, 1},
{7.0, 10.0, 0, 1}, {8.0, 10.0, 0, 1}, {9.0, 10.0, 0, 1}, {10.0, 10.0, 0, 1}, {11.0, 10.0, 0, 1}, {17.0, 10.0, 0, 1},
{18.0, 10.0, 0, 1}, {19.0, 10.0, 0, 1}, {20.0, 10.0, 0, 1}, {21.0, 10.0, 0, 1}, {22.0, 10.0, 0, 1}, {23.0, 10.0, 0, 1},
{24.0, 10.0, 0, 1}, {25.0, 10.0, 0, 1}, {26.0, 10.0, 0, 1}, {27.0, 10.0, 0, 1}, {28.0, 10.0, 0, 1}, {29.0, 10.0, 0, 1},
{30.0, 10.0, 0, 1}, {31.0, 10.0, 0, 1}, {-32.0, 11.0, 0, 1}, {-31.0, 11.0, 0, 1}, {-30.0, 11.0, 0, 1}, {-29.0, 11.0, 0, 1},
{-28.0, 11.0, 0, 1}, {-27.0, 11.0, 0, 1}, {-26.0, 11.0, 0, 1}, {-25.0, 11.0, 0, 1}, {-24.0, 11.0, 0, 1}, {-23.0, 11.0, 0, 1},
{-22.0, 11.0, 0, 1}, {-21.0, 11.0, 0, 1}, {-20.0, 11.0, 0, 1}, {-19.0, 11.0, 0, 1}, {-18.0, 11.0, 0, 1}, {-12.0, 11.0, 0, 1},
{-11.0, 11.0, 0, 1}, {-10.0, 11.0, 0, 1}, {-9.0, 11.0, 0, 1}, {-8.0, 11.0, 0, 1}, {-7.0, 11.0, 0, 1}, {-6.0, 11.0, 0, 1},
{-5.0, 11.0, 0, 1}, {-4.0, 11.0, 0, 1}, {-3.0, 11.0, 0, 1}, {-2.0, 11.0, 0, 1}, {-1.0, 11.0, 0, 1}, {0.0, 11.0, 0, 1},
{1.0, 11.0, 0, 1}, {2.0, 11.0, 0, 1}, {3.0, 11.0, 0, 1}, {4.0, 11.0, 0, 1}, {5.0, 11.0, 0, 1}, {6.0, 11.0, 0, 1},
{7.0, 11.0, 0, 1}, {8.0, 11.0, 0, 1}, {9.0, 11.0, 0, 1}, {10.0, 11.0, 0, 1}, {11.0, 11.0, 0, 1}, {17.0, 11.0, 0, 1},
{18.0, 11.0, 0, 1}, {19.0, 11.0, 0, 1}, {20.0, 11.0, 0, 1}, {21.0, 11.0, 0, 1}, {22.0, 11.0, 0, 1}, {23.0, 11.0, 0, 1},
{24.0, 11.0, 0, 1}, {25.0, 11.0, 0, 1}, {26.0, 11.0, 0, 1}, {27.0, 11.0, 0, 1}, {28.0, 11.0, 0, 1}, {29.0, 11.0, 0, 1},
{30.0, 11.0, 0, 1}, {31.0, 11.0, 0, 1}, {-31.0, 12.0, 0, 1}, {-30.0, 12.0, 0, 1}, {-29.0, 12.0, 0, 1}, {-28.0, 12.0, 0, 1},
{-27.0, 12.0, 0, 1}, {-26.0, 12.0, 0, 1}, {-25.0, 12.0, 0, 1}, {-24.0, 12.0, 0, 1}, {-23.0, 12.0, 0, 1}, {-22.0, 12.0, 0, 1},
{-21.0, 12.0, 0, 1}, {-20.0, 12.0, 0, 1}, {-19.0, 12.0, 0, 1}, {-18.0, 12.0, 0, 1}, {17.0, 12.0, 0, 1}, {18.0, 12.0, 0, 1},
{19.0, 12.0, 0, 1}, {20.0, 12.0, 0, 1}, {21.0, 12.0, 0, 1}, {22.0, 12.0, 0, 1}, {23.0, 12.0, 0, 1}, {24.0, 12.0, 0, 1},
{25.0, 12.0, 0, 1}, {26.0, 12.0, 0, 1}, {27.0, 12.0, 0, 1}, {28.0, 12.0, 0, 1}, {29.0, 12.0, 0, 1}, {30.0, 12.0, 0, 1},
{-21.0, 13.0, 0, 1}, {-20.0, 13.0, 0, 1}, {-19.0, 13.0, 0, 1}, {-18.0, 13.0, 0, 1}, {17.0, 13.0, 0, 1}, {18.0, 13.0, 0, 1},
{19.0, 13.0, 0, 1}, {20.0, 13.0, 0, 1}, {-21.0, 14.0, 0, 1}, {-20.0, 14.0, 0, 1}, {-19.0, 14.0, 0, 1}, {-18.0, 14.0, 0, 1},
{17.0, 14.0, 0, 1}, {18.0, 14.0, 0, 1}, {19.0, 14.0, 0, 1}, {20.0, 14.0, 0, 1}, {-21.0, 15.0, 0, 1}, {-20.0, 15.0, 0, 1},
{-19.0, 15.0, 0, 1}, {-18.0, 15.0, 0, 1}, {17.0, 15.0, 0, 1}, {18.0, 15.0, 0, 1}, {19.0, 15.0, 0, 1}, {20.0, 15.0, 0, 1},
{-21.0, 16.0, 0, 1}, {-20.0, 16.0, 0, 1}, {-19.0, 16.0, 0, 1}, {-18.0, 16.0, 0, 1}, {17.0, 16.0, 0, 1}, {18.0, 16.0, 0, 1},
{19.0, 16.0, 0, 1}, {20.0, 16.0, 0, 1}, {-21.0, 17.0, 0, 1}, {-20.0, 17.0, 0, 1}, {-19.0, 17.0, 0, 1}, {-18.0, 17.0, 0, 1},
{-17.0, 17.0, 0, 1}, {-16.0, 17.0, 0, 1}, {-15.0, 17.0, 0, 1}, {-14.0, 17.0, 0, 1}, {-13.0, 17.0, 0, 1}, {-12.0, 17.0, 0, 1},
{-11.0, 17.0, 0, 1}, {-10.0, 17.0, 0, 1}, {-9.0, 17.0, 0, 1}, {-8.0, 17.0, 0, 1}, {-7.0, 17.0, 0, 1}, {-6.0, 17.0, 0, 1},
{-5.0, 17.0, 0, 1}, {-4.0, 17.0, 0, 1}, {-3.0, 17.0, 0, 1}, {-2.0, 17.0, 0, 1}, {-1.0, 17.0, 0, 1}, {0.0, 17.0, 0, 1},
{1.0, 17.0, 0, 1}, {2.0, 17.0, 0, 1}, {3.0, 17.0, 0, 1}, {4.0, 17.0, 0, 1}, {5.0, 17.0, 0, 1}, {6.0, 17.0, 0, 1},
{7.0, 17.0, 0, 1}, {8.0, 17.0, 0, 1}, {9.0, 17.0, 0, 1}, {10.0, 17.0, 0, 1}, {11.0, 17.0, 0, 1}, {12.0, 17.0, 0, 1},
{13.0, 17.0, 0, 1}, {14.0, 17.0, 0, 1}, {15.0, 17.0, 0, 1}, {16.0, 17.0, 0, 1}, {17.0, 17.0, 0, 1}, {18.0, 17.0, 0, 1},
{19.0, 17.0, 0, 1}, {20.0, 17.0, 0, 1}, {-21.0, 18.0, 0, 1}, {-20.0, 18.0, 0, 1}, {-19.0, 18.0, 0, 1}, {-18.0, 18.0, 0, 1},
{-17.0, 18.0, 0, 1}, {-16.0, 18.0, 0, 1}, {-15.0, 18.0, 0, 1}, {-14.0, 18.0, 0, 1}, {-13.0, 18.0, 0, 1}, {-12.0, 18.0, 0, 1},
{-11.0, 18.0, 0, 1}, {-10.0, 18.0, 0, 1}, {-9.0, 18.0, 0, 1}, {-8.0, 18.0, 0, 1}, {-7.0, 18.0, 0, 1}, {-6.0, 18.0, 0, 1},
{-5.0, 18.0, 0, 1}, {-4.0, 18.0, 0, 1}, {-3.0, 18.0, 0, 1}, {-2.0, 18.0, 0, 1}, {-1.0, 18.0, 0, 1}, {0.0, 18.0, 0, 1},
{1.0, 18.0, 0, 1}, {2.0, 18.0, 0, 1}, {3.0, 18.0, 0, 1}, {4.0, 18.0, 0, 1}, {5.0, 18.0, 0, 1}, {6.0, 18.0, 0, 1},
{7.0, 18.0, 0, 1}, {8.0, 18.0, 0, 1}, {9.0, 18.0, 0, 1}, {10.0, 18.0, 0, 1}, {11.0, 18.0, 0, 1}, {12.0, 18.0, 0, 1},
{13.0, 18.0, 0, 1}, {14.0, 18.0, 0, 1}, {15.0, 18.0, 0, 1}, {16.0, 18.0, 0, 1}, {17.0, 18.0, 0, 1}, {18.0, 18.0, 0, 1},
{19.0, 18.0, 0, 1}, {20.0, 18.0, 0, 1}, {-21.0, 19.0, 0, 1}, {-20.0, 19.0, 0, 1}, {-19.0, 19.0, 0, 1}, {-18.0, 19.0, 0, 1},
{-17.0, 19.0, 0, 1}, {-16.0, 19.0, 0, 1}, {-15.0, 19.0, 0, 1}, {-14.0, 19.0, 0, 1}, {-13.0, 19.0, 0, 1}, {-12.0, 19.0, 0, 1},
{-11.0, 19.0, 0, 1}, {-10.0, 19.0, 0, 1}, {-9.0, 19.0, 0, 1}, {-8.0, 19.0, 0, 1}, {-7.0, 19.0, 0, 1}, {-6.0, 19.0, 0, 1},
{-5.0, 19.0, 0, 1}, {-4.0, 19.0, 0, 1}, {-3.0, 19.0, 0, 1}, {-2.0, 19.0, 0, 1}, {-1.0, 19.0, 0, 1}, {0.0, 19.0, 0, 1},
{1.0, 19.0, 0, 1}, {2.0, 19.0, 0, 1}, {3.0, 19.0, 0, 1}, {4.0, 19.0, 0, 1}, {5.0, 19.0, 0, 1}, {6.0, 19.0, 0, 1},
{7.0, 19.0, 0, 1}, {8.0, 19.0, 0, 1}, {9.0, 19.0, 0, 1}, {10.0, 19.0, 0, 1}, {11.0, 19.0, 0, 1}, {12.0, 19.0, 0, 1},
{13.0, 19.0, 0, 1}, {14.0, 19.0, 0, 1}, {15.0, 19.0, 0, 1}, {16.0, 19.0, 0, 1}, {17.0, 19.0, 0, 1}, {18.0, 19.0, 0, 1},
{19.0, 19.0, 0, 1}, {20.0, 19.0, 0, 1}, {-21.0, 20.0, 0, 1}, {-20.0, 20.0, 0, 1}, {-19.0, 20.0, 0, 1}, {-18.0, 20.0, 0, 1},
{-17.0, 20.0, 0, 1}, {-16.0, 20.0, 0, 1}, {-15.0, 20.0, 0, 1}, {-14.0, 20.0, 0, 1}, {-13.0, 20.0, 0, 1}, {-12.0, 20.0, 0, 1},
{-11.0, 20.0, 0, 1}, {-10.0, 20.0, 0, 1}, {-9.0, 20.0, 0, 1}, {-8.0, 20.0, 0, 1}, {-7.0, 20.0, 0, 1}, {-6.0, 20.0, 0, 1},
{-5.0, 20.0, 0, 1}, {-4.0, 20.0, 0, 1}, {-3.0, 20.0, 0, 1}, {-2.0, 20.0, 0, 1}, {-1.0, 20.0, 0, 1}, {0.0, 20.0, 0, 1},
{1.0, 20.0, 0, 1}, {2.0, 20.0, 0, 1}, {3.0, 20.0, 0, 1}, {4.0, 20.0, 0, 1}, {5.0, 20.0, 0, 1}, {6.0, 20.0, 0, 1},
{7.0, 20.0, 0, 1}, {8.0, 20.0, 0, 1}, {9.0, 20.0, 0, 1}, {10.0, 20.0, 0, 1}, {11.0, 20.0, 0, 1}, {12.0, 20.0, 0, 1},
{13.0, 20.0, 0, 1}, {14.0, 20.0, 0, 1}, {15.0, 20.0, 0, 1}, {16.0, 20.0, 0, 1}, {17.0, 20.0, 0, 1}, {18.0, 20.0, 0, 1},
{19.0, 20.0, 0, 1}, {20.0, 20.0, 0, 1}, {-13.0, 21.0, 0, 1}, {-12.0, 21.0, 0, 1}, {-11.0, 21.0, 0, 1}, {-10.0, 21.0, 0, 1},
{-6.0, 21.0, 0, 1}, {-5.0, 21.0, 0, 1}, {-4.0, 21.0, 0, 1}, {-3.0, 21.0, 0, 1}, {-2.0, 21.0, 0, 1}, {1.0, 21.0, 0, 1},
{2.0, 21.0, 0, 1}, {3.0, 21.0, 0, 1}, {4.0, 21.0, 0, 1}, {5.0, 21.0, 0, 1}, {8.0, 21.0, 0, 1}, {9.0, 21.0, 0, 1},
{10.0, 21.0, 0, 1}, {11.0, 21.0, 0, 1}, {12.0, 21.0, 0, 1}, {-13.0, 22.0, 0, 1}, {-12.0, 22.0, 0, 1}, {-11.0, 22.0, 0, 1},
{-10.0, 22.0, 0, 1}, {-6.0, 22.0, 0, 1}, {-5.0, 22.0, 0, 1}, {-4.0, 22.0, 0, 1}, {-3.0, 22.0, 0, 1}, {-2.0, 22.0, 0, 1},
{1.0, 22.0, 0, 1}, {2.0, 22.0, 0, 1}, {3.0, 22.0, 0, 1}, {4.0, 22.0, 0, 1}, {5.0, 22.0, 0, 1}, {8.0, 22.0, 0, 1},
{9.0, 22.0, 0, 1}, {10.0, 22.0, 0, 1}, {11.0, 22.0, 0, 1}, {12.0, 22.0, 0, 1}, {-13.0, 23.0, 0, 1}, {-12.0, 23.0, 0, 1},
{-11.0, 23.0, 0, 1}, {-10.0, 23.0, 0, 1}, {-6.0, 23.0, 0, 1}, {-5.0, 23.0, 0, 1}, {-4.0, 23.0, 0, 1}, {-3.0, 23.0, 0, 1},
{-2.0, 23.0, 0, 1}, {1.0, 23.0, 0, 1}, {2.0, 23.0, 0, 1}, {3.0, 23.0, 0, 1}, {4.0, 23.0, 0, 1}, {5.0, 23.0, 0, 1},
{8.0, 23.0, 0, 1}, {9.0, 23.0, 0, 1}, {10.0, 23.0, 0, 1}, {11.0, 23.0, 0, 1}, {12.0, 23.0, 0, 1}, {-13.0, 24.0, 0, 1},
{-12.0, 24.0, 0, 1}, {-11.0, 24.0, 0, 1}, {-10.0, 24.0, 0, 1}, {-6.0, 24.0, 0, 1}, {-5.0, 24.0, 0, 1}, {-4.0, 24.0, 0, 1},
{-3.0, 24.0, 0, 1}, {-2.0, 24.0, 0, 1}, {1.0, 24.0, 0, 1}, {2.0, 24.0, 0, 1}, {3.0, 24.0, 0, 1}, {4.0, 24.0, 0, 1},
{5.0, 24.0, 0, 1}, {8.0, 24.0, 0, 1}, {9.0, 24.0, 0, 1}, {10.0, 24.0, 0, 1}, {11.0, 24.0, 0, 1}, {12.0, 24.0, 0, 1},
{-13.0, 25.0, 0, 1}, {-12.0, 25.0, 0, 1}, {-11.0, 25.0, 0, 1}, {-10.0, 25.0, 0, 1}, {-6.0, 25.0, 0, 1}, {-5.0, 25.0, 0, 1},
{-4.0, 25.0, 0, 1}, {-3.0, 25.0, 0, 1}, {-2.0, 25.0, 0, 1}, {1.0, 25.0, 0, 1}, {2.0, 25.0, 0, 1}, {3.0, 25.0, 0, 1},
{4.0, 25.0, 0, 1}, {5.0, 25.0, 0, 1}, {8.0, 25.0, 0, 1}, {9.0, 25.0, 0, 1}, {10.0, 25.0, 0, 1}, {11.0, 25.0, 0, 1},
{12.0, 25.0, 0, 1}, {-13.0, 26.0, 0, 1}, {-12.0, 26.0, 0, 1}, {-11.0, 26.0, 0, 1}, {-10.0, 26.0, 0, 1}, {-6.0, 26.0, 0, 1},
{-5.0, 26.0, 0, 1}, {-4.0, 26.0, 0, 1}, {-3.0, 26.0, 0, 1}, {-2.0, 26.0, 0, 1}, {1.0, 26.0, 0, 1}, {2.0, 26.0, 0, 1},
{3.0, 26.0, 0, 1}, {4.0, 26.0, 0, 1}, {5.0, 26.0, 0, 1}, {8.0, 26.0, 0, 1}, {9.0, 26.0, 0, 1}, {10.0, 26.0, 0, 1},
{11.0, 26.0, 0, 1}, {12.0, 26.0, 0, 1}, {-13.0, 27.0, 0, 1}, {-12.0, 27.0, 0, 1}, {-11.0, 27.0, 0, 1}, {-10.0, 27.0, 0, 1},
{-6.0, 27.0, 0, 1}, {-5.0, 27.0, 0, 1}, {-4.0, 27.0, 0, 1}, {-3.0, 27.0, 0, 1}, {-2.0, 27.0, 0, 1}, {1.0, 27.0, 0, 1},
{2.0, 27.0, 0, 1}, {3.0, 27.0, 0, 1}, {4.0, 27.0, 0, 1}, {5.0, 27.0, 0, 1}, {8.0, 27.0, 0, 1}, {9.0, 27.0, 0, 1},
{10.0, 27.0, 0, 1}, {11.0, 27.0, 0, 1}, {12.0, 27.0, 0, 1}, {-13.0, 28.0, 0, 1}, {-12.0, 28.0, 0, 1}, {-11.0, 28.0, 0, 1},
{-10.0, 28.0, 0, 1}, {-6.0, 28.0, 0, 1}, {-5.0, 28.0, 0, 1}, {-4.0, 28.0, 0, 1}, {-3.0, 28.0, 0, 1}, {-2.0, 28.0, 0, 1},
{1.0, 28.0, 0, 1}, {2.0, 28.0, 0, 1}, {3.0, 28.0, 0, 1}, {4.0, 28.0, 0, 1}, {5.0, 28.0, 0, 1}, {8.0, 28.0, 0, 1},
{9.0, 28.0, 0, 1}, {10.0, 28.0, 0, 1}, {11.0, 28.0, 0, 1}, {12.0, 28.0, 0, 1}, {-13.0, 29.0, 0, 1}, {-12.0, 29.0, 0, 1},
{-11.0, 29.0, 0, 1}, {-10.0, 29.0, 0, 1}, {-6.0, 29.0, 0, 1}, {-5.0, 29.0, 0, 1}, {-4.0, 29.0, 0, 1}, {-3.0, 29.0, 0, 1},
{-2.0, 29.0, 0, 1}, {1.0, 29.0, 0, 1}, {2.0, 29.0, 0, 1}, {3.0, 29.0, 0, 1}, {4.0, 29.0, 0, 1}, {5.0, 29.0, 0, 1},
{8.0, 29.0, 0, 1}, {9.0, 29.0, 0, 1}, {10.0, 29.0, 0, 1}, {11.0, 29.0, 0, 1}, {12.0, 29.0, 0, 1}, {-13.0, 30.0, 0, 1},
{-12.0, 30.0, 0, 1}, {-11.0, 30.0, 0, 1}, {-10.0, 30.0, 0, 1}, {-6.0, 30.0, 0, 1}, {-5.0, 30.0, 0, 1}, {-4.0, 30.0, 0, 1},
{-3.0, 30.0, 0, 1}, {1.0, 30.0, 0, 1}, {2.0, 30.0, 0, 1}, {3.0, 30.0, 0, 1}, {4.0, 30.0, 0, 1}, {5.0, 30.0, 0, 1},
{9.0, 30.0, 0, 1}, {10.0, 30.0, 0, 1}, {11.0, 30.0, 0, 1}, {12.0, 30.0, 0, 1}, {-12.0, 31.0, 0, 1}, {-11.0, 31.0, 0, 1},
{-10.0, 31.0, 0, 1}, {-5.0, 31.0, 0, 1}, {-4.0, 31.0, 0, 1}, {-3.0, 31.0, 0, 1}, {2.0, 31.0, 0, 1}, {3.0, 31.0, 0, 1},
{4.0, 31.0, 0, 1}, {9.0, 31.0, 0, 1}, {10.0, 31.0, 0, 1}, {11.0, 31.0, 0, 1}
};
#endif // CONFIG_3D_OBJECT_CUSTOM

View File

@@ -0,0 +1,18 @@
// File generated by ImgTo3D.py
// Image file converted to 3D matrix: cpu_logo.png
#pragma once
#include <stdint.h>
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
extern const uint8_t image_to_bmp_array_custom[512];
extern const float image_to_3d_matrix_custom[1732][4];
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,114 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <malloc.h>
#include <math.h>
#include "graphics_support.h"
void init_perspective_matrix(dspm::Mat &P_m)
{
const float fov = 90; // field of view in degrees
const float near = 0.0001;
const float far = 1;
const float S = 1 / (tan((fov / 2) * DEG_TO_RAD));
// Initialize matrix to zero
for (int row = 0; row < P_m.rows; row++) {
for (int col = 0; col < P_m.cols; col++) {
P_m(row, col) = 0;
}
}
P_m(0, 0) = S;
P_m(1, 1) = S;
P_m(2, 2) = -far / (far - near);
P_m(3, 2) = (-far * near) / (far - near);
P_m(2, 3) = -1;
P_m(3, 3) = 1;
}
void update_perspective_matrix(dspm::Mat &P_m, float fov)
{
const float near = 0.0001;
const float far = 1;
const float S = 1 / (tan((fov / 2) * DEG_TO_RAD));
// Initialize matrix to zero
for (int row = 0; row < P_m.rows; row++) {
for (int col = 0; col < P_m.cols; col++) {
P_m(row, col) = 0;
}
}
P_m(0, 0) = S;
P_m(1, 1) = S;
P_m(2, 2) = -far / (far - near);
P_m(3, 2) = (-far * near) / (far - near);
P_m(2, 3) = -1;
P_m(3, 3) = 1;
P_m(3, 0) = (float)SSD1606_X_CENTER;
P_m(3, 1) = (float)SSD1606_Y_CENTER;
}
void update_scaling_matrix(dspm::Mat &T_m, bool keep_diagonal, float scale_x, float scale_y, float scale_z)
{
if (keep_diagonal) { // Multiply the diagonal values of the transformation matrix with the scaling
T_m(0, 0) *= scale_x; // (in case a rotation is already applied)
T_m(1, 1) *= scale_y;
T_m(2, 2) *= scale_z;
} else {
T_m(0, 0) = scale_x;
T_m(1, 1) = scale_y;
T_m(2, 2) = scale_z;
}
}
void update_translation_matrix(dspm::Mat &T_m, bool row, float move_x, float move_y, float move_z)
{
if (row) { // update values in 4-th row, if translation matrix is the second multiplier
T_m(3, 0) = move_x;
T_m(3, 1) = move_y;
T_m(3, 2) = move_z;
} else { // update values in 4-th collum, if translation matrix is the first multiplier
T_m(0, 3) = move_x;
T_m(1, 3) = move_y;
T_m(2, 3) = move_z;
}
}
void update_rotation_matrix(dspm::Mat &T_m, float rot_x, float rot_y, float rot_z)
{
dspm::Mat rotation_data(3, 1); // matrix(3x1) that holds x, y, z rotation data
rotation_data(0, 0) = DEG_TO_RAD * rot_x; // rotation data x
rotation_data(1, 0) = DEG_TO_RAD * rot_y; // rotation data y
rotation_data(2, 0) = DEG_TO_RAD * rot_z; // rotation data z
// Create and populate rotation matrix R(3x3). Then inverse it
dspm::Mat R = ekf::eul2rotm(rotation_data.data).t();
// Enlarge rotation matrix from 3x3 to 4x4
for (int row = 0; row < R.rows; row++) { // Copy rotation matrix R(3x3) to transformation matrix T_m(4x4)
for (int col = 0; col < R.cols; col++) {
T_m(row, col) = R(row, col);
}
}
}
void print_matrix(dspm::Mat matrix)
{
for (int rows = 0; rows < matrix.rows; rows++) {
for (int cols = 0; cols < matrix.cols; cols++) {
std::cout << matrix(rows, cols) << ", \t";
}
std::cout << std::endl;
}
std::cout << std::endl << std::endl;
}

Some files were not shown because too many files have changed in this diff Show More