Repository: p-lr/MapCompose Branch: master Commit: 969062913203 Files: 163 Total size: 653.9 KB Directory structure: gitextract_n5gon859/ ├── .gitignore ├── LICENSE ├── Readme.md ├── build.gradle ├── demo/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── assets/ │ │ │ └── tracks/ │ │ │ ├── track1.txt │ │ │ ├── track2.txt │ │ │ └── track3.txt │ │ ├── java/ │ │ │ └── ovh/ │ │ │ └── plrapps/ │ │ │ └── mapcompose/ │ │ │ └── demo/ │ │ │ ├── MainActivity.kt │ │ │ ├── providers/ │ │ │ │ └── TileStreamProviderFactory.kt │ │ │ ├── ui/ │ │ │ │ ├── MapComposeDemoApp.kt │ │ │ │ ├── NavGraph.kt │ │ │ │ ├── screens/ │ │ │ │ │ ├── AddingMarkerDemo.kt │ │ │ │ │ ├── AnimationDemo.kt │ │ │ │ │ ├── CalloutDemo.kt │ │ │ │ │ ├── CenteringOnMarkerDemo.kt │ │ │ │ │ ├── CustomDraw.kt │ │ │ │ │ ├── Home.kt │ │ │ │ │ ├── HttpTilesDemo.kt │ │ │ │ │ ├── InfiniteScrollDemo.kt │ │ │ │ │ ├── LayersDemo.kt │ │ │ │ │ ├── MarkersClusteringDemo.kt │ │ │ │ │ ├── MarkersLazyLoadingDemo.kt │ │ │ │ │ ├── OsmDemo.kt │ │ │ │ │ ├── PathsDemo.kt │ │ │ │ │ ├── RotationDemo.kt │ │ │ │ │ ├── SimpleDemo.kt │ │ │ │ │ └── VisibleAreaPaddingDemo.kt │ │ │ │ ├── theme/ │ │ │ │ │ ├── Color.kt │ │ │ │ │ ├── Theme.kt │ │ │ │ │ └── Type.kt │ │ │ │ └── widgets/ │ │ │ │ ├── Callout.kt │ │ │ │ └── Marker.kt │ │ │ ├── utils/ │ │ │ │ ├── Metrics.kt │ │ │ │ ├── Random.kt │ │ │ │ └── WebMercator.kt │ │ │ └── viewmodels/ │ │ │ ├── AddingMarkerVM.kt │ │ │ ├── AnimationDemoVM.kt │ │ │ ├── CalloutVM.kt │ │ │ ├── CenteringOnMarkerVM.kt │ │ │ ├── CustomDrawVM.kt │ │ │ ├── HttpTilesVM.kt │ │ │ ├── InfiniteScrollVM.kt │ │ │ ├── LayersVM.kt │ │ │ ├── MarkersClusteringVM.kt │ │ │ ├── MarkersLazyLoadingVM.kt │ │ │ ├── OsmVM.kt │ │ │ ├── PathsVM.kt │ │ │ ├── RotationVM.kt │ │ │ ├── SimpleDemoVM.kt │ │ │ └── VisibleAreaPaddingVM.kt │ │ └── res/ │ │ ├── drawable/ │ │ │ ├── ic_launcher_background.xml │ │ │ └── map_marker.xml │ │ ├── drawable-v24/ │ │ │ └── ic_launcher_foreground.xml │ │ ├── mipmap-anydpi-v26/ │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ └── test/ │ └── java/ │ └── ovh/ │ └── plrapps/ │ └── mapcompose/ │ └── demo/ │ └── utils/ │ └── WebMercatorTest.kt ├── doc/ │ └── mapcompose/ │ └── MapCompose.drawio ├── gradle/ │ ├── gradle-daemon-jvm.properties │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── mapcompose/ │ ├── build.gradle │ ├── gradle.properties │ └── src/ │ ├── main/ │ │ ├── AndroidManifest.xml │ │ └── java/ │ │ └── ovh/ │ │ └── plrapps/ │ │ └── mapcompose/ │ │ ├── api/ │ │ │ ├── Annotation.kt │ │ │ ├── ApiDefaults.kt │ │ │ ├── Common.kt │ │ │ ├── DefaultCanvas.kt │ │ │ ├── GesturesApi.kt │ │ │ ├── LayerApi.kt │ │ │ ├── LayoutApi.kt │ │ │ ├── MarkerApi.kt │ │ │ ├── Model.kt │ │ │ ├── PathApi.kt │ │ │ ├── RenderApi.kt │ │ │ └── UtilsApi.kt │ │ ├── core/ │ │ │ ├── ColorFilterProvider.kt │ │ │ ├── Debounce.kt │ │ │ ├── GestureConfiguration.kt │ │ │ ├── Layer.kt │ │ │ ├── Throttle.kt │ │ │ ├── Tile.kt │ │ │ ├── TileCollector.kt │ │ │ ├── TileStreamProvider.kt │ │ │ ├── Viewport.kt │ │ │ └── VisibleTilesResolver.kt │ │ ├── ui/ │ │ │ ├── MapUI.kt │ │ │ ├── gestures/ │ │ │ │ ├── GestureDetector.kt │ │ │ │ ├── TapGestureDetector.kt │ │ │ │ └── model/ │ │ │ │ └── HitType.kt │ │ │ ├── layout/ │ │ │ │ ├── MinimumScaleMode.kt │ │ │ │ ├── Rendering.kt │ │ │ │ └── ZoomPanRotate.kt │ │ │ ├── markers/ │ │ │ │ ├── Clusterer.kt │ │ │ │ ├── LazyLoader.kt │ │ │ │ ├── MarkerComposer.kt │ │ │ │ └── MarkerLayout.kt │ │ │ ├── paths/ │ │ │ │ ├── PathComposer.kt │ │ │ │ ├── RamerDouglaPeucker.kt │ │ │ │ └── model/ │ │ │ │ ├── Cap.kt │ │ │ │ └── PatternItem.kt │ │ │ ├── state/ │ │ │ │ ├── MapState.kt │ │ │ │ ├── PathState.kt │ │ │ │ ├── TileCanvasState.kt │ │ │ │ ├── ZoomPanRotateState.kt │ │ │ │ └── markers/ │ │ │ │ ├── MarkerRenderState.kt │ │ │ │ ├── MarkerState.kt │ │ │ │ └── model/ │ │ │ │ ├── ClusterClickBehavior.kt │ │ │ │ ├── MarkerData.kt │ │ │ │ ├── MarkerType.kt │ │ │ │ └── RenderingStrategy.kt │ │ │ └── view/ │ │ │ └── TileCanvas.kt │ │ └── utils/ │ │ ├── AnimUtils.kt │ │ ├── ApiUtils.kt │ │ ├── BoundingBoxUtils.kt │ │ ├── Collections.kt │ │ ├── Dp.kt │ │ ├── Flow.kt │ │ ├── Geometry.kt │ │ ├── Point.kt │ │ ├── RotationUtils.kt │ │ └── VisibleAreaUtils.kt │ └── test/ │ └── java/ │ └── ovh/ │ └── plrapps/ │ └── mapcompose/ │ ├── core/ │ │ ├── TileCollectorTest.kt │ │ └── VisibleTilesResolverTest.kt │ ├── state/ │ │ └── TileCanvasStateTest.kt │ ├── ui/ │ │ └── paths/ │ │ └── PathComposerTest.kt │ └── utils/ │ ├── GeometryTest.kt │ └── VisibleAreaUtilsTest.kt ├── settings.gradle └── testapp/ ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src/ ├── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── ovh/ │ │ └── plrapps/ │ │ └── mapcompose/ │ │ └── testapp/ │ │ ├── MainActivity.kt │ │ ├── core/ │ │ │ └── ui/ │ │ │ ├── MapComposeTestApp.kt │ │ │ ├── nav/ │ │ │ │ └── NavDestinations.kt │ │ │ └── theme/ │ │ │ ├── Color.kt │ │ │ ├── Theme.kt │ │ │ └── Type.kt │ │ ├── features/ │ │ │ ├── clustering/ │ │ │ │ ├── MarkerClusteringUi.kt │ │ │ │ └── MarkersClusteringViewModel.kt │ │ │ ├── home/ │ │ │ │ └── Home.kt │ │ │ └── layerswitch/ │ │ │ ├── LayerSwitchTest.kt │ │ │ └── LayerSwitchViewModel.kt │ │ └── utils/ │ │ └── Random.kt │ └── res/ │ ├── drawable/ │ │ ├── ic_launcher_background.xml │ │ └── map_marker.xml │ ├── drawable-v24/ │ │ └── ic_launcher_foreground.xml │ ├── mipmap-anydpi-v26/ │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ └── values/ │ ├── colors.xml │ ├── strings.xml │ └── themes.xml └── test/ └── java/ └── ovh/ └── plrapps/ └── mapcompose/ └── testapp/ └── ExampleUnitTest.kt ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.iml .gradle /local.properties /.idea/caches /.idea/libraries /.idea/modules.xml /.idea/workspace.xml /.idea/navEditor.xml /.idea/assetWizardSettings.xml .DS_Store build /captures .idea .externalNativeBuild publish-mavenCentral.sh compile_and_install_demo_release.sh /publishErrors.txt ================================================ FILE: LICENSE ================================================ 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. ================================================ FILE: Readme.md ================================================ [![Maven Central](https://img.shields.io/maven-central/v/ovh.plrapps/mapcompose)](https://central.sonatype.com/artifact/ovh.plrapps/mapcompose) [![GitHub License](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0) [![](https://img.shields.io/badge/ComposeBOM-2026.02.01-brightgreen)](https://developer.android.com/jetpack/compose/bom/bom) 🎉 News: - `3.1.0` now supports infinite scroll (#119). - `3.0.0` is released. The library is now capable of handling much bigger maps, such as world-wide OpenStreetMap at zoom level 17 with a maximum scale of 8. See [Migrate from 2.x.x](#migrate-from-2xx). - Memory footprint has been dramatically reduced on Android 10 and above, by leveraging [Hardware Bitmaps](https://bumptech.github.io/glide/doc/hardwarebitmaps.html). - MapCompose Multiplatform is officially released: https://github.com/p-lr/MapComposeMP \ Works on iOS, MacOS, Windows, Linux, and Android. # MapCompose MapCompose is a fast, memory efficient Jetpack compose library to display tiled maps with minimal effort. It shows the visible part of a tiled map with support of markers and paths, and various gestures (flinging, dragging, scaling, and rotating). An example of setting up: ```kotlin /* Inside your view-model */ val tileStreamProvider = TileStreamProvider { row, col, zoomLvl -> FileInputStream(File("path/{$zoomLvl}/{$row}/{$col}.jpg")) // or it can be a remote HTTP fetch } val state = MapState(4, 4096, 4096).apply { addLayer(tileStreamProvider) enableRotation() } /* Inside a composable */ @Composable fun MapContainer( modifier: Modifier = Modifier, viewModel: YourViewModel ) { MapUI(modifier, state = viewModel.state) } ``` This project holds the source code of this library, plus a demo app - which is useful to get started. To test the demo, just clone the repo and launch the demo app from Android Studio. ## Clustering Marker clustering regroups markers of close proximity into clusters. The video below shows how it works. https://github.com/p-lr/MapCompose/assets/15638794/de48cb1b-396b-44d3-b47a-e3d719e8f38a The sample below shows the relevant part of the code. We can still add regular markers (not managed by a clusterer), such as the red marker in the video. See the [full code](demo/src/main/java/ovh/plrapps/mapcompose/demo/viewmodels/MarkersClusteringVM.kt). ```kotlin /* Add clusterer */ state.addClusterer("default") { ids -> { Cluster(size = ids.size) } } /* Add marker managed by the clusterer */ state.addMarker( id = "marker", x = 0.2, y = 0.3, renderingStrategy = RenderingStrategy.Clustering("default"), ) { Marker() } ``` There's an example in the demo app. ## Installation Add this to your module's build.gradle ```groovy implementation 'ovh.plrapps:mapcompose:3.2.7' ``` Starting with v.2.4.1, the library is using the [compose BOM](https://developer.android.com/jetpack/compose/bom/bom). The version of the BOM is specified in the release notes. The demo app shows an example of how to use it. ## Basics MapCompose is optimized to display maps that have several levels, like this:

Each next level is twice bigger than the former, and provides more details. Overall, this looks like a pyramid. Another common name is "deep-zoom" map. This library comes with a demo app featuring various use-cases such as using markers, paths, map rotation, etc. All examples use the same map stored in the assets, which is a great example of deep-zoom map. MapCompose can also be used with single level maps. ### Usage In a typical application, you create a `MapState` instance inside a `ViewModel` (or whatever component which survives device rotation). Your `MapState` should then be passed to the `MapUI` composable. The code sample at the top of this readme shows an example. Then, whenever you need to update the map (add a marker, a path, change the scale, etc.), you invoke APIs on your `MapState` instance. As its name suggests, `MapState` also _owns_ the state. Therefore, composables will always render consistently - even after a device rotation. All public APIs are located under the [api](mapcompose/src/main/java/ovh/plrapps/mapcompose/api) package. The following sections provide details on the `MapState` class, and give examples of how to add markers, callouts, and paths. All apis should be invoked from the main thread. ### MapState The `MapState` class expects three parameters for its construction: * `levelCount`: The number of levels of the map, * `fullWidth`: The width of the map at scale 1.0, which is the width of last level, * `fullHeight`: The height of the map at scale 1.0, which is the height of last level ### Layers MapCompose supports layers - e.g it's possible to add several tile pyramids. Each level is made of the superposition of tiles from all pyramids at the given level. For example, at the second level (starting from the lowest scale), tiles would look like the image below when three layers are added.

Your implementation of the `TileStreamProvider` interface (see below) is what defines a tile pyramid. It provides `InputStream`s of image files (png, jpg). MapCompose will request tiles using the convention that the origin is at the top-left corner. For example, the tile requested with `row` = 0, and `col = 0` will be positioned at the top-left corner. ```kotlin fun interface TileStreamProvider { suspend fun getTileStream(row: Int, col: Int, zoomLvl: Int): InputStream? } ``` Depending on your configuration, your `TileStreamProvider` implementation might fetch local files, as well as performing remote HTTP requests - it's up to you. You don't have to worry about threading, MapCompose takes care of that (the main thread isn't blocked by `getTileStream` calls). However, in case of HTTP requests, it's advised to create a `MapState` with a higher than default `workerCount`. That optional parameter defines the size of the dedicated thread pool for fetching tiles, and defaults to the number of cores minus one. Typically, you would want to set `workerCount` to 16 when performing HTTP requests. Otherwise, you can safely leave it to its default. To add a layer, use the `addLayer` on your `MapState` instance. There are others APIs for reordering, removing, setting alpha - all dynamically. ### Markers To add a marker, use the [addMarker](https://github.com/p-lr/MapCompose/blob/982caf29ab5e86b58c56812735f60bfe405638ea/mapcompose/src/main/java/ovh/plrapps/mapcompose/api/MarkerApi.kt#L30) API, like so: ```kotlin /* Add a marker at the center of the map */ mapState.addMarker("id", x = 0.5, y = 0.5) { Icon( painter = painterResource(id = R.drawable.map_marker), contentDescription = null, modifier = Modifier.size(50.dp), tint = Color(0xCC2196F3) ) } ```

A marker is a composable that you supply (in the example above, it's an `Icon`). It can be whatever composable you like. A marker does not scale, but it's position updates as the map scales, so it's always attached to the original position. A marker has an anchor point defined - the point which is fixed relatively to the map. This anchor point is defined using relative offsets, which are applied to the width and height of the marker. For example, to have a marker centered horizontally and aligned at the bottom edge (like a typical map pin would do), you'd pass -0.5f and -1.0f as relative offsets (left position is offset by half the width, and top is offset by the full height). If necessary, an absolute offset expressed in pixels can be applied, in addition to the relative offset. Markers can be moved, removed, and be draggable. See the following APIs: [moveMarker](https://github.com/p-lr/MapCompose/blob/2fbf0967290ffe01d63a6c65a3022568ef48b9dd/mapcompose/src/main/java/ovh/plrapps/mapcompose/api/MarkerApi.kt#L72), [removeMarker](https://github.com/p-lr/MapCompose/blob/2fbf0967290ffe01d63a6c65a3022568ef48b9dd/mapcompose/src/main/java/ovh/plrapps/mapcompose/api/MarkerApi.kt#L61), [enableMarkerDrag](https://github.com/p-lr/MapCompose/blob/2fbf0967290ffe01d63a6c65a3022568ef48b9dd/mapcompose/src/main/java/ovh/plrapps/mapcompose/api/MarkerApi.kt#L89). ### Callouts Callouts are typically message popups which are, like markers, attached to a specific position. However, they automatically dismiss on touch down. This default behavior can be changed. To add a callout, use [addCallout](https://github.com/p-lr/MapCompose/blob/2fbf0967290ffe01d63a6c65a3022568ef48b9dd/mapcompose/src/main/java/ovh/plrapps/mapcompose/api/MarkerApi.kt#L220).

Callouts can be programmatically removed (if automatic dismiss was disabled). ### Paths To add a path, use the `addPath` api: ```kotlin mapState.addPath("pathId", color = Color(0xFF448AFF)) { addPoints(points) } ``` The demo app shows a complete example.

## Animate state change It's pretty common to programmatically animate the scroll and/or the scale, or even the rotation of the map. *scroll and/or scale animation* When animating the scale, we generally do so while maintaining the center of the screen at a specific position. Likewise, when animating the scroll position, we can do so with or without animating the scale altogether, using [scrollTo](https://github.com/p-lr/MapCompose/blob/08c0f68f654c1ce27a295f3fb6c25e9cf4274de9/mapcompose/src/main/java/ovh/plrapps/mapcompose/api/LayoutApi.kt#L188) and [snapScrollTo](https://github.com/p-lr/MapCompose/blob/08c0f68f654c1ce27a295f3fb6c25e9cf4274de9/mapcompose/src/main/java/ovh/plrapps/mapcompose/api/LayoutApi.kt#L161). *rotation animation* For animating the rotation while keeping the current scale and scroll, use the [rotateTo](https://github.com/p-lr/MapCompose/blob/08c0f68f654c1ce27a295f3fb6c25e9cf4274de9/mapcompose/src/main/java/ovh/plrapps/mapcompose/api/LayoutApi.kt#L149) API. Both `scrollTo` and `rotateTo` are suspending functions. Therefore, you know exactly when an animation finishes, and you can easily chain animations inside a coroutine. ```kotlin // Inside a ViewModel viewModelScope.launch { mapState.scrollTo(0.8, 0.8, destScale = 2f) mapState.rotateTo(180f, TweenSpec(2000, easing = FastOutSlowInEasing)) } ``` For a detailed example, see the "AnimationDemo". ## Design changes and differences with MapView * In MapView, you had to define bounds before you could add markers. There's no such concept in MapCompose anymore. Now, coordinates are normalized. For example, (x=0.5, y=0.5) is a point located at the center of the map. Normalized coordinates are easier to reason about, and application code can still translate this coordinate system to a custom one. * In MapView, you had to build a configuration and use that configuration to create a `MapView` instance. There's no such thing in MapCompose. Now, you create a `MapState` object with required parameters. * A lot of things which couldn't change after MapView configuration can now be changed dynamically in MapCompose. For example, the `zIndex` of a marker, or the minimum scale mode can be changed at runtime. ## Migrate from `2.x.x` * All apis taking the scale as parameter now require `Double` values instead of `Float`. * A few low-level apis taking the scroll in pixels now require `Double` values instead of `Float`. * The `addMarker` api now longer has the parameter `clipShape`. ## Contributors Marcin (@Nohus) has contributed and fixed some issues. He also thoroughly tested the new layers feature – which made `MapCompose` better. ================================================ FILE: build.gradle ================================================ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { ext { kotlin_version = "2.2.21" coroutine_version = '1.10.2' } repositories { google() mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:9.2.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } ================================================ FILE: demo/.gitignore ================================================ /build ================================================ FILE: demo/build.gradle ================================================ import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { id 'com.android.application' id 'kotlin-android' id "org.jetbrains.kotlin.plugin.compose" version "$kotlin_version" id 'kotlin-parcelize' } android { compileSdk = 36 defaultConfig { applicationId "ovh.plrapps.mapcompose.demo" minSdk = 23 targetSdk = 36 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { useSupportLibrary = true } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 } buildFeatures { compose = true } namespace = 'ovh.plrapps.mapcompose.demo' } kotlin { compilerOptions { freeCompilerArgs.addAll([ '-Xopt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi', '-Xopt-in=androidx.compose.foundation.ExperimentalFoundationApi', ]) jvmTarget = JvmTarget.JVM_17 } } dependencies { implementation 'androidx.core:core-ktx:1.18.0' implementation 'androidx.appcompat:appcompat:1.7.1' // Compose - See https://developer.android.com/jetpack/compose/setup#bom-version-mapping implementation platform('androidx.compose:compose-bom:2026.04.01') implementation "androidx.compose.ui:ui" implementation "androidx.compose.material:material" implementation "androidx.compose.material3:material3" implementation "androidx.compose.ui:ui-tooling-preview" debugImplementation "androidx.compose.ui:ui-tooling" implementation 'androidx.navigation:navigation-compose:2.9.8' implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.10.0' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.10.0' implementation project(':mapcompose') testImplementation 'junit:junit:4.13.2' } ================================================ FILE: demo/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: demo/src/main/AndroidManifest.xml ================================================ ================================================ FILE: demo/src/main/assets/tracks/track1.txt ================================================ 0.6044638908531056,0.23086354170969253 0.6044638908531056,0.230781790986988 0.6075361613235069,0.22873802292007173 0.6100394928179091,0.23168104893644745 0.6137944900595099,0.23225330399520489 0.6170374422227098,0.2303730373736396 0.6207355455667128,0.230945292432339 0.624376755013113,0.23135404604574544 0.628074858357116,0.23168104893644745 0.6307488715443168,0.23429707206217923 0.6302368264659158,0.23797585458272147 0.6306919776467139,0.24165463710326368 0.6304644020563174,0.24533341962380592 0.6329677335507197,0.24811294419488875 0.6345038687859178,0.25154647454737544 0.6371778819731186,0.2539989962276982 0.640762197521921,0.25514350634521316 0.644460300865924,0.2553887585132687 0.6474756774387223,0.25326323972364784 0.6511168868851224,0.2524457324968349 0.654473626843528,0.250974219488618 0.6572614278259298,0.24852169780823716 0.6569200644403274,0.2522004803287794 0.6597078654227291,0.24974795864845659 0.66238187860993,0.25236398177413033 0.6607319555795311,0.2557157614039706 0.6585699874707263,0.25874053814310893 0.6622680908147293,0.2582500338069979 0.665567936875532,0.25653326863078363 0.6686971012435311,0.25457125128645564 0.6675592232915333,0.25816828308435147 0.6662506636467317,0.2617653148821892 0.6641455894355297,0.2647900916213275 0.665567936875532,0.2682236219738142 0.66602308805633,0.2718206537716519 0.6679574805747335,0.2750089319561412 0.6685833134483302,0.2786877144766834 0.6696642975027303,0.2822847462745211 0.6711435388403354,0.28563652590436134 0.6748416421843334,0.28604527951770975 0.6752967933651366,0.28972406203825196 0.6733624008467333,0.2929123402227413 0.671314220533134,0.2959371169618215 0.6712573266355312,0.2996976502050683 0.6736468703347327,0.3025589254987975 0.6751830055699358,0.30591070512863777 0.6756950506483369,0.3096712383718265 0.6719969473043338,0.30983473981717746 0.6691522524243343,0.31220551077485376 0.6700625547859305,0.31580254257274953 0.672964143563533,0.3181733135304258 0.6755812628531361,0.32070758593345317 0.6778001248595338,0.32373236267253336 0.6796207295827364,0.3270023915797272 0.6781983821427341,0.3304359219322139 0.6746709604915347,0.3292096610920525 0.6726796740755335,0.33231618855383727 0.6712004327379333,0.335749718906324 0.6747847482867356,0.33673072757842987 0.6725658862803328,0.3396737535948636 0.6764346713171344,0.3397555043175682 0.6800189868659366,0.3412270173257851 0.6838308780051404,0.3409817651577296 0.6817258037939384,0.34400654189686786 0.678767321118738,0.3461320606864887 0.6774587614739365,0.34964734176167994 0.6754674750579353,0.3527538692234647 0.6733624008467333,0.35577864596254494 0.6696642975027303,0.3556151445171939 0.6663075575443296,0.35398013006362605 0.6626663480979295,0.3545523851223836 0.6598785471155277,0.35700490680276437 0.6576027912115271,0.3598661820964936 0.6592527142419259,0.3632179617263339 0.658683775265927,0.3668967442468762 0.6565787010547249,0.3699215209859564 0.655554610897928,0.37351855278379403 0.6580010484947273,0.37629807735487686 0.6572614278259298,0.37989510915277264 0.6594233959347295,0.38300163661455744 0.6608457433747269,0.3863534162443396 0.6636335443571286,0.3888876886473669 0.6673316477011316,0.3892146915381269 0.6706314937619344,0.3908497059916948 0.6719969473043338,0.3942832363441815 0.6756950506483369,0.3942832363441815 0.6789948967091346,0.3959182507977494 0.6813844404083361,0.39877952609147865 0.685082543752339,0.3984525232007767 0.6886668593011412,0.39755326525131723 0.6923649626451444,0.39722626236061526 0.6948114002419437,0.4000875376543445 0.6977129890195461,0.4023765578893744 0.7014110923635442,0.40286706222542734 0.7051091957075472,0.4029488129481319 0.7060194980691484,0.39935178115023606 0.7067022248403481,0.39567299862969385 0.7091486624371475,0.39297522478131564 0.7122778268051516,0.39093145671434126 0.7137570681427517,0.38757967708455904 0.7152932033779499,0.38422789745471875 0.718934412824355,0.38406439600936776 0.7225756222707551,0.3834921409506103 0.7259892561267536,0.38193887721968894 0.7286632693139545,0.3794046048166616 0.7302562984467555,0.37605282518687944 0.7325889482483592,0.37319154989309206 0.7357750065139611,0.3712295325488223 0.7380507624179619,0.36836825725509303 0.7416919718643619,0.3691857644818479 0.7451624996179633,0.3705755267673603 0.7484054517811631,0.37221054122098624 0.7518190856371667,0.373682054229145 0.7555171889811698,0.37417255856525605 0.7592152923251677,0.37458131217866253 0.7625720322835734,0.3730280484477411 0.7644495309043738,0.3698397702632518 0.7672373318867706,0.36738724858292904 0.7697406633811728,0.36460772401184627 0.7730974033395734,0.3629727095582784 0.7764541432979791,0.36150119655006147 0.7798677771539776,0.36002968354184456 0.7827124720339772,0.3577406633068728 0.7851589096307816,0.35487938801308544 0.783907243883578,0.35144585766059877 0.7822004269555812,0.34817582875346303 0.7803798222323787,0.3449057998463273 0.7783316419187796,0.341881023107189 0.7762265677075776,0.33877449564540424 0.7741783873939734,0.335749718906324 0.7717319497971741,0.3330519450579457 0.7695130877907762,0.3300271683188074 0.7670666501939719,0.32724764374772464 0.764392637006771,0.3247133713446973 0.7624582444883726,0.3215250931602661 0.7598411251987696,0.3189090700345343 0.7562568096499673,0.3178463106397239 0.7529000696915666,0.31629304690880244 0.7503398442995666,0.31367702378307066 0.747438255521964,0.3114697542707453 0.744252197256362,0.30958948764918 0.7420902291475622,0.30656471091004167 0.7419764413523613,0.3028859283894995 0.7447642423347631,0.30043340670917673 0.7473813616243662,0.2978173835834449 0.7497140114259647,0.2948743575670111 0.7525587063059643,0.29258533733203934 0.7551758255955674,0.289887563483603 0.7576222631923667,0.28710803891257825 0.7600118068915682,0.28424676361879087 0.7617755177171729,0.2809767347116552 0.7649046820851719,0.2789329666446808 0.7687734671219736,0.2781154594179259 0.7686027854291749,0.27427317545203267 0.769114830507576,0.27059439293149046 0.7724715704659767,0.26912287992327355 0.7756576287315786,0.26658860752024627 0.777592021249977,0.2633185786131106 0.7804936100275794,0.26094780765543424 0.7827693659315802,0.25767777874824044 0.7836227743955786,0.2539172455050518 0.7827124720339772,0.24999321081645404 0.7837934560883772,0.24623267757326536 0.7843055011667782,0.24255389505272312 0.7848744401427822,0.23879336180953445 0.7841917133715774,0.23503282856628768 0.7835089866003777,0.23127229532309904 0.7831676232147804,0.2275935128025568 0.7868657265587834,0.22685775629844837 0.786524363173181,0.22317897377790613 0.7868657265587834,0.21941844053465936 0.7886294373843831,0.21614841162752363 0.7906776176979822,0.21304188416573885 0.7914172383667848,0.20936310164519664 0.793408524782786,0.2062565741834119 0.7952860234035866,0.20306829599898066 0.7980738243859831,0.20053402359595338 0.8004633680851847,0.19767274830216605 0.8024546545011859,0.19448447011773484 0.8055269249715871,0.1924407020507605 0.8079733625683915,0.18933417458897572 0.8110456330387926,0.18729040652200138 0.8143454790995904,0.1856553920684335 0.8181004763411963,0.18557364134572896 0.8216278979923956,0.18688165290859488 0.8252122135411978,0.18573714279113804 0.8261225159027992,0.18214011099324226 0.8293085741683961,0.18025984437161888 0.8330066775123991,0.17976934003556594 0.8363065235732018,0.18148610521183833 0.837785764910802,0.1848378848416205 0.8392650062484022,0.18827141519416532 0.8415407621524029,0.18532838917773156 0.8419390194356031,0.18156785593448477 0.8430200034900031,0.17797082413664708 0.8456371227796061,0.18066859798502535 0.8466612129364032,0.18426562978292113 0.8483111359668071,0.18091385015308087 0.8485387115572087,0.17723506763253866 0.8482542420692042,0.17347453438934998 0.8463767434484036,0.17028625620486068 0.8471732580148043,0.166689224407023 0.8480835603764055,0.16301044188648076 0.8480266664788076,0.15933165936593852 0.8483680298644051,0.15557112612269178 0.8453526532916068,0.15344560733307094 0.848880074942806,0.15213759577020505 0.8485387115572087,0.1484588132496628 0.848424923762008,0.14469828000647417 0.8492783322260062,0.1411012482085784 0.8455802288820032,0.14101949748593193 0.8419959133332061,0.14191875543539134 0.8385253855796047,0.1431450162755527 0.8357944784948007,0.140528993149879 0.832494632433998,0.1388122279736066 0.8287965290900001,0.1386487265282556 0.827146606059596,0.1420005061580959 0.8247001684627968,0.14469828000647417 0.8210589590163967,0.14551578723322905 0.8179866885459955,0.1475595553002034 0.8142316913043947,0.14764130602290793 0.8105904818579894,0.14829531180431182 0.8068923785139915,0.1487858161403648 0.8033649568627871,0.15001207698058425 0.7996668535187842,0.1502573291485817 0.7996099596211863,0.146496795905393 0.7962532196627857,0.14813181035896086 0.798187612181184,0.1449435321744716 0.7949446600179841,0.14322676699825726 0.7943757210419852,0.1394662337550105 0.7913603444691819,0.14167350326733585 0.7888001190771817,0.1443712771157722 0.7852158035283795,0.14518878434252708 0.7814608062867786,0.14543403651058262 0.7785023236115782,0.14764130602290793 0.7748611141651781,0.1484588132496628 0.771788843694777,0.15066608276198817 0.7682614220435726,0.15172884215679858 0.7646202125971725,0.15270985082896252 0.7609790031507725,0.1535273580557755 0.7576791570899696,0.15508062178663884 0.758589459451571,0.15148358998880113 0.7557447645715664,0.1539361116691239 0.7525587063059643,0.15573462756804274 0.7499415870163664,0.1584324014164791 0.7485761334739669,0.1618659317689658 0.7472675738291653,0.16538121284415708 0.7465848470579657,0.16897824464199476 0.7449349240275618,0.1722482735491305 0.7412937145811617,0.17322928222129444 0.7376525051347615,0.1739650387254029 0.7339544017907585,0.17445554306145583 0.7312803886035576,0.17698981546448314 0.7288339510067582,0.17976934003556594 0.7254772110483576,0.18148610521183833 0.7223480466803535,0.18352987327881268 0.7193326701075553,0.18581889351378447 0.7162035057395512,0.1877809108580543 0.7137570681427517,0.19072393687448808 0.7115382061363489,0.19366696289092186 0.708352147870747,0.19562898023519168 0.7055074529907474,0.19808150191557253 0.7022076069299447,0.19979826709184492 0.6994766998451458,0.19726399468881764 0.6974285195315417,0.19423921794967933 0.6937873100851415,0.19366696289092186 0.6913408724883422,0.19080568759719263 0.6884392837107397,0.19317645855486892 0.6851394376499369,0.1948114730084368 0.6822947427699373,0.1924407020507605 0.6786535333235372,0.1916231948239475 0.6749554299795343,0.19178669626929848 0.6715417961235357,0.1933399600002199 0.6692091463219321,0.19620123529394914 0.6671040721107301,0.19930776275573392 0.6644300589235291,0.2018420351588193 0.6634059687667322,0.20543906695665698 0.6613008945555301,0.20846384369573723 0.6582286240851289,0.2105893624854161 0.6548718841267283,0.21214262621627944 0.6512306746803231,0.2127148812750369 0.6475325713363251,0.21345063777914536 0.6441189374803216,0.2148404000646577 0.6405346219315193,0.21598491018217264 0.6371778819731186,0.21761992463574054 0.6337642481171152,0.21917318836666197 0.6304644020563174,0.22088995354287627 0.6272783437907155,0.2229337216098506 0.6244336489107158,0.22530449256752694 0.6215889540307112,0.22783876497055422 0.6189149408435103,0.2303730373736396 0.6157857764755112,0.23110879387774805 ================================================ FILE: demo/src/main/assets/tracks/track2.txt ================================================ 0.5442701471922805,0.22415998245007007 0.5441563593970797,0.22415998245007007 0.5443839349874813,0.22407823172736555 0.5443839349874813,0.223996481004661 0.5442132532946826,0.22391473028201458 0.5443839349874813,0.22407823172736555 0.5443270410898784,0.22424173317271653 0.5441563593970797,0.22415998245007007 0.5443270410898784,0.2244052346180675 0.5441563593970797,0.22456873606341848 0.5442132532946826,0.22456873606341848 0.5442132532946826,0.22448698534077202 0.544042571601879,0.2243234838954211 0.543530526523478,0.2244052346180675 0.5431322692402777,0.2243234838954211 0.542961587547479,0.22407823172736555 0.5429046936498813,0.223996481004661 0.5420512851858778,0.2226884694418532 0.5419943912882799,0.22260671871914864 0.5415392401074818,0.2222797158284467 0.5409703011314778,0.22170746076968925 0.5409134072338799,0.2216257100469847 0.5401737865650773,0.2212169564336363 0.5398893170770779,0.2212169564336363 0.5400599987698765,0.22129870715628275 0.5400599987698765,0.2213804578789873 0.5401737865650773,0.2212169564336363 0.5399462109746808,0.22088995354287627 0.5396617414866762,0.22064470137487885 0.539263484203481,0.2205629506521743 0.5392065903058781,0.22048119992952786 0.5388083330226778,0.22015419703876782 0.5378980306610767,0.2199089448707704 0.5377842428658759,0.21982719414806587 0.5364756832210794,0.2193366898120129 0.5364187893234764,0.2193366898120129 0.5352809113714786,0.21884618547595996 0.5352809113714786,0.21892793619860643 0.5351102296786748,0.21876443475325547 0.535053335781077,0.21860093330790448 0.5349395479858762,0.21770167535844506 0.5349395479858762,0.21761992463574054 0.5347688662930775,0.21721117102239212 0.534541290702676,0.21688416813163208 0.5342568212146765,0.2163119130728746 0.5342568212146765,0.21623016235022818 0.5336878822386776,0.21492215078736224 0.5336309883410747,0.2148404000646577 0.5333465188530752,0.21451339717395576 0.5328913676722771,0.21353238850184988 0.5328344737746742,0.21345063777914536 0.5327775798770763,0.21320538561108984 0.5324931103890769,0.2128783827203879 0.5324931103890769,0.21263313055239044 0.5323224286962782,0.21255137982968594 0.5321517470034745,0.21214262621627944 0.5320948531058766,0.212060875493633 0.5317534897202741,0.21157037115752197 0.5313552324370739,0.21116161754417356 0.5311845507442753,0.21132511898952455 0.5311845507442753,0.21132511898952455 0.530843187358673,0.21132511898952455 0.5307293995634772,0.211406869712171 0.5303880361778749,0.212060875493633 0.530331142280277,0.21214262621627944 0.5301035666898753,0.2128783827203879 0.5296484155090723,0.2133688870564989 0.5295915216114744,0.21345063777914536 0.5293070521234748,0.21385939139255183 0.5290225826354754,0.21418639428325378 0.5288519009426768,0.2144316464513093 0.5287950070450739,0.2145951478966603 0.528738113147476,0.21467689861930675 0.5289087948402746,0.21492215078736224 0.5288519009426768,0.21508565223271323 0.5289087948402746,0.21533090440076874 0.5286243253522752,0.21582140873682168 0.5286243253522752,0.21598491018217264 0.5286243253522752,0.21623016235022818 0.5285105375570743,0.2167206666862811 0.5281122802738741,0.21721117102239212 0.5280553863762762,0.21729292174503856 0.5279415985810755,0.21761992463574054 0.5275433412978752,0.21851918258519992 0.5274864474002723,0.21860093330790448 0.5268606145266755,0.21950019125736392 0.5267468267314747,0.21982719414806587 0.5266899328338718,0.2199089448707704 0.526576145038671,0.22015419703876782 0.5262347816530737,0.2205629506521743 0.526064099960275,0.2209717042655808 0.5259503121650742,0.2210534549882853 0.526007206062672,0.2212169564336363 0.5259503121650742,0.2212169564336363 0.5257796304722705,0.22170746076968925 0.5254951609842711,0.2218709622150402 0.5251537975986738,0.22195271293774474 0.5249262220082722,0.22219796510574216 0.5248693281106743,0.22219796510574216 0.5244710708274741,0.22260671871914864 0.5243003891346704,0.22260671871914864 0.52390213185147,0.2229337216098506 0.5237883440562744,0.2229337216098506 0.5227073600018693,0.2237512288366636 0.5225935722066736,0.22383297955931003 0.5221953149234734,0.223996481004661 0.5220246332306696,0.223996481004661 0.5212850125618721,0.22424173317271653 0.5211712247666712,0.22424173317271653 0.5208867552786718,0.2243234838954211 0.520204028507472,0.22407823172736555 0.5198057712242719,0.22415998245007007 0.519748877326669,0.22415998245007007 0.5193506200434688,0.22424173317271653 0.5188954688626706,0.22407823172736555 0.5184403176818725,0.22407823172736555 0.5183834237842696,0.22407823172736555 0.5178144848082706,0.22424173317271653 0.5170179702418701,0.22407823172736555 0.5169041824466694,0.22415998245007007 0.5166766068562677,0.2243234838954211 0.5154249411090691,0.2243234838954211 0.5153111533138683,0.22424173317271653 0.5142301692594684,0.2244052346180675 0.513945699771469,0.2243234838954211 0.5138319119762681,0.2243234838954211 0.5131491852050685,0.22407823172736555 0.5125233523314666,0.22407823172736555 0.5124664584338688,0.22407823172736555 0.5122388828434672,0.22415998245007007 0.5114423682770667,0.22407823172736555 0.5112147926866651,0.22415998245007007 0.5111010048914694,0.22424173317271653 0.5101907025298681,0.2243234838954211 0.5098493391442657,0.2244052346180675 0.5097924452466678,0.22448698534077202 0.5090528245778652,0.22424173317271653 0.5085407794994641,0.2244052346180675 0.5084838856018662,0.2244052346180675 0.5074597954450643,0.22456873606341848 0.5074029015474664,0.22465048678612304 0.5073460076498635,0.22473223750876944 0.5071753259570648,0.224977489676825 0.507061538161864,0.22489573895417853 0.5067770686738645,0.22448698534077202 0.5063219174930664,0.2244052346180675 0.5062081296978657,0.2244052346180675 0.5047857822578633,0.22415998245007007 0.5047288883602654,0.22407823172736555 0.5043306310770651,0.22391473028201458 0.5039323737938649,0.2244052346180675 0.5039323737938649,0.22415998245007007 0.5041030554866636,0.22407823172736555 0.5042168432818643,0.22383297955931003 0.5041599493842664,0.22391473028201458 0.5042168432818643,0.22383297955931003 0.5042737371794622,0.22407823172736555 0.5042168432818643,0.22415998245007007 0.504444418872266,0.22415998245007007 0.504387524974663,0.2243234838954211 0.5042168432818643,0.22424173317271653 0.5037616921010662,0.22424173317271653 0.5037047982034633,0.2243234838954211 0.5033065409202631,0.22456873606341848 0.5028513897394649,0.22522274184488048 0.502794495841862,0.22530449256752694 0.5019410873778637,0.22587674762628437 0.5018272995826629,0.22620375051698632 0.5018272995826629,0.22636725196233734 0.5016566178898643,0.22653075340774637 0.5013152545042618,0.22669425485309738 0.5010307850162624,0.22702125774379933 0.5008601033234638,0.22718475918915032 0.5008601033234638,0.2274300113572058 0.5008032094258609,0.22751176207985227 0.4997222253714609,0.22816576786131426 0.4996084375762601,0.22824751858396072 0.4993808619858635,0.22832926930666525 0.4992101802930598,0.22832926930666525 0.4989257108050604,0.22800226641596327 0.49829987793146363,0.22816576786131426 0.49824298403386064,0.22824751858396072 0.4979585145458612,0.22832926930666525 0.4979016206482633,0.22824751858396072 0.49773093895545967,0.22783876497055422 0.4976171511602639,0.22775701424790776 0.49744646946746013,0.2275935128025568 0.4972188938770637,0.22767526352520323 0.4971619999794607,0.22767526352520323 0.4968775304914613,0.22783876497055422 0.4965361671058589,0.22792051569325877 0.4961948037202616,0.22816576786131426 0.4957396525394584,0.22824751858396072 0.49562586474426273,0.22832926930666525 0.4942604112018582,0.2284927707520162 0.4942035173042604,0.22841102002931168 0.4936914722258593,0.22832926930666525 0.49289495765945884,0.2284927707520162 0.4927811698642581,0.2284927707520162 0.4913019285266578,0.22832926930666525 0.49124503462905994,0.22832926930666525 0.49056230785786026,0.22857452147466267 0.4900502627794592,0.22881977364271816 0.4899933688818563,0.22890152436542271 0.48891238482745636,0.22988253303752856 0.48885549092985847,0.22988253303752856 0.4886279153394568,0.2301277852055841 0.48817276415865873,0.23127229532309904 0.48811587026105585,0.23127229532309904 0.4878882946706593,0.23192630110450294 0.4878882946706593,0.23225330399520489 0.4877176129778556,0.2326620576086114 0.4876038251826548,0.23274380833131592 0.4872624617970575,0.2330708112220179 0.4872055678994596,0.23339781411271984 0.48669352282105854,0.23380656772612632 0.48663662892345566,0.23380656772612632 0.4864090533330591,0.23397006917147728 0.4856125387666586,0.23413357061682827 0.48538496317625707,0.23429707206217923 0.48527117538105624,0.23429707206217923 0.484872918097856,0.23437882278488378 0.4845315547122536,0.2347875763982322 0.4841332974290534,0.23495107784364128 0.48407640353145553,0.23503282856628768 0.4837350401458582,0.23535983145698963 0.48322299506745714,0.23560508362504518 0.4829385255794577,0.23593208651574712 0.48282473778425683,0.23593208651574712 0.4818575415250527,0.23601383723845165 0.4815161781394554,0.23625908940644907 0.4814023903442545,0.23634084012915363 0.4807196635730549,0.23683134446520654 0.48083345136825567,0.23691309518791107 0.4807765574706527,0.23707659663326205 0.480605875777854,0.23724009807861302 0.48054898188025624,0.23732184880131757 0.47958178562105197,0.23756710096931496 0.4791835283378517,0.2378123531373705 0.4791266344402539,0.2378123531373705 0.47861458936185286,0.238057605305426 0.4781594381810548,0.23838460819612795 0.47787496869305524,0.23838460819612795 0.47781807479545235,0.2384663589187744 0.4770784541266547,0.2386298603641254 0.47645262125305293,0.23838460819612795 0.4763957273554551,0.23830285747342342 0.4756561066866524,0.23838460819612795 0.47514406160825146,0.23871161108682992 0.47514406160825146,0.23871161108682992 0.47520095550585434,0.23895686325488544 0.4748595921202519,0.23903861397753187 0.4741768653490523,0.23961086903628934 0.4740630775538514,0.2396926197589939 0.4736079263730533,0.23985612120434485 0.4725838362162512,0.24001962264969584 0.47252694231865344,0.24001962264969584 0.472185578933051,0.23985612120434485 0.47207179113785025,0.23993787192699131 0.47201489724025236,0.2401013733723423 0.47207179113785025,0.24051012698574875 0.4722993667282518,0.24051012698574875 0.47241315452345256,0.24051012698574875 0.47286830570425076,0.2407553791538043 0.47326656298745096,0.2414093849352082 0.47326656298745096,0.24157288638055918 0.4733803507826517,0.2424721443300186 0.47349413857785255,0.24296264866612963 0.47349413857785255,0.24296264866612963 0.47349413857785255,0.24361665444753353 0.4733803507826517,0.24378015589288451 0.47286830570425076,0.24402540806094003 0.47286830570425076,0.24410715878364456 0.47252694231865344,0.24467941384234393 0.47241315452345256,0.24541517034645238 0.4723562606258497,0.2454969210691569 0.4719011094450516,0.2459056746825634 0.4717873216498507,0.24606917612791437 0.47173042775225293,0.24639617901861632 0.4715028521618513,0.24647792974132085 0.4715028521618513,0.2465596804639673 0.4717873216498507,0.2468049326320228 0.4715028521618513,0.24705018480002025 0.47121838267385185,0.2472136862454293 0.47099080708345026,0.2473771876907803 0.4709339131858524,0.24745893841342675 0.47070633759545083,0.24754068913613125 0.47019429251704975,0.24754068913613125 0.4700236108242511,0.24762243985877772 0.46973914133625166,0.24794944274953776 0.4696822474386488,0.2480311934721842 0.4695684596434479,0.2482764456402397 0.46934088405305147,0.24852169780823716 0.4692270962578506,0.2488487006989972 0.4690564145650519,0.24901220214434816 0.46899952066744904,0.24925745431234558 0.46899952066744904,0.2493392050350501 0.46865815728185173,0.24966620792575206 0.4683167938962493,0.24974795864845659 0.46820300610104854,0.24982970937110305 0.4680323244082499,0.2502384629845096 0.4680323244082499,0.2503202137072141 0.46797543051064694,0.2505654658752115 0.4676340671250496,0.25130122237931996 0.46752027932984885,0.25154647454737544 0.46752027932984885,0.25154647454737544 0.4672927037394473,0.25170997599272643 0.46672376476344835,0.25154647454737544 0.4660979318898465,0.25146472382467094 0.4659841440946507,0.25146472382467094 0.46507384173304944,0.250974219488618 0.46478937224505,0.250974219488618 0.46467558444984924,0.250974219488618 0.46404975157624745,0.2508924687659134 0.4634239187026456,0.25146472382467094 0.4633670248050477,0.25154647454737544 0.46319634311224905,0.25170997599272643 0.4630825553170483,0.25236398177413033 0.4629118736242445,0.25252748321953944 0.462684298033848,0.2524457324968349 0.462684298033848,0.25236398177413033 0.462684298033848,0.2522004803287794 0.46274119193144586,0.2519552281607819 0.46285497972664663,0.2518734774380774 0.4630256614194453,0.251791726715431 0.46331013090744483,0.2521187296061329 0.46325323700984694,0.2519552281607819 0.4633670248050477,0.25170997599272643 0.4633670248050477,0.2516282252700219 0.4634808126002485,0.2508924687659134 0.4638221759858458,0.2502384629845096 0.4638790698834488,0.250156712261805 0.4641635393714482,0.24974795864845659 0.4648462661426479,0.24942095575775464 0.46467558444984924,0.24925745431234558 0.4646186905522463,0.24917570358969915 0.4642204332690461,0.24917570358969915 0.4643342210642469,0.24925745431234558 0.4645617966546484,0.24893045142164363 0.46501694783544656,0.24876694997629265 0.46507384173304944,0.24876694997629265 0.465301417323446,0.24868519925364618 0.4654152051186468,0.24852169780823716 0.46547209901624975,0.24835819636288614 0.4655858868114505,0.2481946949175352 0.4656996746066463,0.2478676920268332 0.46581346240184707,0.24762243985877772 0.46587035629944995,0.24762243985877772 0.4659841440946507,0.24713193552272478 0.4659841440946507,0.24696843407737382 0.4659841440946507,0.2467231819093183 0.46621171968504727,0.24623267757326536 0.46626861358265026,0.2461509268505608 0.4663824013778459,0.24566042251450787 0.4663824013778459,0.24533341962380592 0.46678065866104623,0.24492466601039942 0.46678065866104623,0.24492466601039942 0.46695134035385,0.24467941384234393 0.46706512814905077,0.24435241095164198 0.4673495976370502,0.24410715878364456 0.46746338543225097,0.24386190661558904 0.46752027932984885,0.24378015589288451 0.4674064915346481,0.24361665444753353 0.4673495976370502,0.24345315300218254 0.4664392952754489,0.24386190661558904 0.4663824013778459,0.24386190661558904 0.46552899291384764,0.24410715878364456 0.465301417323446,0.2444341616743465 0.46507384173304944,0.24459766311969747 0.46501694783544656,0.24467941384234393 0.4649031600402458,0.24508816745575043 0.4643342210642469,0.2459056746825634 0.4642204332690461,0.2459056746825634 0.4637652820882479,0.24606917612791437 0.4633670248050477,0.2461509268505608 0.46285497972664663,0.24582392395985886 0.46279808582904874,0.24582392395985886 0.4623429346482456,0.24566042251450787 0.4620015712626483,0.24516991817845496 0.46177399567224675,0.24508816745575043 0.4616033139794481,0.24541517034645238 0.46148952618424727,0.2454969210691569 0.46103437500344413,0.24582392395985886 0.46097748110584624,0.24623267757326536 0.4606361177202438,0.2465596804639673 0.46052232992504816,0.24664143118667187 0.4606361177202438,0.24688668335466926 0.46057922382264593,0.24705018480002025 0.4607499055154446,0.24745893841342675 0.4604085421298473,0.24794944274953776 0.4603516482322444,0.2480311934721842 0.4599533909490441,0.24811294419488875 0.4595551336658439,0.24835819636288614 0.4593844519730452,0.2488487006989972 0.45932755807544734,0.2488487006989972 0.45915687638264363,0.2490939528669946 0.45824657402104746,0.24966620792575206 0.45824657402104746,0.24974795864845659 0.4575638472498426,0.2503202137072141 0.4572793777618432,0.250647216597916 0.4572224838642453,0.2507289673205625 0.456881120478643,0.2513829731020245 0.45671043878584433,0.25154647454737544 0.45665354488824644,0.2519552281607819 0.45665354488824644,0.25203697888342835 0.45636907540024196,0.2524457324968349 0.45642596929784485,0.2530997382782388 0.4563121815026441,0.25334499044629427 0.4562552876050462,0.2534267411689988 0.4560277120146446,0.25350849189164526 0.4557432425266451,0.2539172455050518 0.45511740965304337,0.2539989962276982 0.45511740965304337,0.2539989962276982 0.4548898340626417,0.2539172455050518 0.45471915236984306,0.2539172455050518 0.4546053645746423,0.2539989962276982 0.4540364255986433,0.2541624976731073 0.4537519561106439,0.2540807469504027 0.453695062213041,0.2540807469504027 0.45346748662264447,0.2540807469504027 0.45329680492984076,0.25457125128645564 0.452670972056244,0.2548165034545112 0.452614078158641,0.2548165034545112 0.4519882452850443,0.25514350634521316 0.45170377579704485,0.2554705092359151 0.4514762002066432,0.2554705092359151 0.4514193063090403,0.2553887585132687 0.4509641551282421,0.2554705092359151 0.45045211004984115,0.2557975121266751 0.4502814283570425,0.2557975121266751 0.45016764056184166,0.2557975121266751 0.44976938327864147,0.2559610135720261 0.4492573382002404,0.2557157614039706 0.4488590809170402,0.2557157614039706 0.4488021870194423,0.2557975121266751 0.44811946024824256,0.2559610135720261 0.4482901419410412,0.25604276429467254 0.44868839922424153,0.2558792628493216 0.44891597481464307,0.2558792628493216 0.44897286871224096,0.2558792628493216 0.44937112599544116,0.2554705092359151 0.4497124893810436,0.2547347527318067 0.44982627717623935,0.2547347527318067 0.45011074666424383,0.25448950056380926 0.4507365795378406,0.25375374405970075 0.45079347343544346,0.2536719933369963 0.4514193063090403,0.2526092339421858 0.4514762002066432,0.2524457324968349 0.4515330941042411,0.2519552281607819 0.45164688189944185,0.251791726715431 0.4518175635922405,0.2516282252700219 0.4522158208754408,0.25146472382467094 0.4523296086706416,0.25130122237931996 0.4523865025682445,0.25121947165667347 0.45250029036344025,0.250974219488618 0.4523296086706416,0.250647216597916 0.45244339646584236,0.2502384629845096 0.4523865025682445,0.25007496153915854 0.45244339646584236,0.24982970937110305 0.45244339646584236,0.24974795864845659 0.45215892697784293,0.24925745431234558 0.45204513918264216,0.24868519925364618 0.45204513918264216,0.24835819636288614 0.4519882452850443,0.2482764456402397 0.45204513918264216,0.2480311934721842 0.4519313513874413,0.24770419058148224 0.4519882452850443,0.2473771876907803 0.4519882452850443,0.2472136862454293 0.45210203308024505,0.24696843407737382 0.45215892697784293,0.24688668335466926 0.4522727147730437,0.24664143118667187 0.452614078158641,0.24623267757326536 0.45295544154424344,0.24574217323721242 0.45301233544184133,0.24566042251450787 0.45341059272504153,0.24557867179186146 0.4535243805202423,0.2454969210691569 0.4536381683154431,0.24508816745575043 0.4536381683154431,0.24467941384234393 0.45358127441784524,0.24459766311969747 0.4535243805202423,0.24435241095164198 0.45329680492984076,0.2431261501114806 0.45329680492984076,0.2431261501114806 0.45284165374904267,0.24271739649807408 0.452670972056244,0.24198163999396566 0.452670972056244,0.24189988927131922 0.452614078158641,0.24157288638055918 0.452670972056244,0.24083712987645073 0.4527847598514448,0.24067362843109974 0.4527278659538418,0.24042837626310234 0.4527278659538418,0.24042837626310234 0.4527847598514448,0.23993787192699131 0.45295544154424344,0.2396926197589939 0.4530692293394442,0.2391203647002364 0.4531261232370421,0.23903861397753187 0.4531261232370421,0.23895686325488544 0.4530692293394442,0.23879336180953445 0.4531261232370421,0.2386298603641254 0.4530692293394442,0.23830285747342342 0.45323991103224287,0.23789410386001697 0.45323991103224287,0.23756710096931496 0.45323991103224287,0.23748535024666856 0.453183017134645,0.2371583473559666 0.45329680492984076,0.23699484591055753 0.4535243805202423,0.2367495937425601 0.4536381683154431,0.23609558796109809 0.4536381683154431,0.23609558796109809 0.4536381683154431,0.23576858507039614 0.4535243805202423,0.2356868343477497 0.45329680492984076,0.2356868343477497 0.45301233544184133,0.23593208651574712 0.45284165374904267,0.23601383723845165 0.45284165374904267,0.23625908940644907 0.4527847598514448,0.23634084012915363 0.452614078158641,0.23650434157450456 0.4522158208754408,0.23666784301985558 0.45170377579704485,0.23732184880131757 0.45164688189944185,0.237403599523964 0.45130551851384454,0.23773060241466595 0.451077942923443,0.23813935602807246 0.451077942923443,0.23830285747342342 0.45102104902584006,0.2384663589187744 0.45090726123064434,0.23854810964147896 0.45085036733304135,0.23854810964147896 0.4506227917426398,0.23871161108682992 0.45045211004984115,0.2391203647002364 0.4497124893810436,0.2391203647002364 0.4495987015858428,0.2391203647002364 0.4492573382002404,0.23944736759093835 0.44902976260983885,0.2401013733723423 0.4488021870194423,0.2403466255403978 0.4488021870194423,0.2403466255403978 0.44817635414584045,0.24100063132185978 0.44811946024824256,0.24116413276721077 0.44794877855543885,0.24116413276721077 0.44783499076024313,0.2414093849352082 0.44783499076024313,0.24149113565791275 0.4477780968626402,0.24165463710326368 0.44760741516984154,0.2418181385486147 0.4470953700914405,0.24206339071667018 0.44681090060344103,0.24239039360737213 0.44675400670583815,0.2424721443300186 0.4465833250130395,0.24271739649807408 0.4461281738322413,0.24296264866612963 0.4460712799346384,0.24328965155683158 0.4460712799346384,0.24361665444753353 0.4460712799346384,0.24361665444753353 0.4460143860370405,0.24410715878364456 0.44590059824183975,0.2444341616743465 0.44544544706104167,0.24476116456504846 0.44538855316343867,0.244842915287753 0.4453316592658408,0.24508816745575043 0.44504718977784136,0.24533341962380592 0.444705826392239,0.24541517034645238 0.4443075691090388,0.24533341962380592 0.444193781313838,0.24533341962380592 0.44322658505463886,0.24516991817845496 0.4430559033618402,0.24525166890110142 0.443112797259438,0.2454969210691569 0.44316969115704097,0.2454969210691569 0.44316969115704097,0.24533341962380592 0.4426576460786399,0.24500641673310397 0.4420318132050381,0.24492466601039942 0.4419749193074402,0.24492466601039942 0.4411215108434368,0.24476116456504846 0.4407801474578395,0.24500641673310397 0.44055257186743785,0.24508816745575043 0.44049567796984007,0.24508816745575043 0.44009742068663976,0.24492466601039942 0.4391871183250385,0.24533341962380592 0.43913022442743554,0.24541517034645238 0.4388457549394361,0.24541517034645238 0.43873196714423535,0.24557867179186146 0.43782166478263906,0.24566042251450787 0.4377078769874383,0.24566042251450787 0.43736651360183587,0.24582392395985886 0.43702515021623856,0.2459056746825634 0.4367406807282341,0.24606917612791437 0.4364562112402346,0.2461509268505608 0.4363993173426367,0.24623267757326536 0.4360579539570344,0.24631442829591182 0.4350907576978352,0.24631442829591182 0.4349769699026344,0.24631442829591182 0.4345787126194342,0.24647792974132085 0.43361151636023504,0.2468049326320228 0.43355462246263715,0.2468049326320228 0.43292878958903536,0.2468049326320228 0.43213227502263485,0.24705018480002025 0.43207538112503185,0.24705018480002025 0.43133576045623434,0.2473771876907803 0.43122197266103357,0.24754068913613125 0.4311650787634357,0.24770419058148224 0.4309943970706319,0.2478676920268332 0.43093750317303403,0.24794944274953776 0.43053924588983383,0.2480311934721842 0.43042545809463306,0.2481946949175352 0.4302547764018344,0.2482764456402397 0.4301409886066336,0.24852169780823716 0.42979962522103127,0.24868519925364618 0.4297427313234334,0.24876694997629265 0.4296289435282326,0.24893045142164363 0.4292875801426353,0.24917570358969915 0.428889322859435,0.24917570358969915 0.42854795947383256,0.2495027064804011 0.4284910655762348,0.2495027064804011 0.4280928082930345,0.24966620792575206 0.4277514449074321,0.24991146009380757 0.42758076321463345,0.24991146009380757 0.42752386931703057,0.2504019644298605 0.4274100815218348,0.25048371515256507 0.4272393998290311,0.25048371515256507 0.4264997791602335,0.2504019644298605 0.42610152187703326,0.2502384629845096 0.42598773408183244,0.250156712261805 0.4258170523890338,0.250156712261805 0.42564637069623007,0.24999321081645404 0.4252481134130298,0.24991146009380757 0.4247360683346288,0.24999321081645404 0.4246791744370309,0.24999321081645404 0.4242240232562328,0.24991146009380757 0.4240533415634291,0.24974795864845659 0.4237119781778318,0.24974795864845659 0.42337061479222937,0.24958445720310563 0.42331372089463154,0.24958445720310563 0.42337061479222937,0.24974795864845659 0.4231999330994307,0.24982970937110305 0.4229154636114313,0.2495027064804011 0.4223465246354324,0.2493392050350501 0.42228963073782944,0.24925745431234558 0.42166379786422764,0.2490939528669946 0.42115175278583167,0.24876694997629265 0.42092417719543007,0.24876694997629265 0.4208672832978322,0.24876694997629265 0.42046902601463193,0.2488487006989972 0.41955872365303065,0.24860344853094166 0.41955872365303065,0.24860344853094166 0.41933114806262906,0.24868519925364618 0.4189897846770267,0.24876694997629265 0.41870531518902726,0.24852169780823716 0.4185346334962286,0.24852169780823716 0.4182501640082291,0.24868519925364618 0.4181932701106262,0.24868519925364618 0.41694160436342753,0.24835819636288614 0.4168847104658297,0.24835819636288614 0.4164295592850265,0.2480311934721842 0.41625887759222785,0.24811294419488875 0.4161450897970271,0.2482764456402397 0.4160313020018263,0.24868519925364618 0.4160313020018263,0.24868519925364618 0.4157468325138268,0.24942095575775464 0.41557615082102817,0.24999321081645404 0.41557615082102817,0.25007496153915854 0.41557615082102817,0.2503202137072141 0.4154054691282295,0.2504019644298605 0.41534857523062657,0.25105597021132253 0.4152347874354258,0.25130122237931996 0.4152347874354258,0.2513829731020245 0.4147227423570247,0.2519552281607819 0.4144382728690253,0.2524457324968349 0.4144382728690253,0.2526092339421858 0.4143813789714274,0.25301798755559235 0.41421069727862875,0.2530997382782388 0.4135848644050269,0.25350849189164526 0.41352797050742907,0.25350849189164526 0.413015925429028,0.25383549478234724 0.41284524373622433,0.2539989962276982 0.41273145594102856,0.25383549478234724 0.4122763047602254,0.25383549478234724 0.41221941086262753,0.2539172455050518 0.41199183527222594,0.25383549478234724 0.41187804747702517,0.2536719933369963 0.41165047188662357,0.25350849189164526 0.41096774511542383,0.25350849189164526 0.41096774511542383,0.25350849189164526 0.4097729732658231,0.25334499044629427 0.4097160793682253,0.2530997382782388 0.4096591854706274,0.25301798755559235 0.40994365495862684,0.2524457324968349 0.41028501834422415,0.2522004803287794 0.4103988061394249,0.2518734774380774 0.41045570003702786,0.2518734774380774 0.41074016952502734,0.25154647454737544 0.4107970634226252,0.250810718043267 0.41096774511542383,0.2505654658752115 0.41096774511542383,0.25048371515256507 0.4111384268082276,0.24999321081645404 0.41119532070582543,0.2493392050350501 0.41130910850102625,0.24917570358969915 0.4113660023986241,0.2490939528669946 0.41153668409142785,0.24893045142164363 0.4115935779890257,0.24876694997629265 0.4114797901938249,0.2484399470855907 0.41165047188662357,0.2477859413041287 0.41165047188662357,0.24770419058148224 0.41153668409142785,0.24754068913613125 0.4114797901938249,0.2472136862454293 0.41153668409142785,0.2465596804639673 0.41153668409142785,0.24631442829591182 0.4114797901938249,0.24623267757326536 0.4117073657842265,0.24557867179186146 0.4120487291698238,0.24508816745575043 0.41221941086262753,0.24492466601039942 0.41221941086262753,0.24492466601039942 0.4123900925554262,0.24467941384234393 0.412503880350627,0.24427066022899552 0.4123900925554262,0.24410715878364456 0.4126176681458278,0.24386190661558904 0.412503880350627,0.24410715878364456 0.4124469864530241,0.24410715878364456 0.4120487291698238,0.24451591239699297 0.4117073657842265,0.24467941384234393 0.41130910850102625,0.24492466601039942 0.4112522146034233,0.24500641673310397 0.41102463901302677,0.24516991817845496 0.4106832756274244,0.24525166890110142 0.4100005488562247,0.24574217323721242 0.40994365495862684,0.24574217323721242 0.4086919892114232,0.24647792974132085 0.4086350953138253,0.24647792974132085 0.40857820141622236,0.24631442829591182 0.4086350953138253,0.2461509268505608 0.4089195648018248,0.24574217323721242 0.40903335259702556,0.24533341962380592 0.40903335259702556,0.24533341962380592 0.40903335259702556,0.24508816745575043 0.4092040342898242,0.24459766311969747 0.4092040342898242,0.24435241095164198 0.40931782208502504,0.24394365733823548 0.40937471598262287,0.24386190661558904 0.40954539767542664,0.24369840517023808 0.4097729732658231,0.24296264866612963 0.4097729732658231,0.24255389505272312 0.4097729732658231,0.2424721443300186 0.40982986716342606,0.24222689216202117 0.41022812444662626,0.24206339071667018 0.41045570003702786,0.24157288638055918 0.41022812444662626,0.24157288638055918 0.4101712305490234,0.24165463710326368 0.4097160793682253,0.24206339071667018 0.4092040342898242,0.24230864288466764 0.4088626709042269,0.24230864288466764 0.40880577700662396,0.24222689216202117 0.4080661563378264,0.24255389505272312 0.4075541112594253,0.24296264866612963 0.4075541112594253,0.2430443993887761 0.4072696417714259,0.24328965155683158 0.40709896007862223,0.24337140227953613 0.4068713844882257,0.24328965155683158 0.40675759669302486,0.24345315300218254 0.40653002110262326,0.24345315300218254 0.40647312720502543,0.24361665444753353 0.405619718741022,0.244188909506291 0.40550593094582116,0.24435241095164198 0.4051076736626209,0.24451591239699297 0.4048232041746215,0.24476116456504846 0.40459562858422493,0.24516991817845496 0.40453873468662205,0.24525166890110142 0.40431115909622045,0.24541517034645238 0.4042542651986226,0.24566042251450787 0.404026689608221,0.24598742540520985 0.4035715384274229,0.24639617901861632 0.4035715384274229,0.24639617901861632 0.40317328114422263,0.24688668335466926 0.40294570555382103,0.24688668335466926 0.4028888116562232,0.24664143118667187 0.40300259945142397,0.24639617901861632 0.40305949334902186,0.24631442829591182 0.40328706893942345,0.24623267757326536 0.4034577506322221,0.2459056746825634 0.4034008567346242,0.24525166890110142 0.40351464452982505,0.24500641673310397 0.40351464452982505,0.24500641673310397 0.40351464452982505,0.24467941384234393 0.4034577506322221,0.24492466601039942 0.4034008567346242,0.24476116456504846 0.4034008567346242,0.244188909506291 0.40317328114422263,0.24435241095164198 0.40317328114422263,0.2444341616743465 0.40305949334902186,0.24467941384234393 0.4026612360658216,0.24500641673310397 0.40226297878262135,0.24557867179186146 0.40220608488502346,0.24557867179186146 0.40163714590901956,0.2459056746825634 0.40135267642102007,0.24639617901861632 0.40106820693302064,0.24647792974132085 0.40101131303542276,0.2465596804639673 0.40049926795702173,0.24688668335466926 0.4003285862642231,0.2468049326320228 0.4006699496498204,0.2465596804639673 0.40049926795702173,0.24631442829591182 0.40049926795702173,0.24623267757326536 0.40055616185461956,0.24582392395985886 0.4006699496498204,0.24598742540520985 0.40084063134261905,0.24606917612791437 0.40078373744502116,0.2459056746825634 0.40078373744502116,0.2454969210691569 0.40078373744502116,0.24541517034645238 0.40101131303542276,0.24476116456504846 0.4011251008306235,0.24402540806094003 0.4011251008306235,0.24394365733823548 0.4012957825234222,0.24345315300218254 0.4011819947282214,0.2431261501114806 0.40101131303542276,0.2431261501114806 0.40072684354742333,0.24345315300218254 0.4006699496498204,0.24353490372488706 0.3995320716978225,0.24451591239699297 0.3994751778002196,0.24451591239699297 0.3989631327218186,0.24492466601039942 0.3983941937458197,0.24500641673310397 0.3981666181554181,0.24492466601039942 0.3980528303602224,0.24492466601039942 0.3976545730770221,0.24508816745575043 0.3974838913842184,0.24516991817845496 0.3974269974866205,0.24541517034645238 0.39725631579382187,0.2454969210691569 0.3968580585106216,0.2454969210691569 0.3968011646130187,0.24557867179186146 0.39628911953461765,0.24631442829591182 0.3961753317394219,0.24664143118667187 0.3958908622514174,0.2467231819093183 0.3958339683538195,0.2468049326320228 0.3953219232754185,0.24696843407737382 0.3952081354802177,0.2465596804639673 0.3953219232754185,0.2461509268505608 0.3953219232754185,0.2459056746825634 0.3953219232754185,0.24582392395985886 0.39560639276341797,0.24541517034645238 0.39628911953461765,0.24492466601039942 0.3964029073298184,0.24476116456504846 0.3964029073298184,0.24476116456504846 0.3964029073298184,0.24467941384234393 0.396118437841819,0.24459766311969747 0.39600465004661817,0.24467941384234393 0.3958339683538195,0.24467941384234393 0.3955494988658201,0.24492466601039942 0.3952081354802177,0.24525166890110142 0.3952081354802177,0.24533341962380592 0.39480987819701746,0.24606917612791437 0.39446851481142015,0.2461509268505608 0.3943547270162193,0.24639617901861632 0.3942978331186164,0.24647792974132085 0.39344442465461804,0.24754068913613125 0.39338753075702015,0.24762243985877772 0.3933306368594172,0.24811294419488875 0.3931030612690207,0.2484399470855907 0.39287548567861913,0.24893045142164363 0.39281859178101625,0.24901220214434816 0.39247722839541893,0.24925745431234558 0.39224965280501733,0.24974795864845659 0.39190828941942,0.25007496153915854 0.39190828941942,0.250156712261805 0.39151003213621977,0.2505654658752115 0.39111177485301946,0.25130122237931996 0.39111177485301946,0.2513829731020245 0.3909979870578187,0.2516282252700219 0.3907704114674171,0.2518734774380774 0.3907704114674171,0.2521187296061329 0.3905428358770155,0.25236398177413033 0.3904290480818147,0.2526909846648904 0.3904290480818147,0.2526909846648904 0.3900876846962174,0.25326323972364784 0.3900307907986145,0.25301798755559235 0.3901445785938153,0.2529362368328878 0.3901445785938153,0.2526909846648904 0.3900307907986145,0.25252748321953944 0.3900307907986145,0.2524457324968349 0.389803215208218,0.2522822310514839 0.3894618518226156,0.2526909846648904 0.38894980674421453,0.2530997382782388 0.38889291284661665,0.2530997382782388 0.3884946555634164,0.2534267411689988 0.3882670799730148,0.2534267411689988 0.3884946555634164,0.2530997382782388 0.3884946555634164,0.2529362368328878 0.3884946555634164,0.25285448611024136 0.38843776166581856,0.2526092339421858 0.3885515494610143,0.2524457324968349 0.38843776166581856,0.2521187296061329 0.3885515494610143,0.251791726715431 0.3883808677682156,0.2516282252700219 0.38832397387061773,0.25170997599272643 0.38832397387061773,0.251791726715431 0.388153292177814,0.2522004803287794 0.3879257165874175,0.25252748321953944 0.3879257165874175,0.2526909846648904 0.38775503489461377,0.25285448611024136 0.3875274593042172,0.25285448611024136 0.3875274593042172,0.25285448611024136 0.38747056540661434,0.2526909846648904 0.38764124709941805,0.25252748321953944 0.38764124709941805,0.25236398177413033 0.3875843532018151,0.2522004803287794 0.38764124709941805,0.2519552281607819 0.3875843532018151,0.251791726715431 0.38775503489461377,0.25154647454737544 0.38775503489461377,0.25146472382467094 0.3879257165874175,0.25121947165667347 0.3879257165874175,0.250647216597916 0.3882670799730148,0.2504019644298605 0.3882670799730148,0.25007496153915854 0.3882670799730148,0.25007496153915854 0.38821018607541696,0.24982970937110305 0.38786882268981454,0.24999321081645404 0.38747056540661434,0.24999321081645404 0.38747056540661434,0.24958445720310563 0.38747056540661434,0.24958445720310563 0.3872998837138157,0.24893045142164363 0.3870723081234141,0.2488487006989972 0.38690162643061543,0.2488487006989972 0.3869585203282133,0.24925745431234558 0.3869585203282133,0.2493392050350501 0.38678783863541466,0.24974795864845659 0.38656026304501306,0.25007496153915854 0.3865033691474152,0.2502384629845096 0.3863326874546165,0.250156712261805 0.3863326874546165,0.24991146009380757 0.3863326874546165,0.24982970937110305 0.38621889965941575,0.2495027064804011 0.3862757935570136,0.2493392050350501 0.3861620057618128,0.24876694997629265 0.3861620057618128,0.24835819636288614 0.3861620057618128,0.2482764456402397 0.3861051118642149,0.2480311934721842 0.38599132406901415,0.2478676920268332 0.3858775362738133,0.24794944274953776 0.3858206423762155,0.2484399470855907 0.38570685458101467,0.24852169780823716 0.3854792789906131,0.24852169780823716 0.38542238509301524,0.24860344853094166 0.38513791560501576,0.24917570358969915 0.3852517034002166,0.24974795864845659 0.3850810217074128,0.24991146009380757 0.385024127809815,0.24991146009380757 0.385024127809815,0.24999321081645404 0.3847965522194134,0.24999321081645404 0.3846827644242126,0.24982970937110305 0.38462587052661473,0.24958445720310563 0.38485344611701633,0.24966620792575206 0.38485344611701633,0.2495027064804011 0.38485344611701633,0.24925745431234558 0.3846827644242126,0.2490939528669946 0.3846827644242126,0.24901220214434816 0.38462587052661473,0.2484399470855907 0.3846827644242126,0.2480311934721842 0.38451208273141396,0.2477859413041287 0.3844551888338161,0.2477859413041287 0.3843982949362132,0.2477859413041287 0.3841707193458166,0.24917570358969915 0.3841138254482137,0.24925745431234558 0.3838293559602143,0.24982970937110305 0.38371556816501345,0.24991146009380757 0.3835448864722148,0.24982970937110305 0.3836017803698127,0.24942095575775464 0.3836586742674156,0.2493392050350501 0.38348799257461186,0.24917570358969915 0.3828621597010151,0.24958445720310563 0.3827483719058143,0.24942095575775464 0.3828621597010151,0.24925745431234558 0.3828621597010151,0.24917570358969915 0.3829759474962159,0.2488487006989972 0.3829759474962159,0.2484399470855907 0.3828052658034122,0.2484399470855907 0.38246390241781486,0.24876694997629265 0.3824070085202119,0.24876694997629265 0.3821794329298154,0.24917570358969915 0.3821794329298154,0.24901220214434816 0.3824070085202119,0.24868519925364618 0.3827483719058143,0.2484399470855907 0.3827483719058143,0.2484399470855907 0.38257769021301563,0.2484399470855907 0.38246390241781486,0.24860344853094166 0.3817811756466151,0.24893045142164363 0.3816104939538114,0.2490939528669946 0.3815536000562135,0.2490939528669946 0.38143981226101276,0.2495027064804011 0.38143981226101276,0.24991146009380757 0.3815536000562135,0.24974795864845659 0.3816104939538114,0.2493392050350501 0.3816104939538114,0.24925745431234558 0.38143981226101276,0.2490939528669946 0.3812691305682141,0.2490939528669946 0.38109844887541544,0.24917570358969915 0.38104155497781256,0.2493392050350501 0.3808708732850139,0.2495027064804011 0.3808708732850139,0.2490939528669946 0.3808708732850139,0.24901220214434816 0.3808708732850139,0.24860344853094166 0.38081397938741096,0.24835819636288614 0.38018814651381416,0.24893045142164363 0.3801312526162112,0.24893045142164363 0.38001746482101045,0.24917570358969915 0.37996057092341257,0.2495027064804011 0.3798467831282118,0.24982970937110305 0.3796761014354131,0.24999321081645404 0.37939163194741365,0.25007496153915854 0.3793347380498107,0.25007496153915854 0.37927784415221283,0.24999321081645404 0.37944852584501154,0.24982970937110305 0.3795623136402123,0.24893045142164363 0.3796761014354131,0.24876694997629265 0.3796761014354131,0.24868519925364618 0.3797898892306139,0.2484399470855907 0.37996057092341257,0.2484399470855907 0.38018814651381416,0.24811294419488875 0.3807001915922152,0.2477859413041287 0.3807001915922152,0.2477859413041287 0.38092776718261173,0.24762243985877772 0.38104155497781256,0.24745893841342675 0.38115534277301333,0.24729543696807577 0.381326024465812,0.24647792974132085 0.381326024465812,0.24647792974132085 0.38149670615861564,0.24582392395985886 0.38172428174901224,0.2454969210691569 0.381838069544213,0.24500641673310397 0.381838069544213,0.24492466601039942 0.3818949634418159,0.24467941384234393 0.38166738785141435,0.24459766311969747 0.381326024465812,0.24508816745575043 0.38115534277301333,0.24516991817845496 0.3812122366706112,0.24533341962380592 0.3812122366706112,0.24533341962380592 0.38104155497781256,0.24541517034645238 0.38092776718261173,0.24582392395985886 0.3806432976946123,0.24606917612791437 0.3805295098994115,0.24623267757326536 0.3803588282066128,0.24639617901861632 0.38030193430901493,0.24631442829591182 0.38024504041141205,0.24606917612791437 0.3805864037970144,0.24582392395985886 0.3806432976946123,0.24566042251450787 0.3806432976946123,0.2454969210691569 0.3805295098994115,0.24533341962380592 0.3803588282066128,0.24525166890110142 0.3803588282066128,0.24525166890110142 0.37996057092341257,0.2454969210691569 0.37996057092341257,0.24582392395985886 0.3799036770258147,0.24598742540520985 0.37944852584501154,0.24623267757326536 0.37939163194741365,0.24623267757326536 0.3788795868690126,0.24647792974132085 0.3787089051762139,0.24688668335466926 0.3783675417906116,0.24705018480002025 0.3783106478930137,0.24713193552272478 0.3780830723026121,0.24713193552272478 0.37768481501941187,0.24713193552272478 0.37694519435060925,0.24745893841342675 0.37688830045301136,0.24754068913613125 0.37660383096501193,0.24762243985877772 0.3764331492722133,0.24754068913613125 0.37631936147701245,0.24729543696807577 0.3770020882482122,0.24696843407737382 0.37705898214581,0.24688668335466926 0.3773434516338095,0.2465596804639673 0.37711587604341296,0.2465596804639673 0.37694519435060925,0.2467231819093183 0.37660383096501193,0.2468049326320228 0.37637625537461034,0.24688668335466926 0.37631936147701245,0.24696843407737382 0.3758073163986114,0.24713193552272478 0.3750676957298088,0.24754068913613125 0.37501080183221097,0.24754068913613125 0.37523837742261257,0.24696843407737382 0.3754090591154112,0.24664143118667187 0.3754090591154112,0.24647792974132085 0.37518148352500963,0.24664143118667187 0.37518148352500963,0.24664143118667187 0.3747832262418094,0.24705018480002025 0.3743849689586091,0.24729543696807577 0.37410049947060964,0.24762243985877772 0.37410049947060964,0.24762243985877772 0.3740436055730118,0.24729543696807577 0.37410049947060964,0.24713193552272478 0.37455565065141283,0.24639617901861632 0.3746125445490107,0.24631442829591182 0.3747832262418094,0.24606917612791437 0.37466943844660855,0.2459056746825634 0.3741573933682126,0.24606917612791437 0.373929817777811,0.2461509268505608 0.3738160299826102,0.24639617901861632 0.3738160299826102,0.24639617901861632 0.3735884543922086,0.24647792974132085 0.37313330321141047,0.24696843407737382 0.3725643642354116,0.2472136862454293 0.3725074703378087,0.24729543696807577 0.3722798947474071,0.24729543696807577 0.37222300084980925,0.24713193552272478 0.3722798947474071,0.24688668335466926 0.37279193982580816,0.24664143118667187 0.37290572762100893,0.24647792974132085 0.37284883372341104,0.24639617901861632 0.3726212581330095,0.24631442829591182 0.3724505764402108,0.24639617901861632 0.3723936825426079,0.2465596804639673 0.371824743566609,0.2467231819093183 0.37193853136180977,0.24647792974132085 0.37199542525940765,0.24647792974132085 0.37233678864501,0.24623267757326536 0.3725643642354116,0.2459056746825634 0.3730764093138076,0.2454969210691569 0.3730764093138076,0.2454969210691569 0.37364534828981155,0.24492466601039942 0.3737022421874094,0.24459766311969747 0.3737022421874094,0.24435241095164198 0.3737022421874094,0.24427066022899552 0.3737591360850123,0.24378015589288451 0.37330398490420913,0.24435241095164198 0.3730195154162097,0.24451591239699297 0.37290572762100893,0.24451591239699297 0.37233678864501,0.24467941384234393 0.3718816374642119,0.24500641673310397 0.37165406187381034,0.24500641673310397 0.3715971679762074,0.24500641673310397 0.371824743566609,0.24476116456504846 0.37193853136180977,0.24459766311969747 0.37199542525940765,0.24402540806094003 0.3717678496690111,0.24402540806094003 0.37171095577140817,0.24402540806094003 0.37165406187381034,0.24427066022899552 0.37136959238581085,0.24451591239699297 0.37136959238581085,0.24435241095164198 0.37171095577140817,0.24386190661558904 0.37171095577140817,0.24378015589288451 0.3720523191570106,0.24361665444753353 0.3723936825426079,0.2431261501114806 0.3724505764402108,0.24279914722077864 0.3724505764402108,0.24271739649807408 0.3726212581330095,0.2424721443300186 0.3729626215186118,0.2424721443300186 0.37336087880181207,0.24230864288466764 0.37341777269940996,0.24206339071667018 0.3734746665970078,0.24189988927131922 0.37341777269940996,0.2418181385486147 0.37319019710900836,0.24165463710326368 0.37267815203060733,0.24189988927131922 0.3721092130546084,0.24198163999396566 0.3720523191570106,0.24206339071667018 0.3717678496690111,0.24239039360737213 0.37136959238581085,0.2430443993887761 0.37114201679540926,0.2430443993887761 0.37114201679540926,0.24296264866612963 0.37114201679540926,0.24288089794342507 0.37136959238581085,0.24214514143931665 0.37142648628340874,0.24149113565791275 0.37142648628340874,0.24149113565791275 0.37165406187381034,0.2412458834898572 0.37216610695221136,0.24116413276721077 0.3721092130546084,0.24100063132185978 0.37233678864501,0.24067362843109974 0.3723936825426079,0.2405918777084533 0.3726212581330095,0.2397743704816403 0.3725643642354116,0.2391203647002364 0.3725074703378087,0.23903861397753187 0.3725074703378087,0.23879336180953445 0.37267815203060733,0.2384663589187744 0.3727350459282103,0.23797585458272147 0.3726212581330095,0.23773060241466595 0.3725643642354116,0.23773060241466595 0.3725074703378087,0.23773060241466595 0.371824743566609,0.23879336180953445 0.3717678496690111,0.2388751125321809 0.3710282290002085,0.2392838661455874 0.3708006534098069,0.2396926197589939 0.3709713351026106,0.23985612120434485 0.3709713351026106,0.23985612120434485 0.3705161839218074,0.2401831240950468 0.36994724494580855,0.2401831240950468 0.36971966935540695,0.2403466255403978 0.36966277545780907,0.24042837626310234 0.3695489876626083,0.2405918777084533 0.3692645181746088,0.24132763421256173 0.36915073037940804,0.2414093849352082 0.36892315478900645,0.2412458834898572 0.3689800486866094,0.24116413276721077 0.36920762427700593,0.24083712987645073 0.3694920937650104,0.23993787192699131 0.3695489876626083,0.23985612120434485 0.36971966935540695,0.2391203647002364 0.3696058815602062,0.2388751125321809 0.36971966935540695,0.2384663589187744 0.36977656325300984,0.23838460819612795 0.36994724494580855,0.23756710096931496 0.36977656325300984,0.23756710096931496 0.36966277545780907,0.23797585458272147 0.36966277545780907,0.238057605305426 0.36937830596980964,0.23830285747342342 0.36863868530100696,0.23895686325488544 0.36858179140340913,0.23903861397753187 0.36829732191540965,0.2392838661455874 0.3677852768370086,0.2401013733723423 0.3677283829394057,0.2401831240950468 0.36761459514420997,0.2403466255403978 0.36744391345140626,0.24051012698574875 0.3672732317586076,0.24051012698574875 0.3671025500658089,0.24042837626310234 0.3673301256562055,0.2401013733723423 0.36744391345140626,0.2397743704816403 0.36750080734900914,0.2396926197589939 0.36761459514420997,0.23895686325488544 0.367557701246607,0.23838460819612795 0.367557701246607,0.23830285747342342 0.367557701246607,0.23764885169201952 0.36784217073460646,0.23683134446520654 0.36784217073460646,0.23683134446520654 0.36784217073460646,0.23650434157450456 0.36812664022260594,0.23625908940644907 0.36829732191540965,0.23576858507039614 0.3682404280178067,0.23552333290234062 0.3682404280178067,0.2354415821796942 0.3684111097106105,0.23470582567558573 0.3682404280178067,0.23454232423023477 0.36806974632500805,0.23470582567558573 0.3684111097106105,0.23495107784364128 0.3684111097106105,0.23495107784364128 0.3678990646322094,0.23552333290234062 0.36761459514420997,0.23576858507039614 0.36738701955380837,0.23585033579310066 0.3672732317586076,0.23585033579310066 0.367045656168206,0.23593208651574712 0.36687497447540734,0.23650434157450456 0.36664739888500575,0.23650434157450456 0.36641982329460926,0.23609558796109809 0.36641982329460926,0.23609558796109809 0.36630603549940843,0.2356868343477497 0.36619224770420766,0.23552333290234062 0.36619224770420766,0.23527808073434323 0.36607845990900684,0.23511457928899224 0.36573709652340447,0.2354415821796942 0.36573709652340447,0.2354415821796942 0.36562330872820875,0.23585033579310066 0.36528194534260633,0.23683134446520654 0.36528194534260633,0.23691309518791107 0.36516815754740556,0.23756710096931496 0.3649974758546069,0.23789410386001697 0.36482679416180824,0.23797585458272147 0.36482679416180824,0.23773060241466595 0.3648836880594061,0.23764885169201952 0.3648836880594061,0.237403599523964 0.3647699002642053,0.23724009807861302 0.36459921857140665,0.23732184880131757 0.36459921857140665,0.23773060241466595 0.36437164298100505,0.23813935602807246 0.36437164298100505,0.238221106750777 0.36437164298100505,0.2384663589187744 0.364428536878608,0.23903861397753187 0.36431474908340716,0.23920211542288286 0.3641440673906085,0.2391203647002364 0.36397338569780485,0.2388751125321809 0.36397338569780485,0.23879336180953445 0.363859597902604,0.23854810964147896 0.363859597902604,0.23838460819612795 0.3637458101074083,0.237403599523964 0.3638027040050062,0.237403599523964 0.3637458101074083,0.23707659663326205 0.3638027040050062,0.23691309518791107 0.36363202231220754,0.23699484591055753 0.3635182345170067,0.23707659663326205 0.36340444672180594,0.23748535024666856 0.3632906589266051,0.23764885169201952 0.3632337650290073,0.23773060241466595 0.36283550774580703,0.238221106750777 0.3627217199506062,0.23895686325488544 0.3627217199506062,0.23903861397753187 0.36260793215540543,0.23985612120434485 0.36238035656500384,0.24042837626310234 0.36232346266740595,0.24051012698574875 0.3619252053842057,0.24108238204450624 0.3618114175890049,0.24132763421256173 0.3616407358962062,0.2414093849352082 0.36152694810100544,0.24116413276721077 0.36147005420340755,0.24116413276721077 0.3616976297938041,0.2403466255403978 0.36158384199860333,0.2396926197589939 0.36152694810100544,0.2396926197589939 0.36141316030580467,0.23944736759093835 0.36152694810100544,0.2391203647002364 0.36141316030580467,0.23879336180953445 0.361242478613006,0.2386298603641254 0.36107179692020736,0.2388751125321809 0.36107179692020736,0.2388751125321809 0.36107179692020736,0.2396926197589939 0.3609580091250066,0.23985612120434485 0.36101490302260447,0.24026487481775136 0.3609580091250066,0.2403466255403978 0.360730433534605,0.24083712987645073 0.36055975184180633,0.24100063132185978 0.3603890701490026,0.24083712987645073 0.3602183884562039,0.24051012698574875 0.3601614945586061,0.24042837626310234 0.36010460066100314,0.23936561686823385 0.35999081286580237,0.23903861397753187 0.35999081286580237,0.23895686325488544 0.3599339189682045,0.23871161108682992 0.359649449480205,0.23797585458272147 0.3595925555826021,0.23756710096931496 0.3595925555826021,0.23748535024666856 0.359649449480205,0.2367495937425601 0.35982013117300365,0.23609558796109809 0.3598770250706066,0.23601383723845165 0.36004770676340525,0.23560508362504518 0.35982013117300365,0.23552333290234062 0.3597063433778029,0.23593208651574712 0.35936497999220557,0.2361773386838026 0.35936497999220557,0.23625908940644907 0.35902361660660315,0.23634084012915363 0.3587960410162016,0.2367495937425601 0.3583408898354035,0.23724009807861302 0.35828399593780563,0.23732184880131757 0.35805642034740404,0.23764885169201952 0.35771505696180167,0.2378123531373705 0.3576581630642038,0.23797585458272147 0.357544375269003,0.23838460819612795 0.357544375269003,0.23838460819612795 0.3574305874738022,0.2386298603641254 0.35737369357620435,0.23895686325488544 0.3573167996786014,0.2391203647002364 0.3573167996786014,0.2395291183136429 0.35725990578100353,0.2397743704816403 0.3572030118834057,0.2397743704816403 0.3569754362930041,0.23944736759093835 0.3566909668050046,0.23895686325488544 0.3565202851122009,0.23936561686823385 0.356463391214603,0.23936561686823385 0.3564064973170052,0.23961086903628934 0.3564064973170052,0.23993787192699131 0.3562358156242014,0.2401013733723423 0.3561789217266036,0.23985612120434485 0.3561789217266036,0.2396926197589939 0.35612202782900065,0.23944736759093835 0.35606513393140277,0.23944736759093835 0.3558375583410012,0.23936561686823385 0.35566687664820257,0.2396926197589939 0.3550410437746007,0.2401831240950468 0.3549841498770029,0.24026487481775136 0.35481346818420423,0.2403466255403978 0.35452899869620474,0.24067362843109974 0.35435831700340104,0.24067362843109974 0.3539600597202008,0.2407553791538043 0.35373248412980424,0.2407553791538043 0.35361869633460347,0.2407553791538043 0.35282218176820296,0.24067362843109974 0.35282218176820296,0.24051012698574875 0.3531066512562024,0.2401831240950468 0.3531635451538003,0.2401831240950468 0.3531635451538003,0.23993787192699131 0.3529928634610016,0.2397743704816403 0.35196877330419957,0.23993787192699131 0.3519118794066017,0.23993787192699131 0.35117225873779906,0.2395291183136429 0.35111536484020117,0.23920211542288286 0.3509446831474025,0.23903861397753187 0.3508877892497996,0.23903861397753187 0.3507171075570009,0.2386298603641254 0.3507740014545988,0.2384663589187744 0.35100157704500035,0.2384663589187744 0.3515705160209993,0.238221106750777 0.3515705160209993,0.23813935602807246 0.3517980916114009,0.23797585458272147 0.3523670305873998,0.23813935602807246 0.35265150007539925,0.23797585458272147 0.35282218176820296,0.2378123531373705 0.35282218176820296,0.23789410386001697 0.35293596956340373,0.237403599523964 0.3529928634610016,0.23764885169201952 0.3531066512562024,0.23756710096931496 0.3530497573585995,0.23748535024666856 0.35293596956340373,0.23789410386001697 0.35259460617780136,0.23789410386001697 0.35219634889460116,0.2378123531373705 0.35202566720180245,0.23756710096931496 0.35202566720180245,0.23756710096931496 0.35185498550899874,0.23724009807861302 0.351741197713803,0.23707659663326205 0.3515136221234014,0.23707659663326205 0.3513998343282006,0.23691309518791107 0.35128604653299983,0.23650434157450456 0.35122915263540194,0.23642259085185816 0.35066021365940303,0.23503282856628768 0.3506033197618001,0.23495107784364128 0.3502619563762028,0.23446057350753022 0.3500343807858012,0.23364306628077533 0.3500343807858012,0.2335613155580708 0.3502619563762028,0.23331606339007338 0.35111536484020117,0.23388831844877275 0.35122915263540194,0.23413357061682827 0.35122915263540194,0.23413357061682827 0.35134294043060277,0.23405181989412374 0.3513998343282006,0.23380656772612632 0.35117225873779906,0.23347956483542437 0.35117225873779906,0.23282555905396235 0.35117225873779906,0.23274380833131592 0.35111536484020117,0.2324985561632604 0.35128604653299983,0.23233505471790944 0.35122915263540194,0.23159929821380099 0.35117225873779906,0.23135404604574544 0.35111536484020117,0.23127229532309904 0.3509446831474025,0.23086354170969253 0.3502619563762028,0.23020953592823054 0.35020506247859984,0.23020953592823054 0.34935165401460155,0.2301277852055841 0.3492947601169986,0.22996428376023312 0.34889650283379836,0.2297190315921776 0.3488396089362005,0.2297190315921776 0.34827066996020156,0.22922852725612466 0.3482137760625986,0.22898327508806915 0.3481568821650008,0.22857452147466267 0.3481568821650008,0.22857452147466267 0.34832756385779945,0.2284927707520162 0.3484982455505981,0.2280840171386097 0.3486120333457989,0.22792051569325877 0.34901029062899913,0.22792051569325877 0.34912407842419996,0.22775701424790776 0.34906718452660207,0.22775701424790776 0.34901029062899913,0.22775701424790776 0.3486120333457989,0.22775701424790776 0.34827066996020156,0.22751176207985227 0.3478724126770013,0.22702125774379933 0.34781551877939837,0.22693950702109478 0.3476448370865997,0.22677600557574382 0.34724657980339946,0.22669425485309738 0.34679142862260137,0.22644900268504187 0.34656385303219983,0.22628550123969088 0.34656385303219983,0.22628550123969088 0.3465069591345969,0.22612199979433992 0.3463931713394012,0.22612199979433992 0.3462224896465974,0.22620375051698632 0.345938020158598,0.22661250413039283 0.3457104445681964,0.22677600557574382 0.3456535506705985,0.22669425485309738 0.34536908118259907,0.22628550123969088 0.34536908118259907,0.2260402490716354 0.3455397628753977,0.2257132461809334 0.34559665677300067,0.2254679940128779 0.34559665677300067,0.22538624329023146 0.345938020158598,0.22407823172736555 0.345938020158598,0.223996481004661 0.3461655957489996,0.22358772739131264 0.34627938354420035,0.2225249679964441 0.34627938354420035,0.22244321727379768 0.3465069591345969,0.22211621438309573 0.34684832252019926,0.22195271293774474 0.3471327920081987,0.22195271293774474 0.34730347370099734,0.22211621438309573 0.3473603675986003,0.22219796510574216 0.34753104929139894,0.22236146655109315 0.3478724126770013,0.2222797158284467 0.34804309436979997,0.22236146655109315 0.34855513944820105,0.22277022016449965 0.3486120333457989,0.22277022016449965 0.34957922960499804,0.22317897377790613 0.34974991129780175,0.22342422594596165 0.34974991129780175,0.22342422594596165 0.3502619563762028,0.22342422594596165 0.3509446831474025,0.2237512288366636 0.35100157704500035,0.2237512288366636 0.35185498550899874,0.2237512288366636 0.35185498550899874,0.22358772739131264 0.3515136221234014,0.22326072450055257 0.3514567282257985,0.22326072450055257 0.35122915263540194,0.2229337216098506 0.35117225873779906,0.2222797158284467 0.35111536484020117,0.2220344636603912 0.3510584709426033,0.22195271293774474 0.3508308953522017,0.22195271293774474 0.3507740014545988,0.22178921149239375 0.3507171075570009,0.2216257100469847 0.3507171075570009,0.2213804578789873 0.35054642586420226,0.22129870715628275 0.35054642586420226,0.22088995354287627 0.35054642586420226,0.2208082028202298 0.3507171075570009,0.22023594776147234 0.35066021365940303,0.21950019125736392 0.3506033197618001,0.21941844053465936 0.35066021365940303,0.218028678249147 0.35066021365940303,0.21794692752644249 0.3507171075570009,0.21753817391309407 0.3509446831474025,0.21729292174503856 0.3508877892497996,0.2167206666862811 0.3509446831474025,0.2167206666862811 0.35100157704500035,0.21663891596363463 0.35100157704500035,0.2160666609048772 0.3508877892497996,0.2156579072914707 0.35043263806900143,0.2156579072914707 0.35037574417139855,0.21557615656876614 0.35031885027380066,0.21557615656876614 0.35043263806900143,0.21541265512341518 0.3507740014545988,0.2152491536780642 0.3509446831474025,0.21516740295541775 0.35128604653299983,0.21516740295541775 0.3515136221234014,0.2150039015100668 0.3515136221234014,0.21492215078736224 0.3517980916114009,0.21467689861930675 0.35231013668980193,0.2144316464513093 0.3524239244850027,0.21418639428325378 0.35265150007539925,0.21402289283790285 0.35265150007539925,0.21402289283790285 0.35293596956340373,0.21361413922449635 0.35293596956340373,0.2133688870564989 0.3530497573585995,0.2129601334430924 0.3530497573585995,0.2127148812750369 0.3530497573585995,0.21255137982968594 0.35322043905140316,0.21214262621627944 0.353334226846604,0.21197912477092845 0.35350490853940264,0.21197912477092845 0.3536755902322013,0.21214262621627944 0.35361869633460347,0.21255137982968594 0.35361869633460347,0.21263313055239044 0.35361869633460347,0.2128783827203879 0.3537893780274021,0.2133688870564989 0.3540169536178037,0.21345063777914536 0.3542445292082002,0.21304188416573885 0.35430142310580315,0.21304188416573885 0.35452899869620474,0.2128783827203879 0.35509793767220366,0.2128783827203879 0.3552686193650023,0.21304188416573885 0.35566687664820257,0.2131236348884434 0.35572377054580046,0.2131236348884434 0.356463391214603,0.21345063777914536 0.35691854239540116,0.21361413922449635 0.3569754362930041,0.21361413922449635 0.3584546776306043,0.21418639428325378 0.35856846542580506,0.21418639428325378 0.3589667227090053,0.21418639428325378 0.359649449480205,0.2139411421151983 0.3598770250706066,0.21402289283790285 0.3599339189682045,0.21402289283790285 0.36055975184180633,0.21418639428325378 0.3612993725106039,0.2137776406698473 0.3613562664082068,0.21369588994720085 0.36175452369140704,0.21345063777914536 0.3619252053842057,0.21353238850184988 0.36260793215540543,0.21320538561108984 0.36266482605300326,0.21320538561108984 0.3627786138482041,0.2131236348884434 0.3627217199506062,0.2133688870564989 0.36289240164340486,0.2133688870564989 0.3630630833362035,0.2133688870564989 0.36340444672180594,0.21304188416573885 0.36363202231220754,0.21279663199774146 0.36368891620980537,0.21279663199774146 0.3649974758546069,0.21189737404828202 0.36505436975220473,0.2118156233255775 0.3652250514450085,0.21157037115752197 0.36539573313780715,0.21157037115752197 0.3656802026258066,0.21173387260287296 0.3659077782162082,0.2118156233255775 0.3662491416018055,0.2114886204348755 0.3663629293970063,0.2114886204348755 0.3664767171922071,0.21116161754417356 0.36693186837300523,0.2105893624854161 0.3669887622706081,0.2103441103173606 0.367045656168206,0.21026235959465606 0.367045656168206,0.21018060887200962 0.3669887622706081,0.21009885814930507 0.36664739888500575,0.20944485236790117 0.3665905049874079,0.20969010453595668 0.3667611866802066,0.2099353567039541 0.36681808057780946,0.21001710742665863 0.3669887622706081,0.21009885814930507 0.3672163378610097,0.21009885814930507 0.3681835341202089,0.20969010453595668 0.36829732191540965,0.20960835381325216 0.3690369425842072,0.20936310164519664 0.36915073037940804,0.20919960019984568 0.3693214120722067,0.20919960019984568 0.3695489876626083,0.20919960019984568 0.3696058815602062,0.20919960019984568 0.36989035104821066,0.20919960019984568 0.3700610327410093,0.2086273451410882 0.3701179266386072,0.20887259730914373 0.3704592900242095,0.20854559441844175 0.3705161839218074,0.20854559441844175 0.3708575473074098,0.20838209297309077 0.37091444120500766,0.20821859152773978 0.3708575473074098,0.20805509008238882 0.37108512289781137,0.20772808719162877 0.3713126984882079,0.20756458574627779 0.37142648628340874,0.20756458574627779 0.3720523191570106,0.20699233068752032 0.3724505764402108,0.20682882924216933 0.3725643642354116,0.20666532779681837 0.3726212581330095,0.20666532779681837 0.3723936825426079,0.20666532779681837 0.3722798947474071,0.2067470785195229 0.3729626215186118,0.20601132201541444 0.3730195154162097,0.20601132201541444 0.3732470910066113,0.20584782057006348 0.3734746665970078,0.20552081767930344 0.3734746665970078,0.20535731623395245 0.3737591360850123,0.2050303133432505 0.3738160299826102,0.204785061175195 0.37387292388020804,0.20470331045254855 0.3740436055730118,0.20429455683914205 0.3744987567538099,0.2038040525030891 0.3747263323442115,0.20339529888968264 0.3747832262418094,0.20339529888968264 0.37512458962741174,0.20315004672162712 0.3752952713202104,0.20282304383092517 0.37575042250100854,0.20241429021751867 0.3758073163986114,0.2023325394948722 0.3758642102962093,0.20192378588146576 0.37569352860341065,0.20151503226805925 0.37512458962741174,0.2016785337134102 0.37512458962741174,0.2016785337134102 0.3743849689586091,0.20176028443611477 0.37398671167540887,0.2016785337134102 0.3737591360850123,0.20176028443611477 0.3737022421874094,0.20176028443611477 0.3734746665970078,0.20192378588146576 0.3729626215186118,0.2018420351588193 0.37290572762100893,0.2016785337134102 0.3729626215186118,0.20151503226805925 0.3729626215186118,0.20135153082270826 0.3729626215186118,0.20126978010006183 0.3730195154162097,0.20086102648665533 0.37313330321141047,0.20045227287324888 0.3730764093138076,0.20004351925984237 0.3730764093138076,0.19979826709184492 0.37313330321141047,0.19971651636914042 0.3735884543922086,0.19849025552897903 0.3735884543922086,0.19840850480627448 0.3737022421874094,0.19816325263827708 0.3735884543922086,0.197999751192868 0.3740436055730118,0.19742749613416863 0.37410049947060964,0.1971822439661131 0.37410049947060964,0.1971004932434086 0.37444186285621206,0.19595598312595175 0.37455565065141283,0.19571073095789623 0.3746125445490107,0.19562898023519168 0.37518148352500963,0.19432096867238385 0.37523837742261257,0.19423921794967933 0.3752952713202104,0.19391221505897738 0.37546595301300906,0.19391221505897738 0.37575042250100854,0.19358521216827543 0.37609178588661085,0.19317645855486892 0.37614867978420874,0.1930947078321644 0.37631936147701245,0.1929312063868134 0.3764900431698111,0.19260420349611146 0.3764331492722133,0.191868446992003 0.3764900431698111,0.19178669626929848 0.37683140655541353,0.19154144410130106 0.37683140655541353,0.19105093976519003 0.3767745126578106,0.19056043542913711 0.3767745126578106,0.19047868470649065 0.37688830045301136,0.19006993109308418 0.37688830045301136,0.1897429282023822 0.37683140655541353,0.1894976760343267 0.37694519435060925,0.18900717169827377 0.37694519435060925,0.18892542097556925 0.37694519435060925,0.18827141519416532 0.37683140655541353,0.18810791374881433 0.37683140655541353,0.18794441230340528 0.37705898214581,0.18761740941270333 0.37711587604341296,0.18753565869005687 0.37745723942901027,0.18622764712719098 0.37745723942901027,0.18614589640448642 0.37768481501941187,0.18581889351378447 0.37768481501941187,0.18557364134572896 0.37774170891700976,0.18581889351378447 0.37774170891700976,0.18516488773238055 0.37774170891700976,0.18508313700967605 0.37796928450741135,0.1843473805055676 0.3780261784050143,0.18377512544681013 0.3780830723026121,0.18369337472416367 0.3783106478930137,0.18336637183340362 0.3788795868690126,0.1831211196654062 0.37922095025460995,0.18279411677470425 0.3793347380498107,0.18271236605199973 0.37944852584501154,0.1824671138839442 0.37996057092341257,0.1818948588252448 0.3801312526162112,0.18148610521183833 0.38018814651381416,0.18132260376648734 0.3807001915922152,0.18042334581702793 0.3807570854898131,0.18001459220362143 0.3807570854898131,0.17993284148091693 0.38092776718261173,0.17952408786751042 0.38092776718261173,0.17870658064075554 0.38092776718261173,0.178624829918051 0.3808708732850139,0.17854307919540455 0.38092776718261173,0.17837957775005356 0.381326024465812,0.17829782702734906 0.38149670615861564,0.17813432558199807 0.3818949634418159,0.17813432558199807 0.38166738785141435,0.17797082413664708 0.38166738785141435,0.17788907341394256 0.38115534277301333,0.1764993111284302 0.38115534277301333,0.17641756040572568 0.38098466108021467,0.17617230823772823 0.38109844887541544,0.17600880679237726 0.3808708732850139,0.17568180390161722 0.3808708732850139,0.17551830245626623 0.3808708732850139,0.17510954884291785 0.3808708732850139,0.17502779812021332 0.38092776718261173,0.1747825459521578 0.38143981226101276,0.17470079522951135 0.38115534277301333,0.17453729378416036 0.3808708732850139,0.17453729378416036 0.38081397938741096,0.17453729378416036 0.3804726160018136,0.17421029089340032 0.3804157221042107,0.17404678944804935 0.3805295098994115,0.17388328800269837 0.3807001915922152,0.1739650387254029 0.38104155497781256,0.1737197865573474 0.38104155497781256,0.17363803583470094 0.3812691305682141,0.17339278366664546 0.38138291836341487,0.17347453438934998 0.38149670615861564,0.1733110329439409 0.38138291836341487,0.1724117749944815 0.38138291836341487,0.1724117749944815 0.3812691305682141,0.17167601849037303 0.38115534277301333,0.17151251704502207 0.3812122366706112,0.17077676054091362 0.3812122366706112,0.17069500981826716 0.38115534277301333,0.17020450548215615 0.38138291836341487,0.1698775025914542 0.3815536000562135,0.16979575186880774 0.3817811756466151,0.1698775025914542 0.38200875123701167,0.16979575186880774 0.3820656451346146,0.16971400114610322 0.3822932207250162,0.16963225042345675 0.3827483719058143,0.1693052475326967 0.3827483719058143,0.16914174608734575 0.3828621597010151,0.16889649391934833 0.3830897352914116,0.16873299247393925 0.38320352308661243,0.16873299247393925 0.3833173108818132,0.1685694910285883 0.3835448864722148,0.16816073741523987 0.3836017803698127,0.16799723596983082 0.3836017803698127,0.1675884823564824 0.3836017803698127,0.16750673163377788 0.3836017803698127,0.1671797287430759 0.3837724620626164,0.16693447657502042 0.3836586742674156,0.16677097512966943 0.3837724620626164,0.16660747368431844 0.3838862498578121,0.16644397223896745 0.3838862498578121,0.16619872007091196 0.3838862498578121,0.16611696934826553 0.3841707193458166,0.16578996645756355 0.3841707193458166,0.1656264650121545 0.3840569315506158,0.16513596067610156 0.3837724620626164,0.16497245923075057 0.38371556816501345,0.16497245923075057 0.3836017803698127,0.16472720706269506 0.38371556816501345,0.16464545634004862 0.3835448864722148,0.16407320128129116 0.38348799257461186,0.16366444766788468 0.38348799257461186,0.16358269694523822 0.38337420477941614,0.1633374447771827 0.383431098677014,0.16309219260912722 0.3838862498578121,0.1626834389957207 0.38400003765301294,0.16227468538237233 0.38400003765301294,0.16219293465966778 0.38394314375541505,0.1617841810462613 0.3838293559602143,0.1616206796009103 0.3837724620626164,0.16113017526485737 0.3836017803698127,0.16080317237415542 0.3836017803698127,0.1607214216514509 0.38326041698421537,0.15998566514734244 0.3828621597010151,0.1596586622566405 0.3827483719058143,0.1596586622566405 0.3824070085202119,0.15933165936593852 0.38223632682741326,0.1584324014164791 0.38223632682741326,0.15835065069377458 0.3821794329298154,0.15761489418966612 0.3822932207250162,0.15696088840826222 0.38235011462261403,0.1568791376855577 0.38257769021301563,0.15679738696291123 0.3827483719058143,0.15679738696291123 0.38291905359861295,0.15696088840826222 0.38303284139381377,0.1573696420216687 0.38337420477941614,0.15761489418966612 0.383431098677014,0.15761489418966612 0.3836586742674156,0.1577783956350171 0.3838293559602143,0.15769664491237068 0.3838862498578121,0.1573696420216687 0.3838293559602143,0.15720614057625965 0.38371556816501345,0.15671563624020668 0.38371556816501345,0.15663388551756025 0.3836586742674156,0.15540762467734082 0.3838862498578121,0.15532587395469435 0.38394314375541505,0.15532587395469435 0.38485344611701633,0.15597987973609825 0.3849672339122171,0.15622513190415377 0.3849672339122171,0.1563068826268002 0.38513791560501576,0.15655213479485572 0.3852517034002166,0.15638863334950476 0.3853085972978144,0.15606163045880278 0.385536172888216,0.15606163045880278 0.3858775362738133,0.1563068826268002 0.38593443017141627,0.15638863334950476 0.38656026304501306,0.15704263913090866 0.38678783863541466,0.15745139274431513 0.38684473253301754,0.1575331434670197 0.3870723081234141,0.15810539852571906 0.3871860959186149,0.1584324014164791 0.3875274593042172,0.15875940430718105 0.3875843532018151,0.15875940430718105 0.3878119287922167,0.15892290575253204 0.3886653372562151,0.1596586622566405 0.388722231153818,0.1596586622566405 0.3895756396178164,0.16047616948345347 0.38968942741301715,0.16063967092880443 0.38974632131061504,0.1607214216514509 0.39025836638901606,0.16129367671020836 0.3904290480818147,0.1613754274329129 0.390827305365015,0.16129367671020836 0.39094109316021575,0.16129367671020836 0.39116866875061734,0.16129367671020836 0.39139624434101894,0.16145717815555932 0.3915669260338176,0.16145717815555932 0.3918513955218171,0.16129367671020836 0.39202207721461574,0.16129367671020836 0.39202207721461574,0.16113017526485737 0.39190828941942,0.16104842454215285 0.3918513955218171,0.16104842454215285 0.3914531382386168,0.1607214216514509 0.39116866875061734,0.16023091731539796 0.3909979870578187,0.16023091731539796 0.3907704114674171,0.16014916659269343 0.3907135175698192,0.16006741587004697 0.3905428358770155,0.15982216370199148 0.39059972977461843,0.15957691153393594 0.39031526028661895,0.1588411550298275 0.39031526028661895,0.15875940430718105 0.3901445785938153,0.15835065069377458 0.3900876846962174,0.1579418970803681 0.3901445785938153,0.1577783956350171 0.39037215418421684,0.1577783956350171 0.39059972977461843,0.1580236478030726 0.3906566236722163,0.1580236478030726 0.3909979870578187,0.15835065069377458 0.3915669260338176,0.1584324014164791 0.39196518331701785,0.15859590286183006 0.39202207721461574,0.15859590286183006 0.39270480398582047,0.15875940430718105 0.39276169788341836,0.15851415213912556 0.39224965280501733,0.15810539852571906 0.39224965280501733,0.15810539852571906 0.3920789711122187,0.15786014635772164 0.39219275890741945,0.15769664491237068 0.3923634406002181,0.15761489418966612 0.39270480398582047,0.1579418970803681 0.39315995516661856,0.15810539852571906 0.39321684906421644,0.15810539852571906 0.3932737429618194,0.15810539852571906 0.3933306368594172,0.1579418970803681 0.39315995516661856,0.15769664491237068 0.3931030612690207,0.1571243898536132 0.3933306368594172,0.1571243898536132 0.39338753075702015,0.15720614057625965 0.3938426819378183,0.1575331434670197 0.39395646973301907,0.1571243898536132 0.3938995758354161,0.15696088840826222 0.39395646973301907,0.15671563624020668 0.39395646973301907,0.15663388551756025 0.39401336363061695,0.15622513190415377 0.39395646973301907,0.15606163045880278 0.3936151063474167,0.15532587395469435 0.3936151063474167,0.15532587395469435 0.39321684906421644,0.1545901174505859 0.39287548567861913,0.15434486528253039 0.392932379576217,0.1541813638371794 0.392932379576217,0.1540996131144749 0.392932379576217,0.1541813638371794 0.39287548567861913,0.1540996131144749 0.3926479100882176,0.15385436094647748 0.39253412229301676,0.15344560733307094 0.39224965280501733,0.15287335227431348 0.39219275890741945,0.15287335227431348 0.3921358650098165,0.152464598660907 0.39202207721461574,0.15189234360214954 0.3917945016242192,0.15148358998880113 0.3917945016242192,0.1514018392660966 0.3915669260338176,0.15099308565269012 0.39151003213621977,0.15042083059393266 0.3916807138290184,0.15042083059393266 0.39196518331701785,0.15042083059393266 0.39202207721461574,0.15050258131663719 0.39276169788341836,0.1507478334846927 0.39281859178101625,0.15091133493004366 0.39281859178101625,0.15066608276198817 0.39270480398582047,0.15042083059393266 0.39270480398582047,0.15042083059393266 0.39247722839541893,0.14976682481252873 0.392420334497816,0.14960332336717774 0.3923634406002181,0.14919456975377127 0.3923065467026203,0.14894931758577384 0.39224965280501733,0.14894931758577384 0.3917945016242192,0.1482135610816654 0.3916807138290184,0.14764130602290793 0.3916807138290184,0.1475595553002034 0.3915669260338176,0.14739605385485244 0.3915669260338176,0.14723255240950145 0.39139624434101894,0.1469055495187995 0.39139624434101894,0.14674204807344854 0.3915669260338176,0.14657854662803946 0.39173760772661625,0.14682379879609497 0.39173760772661625,0.14682379879609497 0.392932379576217,0.14764130602290793 0.3929892734738199,0.1475595553002034 0.3930461673714178,0.1475595553002034 0.39281859178101625,0.14723255240950145 0.39276169788341836,0.14666029735074398 0.39287548567861913,0.14625154373733748 0.39281859178101625,0.14616979301469105 0.39276169788341836,0.14592454084663553 0.39270480398582047,0.14551578723322905 0.39281859178101625,0.14469828000647417 0.39281859178101625,0.1446165292837696 0.39281859178101625,0.14420777567036314 0.3929892734738199,0.14379902205701472 0.3933306368594172,0.14322676699825726 0.3933306368594172,0.14322676699825726 0.3935582124498188,0.14306326555290627 0.3936151063474167,0.14281801338485078 0.3937857880402204,0.14273626266214623 0.39418404532342066,0.14208225688074233 0.39424093922101855,0.14208225688074233 0.39446851481142015,0.14175525399004038 0.39446851481142015,0.14191875543539134 0.3942978331186164,0.1420005061580959 0.39424093922101855,0.1426545119394998 0.39418404532342066,0.14273626266214623 0.3943547270162193,0.1431450162755527 0.3944116209138172,0.1437172713343102 0.3946391965042188,0.1441260249477167 0.3946391965042188,0.14420777567036314 0.39469609040181663,0.14445302783841862 0.39480987819701746,0.1446165292837696 0.39498055988982117,0.14486178145182513 0.3951512415826198,0.1449435321744716 0.3953219232754185,0.1447800307291206 0.3953788171730214,0.14453477856112318 0.3953219232754185,0.14445302783841862 0.3951512415826198,0.14404427422501215 0.3952081354802177,0.14379902205701472 0.3953219232754185,0.14355376988895924 0.3954357110706193,0.1431450162755527 0.3954357110706193,0.14306326555290627 0.39572018055861874,0.14298151483020174 0.396118437841819,0.1424910104941488 0.39645980122742136,0.14298151483020174 0.39645980122742136,0.14298151483020174 0.39668737681781785,0.1431450162755527 0.39691495240821945,0.1431450162755527 0.39697184630581733,0.14355376988895924 0.39702874020342027,0.1437172713343102 0.39719942189621893,0.14388077277966116 0.3974269974866205,0.14388077277966116 0.3974838913842184,0.14388077277966116 0.3981666181554181,0.14404427422501215 0.39873555713142206,0.14404427422501215 0.3989062388242207,0.14428952639306766 0.3989062388242207,0.1443712771157722 0.3989631327218186,0.14445302783841862 0.39919070831222014,0.14445302783841862 0.39919070831222014,0.1447800307291206 0.3990200266194215,0.14486178145182513 0.39856487543861835,0.14453477856112318 0.39850798154102046,0.14445302783841862 0.3981097242578202,0.1441260249477167 0.39793904256502155,0.1441260249477167 0.39776836087221784,0.14420777567036314 0.3975407852818213,0.1441260249477167 0.3973132096914197,0.14379902205701472 0.39725631579382187,0.1437172713343102 0.39719942189621893,0.14347201916625468 0.39668737681781785,0.14322676699825726 0.39663048292022,0.14306326555290627 0.39668737681781785,0.14281801338485078 0.39663048292022,0.14257276121679527 0.39657358902262213,0.1424910104941488 0.3964029073298184,0.14232750904879785 0.3964029073298184,0.14191875543539134 0.39634601343222053,0.14175525399004038 0.39645980122742136,0.1411012482085784 0.39645980122742136,0.1411012482085784 0.3965166951250192,0.14085599604058097 0.39645980122742136,0.14044724242717446 0.39657358902262213,0.1401202395364725 0.39691495240821945,0.13979323664577056 0.39691495240821945,0.13979323664577056 0.39719942189621893,0.13938448303236406 0.3976545730770221,0.13897572941895758 0.3976545730770221,0.13873047725090204 0.3975407852818213,0.13848522508290464 0.3975407852818213,0.13840347436020012 0.3973701035890176,0.13840347436020012 0.3970856341010181,0.13889397869625303 0.39657358902262213,0.13922098158701307 0.39645980122742136,0.13922098158701307 0.39572018055861874,0.1393027323096595 0.3950943476850169,0.13938448303236406 0.39503745378741906,0.1394662337550105 0.3945823026066209,0.139874987368417 0.3943547270162193,0.13954798447771505 0.3942978331186164,0.1393027323096595 0.3942978331186164,0.1390574801416621 0.3942978331186164,0.1390574801416621 0.3943547270162193,0.1386487265282556 0.39424093922101855,0.13848522508290464 0.39424093922101855,0.13832172363755368 0.394525408709018,0.1377494685787962 0.394525408709018,0.1377494685787962 0.39498055988982117,0.1377494685787962 0.39526502937782065,0.1373407149653897 0.3954357110706193,0.1369319613519832 0.3954357110706193,0.1369319613519832 0.3957770744562216,0.13660495846128126 0.3957770744562216,0.13635970629322575 0.39572018055861874,0.13578745123446828 0.3959477561490203,0.1356239497891173 0.3959477561490203,0.1356239497891173 0.39623222563701976,0.1352151961757689 0.39634601343222053,0.1348064425623624 0.3968011646130187,0.13439768894895593 0.3968011646130187,0.13439768894895593 0.39719942189621893,0.13374368316755203 0.3974269974866205,0.13317142810879457 0.3974269974866205,0.13308967738609 0.3975407852818213,0.13292617594073902 0.3974269974866205,0.1326809237726835 0.39776836087221784,0.13219041943663057 0.39771146697461995,0.13169991510057766 0.39776836087221784,0.1316181643778731 0.39799593646261944,0.1311276600418202 0.3981666181554181,0.13039190353771174 0.39822351205302103,0.13031015281500719 0.39822351205302103,0.1300649006470098 0.3981666181554181,0.12916564269755038 0.39799593646261944,0.1290021412521994 0.39793904256502155,0.12892039052949483 0.3976545730770221,0.12802113258003545 0.3974269974866205,0.12769412968933347 0.3973701035890176,0.12769412968933347 0.39691495240821945,0.12753062824398248 0.3968580585106216,0.12736712679857343 0.39657358902262213,0.12663137029446497 0.39657358902262213,0.12654961957181854 0.39645980122742136,0.12630436740376302 0.39634601343222053,0.12614086595841206 0.39623222563701976,0.12556861089965457 0.39628911953461765,0.12532335873165715 0.39628911953461765,0.12524160800895262 0.39634601343222053,0.1245876022275487 0.39628911953461765,0.12417884861414222 0.39634601343222053,0.1239335964460867 0.39634601343222053,0.1239335964460867 0.39657358902262213,0.12319783994197826 0.39691495240821945,0.12270733560592534 0.39697184630581733,0.1226255848832208 0.39714252799862104,0.12238033271522336 0.39776836087221784,0.12164457621111494 0.3978252547698208,0.1215628254884104 0.3981097242578202,0.12123582259770845 0.3982804059506189,0.12099057042965293 0.39856487543861835,0.12082706898430196 0.39873555713142206,0.12058181681630452 0.39879245102901995,0.12050006609359999 0.3989062388242207,0.12033656464824902 0.39919070831222014,0.11968255886678701 0.39941828390262174,0.11935555597608506 0.39941828390262174,0.11927380525343861 0.3995889655954204,0.1190285530853831 0.3995320716978225,0.11927380525343861 0.3993613900050188,0.11911030380808764 0.39941828390262174,0.11894680236267857 0.39919070831222014,0.11861979947197661 0.39913381441462226,0.11861979947197661 0.39884934492662283,0.11829279658127466 0.39862176933622123,0.11829279658127466 0.39822351205302103,0.11804754441321914 0.3980528303602224,0.11821104585857013 0.3981097242578202,0.11845629802662563 0.3981097242578202,0.11845629802662563 0.39799593646261944,0.11829279658127466 0.3976545730770221,0.11804754441321914 0.3973701035890176,0.1177205415225172 0.39719942189621893,0.1177205415225172 0.39702874020342027,0.11747528935451976 0.39697184630581733,0.11747528935451976 0.39691495240821945,0.11755704007716622 0.39691495240821945,0.11698478501840874 0.39668737681781785,0.11665778212770678 0.3965166951250192,0.11673953285041132 0.3965166951250192,0.11698478501840874 0.39645980122742136,0.11706653574111328 0.3958908622514174,0.11739353863181523 0.3957770744562216,0.11731178790911069 0.3958908622514174,0.11698478501840874 0.3958908622514174,0.11673953285041132 0.3958908622514174,0.11665778212770678 0.3958339683538195,0.1162490285143003 0.3958908622514174,0.11608552706894933 0.3958339683538195,0.11584027490089381 0.3957770744562216,0.11526801984219442 0.3958339683538195,0.1151862691194899 0.3961753317394219,0.11445051261538144 0.3958339683538195,0.11428701117003047 0.39566328666102085,0.11445051261538144 0.39566328666102085,0.11445051261538144 0.39572018055861874,0.11428701117003047 0.39566328666102085,0.11404175900197497 0.39526502937782065,0.1141235097246795 0.3952081354802177,0.11387825755662398 0.3953788171730214,0.11379650683397755 0.39549260496821714,0.11355125466592203 0.39549260496821714,0.11355125466592203 0.39572018055861874,0.11330600249786651 0.39572018055861874,0.11306075032986909 0.3960615439442211,0.11232499382576065 0.3960615439442211,0.11232499382576065 0.39645980122742136,0.11158923732165221 0.39657358902262213,0.11093523154019021 0.39657358902262213,0.11085348081754376 0.39663048292022,0.1102812257587863 0.39657358902262213,0.11011772431343532 0.3965166951250192,0.10954546925467784 0.3965166951250192,0.10946371853197331 0.39645980122742136,0.10913671564127135 0.3965166951250192,0.10864621130521843 0.39657358902262213,0.1081557069691074 0.3965166951250192,0.10807395624646095 0.3965166951250192,0.10791045480110997 0.39657358902262213,0.10750170118770348 0.39634601343222053,0.10717469829700153 0.39645980122742136,0.10676594468359504 0.3965166951250192,0.1066841939608905 0.3967442707154208,0.10635719107018855 0.3970856341010181,0.10619368962483756 0.3973132096914197,0.10553968384343367 0.3973132096914197,0.10553968384343367 0.3976545730770221,0.1049674287846762 0.3976545730770221,0.10423167228056776 0.3976545730770221,0.10423167228056776 0.3976545730770221,0.10365941722181028 0.39776836087221784,0.10382291866716126 0.39771146697461995,0.10325066360840379 0.39771146697461995,0.10316891288575734 0.3976545730770221,0.10276015927235085 0.39771146697461995,0.10259665782699989 0.39793904256502155,0.10251490710429535 0.3981097242578202,0.10186090132289144 0.3981097242578202,0.10177915060018691 0.3981097242578202,0.1013703969868385 0.3983372998482218,0.10145214770948494 0.3983941937458197,0.10120689554142943 0.39879245102901995,0.1007163912053765 0.39879245102901995,0.1007163912053765 0.3981666181554181,0.10063464048273005 0.3982804059506189,0.100471139037321 0.39850798154102046,0.100471139037321 0.39850798154102046,0.10030763759197 0.39873555713142206,0.10030763759197 0.39873555713142206,0.10038938831467455 0.3989631327218186,0.10030763759197 0.3990200266194215,0.10014413614661903 0.39913381441462226,0.09998063470126806 0.39919070831222014,0.09957188108786157 0.3994751778002196,0.0992448781971596 0.3994751778002196,0.0992448781971596 0.39964585949302334,0.09908137675180864 0.39964585949302334,0.09875437386110666 0.3998734350834199,0.09875437386110666 0.4000441167762236,0.09891787530645765 0.40021479846902225,0.09883612458375313 0.4003285862642231,0.0985908724157557 0.4003285862642231,0.0985908724157557 0.40049926795702173,0.09826386952499566 0.40084063134261905,0.09777336518894272 0.4012388886258193,0.0975281130209453 0.4012957825234222,0.0975281130209453 0.40135267642102007,0.09744636229824077 0.401409570318623,0.09728286085288979 0.4012388886258193,0.09720111013018526 0.4012388886258193,0.09695585796218784 0.40135267642102007,0.09679235651683685 0.40169403980662244,0.0966288550714278 0.40192161539702403,0.09671060579413232 0.40197850929462187,0.09671060579413232 0.40220608488502346,0.09654710434878135 0.4023198726802243,0.09638360290343036 0.4023198726802243,0.09605660001272841 0.40249055437302295,0.0954025942312664 0.40249055437302295,0.09532084350861997 0.4025474482706208,0.09507559134056445 0.4027750238610224,0.09474858844986249 0.4027750238610224,0.09442158555910245 0.40300259945142397,0.09409458266840048 0.40305949334902186,0.09409458266840048 0.40328706893942345,0.09393108122304952 0.40351464452982505,0.09344057688699658 0.40351464452982505,0.0932770754416456 0.4036853262226237,0.09311357399629462 0.40385600791542237,0.09295007255094365 0.4039129018130202,0.09286832182823912 0.4042542651986226,0.09245956821483262 0.4050507797650231,0.09213256532413067 0.4051076736626209,0.09205081460142614 0.40539214315062544,0.09196906387877968 0.4065869150002262,0.09213256532413067 0.4066438088978241,0.09221431604683519 0.4069282783858235,0.09221431604683519 0.4072696417714259,0.09213256532413067 0.4072696417714259,0.09188731315607515 0.40738342956662166,0.09172381171072418 0.40772479295222397,0.0915603102653732 0.4078385807474248,0.0915603102653732 0.40829373192822294,0.09131505809731769 0.4083506258258258,0.0911515566519667 0.4086919892114232,0.09090630448396929 0.40880577700662396,0.09074280303861831 0.4088626709042269,0.09066105231591379 0.4094316098802258,0.09041580014785826 0.4097160793682253,0.09008879725715631 0.4100574427538276,0.08976179436645436 0.4101143366514255,0.08976179436645436 0.4107970634226252,0.0894347914757524 0.4112522146034233,0.08902603786234592 0.4112522146034233,0.08894428713964138 0.41165047188662357,0.08853553352629298 0.412503880350627,0.08837203208094199 0.41256077424822485,0.08829028135823747 0.41278834983862644,0.08820853063553294 0.4132435010194246,0.08820853063553294 0.41335728881462536,0.08804502919018195 0.41352797050742907,0.0879632784675355 0.4136986522002277,0.08804502919018195 0.4138693338930264,0.08788152774483098 0.4138693338930264,0.08788152774483098 0.4136986522002277,0.08771802629948 0.4138124399954285,0.08755452485412901 0.41375554609782556,0.08739102340877804 0.4144382728690253,0.08698226979537155 0.4144382728690253,0.08698226979537155 0.41432448507382447,0.08673701762731603 0.41449516676662823,0.0866552669046696 0.4148934240498285,0.0866552669046696 0.4154054691282295,0.08632826401396765 0.4154623630258274,0.08632826401396765 0.4159744081042284,0.08600126112326567 0.416714028773026,0.08583775967785662 0.4167709226706289,0.08583775967785662 0.41716917995382913,0.0855925075098592 0.4177381189298281,0.08493850172839719 0.4180225884178275,0.08485675100575074 0.41807948231543046,0.08485675100575074 0.4189328907794288,0.08485675100575074 0.41910357247222746,0.08477500028304621 0.4193880419602269,0.08436624666963971 0.4194449358578298,0.08436624666963971 0.42001387483382874,0.0841209945016423 0.42035523821943116,0.08395749305629133 0.42081038940022925,0.08403924377893776 0.4208672832978322,0.08403924377893776 0.42137932837622816,0.0838757423335868 0.4217206917618305,0.08354873944288482 0.4221189490450308,0.0834669887201803 0.42228963073782944,0.08330348727482932 0.42228963073782944,0.08330348727482932 0.4224603124306281,0.08313998582947835 0.42285856971382835,0.08305823510683188 0.42302925140663206,0.08297648438412736 0.42365508428022886,0.08281298293877638 0.42359819038263097,0.08281298293877638 0.4240533415634291,0.08273123221607186 0.4242240232562328,0.08232247860272346 0.4243947049490315,0.08224072788001892 0.4247929622322317,0.08215897715731438 0.4247929622322317,0.08215897715731438 0.4253619012082306,0.08199547571196342 0.42530500731063275,0.081750223543966 0.425703264593833,0.08134146993055949 0.425703264593833,0.08125971920785496 0.42587394628663167,0.08134146993055949 0.4260446279794303,0.08142322065326403 0.4264428852626306,0.08134146993055949 0.42706871813623243,0.08134146993055949 0.4271825059314332,0.08134146993055949 0.42860485337143045,0.08117796848520853 0.42860485337143045,0.08109621776250399 0.428889322859435,0.08109621776250399 0.4287755350642342,0.08125971920785496 0.42934447404023307,0.08109621776250399 0.4292306862450323,0.08093271631715301 0.42900311065463076,0.08085096559450657 0.42900311065463076,0.08076921487180203 0.4284341716786318,0.08076921487180203 0.4277514449074321,0.08044221198110008 0.42763765711223134,0.08044221198110008 0.4272393998290311,0.08036046125839555 0.4276945510098342,0.08019695981304456 0.4280928082930345,0.0802787105357491 0.42814970219063236,0.08036046125839555 0.42814970219063236,0.08052396270374652 0.428320383883431,0.08060571342645105 0.4288324289618321,0.08068746414915559 0.4287186411666312,0.08052396270374652 0.42894621675703287,0.08052396270374652 0.42900311065463076,0.08060571342645105 0.4292306862450323,0.08076921487180203 0.4296289435282326,0.08076921487180203 0.4299703069138349,0.08093271631715301 0.4300272008114328,0.08076921487180203 0.43019788250423147,0.08068746414915559 0.43019788250423147,0.08068746414915559 0.43042545809463306,0.08060571342645105 0.4309943970706319,0.08085096559450657 0.4311650787634357,0.08068746414915559 0.4311650787634357,0.0802787105357491 0.4311650787634357,0.0802787105357491 0.43173401773943454,0.08011520909039813 0.4319615933298362,0.08003345836769359 0.43207538112503185,0.08019695981304456 0.4319615933298362,0.08036046125839555 0.4319615933298362,0.08052396270374652 0.4320184872274341,0.08060571342645105 0.43213227502263485,0.08060571342645105 0.4323029567154335,0.08076921487180203 0.4332132590770348,0.08085096559450657 0.4334408346674364,0.08101446703985754 0.4334977285650342,0.08101446703985754 0.4337821980530337,0.08109621776250399 0.4340666675410331,0.08134146993055949 0.4345218187218363,0.08199547571196342 0.4345218187218363,0.08199547571196342 0.4346356065170371,0.08215897715731438 0.43480628820983575,0.08232247860272346 0.4350338638002374,0.08264948149342541 0.43554590887863337,0.08305823510683188 0.43560280277623625,0.08313998582947835 0.43594416616183357,0.08363049016553128 0.43628552954743594,0.0838757423335868 0.43656999903543536,0.08420274522428875 0.43662689293303836,0.08420274522428875 0.436797574625837,0.08436624666963971 0.43702515021623856,0.08436624666963971 0.43713893801143433,0.08452974811504879 0.4372527258066351,0.08502025245110173 0.43736651360183587,0.08526550461915723 0.43736651360183587,0.08534725534180368 0.4375940891922375,0.08534725534180368 0.4381630281682364,0.08485675100575074 0.43833370986103504,0.08493850172839719 0.43839060375863803,0.08518375389645269 0.43839060375863803,0.08518375389645269 0.4385043915538388,0.08567425823250563 0.4384474976562359,0.08583775967785662 0.4385043915538388,0.08624651329126311 0.43839060375863803,0.0866552669046696 0.43839060375863803,0.08673701762731603 0.4384474976562359,0.08698226979537155 0.43878886104183823,0.08706402051807607 0.43913022442743554,0.08681876835002057 0.43930090612023925,0.08690051907272511 0.4394715878130379,0.0866552669046696 0.4394715878130379,0.08657351618196506 0.43964226950583657,0.08641001473661408 0.4398698450962382,0.08641001473661408 0.4398129511986352,0.08714577124072254 0.4398698450962382,0.08739102340877804 0.4398698450962382,0.08739102340877804 0.4398698450962382,0.08763627557683355 0.439926738993836,0.08779977702218453 0.439983632891439,0.08812677991288648 0.4403249962770363,0.08861728424893942 0.4403818901746392,0.08869903497164394 0.44066635966263873,0.08869903497164394 0.4404387840722371,0.08820853063553294 0.4404387840722371,0.0879632784675355 0.44055257186743785,0.08755452485412901 0.44055257186743785,0.08755452485412901 0.4408370413554374,0.08690051907272511 0.4408370413554374,0.08649176545931861 0.4407801474578395,0.08608301184591213 0.4407801474578395,0.08608301184591213 0.4408370413554374,0.08591951040056114 0.4410646169458389,0.08583775967785662 0.44095082915063816,0.08575600895521017 0.44100772304823604,0.08551075678715467 0.4411215108434368,0.08518375389645269 0.4412921925362405,0.08493850172839719 0.4412921925362405,0.08493850172839719 0.441519768126637,0.08452974811504879 0.4411784047410397,0.08379399161094034 0.4411784047410397,0.08354873944288482 0.4411215108434368,0.0834669887201803 0.44095082915063816,0.08313998582947835 0.44095082915063816,0.08297648438412736 0.4410646169458389,0.08281298293877638 0.4411784047410397,0.08215897715731438 0.4412352986386376,0.08215897715731438 0.441519768126637,0.081586722098615 0.44157666202423995,0.08101446703985754 0.441519768126637,0.08076921487180203 0.441519768126637,0.08076921487180203 0.4417473437170386,0.08068746414915559 0.4419180254098373,0.08125971920785496 0.44214560100023886,0.08166847282126145 0.44214560100023886,0.08191372498931696 0.44214560100023886,0.08199547571196342 0.4422593887954397,0.0824042293253699 0.44288522166903643,0.08313998582947835 0.4429421155666393,0.08322173655218287 0.44322658505463886,0.08354873944288482 0.4434541606450404,0.0834669887201803 0.4435110545426383,0.08371224088823581 0.4433403728498396,0.08379399161094034 0.44322658505463886,0.08395749305629133 0.44316969115704097,0.08420274522428875 0.44322658505463886,0.08420274522428875 0.44362484233783905,0.08477500028304621 0.4437386301330398,0.08469324956039978 0.4437386301330398,0.08420274522428875 0.4437386301330398,0.0841209945016423 0.4437955240306377,0.08354873944288482 0.44368173623543694,0.08273123221607186 0.44368173623543694,0.08264948149342541 0.44362484233783905,0.08166847282126145 0.44368173623543694,0.08150497137591048 0.4439093118258385,0.081586722098615 0.4439662057234415,0.08166847282126145 0.4445920385970382,0.0824042293253699 0.44476272028984193,0.08289473366142283 0.44476272028984193,0.08297648438412736 0.4449334019826406,0.08338523799753386 0.44504718977784136,0.0834669887201803 0.44510408367543924,0.08363049016553128 0.44521787147064,0.08379399161094034 0.4451609775730421,0.08420274522428875 0.44521787147064,0.08428449594699328 0.4452747653682379,0.08452974811504879 0.4451609775730421,0.08469324956039978 0.4451609775730421,0.08485675100575074 0.4452747653682379,0.0855925075098592 0.4452747653682379,0.08567425823250563 0.4453316592658408,0.08649176545931861 0.44538855316343867,0.08673701762731603 0.44544544706104167,0.08690051907272511 0.4456161287538403,0.08706402051807607 0.4456730226514382,0.08698226979537155 0.4456730226514382,0.08690051907272511 0.4456730226514382,0.08641001473661408 0.4460143860370405,0.08575600895521017 0.4460712799346384,0.08551075678715467 0.4461281738322413,0.0854290060645082 0.44641264332024083,0.08510200317374816 0.4466402189106424,0.08502025245110173 0.4469815822962397,0.08444799739234425 0.4469815822962397,0.08436624666963971 0.4469815822962397,0.0841209945016423 0.4470384761938426,0.08395749305629133 0.4470384761938426,0.0834669887201803 0.4469815822962397,0.08322173655218287 0.4470384761938426,0.08297648438412736 0.4470384761938426,0.08297648438412736 0.4472660517842392,0.08264948149342541 0.4473229456818421,0.08232247860272346 0.44755052127223865,0.081750223543966 0.44760741516984154,0.08166847282126145 0.44755052127223865,0.08109621776250399 0.44692468839864186,0.08060571342645105 0.4468677945010389,0.08052396270374652 0.4466402189106424,0.0802787105357491 0.4464695372178387,0.07986995692234261 0.4465264311154416,0.07970645547699162 0.4464695372178387,0.07954295403164066 0.4465264311154416,0.07905244969552963 0.4465833250130395,0.07897069897288318 0.4466402189106424,0.07880719752753221 0.44669711280824026,0.07839844391412572 0.44681090060344103,0.07823494246877474 0.44692468839864186,0.07766268741001728 0.44692468839864186,0.07758093668737082 0.4470384761938426,0.07717218307396434 0.4469815822962397,0.07692693090590882 0.44720915788664134,0.07692693090590882 0.44755052127223865,0.07643642656985589 0.44760741516984154,0.07635467584715136 0.447891884657841,0.07586417151109842 0.4482901419410412,0.07545541789769195 0.448403929736242,0.07529191645234096 0.4484608236338399,0.07521016572963643 0.44868839922424153,0.07463791067093704 0.4488590809170402,0.0739021541668286 0.4488590809170402,0.07382040344412406 0.44897286871224096,0.07275764404931367 0.44908665650744173,0.07234889043590717 0.4491435504050396,0.07226713971326074 0.4492004443026425,0.07210363826785166 0.44902976260983885,0.07202188754520522 0.44902976260983885,0.07267589332660913 0.44908665650744173,0.07308464694001562 0.44908665650744173,0.07316639766272015 0.4491435504050396,0.07357515127606856 0.44902976260983885,0.07414740633482603 0.44902976260983885,0.0745561599482325 0.44902976260983885,0.0745561599482325 0.4492573382002404,0.07463791067093704 0.4493142320978434,0.07529191645234096 0.4492573382002404,0.07545541789769195 0.44942801989303904,0.07570067006574745 0.44942801989303904,0.07570067006574745 0.4496555954834407,0.07570067006574745 0.44988317107384224,0.07651817729250233 0.45011074666424383,0.07643642656985589 0.45022453445943955,0.07668167873785331 0.4502814283570425,0.07676342946055784 0.45045211004984115,0.07692693090590882 0.4506227917426398,0.07741743524196176 0.4509641551282421,0.07798969030071923 0.45102104902584006,0.07798969030071923 0.45119173071864377,0.07823494246877474 0.4513624124114424,0.07880719752753221 0.45170377579704485,0.07937945258628967 0.4517606696946426,0.07946120330893612 0.4523296086706416,0.08036046125839555 0.45244339646584236,0.08076921487180203 0.45244339646584236,0.08085096559450657 0.45250029036344025,0.08093271631715301 0.45289854764664045,0.08101446703985754 0.4530692293394442,0.08117796848520853 0.453183017134645,0.08134146993055949 0.45329680492984076,0.08199547571196342 0.45335369882744364,0.08199547571196342 0.45341059272504153,0.08248598004807443 0.4535243805202423,0.08281298293877638 0.4535243805202423,0.0834669887201803 0.45358127441784524,0.0834669887201803 0.4536381683154431,0.08371224088823581 0.4537519561106439,0.08428449594699328 0.4536381683154431,0.08444799739234425 0.4537519561106439,0.08493850172839719 0.4538088500082418,0.08493850172839719 0.45386574390584467,0.08518375389645269 0.4537519561106439,0.08551075678715467 0.4537519561106439,0.08567425823250563 0.4540933194962412,0.08616476256861666 0.4541502133938441,0.08616476256861666 0.45392263780344255,0.08616476256861666 0.45392263780344255,0.08632826401396765 0.454207107291442,0.08657351618196506 0.454207107291442,0.08690051907272511 0.45437778898424575,0.08714577124072254 0.45437778898424575,0.08714577124072254 0.45432089508664275,0.08739102340877804 0.4546622584722452,0.08755452485412901 0.45477604626744594,0.0879632784675355 0.45483294016504383,0.08812677991288648 0.45471915236984306,0.08829028135823747 0.45477604626744594,0.08837203208094199 0.45477604626744594,0.08837203208094199 0.4549467279602446,0.08918953930769688 0.4550036218578425,0.08935304075304787 0.45483294016504383,0.08976179436645436 0.45483294016504383,0.0898435450891589 0.45477604626744594,0.08992529581180533 0.4549467279602446,0.08992529581180533 0.4550036218578425,0.09033404942521181 0.45517430355064625,0.09057930159320925 0.45523119744824414,0.09106980592932026 0.45523119744824414,0.09106980592932026 0.4554018791410428,0.09090630448396929 0.4554018791410428,0.09074280303861831 0.45551566693624357,0.09106980592932026 0.45551566693624357,0.09139680882002223 0.4557432425266451,0.09139680882002223 0.455800136424243,0.09139680882002223 0.45585703032184594,0.09139680882002223 0.45562945473144434,0.09139680882002223 0.455800136424243,0.09180556243342872 0.4559139242194438,0.09196906387877968 0.4560846059122425,0.09229606676948166 0.4560846059122425,0.09245956821483262 0.4560277120146446,0.09254131893753716 0.45597081811704165,0.09278657110553458 0.4560846059122425,0.09295007255094365 0.45614149980984536,0.09311357399629462 0.4562552876050462,0.0930318232735901 0.45648286319544273,0.09319532471894107 0.45642596929784485,0.09352232760964302 0.45642596929784485,0.09360407833234756 0.45642596929784485,0.09393108122304952 0.4560846059122425,0.09417633339110502 0.4562552876050462,0.09409458266840048 0.45642596929784485,0.09417633339110502 0.45642596929784485,0.09458508700451151 0.45648286319544273,0.09466683772715795 0.4565966509906435,0.09499384061785993 0.4565966509906435,0.09532084350861997 0.45676733268344216,0.09564784639932192 0.4568242265810451,0.09597484929002387 0.4568242265810451,0.09605660001272841 0.456881120478643,0.09630185218072582 0.45705180217144664,0.0964653536260768 0.45705180217144664,0.0966288550714278 0.45745005945464695,0.09679235651683685 0.4576776350450435,0.09720111013018526 0.4576776350450435,0.09728286085288979 0.4577345289426464,0.0975281130209453 0.45790521063544504,0.09769161446629628 0.4576776350450435,0.09777336518894272 0.4576207411474456,0.09793686663429368 0.4580758923282437,0.09834562024770019 0.4581327862258467,0.09842737097040472 0.45830346791864535,0.09908137675180864 0.45870172520184554,0.09981713325591707 0.45875861909944343,0.09981713325591707 0.45892930079224714,0.10006238542397258 0.45870172520184554,0.09998063470126806 0.458986194689845,0.10022588686932357 0.4593844519730452,0.1007163912053765 0.4594413458706431,0.10079814192808104 0.45966892146104465,0.1013703969868385 0.46006717874424496,0.10194265204553787 0.46012407264184785,0.10194265204553787 0.4602378604370436,0.10235140565894436 0.4602378604370436,0.10276015927235085 0.4604085421298473,0.1028419099949973 0.46052232992504816,0.10325066360840379 0.46052232992504816,0.10325066360840379 0.46057922382264593,0.10300541144040637 0.4606361177202438,0.1028419099949973 0.4606361177202438,0.10259665782699989 0.4607499055154446,0.1024331563816489 0.461091268901047,0.1030871621630528 0.461091268901047,0.10316891288575734 0.4611481627986449,0.10341416505375478 0.461091268901047,0.10398642011251225 0.46097748110584624,0.10365941722181028 0.46097748110584624,0.10390466938986578 0.46097748110584624,0.10390466938986578 0.4612050566962478,0.10406817083521677 0.46126195059384567,0.10382291866716126 0.4616033139794481,0.10365941722181028 0.46171710177464886,0.10374116794451482 0.461660207877046,0.10414992155786322 0.461660207877046,0.10423167228056776 0.46171710177464886,0.10472217661662069 0.46183088956984464,0.10488567806197166 0.4618877834674475,0.10570318528878464 0.4618877834674475,0.10578493601143109 0.4620584651602462,0.1064389417928931 0.4622860407506478,0.107092947574297 0.4622860407506478,0.10717469829700153 0.4622860407506478,0.10741995046499896 0.4621153590578491,0.10741995046499896 0.4620584651602462,0.10782870407840545 0.46222914685304484,0.1081557069691074 0.46245672244344643,0.10807395624646095 0.46245672244344643,0.10807395624646095 0.46279808582904874,0.10799220552375642 0.4630825553170483,0.10799220552375642 0.46365149429304714,0.10766520263305446 0.4637652820882479,0.10766520263305446 0.46410664547384534,0.10766520263305446 0.46444800885944765,0.10782870407840545 0.46450490275704553,0.10807395624646095 0.46450490275704553,0.10823745769181194 0.46439111496184976,0.10848270985986744 0.4643342210642469,0.10856446058251389 0.464277327166649,0.10889146347321585 0.4643342210642469,0.1090549649186249 0.46496005393784867,0.10946371853197331 0.46507384173304944,0.10954546925467784 0.4654152051186468,0.11003597359073078 0.465358311221049,0.11044472720413727 0.4655858868114505,0.11085348081754376 0.4655858868114505,0.11085348081754376 0.4657565685042492,0.11109873298554118 0.4660979318898465,0.11068997937219277 0.4664392952754489,0.11060822864948824 0.4666099769682476,0.11052647792678372 0.46666687086585046,0.11044472720413727 0.46672376476344835,0.11036297648143273 0.46695134035385,0.11077173009483923 0.4673495976370502,0.11077173009483923 0.4676909610226475,0.11077173009483923 0.4678047488178483,0.11060822864948824 0.4678047488178483,0.11060822864948824 0.4679185366130491,0.11068997937219277 0.46774785492025045,0.11085348081754376 0.46757717322744674,0.11077173009483923 0.4683736877938472,0.11085348081754376 0.4683736877938472,0.11093523154019021 0.46860126338424873,0.11109873298554118 0.46848747558904796,0.11118048370824571 0.46945467184825224,0.11134398515359668 0.4695115657458501,0.11142573587630122 0.4700236108242511,0.11150748659894767 0.4703649742098484,0.11167098804429865 0.47099080708345026,0.11158923732165221 0.47099080708345026,0.11158923732165221 0.4719011094450516,0.1119979909350006 0.4722993667282518,0.1119979909350006 0.4723562606258497,0.1119979909350006 0.4725838362162512,0.11207974165770514 0.4734372446802496,0.11281549816181358 0.47349413857785255,0.11289724888451812 0.4741768653490523,0.113714756111273 0.47429065314425306,0.11396000827932852 0.47423375924665007,0.11396000827932852 0.47423375924665007,0.11404175900197497 0.47429065314425306,0.11420526044732594 0.4746320165298504,0.11436876189267692 0.47508716771065357,0.11469576478343696 0.47520095550585434,0.11494101695143438 0.47520095550585434,0.11502276767413892 0.47548542499385377,0.11616727779165385 0.4754285310962509,0.11641252995965128 0.4754285310962509,0.1164942806823558 0.4756561066866524,0.11731178790911069 0.4757130005842503,0.1179657936905727 0.47576989448185325,0.11804754441321914 0.4758267883794511,0.11878330091732758 0.475371637198653,0.11935555597608506 0.4753147433010501,0.11943730669878959 0.47514406160825146,0.12025481392554448 0.4753147433010501,0.12082706898430196 0.4753147433010501,0.1209088197070065 0.47554231889145165,0.12107232115235747 0.475883682277054,0.12066356753895097 0.47605436396985273,0.12058181681630452 0.47645262125305293,0.12066356753895097 0.47656640904825376,0.12066356753895097 0.47696466633145396,0.12082706898430196 0.47736292361465427,0.12172632693376137 0.47741981751225204,0.12172632693376137 0.477988756488251,0.12238033271522336 0.4785008015666521,0.12270733560592534 0.47861458936185286,0.12270733560592534 0.479069740542656,0.12278908632857177 0.4794111039282533,0.12303433849662729 0.47969557341625274,0.1232795906646828 0.47975246731385573,0.12344309211003378 0.47969557341625274,0.12352484283268021 0.47963867951865485,0.12360659355538475 0.4795248917234541,0.12385184572344025 0.47969557341625274,0.12385184572344025 0.4803214062898546,0.12344309211003378 0.480605875777854,0.12336134138732924 0.4807196635730549,0.12336134138732924 0.4810610269586522,0.12344309211003378 0.4815161781394554,0.12377009500073573 0.4819144354226556,0.12377009500073573 0.4820282232178564,0.12377009500073573 0.4829385255794577,0.12352484283268021 0.483279888965055,0.12352484283268021 0.4833936767602558,0.12352484283268021 0.48441776691705785,0.12377009500073573 0.484872918097856,0.12377009500073573 0.48498670589305676,0.12368834427808928 0.48527117538105624,0.12368834427808928 0.48532806927865413,0.12360659355538475 ================================================ FILE: demo/src/main/assets/tracks/track3.txt ================================================ 0.4961379098226587,0.3391014985361062 0.5002342704498619,0.33877449564540424 0.5047288883602654,0.3378752376959448 0.5054116151314652,0.3382839913093513 0.5058098724146654,0.33836574203199776 0.5066632808786637,0.3382839913093513 0.5074029015474664,0.33779348697329836 0.5076873710354658,0.33730298263718733 0.5078011588306666,0.3364037246877279 0.5073460076498635,0.3355044667382685 0.5066632808786637,0.33501396240221554 0.5060943419026648,0.33485046095686455 0.5054685090290629,0.33493221167951104 0.5033065409202631,0.3343599566207536 0.5023393446610639,0.3343599566207536 0.4983567718290615,0.335586217460973 0.49545518305145897,0.3361584725197305 0.49391904781626084,0.3364037246877279 0.48703488620665586,0.3365672261330789 0.4856694326642565,0.3364037246877279 0.4846453425074544,0.3359949710743214 0.48401950963385765,0.33542271601562207 0.48316610116985426,0.3343599566207536 0.4816299659346562,0.3318256842177263 0.48049208798265325,0.3321526871084282 0.4741199714514493,0.3299454175961029 0.4700236108242511,0.3280651509745376 0.4664392952754489,0.3261848843529142 0.465301417323446,0.3255308785715103 0.46285497972664663,0.32373236267253336 0.46217225295544695,0.32356886122718237 0.4618877834674475,0.32324185833648045 0.461091268901047,0.32307835689112946 0.4588155129970463,0.32291485544577847 0.45779142284024427,0.322506101832372 0.45710869606904453,0.32201559749631903 0.45295544154424344,0.3178463106397239 0.4448196141874398,0.32626663507561876 0.4381630281682364,0.3321526871084282 0.4331563651794369,0.3368942290238389 0.43247363840823216,0.33779348697329836 0.43218916892023274,0.33861099420005325 0.4327012139986337,0.341554020216487 0.43218916892023274,0.34179927238454255 0.4322460628178356,0.3431890346700549 0.4320184872274341,0.34417004334221885 0.43173401773943454,0.3449057998463273 0.4296289435282326,0.3471948200812991 0.4217775856594284,0.35422538223168154 0.4180225884178275,0.35782241402951925 0.4078385807474248,0.36656974135611614 0.4060748699218252,0.368204755809684 0.39964585949302334,0.37261929483433465 0.3858206423762155,0.38193887721968894 0.38212253903221244,0.3847184017907717 0.3819518573394138,0.3845549003454207 0.38138291836341487,0.3845549003454207 0.38115534277301333,0.3846366510681253 0.38098466108021467,0.3850454046814737 0.38098466108021467,0.3852906568495292 0.37944852584501154,0.38602641335363763 0.36835421581300754,0.3923212189999116 0.354415210901004,0.40098679560380396 0.35350490853940264,0.4017225521079124 0.35231013668980193,0.4030305636707783 0.3510584709426033,0.40499258101504815 0.3483844577553973,0.4113691373840267 0.34724657980339946,0.413576406896294 0.34559665677300067,0.4159471778540284 0.34332090086899997,0.4181544473662956 0.34030552429619665,0.42036171687862095 0.33353515048179244,0.42453100373527425 0.32636651938419303,0.4304170557680837 0.32374940009458997,0.4321338209443561 0.31117584872498577,0.43859212803598113 0.3077622148689822,0.44071764682560194 0.30747774538098277,0.44047239465760446 0.30668123081458226,0.4403906439348999 0.3062260796337842,0.44055414538025095 0.3059985040433826,0.44088114827095287 0.3058278223505839,0.44145340332971034 0.30332449085618163,0.44202565838846786 0.2987160851505773,0.44267966416987176 0.296269647553778,0.44251616272452077 0.2939369977521794,0.4421074091111724 0.28386677787697245,0.4391643830947386 0.2817617036657704,0.4391643830947386 0.2809651890993699,0.43924613381738503 0.2796566294545734,0.4396548874307915 0.2773808735505727,0.44071764682560194 0.27556026882737017,0.44137165260706396 0.27191905938097005,0.4421891598338188 0.267196865880165,0.44292491633792724 0.2641245954097638,0.4433336699513337 0.25615944974576393,0.4427614148925763 0.253485436558563,0.44292491633792724 0.25018559049776024,0.44374242356474025 0.24785294069615657,0.44472343223684613 0.24625991156335558,0.44586794235436106 0.24415483735215862,0.4478299596986309 0.24227733873135818,0.4491379712614968 0.24005847672495534,0.4503642321016581 0.23766893302575387,0.45126349005117566 0.23641726727855525,0.45159049294187764 0.22776939484335063,0.4523262494459861 0.22372992811375028,0.452816753782039 0.2167888726065474,0.4532255073954455 0.21166842182254206,0.45420651606755136 0.21155463402734126,0.45404301462220037 0.21109948284654315,0.45371601173149845 0.21058743776814212,0.4538795131768494 0.21030296828014267,0.4542882667902559 0.21035986217774053,0.45461526968095783 0.21070122556334292,0.45502402329436437 0.21041675607534346,0.4553510261850663 0.2062066076529394,0.4574765449747452 0.19812767419373872,0.46238158833544873 0.19602259998253668,0.4640166027890167 0.19351926848813442,0.4663056230239884 0.1927227539217339,0.46728663169615237 0.18794366652333097,0.4739084402331284 0.18396109369133354,0.48044849804739986 0.18310768522733012,0.4800397444339934 0.1825387462513312,0.4800397444339934 0.18020609644973265,0.4808572516608064 0.17940958188333214,0.48077550093810184 0.1788406429073282,0.48036674732475343 0.17861306731693166,0.4794674893752359 0.178954430702529,0.47873173287112747 0.18117329270893182,0.47644271263615573 0.18231117066092964,0.47488944890523427 0.18242495845613044,0.47448069529188586 0.18242495845613044,0.4739084402331284 0.18219738286572884,0.47358143734242647 0.17935268798572926,0.4707201620486391 0.17832859782892715,0.4701479069898816 0.17639420531052885,0.4696574026538287 0.175768372436927,0.47039315915793717 0.17480117617772786,0.4713741678301011 0.17406155550892524,0.472518677947558 0.17400466161132735,0.47292743156096445 0.17406155550892524,0.4739901909557749 0.17457360058732627,0.4755434546866963 0.17457360058732627,0.47627921119080474 0.17434602499692975,0.4770149676949132 0.17411844940652815,0.4773419705856151 0.1721840568881248,0.4788952343165365 0.16825837795372522,0.4815112574422103 0.16450338071212436,0.4842907820132931 0.1602932322897203,0.4862527993575629 0.15750543130731856,0.48739730947507787 0.1538642218609185,0.4883783181472418 0.1521574049329167,0.4883783181472418 0.15107642087851678,0.4881330659791863 0.14692316635371563,0.48617104863491645 0.14618354568491806,0.48592579646686096 0.14544392501611542,0.4858440457442145 0.14430604706411762,0.48633455008026744 0.14413536537131388,0.486579802248323 0.1433388508049134,0.48633455008026744 0.14214407895531267,0.4864163008029139 0.1385597634065155,0.4872338080297269 0.13793393053291367,0.4871520573070223 0.13628400750250974,0.4864980515256184 0.13213075297770863,0.4841272805679421 0.12405181951850794,0.4778324749216681 0.11944341381290363,0.47382668951042384 0.11711076401130507,0.4712106663847501 0.11540394708330329,0.46843114181366735 0.11437985692650121,0.46589686941064 0.11341266066730205,0.46156408110863584 0.11250235830570077,0.4568225391932832 0.11170584373930029,0.4542882667902559 0.11090932917289978,0.45257150161398346 0.10954387563050036,0.4503642321016581 0.10652849905770212,0.446685449581174 0.10436653094889717,0.44259791344722527 0.10294418350889989,0.44055414538025095 0.10066842760489919,0.4385103773132766 0.09429631107369525,0.43417758901133047 0.0931015392240945,0.43295132817116905 0.09179297957929297,0.4300083021547353 0.0910533589104954,0.4287820413145158 0.08837934572329446,0.42493975734862255 0.08798108844009422,0.4242040008445142 0.08763972505449184,0.42224198350024433 0.0865587410000919,0.42019821543326996 0.08581912033128927,0.4180726966436492 0.08559154474089273,0.4177456937529472 0.08388472781289097,0.4162741807447303 0.08104003293289136,0.4133311547282965 0.07927632210728666,0.4112873866613222 0.07677299061288943,0.40867136353559036 0.07609026384168469,0.40801735775418646 0.073302462859288,0.4061370911325631 0.06442701483368177,0.3985342739234812 0.06146853215848138,0.39534599573899193 0.05714459594088159,0.38929644226077337 0.05572224850087926,0.3868439205804506 0.05287755362087966,0.3813666221609895 0.049691495355277684,0.37580757301882395 0.04741573945127699,0.3709025296581203 0.04622096760167625,0.36877701086844145 0.04468483236647314,0.3667332428014671 0.040133320558471755,0.3621552023314654 0.0383696097328721,0.3601931849871956 0.03751620126887374,0.3590486748696806 0.03637832331687087,0.35700490680276437 0.03535423316006879,0.3545523851223836 0.03484218808166775,0.3527538692234647 0.034557718593668296,0.35095535332454586 0.034443930798467505,0.349156837425627 0.034614612491271214,0.34629556213183965 0.035183551467270126,0.3435977882834614 0.036890368395271905,0.33771173625059386 0.037231731780869234,0.33607672179702597 0.03762998906406948,0.33329719722594314 0.0376868829616724,0.3317439334950798 0.03745930737127082,0.32904615964664347 0.036890368395271905,0.3264301365209697 0.035923172136072754,0.3239776148405889 0.034330143003271765,0.3210345888241551 0.028640753243267512,0.31261426438826023 0.026706360724869198,0.30991649053988196 0.025397801080067665,0.30819972536360957 0.022723787892866727,0.30542020079258486 0.018798108958462127,0.3019049197173936 0.017375761518464858,0.3010056617679342 0.011458796168059018,0.2977356328607404 0.011117432782461696,0.297326879247392 0.01094675108965798,0.29675462418863446 0.01094675108965798,0.2955283633484731 0.011174326680059563,0.2951196097350666 0.011857053451259265,0.2946291053989556 0.012198416836861643,0.2944656039536046 0.01265356801765976,0.2946291053989556 0.013620764276858915,0.2952831111804176 0.015498262897664414,0.29691812563398545 0.016408565259260644,0.29740862997003836 0.0177740188016651,0.2978173835834449 0.01868432116326134,0.29838963864220236 0.02340651466406643,0.302313673330742 0.024203029230466924,0.30321293128025956 0.025625376670464196,0.3059924558512842 0.02625120954406603,0.30623770801933975 0.02727529970086811,0.30607420657398876 0.027730450881666226,0.30542020079258486 0.027787344779269148,0.30476619501112284 0.027673556984068357,0.30435744139771637 0.0273890874960689,0.3040304385070144 0.024203029230466924,0.3019049197173936 0.01936704793446609,0.2978173835834449 0.018456745572864804,0.29724512852468743 0.01657924695206436,0.29642762129793254 0.016010307976060397,0.2958553662391751 0.01572583848806094,0.29520136045771306 0.015384475102463619,0.2936480967268497 0.015498262897664414,0.29242183588668835 0.015782732385663866,0.2916860793825799 0.01663614084966223,0.2904598185423604 0.01726197372326406,0.289887563483603 0.01822916998246322,0.28956056059290103 0.01931015403686317,0.28947880987025454 0.026820148520064938,0.2906233199877114 0.02744598139366677,0.29054156926506497 0.028185602062469395,0.290378067819714 0.028754541038468306,0.29005106492895394 0.02920969221926642,0.28956056059290103 0.029664843400069592,0.2888248040887926 0.029949312888069044,0.2875985432486312 0.029778631195270383,0.28130373760235716 0.028868328833669098,0.2781154594179259 0.02744598139366677,0.27435492617467916 0.02522711938726395,0.26642510607489533 0.02465818041126504,0.2630733264450551 0.024259923128064794,0.2616018134368382 0.022837575688067522,0.2583317845297024 0.02221174281446569,0.25628801646272803 0.021244546555266534,0.25236398177413033 0.021016970964864948,0.24982970937110305 0.021073864862462818,0.24794944274953776 0.021642803838466777,0.24353490372488706 0.01891189675366292,0.2156579072914707 0.017944700494463763,0.21173387260287296 0.01822916998246322,0.2116521218802265 0.018627427265663465,0.21107986682146906 0.018627427265663465,0.21075286393076706 0.018513639470462674,0.2104258610400651 0.018001594392061636,0.21009885814930507 0.0177740188016651,0.21009885814930507 0.0177740188016651,0.20887259730914373 0.017944700494463763,0.20715583213287128 0.014644854433660995,0.1739650387254029 0.014019021560059162,0.17126726487702462 0.012369098529660304,0.16922349681005028 0.010889857192060107,0.16799723596983082 0.003948801684857246,0.1641549520039376 0.0014454701904549755,0.16227468538237233 -0.0015130124847454185,0.1609666738195064 -0.004585282955146604,0.16006741587004697 -0.03957502997916037,0.1573696420216687 -0.04355760281116284,0.15761489418966612 -0.04606093430556512,0.15867765358447655 -0.057041456542368314,0.16366444766788468 -0.05823622839196906,0.16399145055858663 -0.060113727012769506,0.16390969983594017 -0.06182054394077128,0.16341919549982914 -0.06716857031517318,0.1607214216514509 -0.06819266047197017,0.16006741587004697 -0.0709804614543719,0.15875940430718105 -0.07337000515357339,0.15851415213912556 -0.07644227562397457,0.15875940430718105 -0.07951454609437575,0.1581871492484236 -0.0821885592815767,0.1573696420216687 -0.08412295179998008,0.15704263913090866 -0.08742279786078283,0.1571243898536132 -0.08856067581278065,0.15679738696291123 -0.08958476596958273,0.1563068826268002 -0.09077953781918346,0.15532587395469435 -0.09191741577118129,0.15450836672788137 -0.09305529372318416,0.1539361116691239 -0.09533104962718486,0.15336385661036644 -0.09595688250078163,0.15303685371966447 -0.09692407875998585,0.15221934649290958 -0.0986877895855855,0.1500938277032307 -0.09993945533278409,0.1479683089136099 -0.10102043938718408,0.1464150451826885 -0.10312551359838609,0.1446165292837696 -0.10392202816478657,0.1428997641075553 -0.10426339155038897,0.14036549170446994 -0.10471854273118708,0.13897572941895758 -0.1054581633999897,0.13807647146949814 -0.10631157186398807,0.13742246568809424 -0.1088717972559882,0.13619620484787476 -0.10961141792479082,0.1352151961757689 -0.11063550808158787,0.13276267449538803 -0.11126134095518969,0.13210866871398413 -0.11188717382879151,0.1317816658232241 -0.11461808091359033,0.1316181643778731 -0.11547148937759374,0.13120941076446663 -0.11934027441439543,0.12916564269755038 -0.12019368287839377,0.12802113258003545 -0.12116087913759294,0.1256503616223591 -0.12150224252319533,0.12254383416057436 -0.1222418631919929,0.12180807765646591 -0.12320905945119712,0.12148107476576395 -0.12747610177119903,0.12148107476576395 -0.12884155531359842,0.1211540718750039 -0.1341895816880003,0.11927380525343861 -0.13572571692319838,0.11829279658127466 -0.13709117046560282,0.11714828646375972 -0.13828594231520355,0.11502276767413892 -0.14135821278560476,0.10840095913716291 -0.14477184664160325,0.1043134230032142 -0.14727517813600552,0.1007163912053765 -0.14852684388320414,0.09957188108786157 -0.14926646455200676,0.0992448781971596 -0.151257750968008,0.0989996260291041 -0.1520542655344085,0.09916312747451317 -0.15683335293281145,0.10104339409607846 -0.1579143369872114,0.10177915060018691 -0.16115728915041125,0.1049674287846762 -0.16257963659041358,0.1062754403475421 -0.16639152772961233,0.10782870407840545 -0.16838281414561357,0.10840095913716291 -0.17043099445921267,0.10930021708662234 -0.17373084052001547,0.11036297648143273 -0.17794098894241953,0.11207974165770514 -0.18175288008161827,0.1124067445484071 -0.18357348480482086,0.11175273876700319 -0.1860768162992231,0.10897321419592038 -0.18738537594401958,0.107746953355759 -0.18840946610082165,0.10750170118770348 -0.18988870743842187,0.10758345191040802 -0.19091279759522395,0.10733819974235251 -0.19261961452322574,0.10611193890219113 -0.19347302298722407,0.10570318528878464 -0.19432643145122247,0.10562143456608011 -0.19569188499362689,0.10594843745684016 -0.1966021873552231,0.1066841939608905 -0.20121059306082748,0.11085348081754376 -0.20439665132642942,0.11355125466592203 -0.20684308892322875,0.11543152128754541 -0.20832233026082897,0.11641252995965128 -0.21116702514083363,0.11739353863181523 -0.21184975191203334,0.1179657936905727 -0.21236179699043436,0.11870155019468115 -0.21264626647843382,0.1200913124801935 -0.21213422140003277,0.1243423500594932 -0.21219111529763066,0.12646786884911398 -0.21241869088803225,0.1281846340253864 -0.21440997730403347,0.13210866871398413 -0.21497891628003238,0.1328444252180926 -0.2154909613584334,0.133253178831441 -0.21605990033443231,0.1334984309994965 -0.21714088438883225,0.1334984309994965 -0.21953042808803377,0.13317142810879457 -0.22066830604003665,0.13366193244484748 -0.2212941389136334,0.13423418750360494 -0.22169239619683365,0.13488819328500884 -0.22260269855843492,0.13856697580555108 -0.22305784973923812,0.1394662337550105 -0.2237974704080357,0.14003848881376796 -0.2248215605648378,0.14044724242717446 -0.22544739343843959,0.140528993149879 -0.226812846980839,0.1401202395364725 -0.22846277001123785,0.13856697580555108 -0.23107988930084092,0.13652320773857674 -0.23335564520484162,0.1345611903943069 -0.23420905366883996,0.133907184612903 -0.23517624992803912,0.1334984309994965 -0.23591587059684174,0.13333492955414553 -0.2398415495312413,0.13415243678090039 -0.24115010917604282,0.13415243678090039 -0.24627055996004818,0.13341668027679196 -0.24854631586404888,0.13259917305003707 -0.24939972432804722,0.13251742232733255 -0.2519599497200473,0.13308967738609 -0.254804644600052,0.1334984309994965 -0.2556580530640504,0.13374368316755203 -0.2586734296368537,0.13635970629322575 -0.2596406258960528,0.13701371207468777 -0.2604940343600512,0.13742246568809424 -0.26225774518565087,0.13742246568809424 -0.26584206073445305,0.13717721352003873 -0.2668092569936522,0.1373407149653897 -0.26771955935525354,0.1377494685787962 -0.26828849833125745,0.1381582221921446 -0.26891433120485425,0.13979323664577056 -0.2699953152592542,0.14142825109933843 -0.2723279650608578,0.1431450162755527 -0.27420546368165827,0.14420777567036314 -0.2747175087600593,0.14469828000647417 -0.2738641002960559,0.14469828000647417 -0.27289690403685674,0.14404427422501215 -0.2713038749040557,0.14339026844360825 -0.268004028843253,0.14224575832609332 -0.26453350108965157,0.14069249459522998 -0.26322494144485503,0.14036549170446994 -0.2620301695952543,0.14044724242717446 -0.26055092825765414,0.1407742453178764 -0.25702350660644974,0.14208225688074233 -0.2561132042448485,0.14232750904879785 -0.25491843239524775,0.1420005061580959 -0.2529271459792465,0.1411012482085784 -0.2524151009008505,0.14101949748593193 -0.25201684361765025,0.1411829989312829 -0.2517323741296508,0.14175525399004038 -0.2524151009008505,0.1441260249477167 -0.253211615467251,0.14616979301469105 -0.2543494934192488,0.14854056397236737 -0.25554426526884955,0.15001207698058425 -0.2564545676304509,0.15058433203934174 -0.25759244558244865,0.15082958420733916 -0.25946994420324915,0.15082958420733916 -0.26453350108965157,0.1503390798712862 -0.2653300156560521,0.1503390798712862 -0.26612653022245253,0.15082958420733916 -0.26629721191525624,0.15156534071144762 -0.2662403180176533,0.15230109721555604 -0.26584206073445305,0.15287335227431348 -0.2644197132944558,0.1536908595011265 -0.26003888317925306,0.15589812901345182 -0.2595837319984499,0.15663388551756025 -0.25946994420324915,0.15745139274431513 -0.2598113075888515,0.1581871492484236 -0.26066471605284985,0.15908640719788303 -0.264305925499255,0.16104842454215285 -0.2662403180176533,0.16153892887826388 -0.26715062037925463,0.16145717815555932 -0.26823160443365457,0.1612119259875619 -0.26971084577125476,0.1612119259875619 -0.2703366786448566,0.1613754274329129 -0.27073493592805686,0.1618659317689658 -0.2707918298256547,0.16235643610501876 -0.27073493592805686,0.16309219260912722 -0.27039357254245444,0.16341919549982914 -0.26971084577125476,0.16374619839058918 -0.266979938686456,0.16423670272664215 -0.26453350108965157,0.1654629635668035 -0.26385077431845183,0.16570821573485903 -0.26299736585445344,0.16570821573485903 -0.26038024656485037,0.1652177113988061 -0.25918547471524966,0.1652177113988061 -0.25713729440165056,0.1650542099534551 -0.2562838859376522,0.1650542099534551 -0.2538374483408478,0.16578996645756355 -0.2519599497200473,0.16644397223896745 -0.253211615467251,0.16767023307912884 -0.2545770690096504,0.16824248813788634 -0.25486153849764986,0.1685694910285883 -0.2564545676304509,0.17216652282648406 -0.25719418829924845,0.17322928222129444 -0.2652162278608563,0.185246638455027 -0.2703366786448566,0.19235895132805594 -0.2705642542352582,0.19358521216827543 -0.2704504664400574,0.19432096867238385 -0.2714176626992565,0.19464797156308583 -0.27238485895845566,0.19546547878984072 -0.2990680969328672,0.23437882278488378 -0.3051557439760717,0.24296264866612963 -0.30595225854247216,0.24386190661558904 -0.3061229402352708,0.24353490372488706 -0.3063505158256724,0.24337140227953613 -0.3066918792112697,0.24345315300218254 -0.30709013649447,0.24369840517023808 -0.30726081818727374,0.244188909506291 -0.30726081818727374,0.244842915287753 -0.30703324259687215,0.24516991817845496 -0.30674877310887266,0.24525166890110142 -0.3168189929840746,0.2674061147470012 -0.33513882801128086,0.30689171380074365 -0.33536640360168246,0.30836322680896056 -0.3357077669872849,0.3090172325904226 -0.33616291816808297,0.30926248475847806 -0.3367887510416848,0.30983473981717746 -0.33690253883688565,0.3106522470439904 -0.3366180693488811,0.3114697542707453 -0.33701632663208136,0.31261426438826023 -0.3374145839152816,0.31343177161507324 -0.33934897643368495,0.316374797631507 -0.34105579336168673,0.3195630758159382 -0.3439573821392842,0.32561262929415674 -0.345664199067286,0.32945491326004994 -0.34737101599528775,0.33288844361253667 -0.35823775043689016,0.35692315608005987 -0.3650650181488973,0.3723740426663372 -0.3654063815344946,0.37482656434666 -0.3651219120464952,0.37736083674968723 -0.36478054866089277,0.37776959036309377 -0.3646098669680941,0.3787505990352577 -0.3647236547632949,0.381121369992934 -0.36495123035369653,0.3825928830011509 -0.3681941825168964,0.38300163661455744 -0.36876312149289525,0.38300163661455744 -0.37331463330089665,0.38063086565688103 -0.37564728310250023,0.3799768598754191 -0.3822469752241007,0.3776060889177427 -0.3827590203025018,0.3771973353043363 -0.38292970199530046,0.37646157880022785 -0.38332795927850066,0.37613457590952587 -0.3846934128209052,0.37621632663223037 -0.3851485640017033,0.37646157880022785 -0.3854330334897027,0.3767885816909879 -0.3849778823089046,0.37801484253114925 -0.38520545789930116,0.37948635553936616 -0.38571750297770213,0.3800586105981236 -0.38787947108650206,0.3808761178248785 -0.3891311368337057,0.38185712649704245 -0.39009833309290487,0.38300163661455744 -0.39248787679210634,0.38520890612688274 -0.39328439135850685,0.3861081640763422 -0.39334128525610473,0.3864351669670441 -0.3931706035633061,0.387252674193799 -0.39248787679210634,0.38749792636185454 -0.391634468328108,0.387252674193799 -0.38901734903850493,0.3852906568495292 -0.38833462226730525,0.38512715540417825 -0.38787947108650206,0.38512715540417825 -0.38748121380330686,0.38537240757223373 -0.38708295652010666,0.38586291190828664 -0.38713985041770443,0.3865986684123951 -0.387424319905704,0.3871709234711525 -0.3882208344721045,0.38823368286596294 -0.3894725002193031,0.3891329408154224 -0.39675491911210836,0.3925664711679091 -0.39721007029290645,0.39297522478131564 -0.39760832757610665,0.3939562334534796 -0.3976652214737096,0.39510074357093644 -0.39726696419050933,0.3961635029658049 -0.3966980252145105,0.39689925946991333 -0.3957877228529091,0.3984525232007767 -0.3885621978577068,0.4036028187295358 -0.3837831104593038,0.40523783318310364 -0.38179182404330264,0.4062188418552676 -0.3814504606577002,0.40679109691402504 -0.381564248452901,0.40760860414078 -0.38264523250730104,0.4093253693170524 -0.3837831104593038,0.41014287654380727 -0.3850916701041054,0.41071513160256473 -0.3864571236465048,0.41046987943450924 -0.38787947108650206,0.4098976243758098 -0.3891311368337057,0.40957062148504975 -0.389529394116906,0.4096523722077543 -0.38987075750250333,0.4099793750984563 -0.3899845452977041,0.41038812871186275 -0.3899845452977041,0.4107968823252693 -0.3896431819121068,0.4112056359386177 -0.3876518954961055,0.41202314316543065 -0.38662780533930347,0.41259539822418806 -0.38355553486890226,0.4166011836354323 -0.3779799329040988,0.4201164647106236 -0.37684205495210105,0.4210974733827294 -0.37604554038570054,0.42158797771884043 -0.37496455633130055,0.42183322988683786 -0.3718922858608994,0.4213427255507849 -0.37064062011369575,0.42150622699613594 -0.3681941825168964,0.42224198350024433 -0.36546327543209756,0.4226507371136508 -0.36495123035369653,0.4229777400043528 -0.3647236547632949,0.42346824434040575 -0.36478054866089277,0.42395874867651673 ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/MainActivity.kt ================================================ package ovh.plrapps.mapcompose.demo import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview import ovh.plrapps.mapcompose.demo.ui.MapComposeDemoApp import ovh.plrapps.mapcompose.demo.ui.theme.MapComposeTheme class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge() super.onCreate(savedInstanceState) setContent { MapComposeTheme { MapComposeDemoApp() } } } } @Preview(showBackground = true) @Composable fun DefaultPreview() { MapComposeTheme { MapComposeDemoApp() } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/providers/TileStreamProviderFactory.kt ================================================ package ovh.plrapps.mapcompose.demo.providers import android.content.Context import ovh.plrapps.mapcompose.core.TileStreamProvider fun makeTileStreamProvider(appContext: Context) = TileStreamProvider { row, col, zoomLvl -> try { appContext.assets?.open("tiles/mont_blanc_layered/$zoomLvl/$row/$col.jpg") } catch (e: Exception) { null } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/MapComposeDemoApp.kt ================================================ package ovh.plrapps.mapcompose.demo.ui import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.runtime.Composable import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import ovh.plrapps.mapcompose.demo.ui.screens.AddingMarkerDemo import ovh.plrapps.mapcompose.demo.ui.screens.AnimationDemo import ovh.plrapps.mapcompose.demo.ui.screens.CalloutDemo import ovh.plrapps.mapcompose.demo.ui.screens.CenteringOnMarkerDemo import ovh.plrapps.mapcompose.demo.ui.screens.CustomDrawDemo import ovh.plrapps.mapcompose.demo.ui.screens.Home import ovh.plrapps.mapcompose.demo.ui.screens.HttpTilesDemo import ovh.plrapps.mapcompose.demo.ui.screens.InfiniteScrollDemo import ovh.plrapps.mapcompose.demo.ui.screens.LayersDemoSimple import ovh.plrapps.mapcompose.demo.ui.screens.MapDemoSimple import ovh.plrapps.mapcompose.demo.ui.screens.MarkersClusteringDemo import ovh.plrapps.mapcompose.demo.ui.screens.MarkersLazyLoadingDemo import ovh.plrapps.mapcompose.demo.ui.screens.OsmDemo import ovh.plrapps.mapcompose.demo.ui.screens.PathsDemo import ovh.plrapps.mapcompose.demo.ui.screens.RotationDemo import ovh.plrapps.mapcompose.demo.ui.screens.VisibleAreaPaddingDemo import ovh.plrapps.mapcompose.demo.ui.theme.MapComposeTheme @Composable fun MapComposeDemoApp() { val navController = rememberNavController() MapComposeTheme { NavHost(navController, startDestination = HOME) { composable(HOME) { Home(demoListState = rememberLazyListState()) { navController.navigate(it.name) } } composable(MainDestinations.MAP_ALONE.name) { MapDemoSimple() } composable(MainDestinations.LAYERS_DEMO.name) { LayersDemoSimple() } composable(MainDestinations.MAP_WITH_ROTATION_CONTROLS.name) { RotationDemo() } composable(MainDestinations.ADDING_MARKERS.name) { AddingMarkerDemo() } composable(MainDestinations.CENTERING_ON_MARKER.name) { CenteringOnMarkerDemo() } composable(MainDestinations.PATHS.name) { PathsDemo() } composable(MainDestinations.CUSTOM_DRAW.name) { CustomDrawDemo() } composable(MainDestinations.CALLOUT_DEMO.name) { CalloutDemo() } composable(MainDestinations.ANIMATION_DEMO.name) { AnimationDemo() } composable(MainDestinations.INFINITE_SCROLL.name) { InfiniteScrollDemo() } composable(MainDestinations.OSM_DEMO.name) { OsmDemo() } composable(MainDestinations.HTTP_TILES_DEMO.name) { HttpTilesDemo() } composable(MainDestinations.VISIBLE_AREA_PADDING.name) { VisibleAreaPaddingDemo() } composable(MainDestinations.MARKERS_CLUSTERING.name) { MarkersClusteringDemo() } composable(MainDestinations.MARKERS_LAZY_LOADING.name) { MarkersLazyLoadingDemo() } } } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/NavGraph.kt ================================================ package ovh.plrapps.mapcompose.demo.ui const val HOME = "home" enum class MainDestinations(val title: String) { MAP_ALONE("Simple map"), LAYERS_DEMO("Layers demo"), MAP_WITH_ROTATION_CONTROLS("Map with rotation controls"), ADDING_MARKERS("Adding markers"), CENTERING_ON_MARKER("Centering on marker"), PATHS("Map with paths"), CUSTOM_DRAW("Map with custom drawings"), CALLOUT_DEMO("Callout (tap markers)"), ANIMATION_DEMO("Animation demo"), INFINITE_SCROLL("Infinite scroll demo"), OSM_DEMO("Open Street Map demo"), HTTP_TILES_DEMO("Remote HTTP tiles"), VISIBLE_AREA_PADDING("Visible area padding"), MARKERS_CLUSTERING("Markers clustering"), MARKERS_LAZY_LOADING("Markers lazy loading") } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/screens/AddingMarkerDemo.kt ================================================ @file:OptIn(ExperimentalMaterial3Api::class) package ovh.plrapps.mapcompose.demo.ui.screens import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import ovh.plrapps.mapcompose.demo.ui.MainDestinations import ovh.plrapps.mapcompose.demo.viewmodels.AddingMarkerVM import ovh.plrapps.mapcompose.ui.MapUI @Composable fun AddingMarkerDemo( modifier: Modifier = Modifier, viewModel: AddingMarkerVM = viewModel(), ) { Scaffold( topBar = { TopAppBar( title = { Text(MainDestinations.ADDING_MARKERS.title) }, ) } ) { padding -> Column( modifier .padding(padding) .fillMaxSize()) { MapUI( modifier.weight(2f), state = viewModel.state ) Row(verticalAlignment = Alignment.CenterVertically) { Button(onClick = { viewModel.addMarker() }, Modifier.padding(8.dp)) { Text(text = "Add marker") } Text("Drag markers with finger") } } } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/screens/AnimationDemo.kt ================================================ @file:OptIn(ExperimentalMaterial3Api::class) package ovh.plrapps.mapcompose.demo.ui.screens import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import ovh.plrapps.mapcompose.demo.ui.MainDestinations import ovh.plrapps.mapcompose.demo.viewmodels.AnimationDemoVM import ovh.plrapps.mapcompose.ui.MapUI @Composable fun AnimationDemo( viewModel: AnimationDemoVM = viewModel(), onRestart: () -> Unit = viewModel::startAnimation ) { Scaffold( topBar = { TopAppBar( title = { Text(MainDestinations.ANIMATION_DEMO.title) }, ) } ) { padding -> Column( Modifier .padding(padding) .fillMaxSize()) { MapUI( Modifier.weight(1f), state = viewModel.state ) Button(onClick = { onRestart() }, Modifier.padding(8.dp)) { Text(text = "Start") } } } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/screens/CalloutDemo.kt ================================================ @file:OptIn(ExperimentalMaterial3Api::class) package ovh.plrapps.mapcompose.demo.ui.screens import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.lifecycle.viewmodel.compose.viewModel import ovh.plrapps.mapcompose.demo.ui.MainDestinations import ovh.plrapps.mapcompose.demo.viewmodels.CalloutVM import ovh.plrapps.mapcompose.ui.MapUI @Composable fun CalloutDemo( viewModel: CalloutVM = viewModel() ) { Scaffold( topBar = { TopAppBar( title = { Text(MainDestinations.CALLOUT_DEMO.title) }, ) } ) { padding -> Column( Modifier .padding(padding) .fillMaxSize()) { MapUI(state = viewModel.state) } } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/screens/CenteringOnMarkerDemo.kt ================================================ @file:OptIn(ExperimentalMaterial3Api::class) package ovh.plrapps.mapcompose.demo.ui.screens import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import ovh.plrapps.mapcompose.demo.ui.MainDestinations import ovh.plrapps.mapcompose.demo.viewmodels.CenteringOnMarkerVM import ovh.plrapps.mapcompose.ui.MapUI @Composable fun CenteringOnMarkerDemo( modifier: Modifier = Modifier, viewModel: CenteringOnMarkerVM = viewModel(), onCenter: () -> Unit = viewModel::onCenter ) { Scaffold( topBar = { TopAppBar( title = { Text(MainDestinations.CENTERING_ON_MARKER.title) }, ) } ) { padding -> Column( modifier .padding(padding) .fillMaxSize()) { MapUI( modifier.weight(1f), state = viewModel.state ) Button(onClick = onCenter, Modifier.padding(8.dp)) { Text(text = "Center on marker") } } } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/screens/CustomDraw.kt ================================================ @file:OptIn(ExperimentalMaterial3Api::class) package ovh.plrapps.mapcompose.demo.ui.screens import androidx.compose.foundation.Canvas import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import ovh.plrapps.mapcompose.api.DefaultCanvas import ovh.plrapps.mapcompose.api.fullSize import ovh.plrapps.mapcompose.api.scale import ovh.plrapps.mapcompose.demo.ui.MainDestinations import ovh.plrapps.mapcompose.demo.utils.pxToDp import ovh.plrapps.mapcompose.demo.viewmodels.CustomDrawVM import ovh.plrapps.mapcompose.ui.MapUI import ovh.plrapps.mapcompose.ui.state.MapState import kotlin.math.log10 import kotlin.math.pow /** * This demo shows how to embed custom drawings inside [MapUI]. */ @Composable fun CustomDrawDemo(viewModel: CustomDrawVM = viewModel()) { Scaffold( topBar = { TopAppBar( title = { Text(MainDestinations.CUSTOM_DRAW.title) }, ) } ) { padding -> CustomDraw(Modifier.padding(padding), viewModel) } } /** * This demo shows how to embed custom drawings inside [MapUI]. */ @Composable private fun CustomDraw( modifier: Modifier = Modifier, viewModel: CustomDrawVM ) { Box(modifier) { MapUI(state = viewModel.state) { Square( modifier = Modifier, mapState = viewModel.state, position = Offset( viewModel.state.fullSize.width / 2f - 300f, viewModel.state.fullSize.height / 2f - 300f ), color = Color(0xff5c6bc0), isScaling = true ) Square( modifier = Modifier, mapState = viewModel.state, position = Offset( viewModel.state.fullSize.width / 2f, viewModel.state.fullSize.height / 2f ), color = Color(0xff087f23), isScaling = false ) Line( modifier = Modifier, mapState = viewModel.state, color = Color(0xAAF44336), p1 = with(viewModel) { Offset( (p1x * state.fullSize.width).toFloat(), (p1y * state.fullSize.height).toFloat() ) }, p2 = with(viewModel) { Offset( (p2x * state.fullSize.width).toFloat(), (p2y * state.fullSize.height).toFloat() ) } ) } ScaleIndicator( controller = viewModel.scaleIndicatorController, lineColor = Color.Black ) } } @Composable fun ScaleIndicator( controller: ScaleIndicatorController, lineColor: Color ) { Box(Modifier.height(50.dp)) { Canvas( modifier = Modifier .alpha(0.8f) .padding(5.dp) .size(pxToDp(controller.widthPx).dp, 15.dp) ) { val width = controller.widthPx * controller.widthRatio val height = size.height drawLine(lineColor, Offset(0f, height / 2), Offset(width, height / 2), 2.dp.toPx()) drawLine( lineColor, Offset(0f, 0f), Offset(0f, height), 2.dp.toPx(), cap = StrokeCap.Round ) drawLine( lineColor, Offset(width, 0f), Offset(width, height), 2.dp.toPx(), cap = StrokeCap.Round ) } Text( text = controller.scaleText, color = Color.White, modifier = Modifier .padding(start = 16.dp, top = 20.dp) .background(color = Color(0x885D4037), shape = RoundedCornerShape(4.dp)) .padding(start = 5.dp, end = 5.dp) ) } } class ScaleIndicatorController(val widthPx: Int, initScale: Double) { var widthRatio by mutableFloatStateOf(0f) var scaleText by mutableStateOf("") private var snapScale: Double = initScale private var snapWidthRatio = 0f init { snapToNewValue(initScale) } fun onScaleChanged(scale: Double) { val ratio = (scale / snapScale).toFloat() if (widthRatio * ratio in 0.5f..1f) { widthRatio = snapWidthRatio * ratio } else { snapToNewValue(scale) } } private fun snapToNewValue(scale: Double) { val distance = distanceForPx(widthPx, scale) val snap = computeSnapValue(distance) ?: return snapScale = scale widthRatio = snap.toFloat() / distance snapWidthRatio = widthRatio scaleText = formatDistance(snap) } /** * Computes the distance in meters, given a size in pixels. */ private fun distanceForPx(nPx: Int, scale: Double): Int { // TODO: This a simplified calculation return (widthPx * 5 / scale).toInt() } private fun formatDistance(d: Int): String { return "$d m" } /** * A snap value is an entire multiple of power of 10, which is lower than [input]. * The first digit of a snap value is either 1, 2, 3, or 5. * For example: 835 -> 500, 480 -> 300, 270 -> 200, 114 -> 100 * The snap value is always greater than half of [input]. */ private fun computeSnapValue(input: Int): Int? { if (input <= 1) return null // Lowest entire power of 10 val power = (log10(input.toDouble())).toInt() val power10 = 10.0.pow(power) val mostSignificantDigit = (input / power10).toInt() return when { mostSignificantDigit >= 5 -> 5 * power10 mostSignificantDigit >= 3 -> 3 * power10 mostSignificantDigit >= 2 -> 2 * power10 else -> power10 }.toInt() } } /** * Here, we define a square with various inputs such as [position], [color], and [isScaling]. * Our custom composable is based on [DefaultCanvas], which is provided by the MapCompose library. * Since [DefaultCanvas] moves, scales, and rotates with the map, so does our custom square composable. */ @Composable fun Square( modifier: Modifier, mapState: MapState, position: Offset, color: Color, isScaling: Boolean ) { DefaultCanvas( modifier = modifier, mapState = mapState ) { val side = if (isScaling) 300f else (300f / mapState.scale).toFloat() drawRect( color, topLeft = position, size = Size(side, side) ) } } @Composable fun Line( modifier: Modifier, mapState: MapState, color: Color, p1: Offset, p2: Offset ) { DefaultCanvas( modifier = modifier, mapState = mapState ) { drawLine(color, start = p1, end = p2, strokeWidth = (8.0 / mapState.scale).toFloat()) } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/screens/Home.kt ================================================ @file:OptIn(ExperimentalMaterial3Api::class) package ovh.plrapps.mapcompose.demo.ui.screens import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyListState import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import ovh.plrapps.mapcompose.demo.R import ovh.plrapps.mapcompose.demo.ui.MainDestinations @Composable fun Home(demoListState: LazyListState, onDemoSelected: (dest: MainDestinations) -> Unit) { Scaffold( topBar = { TopAppBar( title = { Text(stringResource(R.string.app_name)) }, ) } ) { padding -> LazyColumn( Modifier.padding(padding).fillMaxWidth(), state = demoListState, horizontalAlignment = Alignment.CenterHorizontally ) { MainDestinations.entries.map { dest -> item { Button( onClick = { onDemoSelected.invoke(dest) } ) { Text(text = dest.title) } } } } } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/screens/HttpTilesDemo.kt ================================================ @file:OptIn(ExperimentalMaterial3Api::class) package ovh.plrapps.mapcompose.demo.ui.screens import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.lifecycle.viewmodel.compose.viewModel import ovh.plrapps.mapcompose.demo.ui.MainDestinations import ovh.plrapps.mapcompose.demo.viewmodels.HttpTilesVM import ovh.plrapps.mapcompose.ui.MapUI @Composable fun HttpTilesDemo( modifier: Modifier = Modifier, viewModel: HttpTilesVM = viewModel() ) { Scaffold( topBar = { TopAppBar( title = { Text(MainDestinations.HTTP_TILES_DEMO.title) }, ) } ) { padding -> MapUI( modifier.padding(padding), state = viewModel.state ) } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/screens/InfiniteScrollDemo.kt ================================================ @file:OptIn(ExperimentalMaterial3Api::class) package ovh.plrapps.mapcompose.demo.ui.screens import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.lifecycle.viewmodel.compose.viewModel import ovh.plrapps.mapcompose.demo.ui.MainDestinations import ovh.plrapps.mapcompose.demo.viewmodels.InfiniteScrollVM import ovh.plrapps.mapcompose.ui.MapUI @Composable fun InfiniteScrollDemo( modifier: Modifier = Modifier, viewModel: InfiniteScrollVM = viewModel() ) { Scaffold( topBar = { TopAppBar( title = { Text(MainDestinations.INFINITE_SCROLL.title) }, ) } ) { padding -> MapUI(modifier.padding(padding), state = viewModel.state) } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/screens/LayersDemo.kt ================================================ @file:OptIn(ExperimentalMaterial3Api::class) package ovh.plrapps.mapcompose.demo.ui.screens import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Slider import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import ovh.plrapps.mapcompose.demo.ui.MainDestinations import ovh.plrapps.mapcompose.demo.viewmodels.LayersVM import ovh.plrapps.mapcompose.ui.MapUI import ovh.plrapps.mapcompose.ui.state.MapState @Composable fun LayersDemoSimple(viewModel: LayersVM = viewModel()) { Scaffold( topBar = { TopAppBar( title = { Text(MainDestinations.LAYERS_DEMO.title) }, ) } ) { padding -> LayersDemoScreen( Modifier.padding(padding), viewModel.state, onSlopesOpacity = viewModel::setSlopesOpacity, onRoadOpacity = viewModel::setRoadOpacity ) } } @Composable fun LayersDemoScreen( modifier: Modifier = Modifier, mapState: MapState, onSlopesOpacity: (Float) -> Unit, onRoadOpacity: (Float) -> Unit ) { var slopesSliderValue by remember { mutableFloatStateOf(0.6f) } var roadSliderValue by remember { mutableFloatStateOf(1f) } Column(modifier) { MapUI(Modifier.weight(1f), state = mapState) LayerSlider( name = "Slopes", value = slopesSliderValue, onValueChange = { slopesSliderValue = it onSlopesOpacity(it) } ) LayerSlider( name = "Roads", value = roadSliderValue, onValueChange = { roadSliderValue = it onRoadOpacity(it) } ) } } @Composable private fun LayerSlider(name: String, value: Float, onValueChange: (Float) -> Unit) { Row( Modifier .height(50.dp) .padding(horizontal = 16.dp)) { Row(verticalAlignment = Alignment.CenterVertically) { Text(text = name, Modifier.padding(horizontal = 16.dp)) Slider( value = value, onValueChange = onValueChange ) } } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/screens/MarkersClusteringDemo.kt ================================================ @file:OptIn(ExperimentalMaterial3Api::class) package ovh.plrapps.mapcompose.demo.ui.screens import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.lifecycle.viewmodel.compose.viewModel import ovh.plrapps.mapcompose.demo.ui.MainDestinations import ovh.plrapps.mapcompose.demo.viewmodels.MarkersClusteringVM import ovh.plrapps.mapcompose.ui.MapUI @Composable fun MarkersClusteringDemo( modifier: Modifier = Modifier, viewModel: MarkersClusteringVM = viewModel() ) { Scaffold( topBar = { TopAppBar( title = { Text(MainDestinations.MARKERS_CLUSTERING.title) }, ) } ) { padding -> MapUI(modifier.padding(padding), state = viewModel.state) } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/screens/MarkersLazyLoadingDemo.kt ================================================ @file:OptIn(ExperimentalMaterial3Api::class) package ovh.plrapps.mapcompose.demo.ui.screens import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.lifecycle.viewmodel.compose.viewModel import ovh.plrapps.mapcompose.demo.ui.MainDestinations import ovh.plrapps.mapcompose.demo.viewmodels.MarkersLazyLoadingVM import ovh.plrapps.mapcompose.ui.MapUI @Composable fun MarkersLazyLoadingDemo( modifier: Modifier = Modifier, viewModel: MarkersLazyLoadingVM = viewModel() ) { Scaffold( topBar = { TopAppBar( title = { Text(MainDestinations.MARKERS_LAZY_LOADING.title) }, ) } ) { padding -> MapUI(modifier.padding(padding), state = viewModel.state) } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/screens/OsmDemo.kt ================================================ @file:OptIn(ExperimentalMaterial3Api::class) package ovh.plrapps.mapcompose.demo.ui.screens import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.lifecycle.viewmodel.compose.viewModel import ovh.plrapps.mapcompose.demo.ui.MainDestinations import ovh.plrapps.mapcompose.demo.viewmodels.OsmVM import ovh.plrapps.mapcompose.ui.MapUI @Composable fun OsmDemo( modifier: Modifier = Modifier, viewModel: OsmVM = viewModel() ) { Scaffold( topBar = { TopAppBar( title = { Text(MainDestinations.OSM_DEMO.title) }, ) } ) { padding -> MapUI( modifier.padding(padding), state = viewModel.state ) } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/screens/PathsDemo.kt ================================================ @file:OptIn(ExperimentalMaterial3Api::class) package ovh.plrapps.mapcompose.demo.ui.screens import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.lifecycle.viewmodel.compose.viewModel import ovh.plrapps.mapcompose.demo.ui.MainDestinations import ovh.plrapps.mapcompose.demo.viewmodels.PathsVM import ovh.plrapps.mapcompose.ui.MapUI @Composable fun PathsDemo( modifier: Modifier = Modifier, viewModel: PathsVM = viewModel() ) { Scaffold( topBar = { TopAppBar( title = { Text(MainDestinations.PATHS.title) }, ) } ) { padding -> MapUI( modifier.padding(padding), state = viewModel.state ) } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/screens/RotationDemo.kt ================================================ @file:OptIn(ExperimentalMaterial3Api::class) package ovh.plrapps.mapcompose.demo.ui.screens import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Slider import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import ovh.plrapps.mapcompose.api.rotation import ovh.plrapps.mapcompose.demo.ui.MainDestinations import ovh.plrapps.mapcompose.demo.viewmodels.RotationVM import ovh.plrapps.mapcompose.ui.MapUI import ovh.plrapps.mapcompose.ui.state.MapState @Composable fun RotationDemo(modifier: Modifier = Modifier, viewModel: RotationVM = viewModel()) { Scaffold( topBar = { TopAppBar( title = { Text(MainDestinations.MAP_WITH_ROTATION_CONTROLS.title) }, ) } ) { padding -> RotationScreen( modifier.padding(padding), mapState = viewModel.state, onRotate = viewModel::onRotate ) } } @Composable private fun RotationScreen( modifier: Modifier = Modifier, mapState: MapState, onRotate: () -> Unit ) { val sliderValue = mapState.rotation / 360f Column(modifier.fillMaxSize()) { MapUI( Modifier.weight(1f), state = mapState ) Row { Button(onClick = onRotate, Modifier.padding(8.dp)) { Text(text = "Rotate 90°") } Slider( value = sliderValue, valueRange = 0f..0.9999f, modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp), onValueChange = { v -> mapState.rotation = v * 360f }) } } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/screens/SimpleDemo.kt ================================================ @file:OptIn(ExperimentalMaterial3Api::class) package ovh.plrapps.mapcompose.demo.ui.screens import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.lifecycle.viewmodel.compose.viewModel import ovh.plrapps.mapcompose.demo.ui.MainDestinations import ovh.plrapps.mapcompose.demo.viewmodels.SimpleDemoVM import ovh.plrapps.mapcompose.ui.MapUI @Composable fun MapDemoSimple( modifier: Modifier = Modifier, viewModel: SimpleDemoVM = viewModel() ) { Scaffold( topBar = { TopAppBar( title = { Text(MainDestinations.MAP_ALONE.title) }, ) } ) { padding -> MapUI(modifier.padding(padding), state = viewModel.state) } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/screens/VisibleAreaPaddingDemo.kt ================================================ @file:OptIn(ExperimentalMaterial3Api::class) package ovh.plrapps.mapcompose.demo.ui.screens import androidx.compose.animation.expandHorizontally import androidx.compose.animation.expandVertically import androidx.compose.animation.shrinkHorizontally import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import ovh.plrapps.mapcompose.api.centerOnMarker import ovh.plrapps.mapcompose.api.setVisibleAreaPadding import ovh.plrapps.mapcompose.demo.ui.MainDestinations import ovh.plrapps.mapcompose.demo.viewmodels.VisibleAreaPaddingVM import ovh.plrapps.mapcompose.ui.MapUI import ovh.plrapps.mapcompose.ui.state.MapState @Composable fun VisibleAreaPaddingDemo( viewModel: VisibleAreaPaddingVM = viewModel() ) { Scaffold( topBar = { TopAppBar( title = { Text(MainDestinations.VISIBLE_AREA_PADDING.title) }, ) } ) { padding -> VisibleAreaPaddingScreen(Modifier.padding(padding), viewModel.state) } } @Composable private fun VisibleAreaPaddingScreen( modifier: Modifier, mapState: MapState ) { val obstructionSize = 100.dp val obstructionColor = Color(0xA0000000) var leftObstructionEnabled by remember { mutableStateOf(true) } var rightObstructionEnabled by remember { mutableStateOf(false) } var topObstructionEnabled by remember { mutableStateOf(false) } var bottomObstructionEnabled by remember { mutableStateOf(false) } Column( modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally ) { Row( modifier = Modifier .fillMaxWidth() .clickable { topObstructionEnabled = !topObstructionEnabled }, horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { Switch(topObstructionEnabled, onCheckedChange = null) Text( "Top ", // Same width as "Bottom" modifier = Modifier.padding(start = 4.dp), fontFamily = FontFamily.Monospace ) } Row( modifier = Modifier .fillMaxWidth() .clickable { topObstructionEnabled = !topObstructionEnabled }, horizontalArrangement = Arrangement.SpaceAround ) { Row( modifier = Modifier.clickable { leftObstructionEnabled = !leftObstructionEnabled }, verticalAlignment = Alignment.CenterVertically ) { Switch(leftObstructionEnabled, onCheckedChange = null) Text( "Left", modifier = Modifier.padding(start = 4.dp), fontFamily = FontFamily.Monospace ) } Row( modifier = Modifier.clickable { rightObstructionEnabled = !rightObstructionEnabled }, verticalAlignment = Alignment.CenterVertically ) { Switch(rightObstructionEnabled, onCheckedChange = null) Text( "Right", modifier = Modifier.padding(start = 4.dp), fontFamily = FontFamily.Monospace ) } } Row( modifier = Modifier .fillMaxWidth() .clickable { bottomObstructionEnabled = !bottomObstructionEnabled }, horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { Switch(bottomObstructionEnabled, onCheckedChange = null) Text( "Bottom", modifier = Modifier.padding(start = 4.dp), fontFamily = FontFamily.Monospace ) } Spacer(Modifier.height(8.dp)) Box { MapUI( state = mapState ) androidx.compose.animation.AnimatedVisibility( visible = leftObstructionEnabled, enter = expandHorizontally(), exit = shrinkHorizontally(), modifier = Modifier.align(Alignment.CenterStart) ) { Surface( color = obstructionColor, modifier = Modifier .fillMaxHeight() .width(obstructionSize) ) {} } androidx.compose.animation.AnimatedVisibility( visible = rightObstructionEnabled, enter = expandHorizontally(expandFrom = Alignment.Start), exit = shrinkHorizontally(), modifier = Modifier.align(Alignment.CenterEnd) ) { Surface( color = obstructionColor, modifier = Modifier .fillMaxHeight() .width(obstructionSize) ) {} } androidx.compose.animation.AnimatedVisibility( visible = topObstructionEnabled, enter = expandVertically(), exit = shrinkVertically(), modifier = Modifier.align(Alignment.TopCenter) ) { Surface( color = obstructionColor, modifier = Modifier .fillMaxWidth() .height(obstructionSize) ) {} } androidx.compose.animation.AnimatedVisibility( visible = bottomObstructionEnabled, enter = expandVertically(), exit = shrinkVertically(), modifier = Modifier.align(Alignment.BottomCenter) ) { Surface( color = obstructionColor, modifier = Modifier .fillMaxWidth() .height(obstructionSize) ) {} } } } LaunchedEffect( leftObstructionEnabled, rightObstructionEnabled, topObstructionEnabled, bottomObstructionEnabled ) { mapState.setVisibleAreaPadding( left = if (leftObstructionEnabled) obstructionSize else 0.dp, right = if (rightObstructionEnabled) obstructionSize else 0.dp, top = if (topObstructionEnabled) obstructionSize else 0.dp, bottom = if (bottomObstructionEnabled) obstructionSize else 0.dp ) mapState.centerOnMarker("m0") } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/theme/Color.kt ================================================ package ovh.plrapps.mapcompose.demo.ui.theme import androidx.compose.ui.graphics.Color val primaryLight = Color(0xFF415F91) val onPrimaryLight = Color(0xFFFFFFFF) val primaryContainerLight = Color(0xFFD6E3FF) val onPrimaryContainerLight = Color(0xFF001B3E) val secondaryLight = Color(0xFF565F71) val onSecondaryLight = Color(0xFFFFFFFF) val secondaryContainerLight = Color(0xFFDAE2F9) val onSecondaryContainerLight = Color(0xFF131C2B) val tertiaryLight = Color(0xFF705575) val onTertiaryLight = Color(0xFFFFFFFF) val tertiaryContainerLight = Color(0xFFFAD8FD) val onTertiaryContainerLight = Color(0xFF28132E) val errorLight = Color(0xFFBA1A1A) val onErrorLight = Color(0xFFFFFFFF) val errorContainerLight = Color(0xFFFFDAD6) val onErrorContainerLight = Color(0xFF410002) val backgroundLight = Color(0xFFF9F9FF) val onBackgroundLight = Color(0xFF191C20) val surfaceLight = Color(0xFFF9F9FF) val onSurfaceLight = Color(0xFF191C20) val surfaceVariantLight = Color(0xFFE0E2EC) val onSurfaceVariantLight = Color(0xFF44474E) val outlineLight = Color(0xFF74777F) val outlineVariantLight = Color(0xFFC4C6D0) val scrimLight = Color(0xFF000000) val inverseSurfaceLight = Color(0xFF2E3036) val inverseOnSurfaceLight = Color(0xFFF0F0F7) val inversePrimaryLight = Color(0xFFAAC7FF) val surfaceDimLight = Color(0xFFD9D9E0) val surfaceBrightLight = Color(0xFFF9F9FF) val surfaceContainerLowestLight = Color(0xFFFFFFFF) val surfaceContainerLowLight = Color(0xFFF3F3FA) val surfaceContainerLight = Color(0xFFEDEDF4) val surfaceContainerHighLight = Color(0xFFE7E8EE) val surfaceContainerHighestLight = Color(0xFFE2E2E9) val primaryLightMediumContrast = Color(0xFF234373) val onPrimaryLightMediumContrast = Color(0xFFFFFFFF) val primaryContainerLightMediumContrast = Color(0xFF5875A8) val onPrimaryContainerLightMediumContrast = Color(0xFFFFFFFF) val secondaryLightMediumContrast = Color(0xFF3A4354) val onSecondaryLightMediumContrast = Color(0xFFFFFFFF) val secondaryContainerLightMediumContrast = Color(0xFF6C7588) val onSecondaryContainerLightMediumContrast = Color(0xFFFFFFFF) val tertiaryLightMediumContrast = Color(0xFF523A58) val onTertiaryLightMediumContrast = Color(0xFFFFFFFF) val tertiaryContainerLightMediumContrast = Color(0xFF876B8C) val onTertiaryContainerLightMediumContrast = Color(0xFFFFFFFF) val errorLightMediumContrast = Color(0xFF8C0009) val onErrorLightMediumContrast = Color(0xFFFFFFFF) val errorContainerLightMediumContrast = Color(0xFFDA342E) val onErrorContainerLightMediumContrast = Color(0xFFFFFFFF) val backgroundLightMediumContrast = Color(0xFFF9F9FF) val onBackgroundLightMediumContrast = Color(0xFF191C20) val surfaceLightMediumContrast = Color(0xFFF9F9FF) val onSurfaceLightMediumContrast = Color(0xFF191C20) val surfaceVariantLightMediumContrast = Color(0xFFE0E2EC) val onSurfaceVariantLightMediumContrast = Color(0xFF40434A) val outlineLightMediumContrast = Color(0xFF5C5F67) val outlineVariantLightMediumContrast = Color(0xFF787A83) val scrimLightMediumContrast = Color(0xFF000000) val inverseSurfaceLightMediumContrast = Color(0xFF2E3036) val inverseOnSurfaceLightMediumContrast = Color(0xFFF0F0F7) val inversePrimaryLightMediumContrast = Color(0xFFAAC7FF) val surfaceDimLightMediumContrast = Color(0xFFD9D9E0) val surfaceBrightLightMediumContrast = Color(0xFFF9F9FF) val surfaceContainerLowestLightMediumContrast = Color(0xFFFFFFFF) val surfaceContainerLowLightMediumContrast = Color(0xFFF3F3FA) val surfaceContainerLightMediumContrast = Color(0xFFEDEDF4) val surfaceContainerHighLightMediumContrast = Color(0xFFE7E8EE) val surfaceContainerHighestLightMediumContrast = Color(0xFFE2E2E9) val primaryLightHighContrast = Color(0xFF00214A) val onPrimaryLightHighContrast = Color(0xFFFFFFFF) val primaryContainerLightHighContrast = Color(0xFF234373) val onPrimaryContainerLightHighContrast = Color(0xFFFFFFFF) val secondaryLightHighContrast = Color(0xFF192232) val onSecondaryLightHighContrast = Color(0xFFFFFFFF) val secondaryContainerLightHighContrast = Color(0xFF3A4354) val onSecondaryContainerLightHighContrast = Color(0xFFFFFFFF) val tertiaryLightHighContrast = Color(0xFF301A35) val onTertiaryLightHighContrast = Color(0xFFFFFFFF) val tertiaryContainerLightHighContrast = Color(0xFF523A58) val onTertiaryContainerLightHighContrast = Color(0xFFFFFFFF) val errorLightHighContrast = Color(0xFF4E0002) val onErrorLightHighContrast = Color(0xFFFFFFFF) val errorContainerLightHighContrast = Color(0xFF8C0009) val onErrorContainerLightHighContrast = Color(0xFFFFFFFF) val backgroundLightHighContrast = Color(0xFFF9F9FF) val onBackgroundLightHighContrast = Color(0xFF191C20) val surfaceLightHighContrast = Color(0xFFF9F9FF) val onSurfaceLightHighContrast = Color(0xFF000000) val surfaceVariantLightHighContrast = Color(0xFFE0E2EC) val onSurfaceVariantLightHighContrast = Color(0xFF21242B) val outlineLightHighContrast = Color(0xFF40434A) val outlineVariantLightHighContrast = Color(0xFF40434A) val scrimLightHighContrast = Color(0xFF000000) val inverseSurfaceLightHighContrast = Color(0xFF2E3036) val inverseOnSurfaceLightHighContrast = Color(0xFFFFFFFF) val inversePrimaryLightHighContrast = Color(0xFFE5ECFF) val surfaceDimLightHighContrast = Color(0xFFD9D9E0) val surfaceBrightLightHighContrast = Color(0xFFF9F9FF) val surfaceContainerLowestLightHighContrast = Color(0xFFFFFFFF) val surfaceContainerLowLightHighContrast = Color(0xFFF3F3FA) val surfaceContainerLightHighContrast = Color(0xFFEDEDF4) val surfaceContainerHighLightHighContrast = Color(0xFFE7E8EE) val surfaceContainerHighestLightHighContrast = Color(0xFFE2E2E9) val primaryDark = Color(0xFFAAC7FF) val onPrimaryDark = Color(0xFF0A305F) val primaryContainerDark = Color(0xFF284777) val onPrimaryContainerDark = Color(0xFFD6E3FF) val secondaryDark = Color(0xFFBEC6DC) val onSecondaryDark = Color(0xFF283141) val secondaryContainerDark = Color(0xFF3E4759) val onSecondaryContainerDark = Color(0xFFDAE2F9) val tertiaryDark = Color(0xFFDDBCE0) val onTertiaryDark = Color(0xFF3F2844) val tertiaryContainerDark = Color(0xFF573E5C) val onTertiaryContainerDark = Color(0xFFFAD8FD) val errorDark = Color(0xFFFFB4AB) val onErrorDark = Color(0xFF690005) val errorContainerDark = Color(0xFF93000A) val onErrorContainerDark = Color(0xFFFFDAD6) val backgroundDark = Color(0xFF111318) val onBackgroundDark = Color(0xFFE2E2E9) val surfaceDark = Color(0xFF111318) val onSurfaceDark = Color(0xFFE2E2E9) val surfaceVariantDark = Color(0xFF44474E) val onSurfaceVariantDark = Color(0xFFC4C6D0) val outlineDark = Color(0xFF8E9099) val outlineVariantDark = Color(0xFF44474E) val scrimDark = Color(0xFF000000) val inverseSurfaceDark = Color(0xFFE2E2E9) val inverseOnSurfaceDark = Color(0xFF2E3036) val inversePrimaryDark = Color(0xFF415F91) val surfaceDimDark = Color(0xFF111318) val surfaceBrightDark = Color(0xFF37393E) val surfaceContainerLowestDark = Color(0xFF0C0E13) val surfaceContainerLowDark = Color(0xFF191C20) val surfaceContainerDark = Color(0xFF1D2024) val surfaceContainerHighDark = Color(0xFF282A2F) val surfaceContainerHighestDark = Color(0xFF33353A) val primaryDarkMediumContrast = Color(0xFFB1CBFF) val onPrimaryDarkMediumContrast = Color(0xFF001634) val primaryContainerDarkMediumContrast = Color(0xFF7491C7) val onPrimaryContainerDarkMediumContrast = Color(0xFF000000) val secondaryDarkMediumContrast = Color(0xFFC2CBE0) val onSecondaryDarkMediumContrast = Color(0xFF0D1626) val secondaryContainerDarkMediumContrast = Color(0xFF8891A5) val onSecondaryContainerDarkMediumContrast = Color(0xFF000000) val tertiaryDarkMediumContrast = Color(0xFFE1C0E5) val onTertiaryDarkMediumContrast = Color(0xFF230E29) val tertiaryContainerDarkMediumContrast = Color(0xFFA487A9) val onTertiaryContainerDarkMediumContrast = Color(0xFF000000) val errorDarkMediumContrast = Color(0xFFFFBAB1) val onErrorDarkMediumContrast = Color(0xFF370001) val errorContainerDarkMediumContrast = Color(0xFFFF5449) val onErrorContainerDarkMediumContrast = Color(0xFF000000) val backgroundDarkMediumContrast = Color(0xFF111318) val onBackgroundDarkMediumContrast = Color(0xFFE2E2E9) val surfaceDarkMediumContrast = Color(0xFF111318) val onSurfaceDarkMediumContrast = Color(0xFFFBFAFF) val surfaceVariantDarkMediumContrast = Color(0xFF44474E) val onSurfaceVariantDarkMediumContrast = Color(0xFFC8CAD4) val outlineDarkMediumContrast = Color(0xFFA0A3AC) val outlineVariantDarkMediumContrast = Color(0xFF80838C) val scrimDarkMediumContrast = Color(0xFF000000) val inverseSurfaceDarkMediumContrast = Color(0xFFE2E2E9) val inverseOnSurfaceDarkMediumContrast = Color(0xFF282A2F) val inversePrimaryDarkMediumContrast = Color(0xFF294878) val surfaceDimDarkMediumContrast = Color(0xFF111318) val surfaceBrightDarkMediumContrast = Color(0xFF37393E) val surfaceContainerLowestDarkMediumContrast = Color(0xFF0C0E13) val surfaceContainerLowDarkMediumContrast = Color(0xFF191C20) val surfaceContainerDarkMediumContrast = Color(0xFF1D2024) val surfaceContainerHighDarkMediumContrast = Color(0xFF282A2F) val surfaceContainerHighestDarkMediumContrast = Color(0xFF33353A) val primaryDarkHighContrast = Color(0xFFFBFAFF) val onPrimaryDarkHighContrast = Color(0xFF000000) val primaryContainerDarkHighContrast = Color(0xFFB1CBFF) val onPrimaryContainerDarkHighContrast = Color(0xFF000000) val secondaryDarkHighContrast = Color(0xFFFBFAFF) val onSecondaryDarkHighContrast = Color(0xFF000000) val secondaryContainerDarkHighContrast = Color(0xFFC2CBE0) val onSecondaryContainerDarkHighContrast = Color(0xFF000000) val tertiaryDarkHighContrast = Color(0xFFFFF9FA) val onTertiaryDarkHighContrast = Color(0xFF000000) val tertiaryContainerDarkHighContrast = Color(0xFFE1C0E5) val onTertiaryContainerDarkHighContrast = Color(0xFF000000) val errorDarkHighContrast = Color(0xFFFFF9F9) val onErrorDarkHighContrast = Color(0xFF000000) val errorContainerDarkHighContrast = Color(0xFFFFBAB1) val onErrorContainerDarkHighContrast = Color(0xFF000000) val backgroundDarkHighContrast = Color(0xFF111318) val onBackgroundDarkHighContrast = Color(0xFFE2E2E9) val surfaceDarkHighContrast = Color(0xFF111318) val onSurfaceDarkHighContrast = Color(0xFFFFFFFF) val surfaceVariantDarkHighContrast = Color(0xFF44474E) val onSurfaceVariantDarkHighContrast = Color(0xFFFBFAFF) val outlineDarkHighContrast = Color(0xFFC8CAD4) val outlineVariantDarkHighContrast = Color(0xFFC8CAD4) val scrimDarkHighContrast = Color(0xFF000000) val inverseSurfaceDarkHighContrast = Color(0xFFE2E2E9) val inverseOnSurfaceDarkHighContrast = Color(0xFF000000) val inversePrimaryDarkHighContrast = Color(0xFF002959) val surfaceDimDarkHighContrast = Color(0xFF111318) val surfaceBrightDarkHighContrast = Color(0xFF37393E) val surfaceContainerLowestDarkHighContrast = Color(0xFF0C0E13) val surfaceContainerLowDarkHighContrast = Color(0xFF191C20) val surfaceContainerDarkHighContrast = Color(0xFF1D2024) val surfaceContainerHighDarkHighContrast = Color(0xFF282A2F) val surfaceContainerHighestDarkHighContrast = Color(0xFF33353A) ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/theme/Theme.kt ================================================ package ovh.plrapps.mapcompose.demo.ui.theme import android.os.Build import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.MaterialTheme import androidx.compose.material3.lightColorScheme import androidx.compose.material3.darkColorScheme import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext private val lightScheme = lightColorScheme( primary = primaryLight, onPrimary = onPrimaryLight, primaryContainer = primaryContainerLight, onPrimaryContainer = onPrimaryContainerLight, secondary = secondaryLight, onSecondary = onSecondaryLight, secondaryContainer = secondaryContainerLight, onSecondaryContainer = onSecondaryContainerLight, tertiary = tertiaryLight, onTertiary = onTertiaryLight, tertiaryContainer = tertiaryContainerLight, onTertiaryContainer = onTertiaryContainerLight, error = errorLight, onError = onErrorLight, errorContainer = errorContainerLight, onErrorContainer = onErrorContainerLight, background = backgroundLight, onBackground = onBackgroundLight, surface = surfaceLight, onSurface = onSurfaceLight, surfaceVariant = surfaceVariantLight, onSurfaceVariant = onSurfaceVariantLight, outline = outlineLight, outlineVariant = outlineVariantLight, scrim = scrimLight, inverseSurface = inverseSurfaceLight, inverseOnSurface = inverseOnSurfaceLight, inversePrimary = inversePrimaryLight, surfaceDim = surfaceDimLight, surfaceBright = surfaceBrightLight, surfaceContainerLowest = surfaceContainerLowestLight, surfaceContainerLow = surfaceContainerLowLight, surfaceContainer = surfaceContainerLight, surfaceContainerHigh = surfaceContainerHighLight, surfaceContainerHighest = surfaceContainerHighestLight, ) private val darkScheme = darkColorScheme( primary = primaryDark, onPrimary = onPrimaryDark, primaryContainer = primaryContainerDark, onPrimaryContainer = onPrimaryContainerDark, secondary = secondaryDark, onSecondary = onSecondaryDark, secondaryContainer = secondaryContainerDark, onSecondaryContainer = onSecondaryContainerDark, tertiary = tertiaryDark, onTertiary = onTertiaryDark, tertiaryContainer = tertiaryContainerDark, onTertiaryContainer = onTertiaryContainerDark, error = errorDark, onError = onErrorDark, errorContainer = errorContainerDark, onErrorContainer = onErrorContainerDark, background = backgroundDark, onBackground = onBackgroundDark, surface = surfaceDark, onSurface = onSurfaceDark, surfaceVariant = surfaceVariantDark, onSurfaceVariant = onSurfaceVariantDark, outline = outlineDark, outlineVariant = outlineVariantDark, scrim = scrimDark, inverseSurface = inverseSurfaceDark, inverseOnSurface = inverseOnSurfaceDark, inversePrimary = inversePrimaryDark, surfaceDim = surfaceDimDark, surfaceBright = surfaceBrightDark, surfaceContainerLowest = surfaceContainerLowestDark, surfaceContainerLow = surfaceContainerLowDark, surfaceContainer = surfaceContainerDark, surfaceContainerHigh = surfaceContainerHighDark, surfaceContainerHighest = surfaceContainerHighestDark, ) private val mediumContrastLightColorScheme = lightColorScheme( primary = primaryLightMediumContrast, onPrimary = onPrimaryLightMediumContrast, primaryContainer = primaryContainerLightMediumContrast, onPrimaryContainer = onPrimaryContainerLightMediumContrast, secondary = secondaryLightMediumContrast, onSecondary = onSecondaryLightMediumContrast, secondaryContainer = secondaryContainerLightMediumContrast, onSecondaryContainer = onSecondaryContainerLightMediumContrast, tertiary = tertiaryLightMediumContrast, onTertiary = onTertiaryLightMediumContrast, tertiaryContainer = tertiaryContainerLightMediumContrast, onTertiaryContainer = onTertiaryContainerLightMediumContrast, error = errorLightMediumContrast, onError = onErrorLightMediumContrast, errorContainer = errorContainerLightMediumContrast, onErrorContainer = onErrorContainerLightMediumContrast, background = backgroundLightMediumContrast, onBackground = onBackgroundLightMediumContrast, surface = surfaceLightMediumContrast, onSurface = onSurfaceLightMediumContrast, surfaceVariant = surfaceVariantLightMediumContrast, onSurfaceVariant = onSurfaceVariantLightMediumContrast, outline = outlineLightMediumContrast, outlineVariant = outlineVariantLightMediumContrast, scrim = scrimLightMediumContrast, inverseSurface = inverseSurfaceLightMediumContrast, inverseOnSurface = inverseOnSurfaceLightMediumContrast, inversePrimary = inversePrimaryLightMediumContrast, surfaceDim = surfaceDimLightMediumContrast, surfaceBright = surfaceBrightLightMediumContrast, surfaceContainerLowest = surfaceContainerLowestLightMediumContrast, surfaceContainerLow = surfaceContainerLowLightMediumContrast, surfaceContainer = surfaceContainerLightMediumContrast, surfaceContainerHigh = surfaceContainerHighLightMediumContrast, surfaceContainerHighest = surfaceContainerHighestLightMediumContrast, ) private val highContrastLightColorScheme = lightColorScheme( primary = primaryLightHighContrast, onPrimary = onPrimaryLightHighContrast, primaryContainer = primaryContainerLightHighContrast, onPrimaryContainer = onPrimaryContainerLightHighContrast, secondary = secondaryLightHighContrast, onSecondary = onSecondaryLightHighContrast, secondaryContainer = secondaryContainerLightHighContrast, onSecondaryContainer = onSecondaryContainerLightHighContrast, tertiary = tertiaryLightHighContrast, onTertiary = onTertiaryLightHighContrast, tertiaryContainer = tertiaryContainerLightHighContrast, onTertiaryContainer = onTertiaryContainerLightHighContrast, error = errorLightHighContrast, onError = onErrorLightHighContrast, errorContainer = errorContainerLightHighContrast, onErrorContainer = onErrorContainerLightHighContrast, background = backgroundLightHighContrast, onBackground = onBackgroundLightHighContrast, surface = surfaceLightHighContrast, onSurface = onSurfaceLightHighContrast, surfaceVariant = surfaceVariantLightHighContrast, onSurfaceVariant = onSurfaceVariantLightHighContrast, outline = outlineLightHighContrast, outlineVariant = outlineVariantLightHighContrast, scrim = scrimLightHighContrast, inverseSurface = inverseSurfaceLightHighContrast, inverseOnSurface = inverseOnSurfaceLightHighContrast, inversePrimary = inversePrimaryLightHighContrast, surfaceDim = surfaceDimLightHighContrast, surfaceBright = surfaceBrightLightHighContrast, surfaceContainerLowest = surfaceContainerLowestLightHighContrast, surfaceContainerLow = surfaceContainerLowLightHighContrast, surfaceContainer = surfaceContainerLightHighContrast, surfaceContainerHigh = surfaceContainerHighLightHighContrast, surfaceContainerHighest = surfaceContainerHighestLightHighContrast, ) private val mediumContrastDarkColorScheme = darkColorScheme( primary = primaryDarkMediumContrast, onPrimary = onPrimaryDarkMediumContrast, primaryContainer = primaryContainerDarkMediumContrast, onPrimaryContainer = onPrimaryContainerDarkMediumContrast, secondary = secondaryDarkMediumContrast, onSecondary = onSecondaryDarkMediumContrast, secondaryContainer = secondaryContainerDarkMediumContrast, onSecondaryContainer = onSecondaryContainerDarkMediumContrast, tertiary = tertiaryDarkMediumContrast, onTertiary = onTertiaryDarkMediumContrast, tertiaryContainer = tertiaryContainerDarkMediumContrast, onTertiaryContainer = onTertiaryContainerDarkMediumContrast, error = errorDarkMediumContrast, onError = onErrorDarkMediumContrast, errorContainer = errorContainerDarkMediumContrast, onErrorContainer = onErrorContainerDarkMediumContrast, background = backgroundDarkMediumContrast, onBackground = onBackgroundDarkMediumContrast, surface = surfaceDarkMediumContrast, onSurface = onSurfaceDarkMediumContrast, surfaceVariant = surfaceVariantDarkMediumContrast, onSurfaceVariant = onSurfaceVariantDarkMediumContrast, outline = outlineDarkMediumContrast, outlineVariant = outlineVariantDarkMediumContrast, scrim = scrimDarkMediumContrast, inverseSurface = inverseSurfaceDarkMediumContrast, inverseOnSurface = inverseOnSurfaceDarkMediumContrast, inversePrimary = inversePrimaryDarkMediumContrast, surfaceDim = surfaceDimDarkMediumContrast, surfaceBright = surfaceBrightDarkMediumContrast, surfaceContainerLowest = surfaceContainerLowestDarkMediumContrast, surfaceContainerLow = surfaceContainerLowDarkMediumContrast, surfaceContainer = surfaceContainerDarkMediumContrast, surfaceContainerHigh = surfaceContainerHighDarkMediumContrast, surfaceContainerHighest = surfaceContainerHighestDarkMediumContrast, ) private val highContrastDarkColorScheme = darkColorScheme( primary = primaryDarkHighContrast, onPrimary = onPrimaryDarkHighContrast, primaryContainer = primaryContainerDarkHighContrast, onPrimaryContainer = onPrimaryContainerDarkHighContrast, secondary = secondaryDarkHighContrast, onSecondary = onSecondaryDarkHighContrast, secondaryContainer = secondaryContainerDarkHighContrast, onSecondaryContainer = onSecondaryContainerDarkHighContrast, tertiary = tertiaryDarkHighContrast, onTertiary = onTertiaryDarkHighContrast, tertiaryContainer = tertiaryContainerDarkHighContrast, onTertiaryContainer = onTertiaryContainerDarkHighContrast, error = errorDarkHighContrast, onError = onErrorDarkHighContrast, errorContainer = errorContainerDarkHighContrast, onErrorContainer = onErrorContainerDarkHighContrast, background = backgroundDarkHighContrast, onBackground = onBackgroundDarkHighContrast, surface = surfaceDarkHighContrast, onSurface = onSurfaceDarkHighContrast, surfaceVariant = surfaceVariantDarkHighContrast, onSurfaceVariant = onSurfaceVariantDarkHighContrast, outline = outlineDarkHighContrast, outlineVariant = outlineVariantDarkHighContrast, scrim = scrimDarkHighContrast, inverseSurface = inverseSurfaceDarkHighContrast, inverseOnSurface = inverseOnSurfaceDarkHighContrast, inversePrimary = inversePrimaryDarkHighContrast, surfaceDim = surfaceDimDarkHighContrast, surfaceBright = surfaceBrightDarkHighContrast, surfaceContainerLowest = surfaceContainerLowestDarkHighContrast, surfaceContainerLow = surfaceContainerLowDarkHighContrast, surfaceContainer = surfaceContainerDarkHighContrast, surfaceContainerHigh = surfaceContainerHighDarkHighContrast, surfaceContainerHighest = surfaceContainerHighestDarkHighContrast, ) @Immutable data class ColorFamily( val color: Color, val onColor: Color, val colorContainer: Color, val onColorContainer: Color ) val unspecified_scheme = ColorFamily( Color.Unspecified, Color.Unspecified, Color.Unspecified, Color.Unspecified ) @Composable fun MapComposeTheme( darkTheme: Boolean = isSystemInDarkTheme(), // Dynamic color is available on Android 12+ dynamicColor: Boolean = true, content: @Composable() () -> Unit ) { val colorScheme = when { dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { val context = LocalContext.current if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) } darkTheme -> darkScheme else -> lightScheme } MaterialTheme( colorScheme = colorScheme, typography = AppTypography, content = content ) } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/theme/Type.kt ================================================ package ovh.plrapps.mapcompose.demo.ui.theme import androidx.compose.material3.Typography val AppTypography = Typography() ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/widgets/Callout.kt ================================================ package ovh.plrapps.mapcompose.demo.ui.widgets import android.animation.TimeInterpolator import android.view.animation.OvershootInterpolator import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.Easing import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import java.math.RoundingMode import java.text.DecimalFormat /** * A callout which animates its entry with an overshoot scaling interpolator. */ @Composable fun Callout( x: Double, y: Double, title: String, shouldAnimate: Boolean, onAnimationDone: () -> Unit ) { var animVal by remember { mutableStateOf(if (shouldAnimate) 0f else 1f) } LaunchedEffect(true) { if (shouldAnimate) { Animatable(0f).animateTo( targetValue = 1f, animationSpec = tween(250, easing = overshootEasing) ) { animVal = value } onAnimationDone() } } Surface( Modifier .alpha(animVal) .padding(10.dp) .graphicsLayer { scaleX = animVal scaleY = animVal transformOrigin = TransformOrigin(0.5f, 1f) }, shape = RoundedCornerShape(5.dp), shadowElevation = 10.dp ) { Column(Modifier.padding(16.dp)) { Text( text = title, modifier = Modifier.align(alignment = Alignment.CenterHorizontally), fontSize = 14.sp, textAlign = TextAlign.Center, fontWeight = FontWeight.Bold, ) Text( text = "position ${df.format(x)} , ${df.format(y)}", modifier = Modifier .align(alignment = Alignment.CenterHorizontally) .padding(top = 4.dp), fontSize = 12.sp, textAlign = TextAlign.Center, ) } } } private val df = DecimalFormat("#.##").apply { roundingMode = RoundingMode.CEILING } private val overshootEasing = OvershootInterpolator(1.2f).toEasing() private fun TimeInterpolator.toEasing() = Easing { x -> getInterpolation(x) } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/ui/widgets/Marker.kt ================================================ package ovh.plrapps.mapcompose.demo.ui.widgets import androidx.compose.foundation.layout.size import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import ovh.plrapps.mapcompose.demo.R @Composable fun Marker() = Icon( painter = painterResource(id = R.drawable.map_marker), contentDescription = null, modifier = Modifier.size(50.dp), tint = Color(0xCC2196F3) ) ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/utils/Metrics.kt ================================================ package ovh.plrapps.mapcompose.demo.utils import android.content.res.Resources /** * Convert px to dp */ fun pxToDp(px: Int): Int { return (px / Resources.getSystem().displayMetrics.density).toInt() } /** * Convert dp to px */ fun dpToPx(dp: Int): Int { return (dp * Resources.getSystem().displayMetrics.density).toInt() } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/utils/Random.kt ================================================ package ovh.plrapps.mapcompose.demo.utils import kotlin.random.Random.Default.nextDouble fun randomDouble(center: Double, radius: Double) : Double { return nextDouble(from = center - radius, until = center + radius) } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/utils/WebMercator.kt ================================================ package ovh.plrapps.mapcompose.demo.utils import kotlin.math.PI import kotlin.math.atan import kotlin.math.exp import kotlin.math.floor import kotlin.math.ln import kotlin.math.tan /** * Given a [latitude] and [longitude], get the corresponding relative coordinates (values between * 0.0 and 1.0). * It is assumed that the map uses the Web Mercator projection. */ fun latLonToNormalized(latitude: Double, longitude: Double): Pair { val latRad = latitude * PI / 180.0 val lngRad = longitude * PI / 180.0 // Web Mercator projected coordinates val X = earthRadius * lngRad val Y = earthRadius * ln(tan((PI / 4.0) + (latRad / 2.0))) // Relative coordinates for MapCompose val piR = earthRadius * PI val normalizedX = (X + piR) / (2.0 * piR) val normalizedY = (piR - Y) / (2.0 * piR) return Pair(normalizedX, normalizedY) } /** * Given relative coordinates in a world map (a square of size 2.0 * piR), get the corresponding * latitude and longitude. * It is assumed that the map uses the Web Mercator projection. */ fun normalizedToLatLon(normalizedX: Double, normalizedY: Double): Pair { val piR = earthRadius * PI val mercatorX = normalizedX * (2.0 * piR) - piR val mercatorY = piR - normalizedY * (2.0 * piR) val num = mercatorX / earthRadius val num2 = num * 180.0 / PI val num3 = floor((num2 + 180) / 360.0f) val lng = num2 - (num3 * 360) val num4 = PI / 2 - (2.0 * atan(exp(-mercatorY / earthRadius))) val lat = num4 * 180.0 / PI return Pair(lat, lng) } private const val earthRadius = 6_378_137.0 // in meters ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/viewmodels/AddingMarkerVM.kt ================================================ package ovh.plrapps.mapcompose.demo.viewmodels import android.app.Application import androidx.compose.foundation.layout.size import androidx.compose.material.Icon import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.lifecycle.AndroidViewModel import ovh.plrapps.mapcompose.api.* import ovh.plrapps.mapcompose.demo.R import ovh.plrapps.mapcompose.demo.providers.makeTileStreamProvider import ovh.plrapps.mapcompose.ui.state.MapState class AddingMarkerVM(application: Application) : AndroidViewModel(application) { private val tileStreamProvider = makeTileStreamProvider(application.applicationContext) private var markerCount = 0 val state = MapState(4, 8192, 8192) { scale(0.0) // zoom-out to minimum scale }.apply { addLayer(tileStreamProvider) onMarkerMove { id, x, y, _, _ -> println("move $id $x $y") } onMarkerClick { id, x, y -> println("marker click $id $x $y") } onMarkerLongPress { id, x, y -> println("on marker long press $id $x $y") } onTap { x, y -> println("on tap $x $y") } onLongPress { x, y -> println("on long press $x $y") } enableRotation() setScrollOffsetRatio(0.5f, 0.5f) } fun addMarker() { state.addMarker("marker$markerCount", 0.5, 0.5) { Icon( painter = painterResource(id = R.drawable.map_marker), contentDescription = null, modifier = Modifier.size(50.dp), tint = Color(0xCC2196F3) ) } state.enableMarkerDrag("marker$markerCount") markerCount++ } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/viewmodels/AnimationDemoVM.kt ================================================ package ovh.plrapps.mapcompose.demo.viewmodels import android.app.Application import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.SnapSpec import androidx.compose.animation.core.TweenSpec import androidx.compose.ui.geometry.Offset import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.Job import kotlinx.coroutines.launch import ovh.plrapps.mapcompose.api.addLayer import ovh.plrapps.mapcompose.api.addMarker import ovh.plrapps.mapcompose.api.enableRotation import ovh.plrapps.mapcompose.api.onTouchDown import ovh.plrapps.mapcompose.api.rotateTo import ovh.plrapps.mapcompose.api.scrollTo import ovh.plrapps.mapcompose.api.shouldLoopScale import ovh.plrapps.mapcompose.demo.providers.makeTileStreamProvider import ovh.plrapps.mapcompose.demo.ui.widgets.Marker import ovh.plrapps.mapcompose.ui.state.MapState /** * This demo shows how animations can be chained one after another. * Since animations APIs are suspending functions, this is easy to do. */ class AnimationDemoVM(application: Application) : AndroidViewModel(application) { private val tileStreamProvider = makeTileStreamProvider(application.applicationContext) private var job: Job? = null private val spec = TweenSpec(2000, easing = FastOutSlowInEasing) val state = MapState(4, 8192, 8192).apply { addLayer(tileStreamProvider) shouldLoopScale = true enableRotation() addMarker("m0", 0.5, 0.5) { Marker() } addMarker("m1", 0.78, 0.78) { Marker() } addMarker("m2", 0.79, 0.79) { Marker() } addMarker("m3", 0.785, 0.72) { Marker() } onTouchDown { job?.cancel() } viewModelScope.launch { scrollTo(0.5, 0.5, 2.0, SnapSpec()) } } fun startAnimation() { /* Cancel ongoing animation */ job?.cancel() /* Start a new one */ with(state) { job = viewModelScope.launch { scrollTo(0.0, 0.0, 2.0, spec, screenOffset = Offset.Zero) scrollTo(0.8, 0.8, 2.0, spec) rotateTo(180f, spec) scrollTo(0.5, 0.5, 0.5, spec) scrollTo(0.5, 0.5, 2.0, TweenSpec(800, easing = FastOutSlowInEasing)) rotateTo(0f, TweenSpec(1000, easing = FastOutSlowInEasing)) } } } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/viewmodels/CalloutVM.kt ================================================ package ovh.plrapps.mapcompose.demo.viewmodels import android.app.Application import androidx.compose.foundation.layout.size import androidx.compose.material3.Icon import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.dp import androidx.lifecycle.AndroidViewModel import ovh.plrapps.mapcompose.api.addCallout import ovh.plrapps.mapcompose.api.addLayer import ovh.plrapps.mapcompose.api.addMarker import ovh.plrapps.mapcompose.api.onCalloutClick import ovh.plrapps.mapcompose.api.onMarkerClick import ovh.plrapps.mapcompose.api.removeCallout import ovh.plrapps.mapcompose.api.scale import ovh.plrapps.mapcompose.demo.R import ovh.plrapps.mapcompose.demo.providers.makeTileStreamProvider import ovh.plrapps.mapcompose.demo.ui.widgets.Callout import ovh.plrapps.mapcompose.ui.state.MapState class CalloutVM(application: Application) : AndroidViewModel(application) { private val tileStreamProvider = makeTileStreamProvider(application.applicationContext) /* Define the markers data (id and position) */ private val markers = listOf( MarkerInfo("Callout #1", 0.45, 0.6), MarkerInfo("Callout #2", 0.24, 0.1), MarkerInfo("Callout #3", 0.25, 0.18), MarkerInfo(TAP_TO_DISMISS_ID, 0.4, 0.3) ) val state = MapState(4, 8192, 8192).apply { addLayer(tileStreamProvider) /* Add all markers */ for (marker in markers) { addMarker(marker.id, marker.x, marker.y) { Icon( painter = painterResource(id = R.drawable.map_marker), contentDescription = null, modifier = Modifier.size(50.dp), tint = Color(0xCC2196F3) ) } } scale = 0.0 /** * On marker click, add a callout. If the id is [TAP_TO_DISMISS_ID], set auto-dismiss * to false. For this particular id, we programmatically remove the callout on tap. */ onMarkerClick { id, x, y -> var shouldAnimate by mutableStateOf(true) addCallout( id, x, y, absoluteOffset = DpOffset(0.dp, (-50).dp), autoDismiss = id != TAP_TO_DISMISS_ID, clickable = id == TAP_TO_DISMISS_ID ) { Callout(x, y, title = id, shouldAnimate) { shouldAnimate = false } } } /** * Register a click listener on callouts. We don't need to remove the other callouts * because they automatically dismiss on touch down. */ onCalloutClick { id, _, _ -> if (id == TAP_TO_DISMISS_ID) removeCallout(TAP_TO_DISMISS_ID) } } } private data class MarkerInfo(val id: String, val x: Double, val y: Double) private const val TAP_TO_DISMISS_ID = "Tap me to dismiss" ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/viewmodels/CenteringOnMarkerVM.kt ================================================ package ovh.plrapps.mapcompose.demo.viewmodels import android.app.Application import androidx.compose.foundation.layout.size import androidx.compose.material.Icon import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.launch import ovh.plrapps.mapcompose.api.addLayer import ovh.plrapps.mapcompose.api.addMarker import ovh.plrapps.mapcompose.api.centerOnMarker import ovh.plrapps.mapcompose.api.enableRotation import ovh.plrapps.mapcompose.demo.R import ovh.plrapps.mapcompose.demo.providers.makeTileStreamProvider import ovh.plrapps.mapcompose.ui.state.MapState class CenteringOnMarkerVM(application: Application) : AndroidViewModel(application) { private val tileStreamProvider = makeTileStreamProvider(application.applicationContext) val state = MapState(4, 8192, 8192) { rotation(45f) }.apply { addLayer(tileStreamProvider) addMarker("parking", 0.2457938, 0.3746023) { Icon( painter = painterResource(id = R.drawable.map_marker), contentDescription = null, modifier = Modifier.size(50.dp), tint = Color(0xCC2196F3) ) } enableRotation() } fun onCenter() { viewModelScope.launch { state.centerOnMarker("parking", destScale = 1.0, destAngle = 0f) } } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/viewmodels/CustomDrawVM.kt ================================================ package ovh.plrapps.mapcompose.demo.viewmodels import android.app.Application import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.launch import ovh.plrapps.mapcompose.api.addLayer import ovh.plrapps.mapcompose.api.addMarker import ovh.plrapps.mapcompose.api.enableMarkerDrag import ovh.plrapps.mapcompose.api.enableRotation import ovh.plrapps.mapcompose.api.moveMarker import ovh.plrapps.mapcompose.api.scale import ovh.plrapps.mapcompose.api.scrollTo import ovh.plrapps.mapcompose.api.setStateChangeListener import ovh.plrapps.mapcompose.api.shouldLoopScale import ovh.plrapps.mapcompose.demo.providers.makeTileStreamProvider import ovh.plrapps.mapcompose.demo.ui.screens.ScaleIndicatorController import ovh.plrapps.mapcompose.ui.MapUI import ovh.plrapps.mapcompose.ui.state.MapState /** * In this example, we're adding two markers with custom drag interceptors which update [p1x], [p1y], * [p2x], and [p2y] states. In turn, when those state change, the line joining the two markers updates. * The line is added as a custom view inside [MapUI] composable. */ class CustomDrawVM(application: Application) : AndroidViewModel(application) { private val tileStreamProvider = makeTileStreamProvider(application.applicationContext) var p1x by mutableStateOf(0.6) var p1y by mutableStateOf(0.6) var p2x by mutableStateOf(0.4) var p2y by mutableStateOf(0.4) val state = MapState(4, 8192, 8192).apply { addLayer(tileStreamProvider) shouldLoopScale = true enableRotation() viewModelScope.launch { scrollTo(0.5, 0.5, 1.1) } } val scaleIndicatorController = ScaleIndicatorController(450, state.scale) init { state.addMarker("m1", p1x, p1y, Offset(-0.5f, -0.5f)) { Box( modifier = Modifier .size(50.dp) .clip(CircleShape) .background(Color(0xAAF44336)) ) } state.addMarker("m2", p2x, p2y, Offset(-0.5f, -0.5f)) { Box( modifier = Modifier .size(50.dp) .clip(CircleShape) .background(Color(0xAAF44336)) ) } state.enableMarkerDrag("m1") { id, x, y, dx, dy, _, _ -> p1x = x + dx p1y = y + dy state.moveMarker(id, p1x, p1y) } state.enableMarkerDrag("m2") { id, x, y, dx, dy, _, _ -> p2x = x + dx p2y = y + dy state.moveMarker(id, p2x, p2y) } state.setStateChangeListener { scaleIndicatorController.onScaleChanged(scale) } } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/viewmodels/HttpTilesVM.kt ================================================ package ovh.plrapps.mapcompose.demo.viewmodels import androidx.lifecycle.ViewModel import ovh.plrapps.mapcompose.api.addLayer import ovh.plrapps.mapcompose.api.scale import ovh.plrapps.mapcompose.api.shouldLoopScale import ovh.plrapps.mapcompose.core.TileStreamProvider import ovh.plrapps.mapcompose.ui.state.MapState import java.io.BufferedInputStream import java.net.HttpURLConnection import java.net.URL /** * Shows how MapCompose behaves with remote HTTP tiles. */ class HttpTilesVM : ViewModel() { private val tileStreamProvider = makeTileStreamProvider() val state = MapState( levelCount = 4, fullWidth = 8192, fullHeight = 8192, workerCount = 16 // Notice how we increase the worker count when performing HTTP requests ).apply { addLayer(tileStreamProvider) scale = 0.0 shouldLoopScale = true } } /** * A [TileStreamProvider] which performs HTTP requests. */ private fun makeTileStreamProvider() = TileStreamProvider { row, col, zoomLvl -> try { val url = URL("https://raw.githubusercontent.com/p-lr/MapCompose/master/demo/src/main/assets/tiles/mont_blanc_layered/$zoomLvl/$row/$col.jpg") val connection = url.openConnection() as HttpURLConnection connection.doInput = true connection.connect() BufferedInputStream(connection.inputStream) } catch (e: Exception) { e.printStackTrace() null } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/viewmodels/InfiniteScrollVM.kt ================================================ package ovh.plrapps.mapcompose.demo.viewmodels import android.app.Application import android.content.Context import androidx.lifecycle.AndroidViewModel import ovh.plrapps.mapcompose.api.addLayer import ovh.plrapps.mapcompose.api.enableRotation import ovh.plrapps.mapcompose.api.shouldLoopScale import ovh.plrapps.mapcompose.core.TileStreamProvider import ovh.plrapps.mapcompose.ui.state.MapState class InfiniteScrollVM(application: Application) : AndroidViewModel(application) { private val tileStreamProvider = makeWorldTileStreamProvider(application.applicationContext) val state = MapState(5, 8192, 8192) { scale(0.1) infiniteScrollX(true) }.apply { addLayer(tileStreamProvider) shouldLoopScale = true enableRotation() } } private fun makeWorldTileStreamProvider(appContext: Context) = TileStreamProvider { row, col, zoomLvl -> try { appContext.assets?.open("tiles/world/$zoomLvl/$row/$col.jpg") } catch (e: Exception) { null } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/viewmodels/LayersVM.kt ================================================ package ovh.plrapps.mapcompose.demo.viewmodels import android.app.Application import android.content.Context import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.launch import ovh.plrapps.mapcompose.api.addLayer import ovh.plrapps.mapcompose.api.enableRotation import ovh.plrapps.mapcompose.api.scrollTo import ovh.plrapps.mapcompose.api.setLayerOpacity import ovh.plrapps.mapcompose.api.shouldLoopScale import ovh.plrapps.mapcompose.core.TileStreamProvider import ovh.plrapps.mapcompose.ui.state.MapState class LayersVM(application: Application) : AndroidViewModel(application) { private val tileStreamProvider = makeTileStreamProvider(application.applicationContext, imageExt = ".jpg") private val slopesLayerProvider = makeTileStreamProvider(application.applicationContext, "ign-slopes-", imageExt = ".png") private val roadLayerProvider = makeTileStreamProvider(application.applicationContext, "ign-road-", imageExt = ".png") private var slopesId: String? = null private var roadId: String? = null val state = MapState(4, 8192, 8192).apply { shouldLoopScale = true enableRotation() viewModelScope.launch { scrollTo(0.4, 0.4, 1.0) } addLayer(tileStreamProvider) slopesId = addLayer(slopesLayerProvider, initialOpacity = 0.6f) roadId = addLayer(roadLayerProvider, initialOpacity = 1f) } private fun makeTileStreamProvider(appContext: Context, layer: String = "", imageExt: String) = TileStreamProvider { row, col, zoomLvl -> try { appContext.assets?.open("tiles/mont_blanc_layered/$zoomLvl/$row/$layer$col$imageExt") } catch (e: Exception) { null } } fun setSlopesOpacity(opacity: Float) { slopesId?.also { id -> state.setLayerOpacity(id, opacity) } } fun setRoadOpacity(opacity: Float) { roadId?.also { id -> state.setLayerOpacity(id, opacity) } } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/viewmodels/MarkersClusteringVM.kt ================================================ package ovh.plrapps.mapcompose.demo.viewmodels import android.app.Application import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.lifecycle.AndroidViewModel import ovh.plrapps.mapcompose.api.addClusterer import ovh.plrapps.mapcompose.api.addLayer import ovh.plrapps.mapcompose.api.addMarker import ovh.plrapps.mapcompose.demo.R import ovh.plrapps.mapcompose.demo.providers.makeTileStreamProvider import ovh.plrapps.mapcompose.ui.state.MapState import ovh.plrapps.mapcompose.ui.state.markers.model.RenderingStrategy /** * Shows how to define and use a marker clusterer. */ class MarkersClusteringVM(application: Application) : AndroidViewModel(application) { private val tileStreamProvider = makeTileStreamProvider(application.applicationContext) val state = MapState(4, 8192, 8192) { scale(0.2) maxScale(8.0) scroll(0.5, 0.5) }.apply { addLayer(tileStreamProvider) } init { /* Add a marker clusterer to manage markers. In this example, we use "default" for the id */ state.addClusterer("default") { ids -> { Cluster(size = ids.size) } } /* Add some markers to the map, using the same clusterer id we just defined (if a marker * is added without any clusterer, it won't be managed by any clusterer)*/ listOf( 0.5 to 0.5, 0.51 to 0.5, 0.5 to 0.54, 0.51 to 0.54, 0.6 to 0.52, 0.48 to 0.35, 0.48 to 0.355, 0.485 to 0.35, 0.52 to 0.35, 0.515 to 0.36, 0.515 to 0.355, ).forEachIndexed { i, pair -> state.addMarker( id = "marker-$i", x = pair.first, y = pair.second, renderingStrategy = RenderingStrategy.Clustering("default"), ) { Marker() } } /* We can still add regular markers */ state.addMarker( "marker-regular", 0.52, 0.36, clickable = false ) { Icon( painter = painterResource(id = R.drawable.map_marker), contentDescription = null, modifier = Modifier.size(50.dp), tint = Color(0xEEF44336) ) } } @Composable private fun Marker() { Icon( painter = painterResource(id = R.drawable.map_marker), contentDescription = null, modifier = Modifier.size(50.dp), tint = Color(0xEE2196F3) ) } @Composable private fun Cluster(size: Int) { /* Here we can customize the cluster style */ Box( modifier = Modifier .background( Color(0x992196F3), shape = CircleShape ) .size(50.dp), contentAlignment = Alignment.Center ) { Text(text = size.toString(), color = Color.White) } } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/viewmodels/MarkersLazyLoadingVM.kt ================================================ package ovh.plrapps.mapcompose.demo.viewmodels import android.app.Application import androidx.compose.foundation.layout.size import androidx.compose.material3.Icon import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.lifecycle.AndroidViewModel import ovh.plrapps.mapcompose.api.addLayer import ovh.plrapps.mapcompose.api.addLazyLoader import ovh.plrapps.mapcompose.api.addMarker import ovh.plrapps.mapcompose.api.onMarkerClick import ovh.plrapps.mapcompose.api.shouldLoopScale import ovh.plrapps.mapcompose.demo.R import ovh.plrapps.mapcompose.ui.layout.Forced import ovh.plrapps.mapcompose.ui.state.MapState import ovh.plrapps.mapcompose.ui.state.markers.model.RenderingStrategy import kotlin.random.Random /** * Shows how to define and use a marker lazy-loader. */ class MarkersLazyLoadingVM(application: Application) : AndroidViewModel(application) { private val tileStreamProvider = ovh.plrapps.mapcompose.demo.providers.makeTileStreamProvider(application.applicationContext) val state = MapState(4, 8192, 8192) { minimumScaleMode(Forced(1.0)) scale(1.0) maxScale(4.0) scroll(0.5, 0.5) }.apply { addLayer(tileStreamProvider) shouldLoopScale = true } init { /* Add a marker lazy loader. In this example, we use "default" for the id */ state.addLazyLoader("default") repeat(200) { i -> val x = Random.nextDouble() val y = Random.nextDouble() /* Notice how we set the rendering strategy to lazy loading with the same id */ state.addMarker( "marker-$i", x, y, renderingStrategy = RenderingStrategy.LazyLoading(lazyLoaderId = "default") ) { Icon( painter = painterResource(id = R.drawable.map_marker), contentDescription = null, modifier = Modifier.size(50.dp), tint = Color(0xEE2196F3) ) } } /* We can still add regular markers */ state.addMarker( "marker-regular", 0.5, 0.5, ) { Icon( painter = painterResource(id = R.drawable.map_marker), contentDescription = null, modifier = Modifier.size(50.dp), tint = Color(0xEEF44336) ) } state.onMarkerClick { id, x, y -> println("marker click $id $x $y") } } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/viewmodels/OsmVM.kt ================================================ package ovh.plrapps.mapcompose.demo.viewmodels import androidx.compose.foundation.layout.size import androidx.compose.material3.Icon import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.lifecycle.ViewModel import ovh.plrapps.mapcompose.api.addLayer import ovh.plrapps.mapcompose.api.addMarker import ovh.plrapps.mapcompose.core.TileStreamProvider import ovh.plrapps.mapcompose.demo.R import ovh.plrapps.mapcompose.demo.utils.latLonToNormalized import ovh.plrapps.mapcompose.ui.layout.Forced import ovh.plrapps.mapcompose.ui.state.MapState import java.io.BufferedInputStream import java.net.HttpURLConnection import java.net.URL import kotlin.math.pow /** * Shows how to use WMTS tile servers with MapCompose, such as Open Street Map. */ class OsmVM : ViewModel() { private val tileStreamProvider = makeTileStreamProvider() private val maxLevel = 16 private val minLevel = 12 private val mapSize = mapSizeAtLevel(maxLevel, tileSize = 256) private val paris = latLonToNormalized(48.856667, 2.351667) // Paris private val x = paris.first private val y = paris.second val state = MapState(levelCount = maxLevel + 1, mapSize, mapSize, workerCount = 16) { minimumScaleMode(Forced(1 / 2.0.pow(maxLevel - minLevel))) scroll(x, y) scale(0.0) // to zoom out initially }.apply { addLayer(tileStreamProvider) addMarker("id", x, y) { Icon( painter = painterResource(id = R.drawable.map_marker), contentDescription = null, modifier = Modifier.size(50.dp), tint = Color(0xCC2196F3) ) } } } /** * A [TileStreamProvider] which performs HTTP requests. */ private fun makeTileStreamProvider() = TileStreamProvider { row, col, zoomLvl -> try { val url = URL("https://tile.openstreetmap.org/$zoomLvl/$col/$row.png") val connection = url.openConnection() as HttpURLConnection // OSM requires a user-agent connection.setRequestProperty("User-Agent", "Chrome/120.0.0.0 Safari/537.36") connection.doInput = true connection.connect() BufferedInputStream(connection.inputStream) } catch (e: Exception) { e.printStackTrace() null } } /** * wmts level are 0 based. * At level 0, the map corresponds to just one tile. */ private fun mapSizeAtLevel(wmtsLevel: Int, tileSize: Int): Int { return tileSize * 2.0.pow(wmtsLevel).toInt() } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/viewmodels/PathsVM.kt ================================================ package ovh.plrapps.mapcompose.demo.viewmodels import android.app.Application import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.dp import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.launch import ovh.plrapps.mapcompose.api.addCallout import ovh.plrapps.mapcompose.api.addLayer import ovh.plrapps.mapcompose.api.addPath import ovh.plrapps.mapcompose.api.enableRotation import ovh.plrapps.mapcompose.api.onPathClick import ovh.plrapps.mapcompose.api.onPathLongPress import ovh.plrapps.mapcompose.api.scrollTo import ovh.plrapps.mapcompose.api.shouldLoopScale import ovh.plrapps.mapcompose.demo.providers.makeTileStreamProvider import ovh.plrapps.mapcompose.demo.ui.widgets.Callout import ovh.plrapps.mapcompose.ui.paths.PathDataBuilder import ovh.plrapps.mapcompose.ui.paths.model.PatternItem import ovh.plrapps.mapcompose.ui.paths.model.PatternItem.Dash import ovh.plrapps.mapcompose.ui.paths.model.PatternItem.Gap import ovh.plrapps.mapcompose.ui.state.MapState /** * In this sample, we add "tracks" to the map. The tracks are rendered as paths using MapCompose. */ class PathsVM(application: Application) : AndroidViewModel(application) { private val tileStreamProvider = makeTileStreamProvider(application.applicationContext) val state = MapState(4, 8192, 8192).apply { addLayer(tileStreamProvider) shouldLoopScale = true enableRotation() /** * Demonstrates path click. */ onPathClick { id, x, y -> var shouldAnimate by mutableStateOf(true) addCallout( id, x, y, absoluteOffset = DpOffset(0.dp, (-10).dp), ) { Callout(x, y, title = "Click on $id", shouldAnimate) { shouldAnimate = false } } } /** * Demonstrates path long-press. */ onPathLongPress { id, x, y -> var shouldAnimate by mutableStateOf(true) addCallout( id, x, y, absoluteOffset = DpOffset(0.dp, (-10).dp), ) { Callout(x, y, title = "Long-press on $id", shouldAnimate) { shouldAnimate = false } } } viewModelScope.launch { scrollTo(0.72, 0.3) } } init { /* Add tracks */ addTrack("track1", Color(0xFF448AFF)) addTrack("track2", Color(0xFFFFFF00)) addTrack("track3", pattern = listOf(Dash(8.dp), Gap(4.dp))) // filled polygon with(state) { addPath( id = "filled polygon", color = Color.Green, fillColor = Color.Green.copy(alpha = .6f), ) { // Pentagon addPoint(0.2009, 0.17878) addPoint(0.08909, 0.2151) addPoint(0.01999, 0.12) addPoint(0.08909, 0.02489) addPoint(0.2009, 0.06122) } } } /** * In this sample, we retrieve track points from text files in the assets. * To add a path, use the [addPath] api. From inside the builder block, you can add individual * points or a list of points. * Here, since we're getting points from a sequence, we add them on the fly using [PathDataBuilder.addPoint]. */ private fun addTrack( trackName: String, color: Color? = null, pattern: List? = null, clickable: Boolean = true ) { with(state) { val lines = getApplication().applicationContext.assets?.open( "tracks/$trackName.txt" )?.bufferedReader()?.lineSequence() ?: return@with addPath( id = trackName, color = color, clickable = clickable, pattern = pattern, offset = 1 ) { for (line in lines) { val values = line.split(',').map(String::toDouble) addPoint(values[0], values[1]) } } } } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/viewmodels/RotationVM.kt ================================================ package ovh.plrapps.mapcompose.demo.viewmodels import android.app.Application import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.launch import ovh.plrapps.mapcompose.api.addLayer import ovh.plrapps.mapcompose.api.enableRotation import ovh.plrapps.mapcompose.api.rotateTo import ovh.plrapps.mapcompose.api.rotation import ovh.plrapps.mapcompose.api.scale import ovh.plrapps.mapcompose.api.scroll import ovh.plrapps.mapcompose.api.setScrollOffsetRatio import ovh.plrapps.mapcompose.api.setStateChangeListener import ovh.plrapps.mapcompose.demo.providers.makeTileStreamProvider import ovh.plrapps.mapcompose.ui.state.MapState class RotationVM(application: Application) : AndroidViewModel(application) { private val tileStreamProvider = makeTileStreamProvider(application.applicationContext) val state = MapState(4, 8192, 8192).apply { addLayer(tileStreamProvider) enableRotation() setScrollOffsetRatio(0.3f, 0.3f) scale = 0.0 /* Not useful here, just showing how this API works */ setStateChangeListener { println("scale: $scale, scroll: $scroll, rotation: $rotation") } } fun onRotate() { viewModelScope.launch { state.rotateTo(state.rotation + 90f) } } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/viewmodels/SimpleDemoVM.kt ================================================ package ovh.plrapps.mapcompose.demo.viewmodels import android.app.Application import androidx.lifecycle.AndroidViewModel import ovh.plrapps.mapcompose.api.addLayer import ovh.plrapps.mapcompose.api.enableRotation import ovh.plrapps.mapcompose.api.shouldLoopScale import ovh.plrapps.mapcompose.demo.providers.makeTileStreamProvider import ovh.plrapps.mapcompose.ui.state.MapState class SimpleDemoVM(application: Application) : AndroidViewModel(application) { private val tileStreamProvider = makeTileStreamProvider(application.applicationContext) val state = MapState(4, 8448, 8448) { scale(1.2) }.apply { addLayer(tileStreamProvider) shouldLoopScale = true enableRotation() } } ================================================ FILE: demo/src/main/java/ovh/plrapps/mapcompose/demo/viewmodels/VisibleAreaPaddingVM.kt ================================================ package ovh.plrapps.mapcompose.demo.viewmodels import android.app.Application import androidx.lifecycle.AndroidViewModel import ovh.plrapps.mapcompose.api.addLayer import ovh.plrapps.mapcompose.api.addMarker import ovh.plrapps.mapcompose.api.enableRotation import ovh.plrapps.mapcompose.demo.providers.makeTileStreamProvider import ovh.plrapps.mapcompose.demo.ui.widgets.Marker import ovh.plrapps.mapcompose.ui.state.MapState class VisibleAreaPaddingVM(application: Application) : AndroidViewModel(application) { private val tileStreamProvider = makeTileStreamProvider(application.applicationContext) val state = MapState(4, 8192, 8192) { scale(1.2) }.apply { enableRotation() addLayer(tileStreamProvider) addMarker("m0", 0.5, 0.5) { Marker() } } } ================================================ FILE: demo/src/main/res/drawable/ic_launcher_background.xml ================================================ ================================================ FILE: demo/src/main/res/drawable/map_marker.xml ================================================ ================================================ FILE: demo/src/main/res/drawable-v24/ic_launcher_foreground.xml ================================================ ================================================ FILE: demo/src/main/res/mipmap-anydpi-v26/ic_launcher.xml ================================================ ================================================ FILE: demo/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml ================================================ ================================================ FILE: demo/src/main/res/values/colors.xml ================================================ #FFBB86FC #FF6200EE #FF3700B3 #FF03DAC5 #FF018786 #FF000000 #FFFFFFFF ================================================ FILE: demo/src/main/res/values/strings.xml ================================================ MapCompose Demo ================================================ FILE: demo/src/main/res/values/themes.xml ================================================