4
.github/workflows/ci-build.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
os: [windows-latest, macos-latest]
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
- name: Check clippy lints
|
||||
run: cargo clippy --all-targets --all-features -- -D warnings
|
||||
|
||||
- name: Install dependencies
|
||||
- name: Install Rust dependencies
|
||||
run: cargo fetch
|
||||
|
||||
- name: Build
|
||||
|
||||
50
.gitignore
vendored
@@ -1,5 +1,51 @@
|
||||
# Environment files
|
||||
.env
|
||||
.envrc
|
||||
/.direnv
|
||||
|
||||
# Build artifacts
|
||||
/target
|
||||
**/*.rs.bk
|
||||
|
||||
# Lock files
|
||||
Cargo.lock
|
||||
export.json
|
||||
parsed_osm_data.txt
|
||||
|
||||
# IDE/editor files
|
||||
.idea/
|
||||
/.vscode/
|
||||
/*.swp
|
||||
*.iml
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.ps1
|
||||
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
*.tmp
|
||||
*.log
|
||||
|
||||
# Generated files
|
||||
/export.json
|
||||
/parsed_osm_data.txt
|
||||
/gen/
|
||||
/build/
|
||||
*.rmeta
|
||||
*.dSYM
|
||||
|
||||
# Tauri specific
|
||||
flake/
|
||||
capabilities/
|
||||
gen/
|
||||
|
||||
# Miscellaneous
|
||||
*.bak
|
||||
*.old
|
||||
*.orig
|
||||
|
||||
# Ignore all in flake directory except specific files
|
||||
/flake/*
|
||||
!/flake/flake.nix
|
||||
!/flake/flake.lock
|
||||
|
||||
11
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "arnis"
|
||||
version = "2.0.0"
|
||||
version = "2.1.0"
|
||||
edition = "2021"
|
||||
description = "Arnis - Generate real life cities in Minecraft"
|
||||
homepage = "https://github.com/louis-e/arnis"
|
||||
@@ -11,9 +11,13 @@ readme = "README.md"
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2", features = [] }
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.1", features = ["derive"] }
|
||||
colored = "2.1.0"
|
||||
dirs = "4.0.0"
|
||||
fastanvil = "0.31.0"
|
||||
fastnbt = "2.5.0"
|
||||
fnv = "1.0.7"
|
||||
@@ -24,6 +28,11 @@ nalgebra = "0.33.0"
|
||||
once_cell = "1.19.0"
|
||||
rand = "0.8.5"
|
||||
reqwest = { version = "0.12.7", features = ["blocking", "json"] }
|
||||
rfd = "0.15.0"
|
||||
semver = "1.0.23"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
tauri = { version = "2", features = [] }
|
||||
tauri-plugin-dialog = "2.0.0"
|
||||
tauri-plugin-shell = "2"
|
||||
tokio = { version = "1.42.0", features = ["full"] }
|
||||
|
||||
40
README.md
@@ -2,7 +2,7 @@
|
||||
<img width="456" height="125" src="https://github.com/louis-e/arnis/blob/main/gitassets/logo.png?raw=true">
|
||||
</p>
|
||||
|
||||
# Arnis [](https://github.com/louis-e/arnis/actions)
|
||||
# Arnis [](https://github.com/louis-e/arnis/actions) [<img alt="GitHub Release" src="https://img.shields.io/github/v/release/louis-e/arnis" />](https://github.com/louis-e/arnis/releases) [<img alt="GitHub Downloads (all assets, all releases" src="https://img.shields.io/github/downloads/louis-e/arnis/total" />](https://github.com/louis-e/arnis/releases)
|
||||
|
||||
This open source project written in Rust generates any chosen location from the real world in Minecraft Java Edition with a high level of detail.
|
||||
|
||||
@@ -13,6 +13,28 @@ By leveraging geospatial data from OpenStreetMap and utilizing the powerful capa
|
||||
|
||||
Arnis is designed to handle large-scale data and generate rich, immersive environments that bring real-world cities, landmarks, and natural features into the Minecraft universe. Whether you're looking to replicate your hometown, explore urban environments, or simply build something unique and realistic, Arnis offers a comprehensive toolset to achieve your vision.
|
||||
|
||||
## :keyboard: Usage
|
||||
<img width="60%" src="https://github.com/louis-e/arnis/blob/main/gitassets/gui.png?raw=true"><br>
|
||||
Download the [latest release](https://github.com/louis-e/arnis/releases/) or [compile](#trophy-open-source) the project on your own.
|
||||
|
||||
Make sure to generate a new flat world in advance in Minecraft. Then choose your area in Arnis using the rectangle tool and select your Minecraft world - then simply click on 'Start Generation'!
|
||||
The world will always be generated starting from the coordinates 0 0 0.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Alternatively you can also run Arnis the old fashioned way in the command line.</summary>
|
||||
|
||||
```arnis.exe --path="C:/YOUR_PATH/.minecraft/saves/worldname" --bbox="min_lng,min_lat,max_lng,max_lat"```
|
||||
|
||||
The --bbox parameter specifies the bounding box coordinates in the format: min_lng,min_lat,max_lng,max_lat. Use --path to specify the location of the Minecraft world.
|
||||
|
||||
<img width="60%" src="https://github.com/louis-e/arnis/blob/main/gitassets/bbox-finder.png?raw=true"><br>
|
||||
Use http://bboxfinder.com/ to draw a rectangle of your wanted area. Then copy the four box coordinates as shown below and use them as the input for the --bbox parameter. Try starting with a small area since large areas take a lot of computing power and time to process.<br>
|
||||
|
||||
<i>Note: This might not be working right now since the console gets suppressed.</i>
|
||||
|
||||
</details>
|
||||
|
||||
## :floppy_disk: How it works
|
||||

|
||||
|
||||
@@ -26,19 +48,6 @@ The raw data obtained from the API *[(see FAQ)](#question-faq)* includes each el
|
||||
5. Generate Ground Layer: A ground layer is generated based on the provided scale factors to provide a base for the entire Minecraft world. This step ensures all areas have an appropriate foundation (e.g., grass and dirt layers).
|
||||
6. Save the Minecraft World: All the modified chunks are saved back to the Minecraft region files.
|
||||
|
||||
## :keyboard: Usage
|
||||
Get the [latest release](https://github.com/louis-e/arnis/releases/) or [compile](#trophy-open-source) the project on your own.
|
||||
#### Run: ```arnis.exe --path="C:/YOUR_PATH/.minecraft/saves/worldname" --bbox="min_lng,min_lat,max_lng,max_lat"```
|
||||
|
||||
### How to find your bbox coordinates
|
||||
Use http://bboxfinder.com/ to draw a rectangle of your wanted area. Then copy the four box coordinates as shown below and use them as the input for the --bbox parameter.
|
||||

|
||||
The world will always be generated starting from the coordinates 0 0 0. Try starting with a small area since large areas take a lot of computing power and time to process.
|
||||
|
||||
Manually generate a new Minecraft world (preferably a flat world) before running the script.
|
||||
The --bbox parameter specifies the bounding box coordinates in the format: min_lng,min_lat,max_lng,max_lat.
|
||||
Use --path to specify the location of the Minecraft world.
|
||||
|
||||
## :question: FAQ
|
||||
- *Wasn't this written in Python before?*<br>
|
||||
Yes! Arnis was initially developed in Python, which benefited from Python's open-source friendliness and ease of readability. This is why we strive for clear, well-documented code in the Rust port of this project to find the right balance. I decided to port the project to Rust to learn more about it and push the algorithm's performance further. We were nearing the limits of optimization in Python, and Rust's capabilities allow for even better performance and efficiency. The old Python implementation is still available in the python-legacy branch.
|
||||
@@ -51,7 +60,6 @@ The project is named after the smallest city in Germany, Arnis[^2]. The city's s
|
||||
|
||||
## :memo: ToDo and Known Bugs
|
||||
Feel free to choose an item from the To-Do or Known Bugs list, or bring your own idea to the table. Bug reports shall be raised as a Github issue. Contributions are highly welcome and appreciated!
|
||||
- [ ] Design and implement a GUI
|
||||
- [ ] Memory optimization
|
||||
- [ ] Fix Github Action Workflow for releasing Linux & MacOS Binary
|
||||
- [ ] Evaluate and implement multithreaded region saving
|
||||
@@ -67,6 +75,7 @@ Feel free to choose an item from the To-Do or Known Bugs list, or bring your own
|
||||
- [ ] Evaluate and implement elevation
|
||||
- [ ] Generate a few big cities using high performance hardware and make them available to download
|
||||
- [ ] Implement memory mapped storing of chunks to reduce memory usage
|
||||
- [x] Design and implement a GUI
|
||||
- [x] Fix faulty empty chunks ([https://github.com/owengage/fastnbt/issues/120](https://github.com/owengage/fastnbt/issues/120)) (workaround found)
|
||||
|
||||
## :trophy: Open Source
|
||||
@@ -81,6 +90,7 @@ Feel free to choose an item from the To-Do or Known Bugs list, or bring your own
|
||||
This project is open source and welcomes contributions from everyone! Whether you're interested in fixing bugs, improving performance, adding new features, or enhancing documentation, your input is valuable. Simply fork the repository, make your changes, and submit a pull request. We encourage discussions and suggestions to ensure the project remains modular, optimized, and easy to use for the community. You can use the parameter --debug to get a more detailed output of the processed values, which can be helpful for debugging and development. Contributions of all levels are appreciated, and your efforts help improve this tool for everyone.
|
||||
|
||||
Build and run it using: ```cargo run --release -- --path="C:/YOUR_PATH/.minecraft/saves/worldname" --bbox="min_lng,min_lat,max_lng,max_lat"```<br>
|
||||
For the GUI: ```cargo run --release```<br>
|
||||
|
||||
After your pull request was merged, I will take care of regularly creating update releases which will include your changes.
|
||||
|
||||
|
||||
347
gui-src/css/bbox.css
Normal file
@@ -0,0 +1,347 @@
|
||||
html,
|
||||
body,
|
||||
#map {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
}
|
||||
|
||||
#info-box {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
bottom: 0;
|
||||
border: 0 0 7px 0;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
#coord-format {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 15;
|
||||
}
|
||||
|
||||
#coord-format .bboxlabel {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#coord-format form {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#info img {
|
||||
vertical-align: middle;
|
||||
height: 16px;
|
||||
width: auto;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
#info img:hover {
|
||||
opacity: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#info-toggle ul {
|
||||
margin: 0 0 0 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#info-toggle ul li {
|
||||
display: inline-block;
|
||||
padding: 4px 7px 0;
|
||||
background-color: rgba(230, 230, 230, 0.4);
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#info-toggle ul li.active {
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
#info-toggle-button {
|
||||
background-color: rgba(0, 0, 0, 0.7) !important;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#info-toggle-button:hover {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
#projlabel,
|
||||
#wgslabel {
|
||||
display: inline-block;
|
||||
color: #333;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
#projcoords {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.coords {
|
||||
text-align: left;
|
||||
padding: 7px 0;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
#bbounds,
|
||||
#mbounds,
|
||||
#mcenter {
|
||||
font-size: small;
|
||||
display: block;
|
||||
z-index: 10000;
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
#mouse,
|
||||
#tile,
|
||||
#zoom {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.bboxlabel {
|
||||
font-size: small;
|
||||
font-weight: bold;
|
||||
z-index: 10000;
|
||||
background-color: black;
|
||||
color: white;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
padding-left: 2px;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.bboxllpos,
|
||||
.bboxllpossmall,
|
||||
.bboxprojpos,
|
||||
.bboxprojpossmall,
|
||||
.tilesmall,
|
||||
.zoomsmall {
|
||||
font-size: small;
|
||||
font-weight: bold;
|
||||
color: black;
|
||||
display: inline-block;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.bboxllpos {
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
.bboxllpossmall {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.bboxprojpos {
|
||||
width: 450px;
|
||||
}
|
||||
|
||||
.bboxprojpossmall {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.tilesmall {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.zoomsmall {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
#map-ui-proj {
|
||||
position: absolute;
|
||||
top: 460px;
|
||||
left: 10px;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#map-ui-proj a {
|
||||
font: normal 13px/18px 'Helvetica Neue', Helvetica, sans-serif;
|
||||
background: #FFF;
|
||||
color: #3C4E5A;
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 1px solid #BBB;
|
||||
border-bottom-width: 0;
|
||||
min-width: 75px;
|
||||
padding: 2px;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#map-ui-proj a:hover {
|
||||
background: #ECF5FA;
|
||||
}
|
||||
|
||||
#map-ui-proj li:last-child a {
|
||||
border-bottom-width: 1px;
|
||||
-webkit-border-radius: 0 0 3px 3px;
|
||||
border-radius: 0 0 3px 3px;
|
||||
}
|
||||
|
||||
#map-ui-proj li:first-child a {
|
||||
-webkit-border-radius: 3px 3px 0 0;
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
|
||||
#map-ui-proj a.active {
|
||||
background: #3887BE;
|
||||
border-color: #3887BE;
|
||||
border-top-color: #FFF;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.epsglabel {
|
||||
font-size: small;
|
||||
font-weight: bold;
|
||||
background-color: black;
|
||||
color: white;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
#map-ui {
|
||||
position: absolute;
|
||||
top: 330px;
|
||||
left: 12px;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
#map-ui a {
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ccc;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
background-image: url('css/maps/images/bbox-sprites.png');
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
#map-ui a:hover {
|
||||
background-color: #ECF5FA;
|
||||
}
|
||||
|
||||
#map-ui li:last-child a {
|
||||
border-bottom-width: 1px;
|
||||
-webkit-border-radius: 0 0 3px 3px;
|
||||
border-radius: 0 0 3px 3px;
|
||||
background-position: -33px -2px;
|
||||
}
|
||||
|
||||
#map-ui li:last-child a.enabled {
|
||||
border-bottom-width: 1px;
|
||||
-webkit-border-radius: 0 0 3px 3px;
|
||||
border-radius: 0 0 3px 3px;
|
||||
background-position: -278px -2px;
|
||||
}
|
||||
|
||||
#map-ui li:first-child a {
|
||||
-webkit-border-radius: 3px 3px 0 0;
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
|
||||
#create-geojson a.enabled {
|
||||
background-position: -248px -2px;
|
||||
}
|
||||
|
||||
#create-geojson a {
|
||||
background-position: -2px -2px;
|
||||
}
|
||||
|
||||
#geolocation a {
|
||||
background-position: -186px -2px;
|
||||
}
|
||||
|
||||
#geolocation a.active {
|
||||
background-position: -63px -2px;
|
||||
}
|
||||
|
||||
#help a.enabled {
|
||||
background-position: -342px -2px;
|
||||
}
|
||||
|
||||
#help a {
|
||||
background-position: -93px -2px;
|
||||
}
|
||||
|
||||
.zeroclipboard-is-hover {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.leaflet-sidebar textarea {
|
||||
/* display: none; */
|
||||
height: 95%;
|
||||
width: 100%;
|
||||
border: 1;
|
||||
padding: 2em;
|
||||
resize: none;
|
||||
-webkit-box-sizing: border-box;
|
||||
/* Safari/Chrome, other WebKit */
|
||||
-moz-box-sizing: border-box;
|
||||
/* Firefox, other Gecko */
|
||||
box-sizing: border-box;
|
||||
/* Opera/IE 8+ */
|
||||
}
|
||||
|
||||
.leaflet-sidebar button {
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.leaflet-sidebar .close {
|
||||
z-index: 10001;
|
||||
}
|
||||
|
||||
.ui-autocomplete {
|
||||
max-height: 180px;
|
||||
overflow-y: auto;
|
||||
/* prevent horizontal scrollbar */
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* IE 6 doesn't support max-height
|
||||
* we use height instead, but this forces the menu to always be this tall
|
||||
*/
|
||||
* html .ui-autocomplete {
|
||||
height: 180px;
|
||||
}
|
||||
|
||||
|
||||
.unblurred.leaflet-tile-loaded {
|
||||
|
||||
-moz-filter: blur(0) sepia(0) invert(0);
|
||||
-webkit-filter: blur(0) sepia(0) invert(0);
|
||||
filter: blur(0) sepia(0) invert(0);
|
||||
|
||||
-moz-transition: all 1s ease;
|
||||
-webkit-transition: all 1s ease;
|
||||
transition: all 1s ease;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.blurred.leaflet-tile-loaded {
|
||||
|
||||
-moz-filter: blur(1px) sepia(1) invert(1);
|
||||
-moz-transition: all 1s ease;
|
||||
|
||||
-webkit-filter: blur(1px) sepia(1) invert(1);
|
||||
-webkit-transition: all 1s ease;
|
||||
|
||||
filter: blur(1px) sepia(1) invert(1);
|
||||
transition: all 1s ease;
|
||||
|
||||
}
|
||||
BIN
gui-src/css/libs/ui-lightness/images/animated-overlay.gif
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 418 B |
|
After Width: | Height: | Size: 312 B |
|
After Width: | Height: | Size: 205 B |
|
After Width: | Height: | Size: 262 B |
|
After Width: | Height: | Size: 348 B |
|
After Width: | Height: | Size: 207 B |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 278 B |
|
After Width: | Height: | Size: 328 B |
BIN
gui-src/css/libs/ui-lightness/images/ui-icons_222222_256x240.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
gui-src/css/libs/ui-lightness/images/ui-icons_228ef1_256x240.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
gui-src/css/libs/ui-lightness/images/ui-icons_ef8c08_256x240.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
gui-src/css/libs/ui-lightness/images/ui-icons_ffd27a_256x240.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
gui-src/css/libs/ui-lightness/images/ui-icons_ffffff_256x240.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
1177
gui-src/css/libs/ui-lightness/jquery-ui-1.10.3.custom.css
vendored
Normal file
7
gui-src/css/libs/ui-lightness/jquery-ui-1.10.3.custom.min.css
vendored
Normal file
BIN
gui-src/css/maps/images/bbox-sprites.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
505
gui-src/css/maps/images/bbox-sprites.svg
Normal file
@@ -0,0 +1,505 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="740"
|
||||
height="60"
|
||||
viewBox="0 0 740.00003 59.999999"
|
||||
enable-background="new 0 0 100 100"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="bbox-sprites.svg"
|
||||
inkscape:export-filename="/Users/aaronr/github/bboxfinder.com/css/maps/images/bbox-sprites.png"
|
||||
inkscape:export-xdpi="45"
|
||||
inkscape:export-ydpi="45"><metadata
|
||||
id="metadata51"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs49"><inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 50 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="100 : 50 : 1"
|
||||
inkscape:persp3d-origin="50 : 33.333333 : 1"
|
||||
id="perspective5373" /></defs><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1226"
|
||||
inkscape:window-height="844"
|
||||
id="namedview47"
|
||||
showgrid="true"
|
||||
inkscape:zoom="1.32"
|
||||
inkscape:cx="372.13373"
|
||||
inkscape:cy="27.069218"
|
||||
inkscape:window-x="8"
|
||||
inkscape:window-y="1"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="Layer_1"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
borderlayer="false"><inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid6480"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" /></sodipodi:namedview>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<g
|
||||
id="g3285"
|
||||
transform="matrix(0.84510875,0,0,0.84510875,2.4666349,3.9025275)"><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3147"
|
||||
d="m 19.02918,27.70898 0,-1.42397 1.52567,0 1.52569,0 0,-4.78047 0,-4.78046 -1.6274,0 -1.62738,0 0,1.52568 0,1.52568 -1.52567,0 -1.52569,0 0,-3.05136 0,-3.05135 7.83182,0 7.83182,0 0,3.05135 0,3.05136 -1.52569,0 -1.52567,0 0,-1.52568 0,-1.52568 -1.62739,0 -1.62739,0 0,4.78046 0,4.78047 1.52568,0 1.52567,0 0,1.42397 0,1.42396 -4.57703,0 -4.57704,0 0,-1.42396 z"
|
||||
style="fill:#464646;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3149"
|
||||
d="m 19.64356,39.48975 0,-5.51027 1.35498,0 1.35497,0 0,4.15529 0,4.15527 12.64649,0 12.6465,0 0,-9.8462 0,-9.84619 -5.60059,0 -5.60059,0 0,-1.26465 0,-1.26465 6.95558,0 6.95556,0 0,12.46582 0,12.46583 L 35,45 l -15.35644,0 0,-5.51025 z"
|
||||
style="fill:#464646;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /></g><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6172"
|
||||
d=""
|
||||
style="fill:#bbbbbb;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6178"
|
||||
d=""
|
||||
style="fill:#bbbbbb;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6184"
|
||||
d=""
|
||||
style="fill:#bbbbbb;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6186"
|
||||
d=""
|
||||
style="fill:#bbbbbb;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6270"
|
||||
d=""
|
||||
style="fill:#bbbbbb;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6288"
|
||||
d=""
|
||||
style="fill:#bbbbbb;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6682"
|
||||
d=""
|
||||
style="fill:#bbbbbb;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6684"
|
||||
d=""
|
||||
style="fill:#bbbbbb;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><g
|
||||
id="g3192"
|
||||
transform="matrix(0.27873303,0,0,0.27873303,128.9627,14.868054)"
|
||||
style="fill:#464646;fill-opacity:1">
|
||||
<g
|
||||
id="g3194"
|
||||
style="fill:#464646;fill-opacity:1">
|
||||
<rect
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd"
|
||||
x="-114.388"
|
||||
y="10.951"
|
||||
clip-rule="evenodd"
|
||||
width="20.32"
|
||||
height="20.318001"
|
||||
id="rect3196" />
|
||||
<rect
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd"
|
||||
x="-114.388"
|
||||
y="36.349998"
|
||||
clip-rule="evenodd"
|
||||
width="20.32"
|
||||
height="20.318001"
|
||||
id="rect3198" />
|
||||
<rect
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd"
|
||||
x="-114.388"
|
||||
y="61.748001"
|
||||
clip-rule="evenodd"
|
||||
width="20.32"
|
||||
height="20.319"
|
||||
id="rect3200" />
|
||||
<rect
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd"
|
||||
x="-139.785"
|
||||
y="10.951"
|
||||
clip-rule="evenodd"
|
||||
width="20.318001"
|
||||
height="20.318001"
|
||||
id="rect3202" />
|
||||
<rect
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd"
|
||||
x="-139.785"
|
||||
y="36.349998"
|
||||
clip-rule="evenodd"
|
||||
width="20.318001"
|
||||
height="20.318001"
|
||||
id="rect3204" />
|
||||
<rect
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd"
|
||||
x="-139.785"
|
||||
y="61.748001"
|
||||
clip-rule="evenodd"
|
||||
width="20.318001"
|
||||
height="20.319"
|
||||
id="rect3206" />
|
||||
<rect
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd"
|
||||
x="-165.187"
|
||||
y="10.951"
|
||||
clip-rule="evenodd"
|
||||
width="20.32"
|
||||
height="20.318001"
|
||||
id="rect3208" />
|
||||
<rect
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd"
|
||||
x="-165.187"
|
||||
y="36.349998"
|
||||
clip-rule="evenodd"
|
||||
width="20.32"
|
||||
height="20.318001"
|
||||
id="rect3210" />
|
||||
<rect
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd"
|
||||
x="-165.187"
|
||||
y="61.748001"
|
||||
clip-rule="evenodd"
|
||||
width="20.32"
|
||||
height="20.319"
|
||||
id="rect3212" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
clip-rule="evenodd"
|
||||
d="m -175.144,0.991 v 90.855 h 91.032 V 0.991 h -91.032 z m 84.395,84.217 h -77.757 V 7.63 h 77.757 v 77.578 z"
|
||||
id="path3214" />
|
||||
</g><g
|
||||
style="opacity:0.4;fill:#464646;fill-opacity:1"
|
||||
transform="matrix(0.27657836,0,0,0.27657836,373.31286,14.597384)"
|
||||
id="g3288">
|
||||
<g
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
id="g3290">
|
||||
<rect
|
||||
id="rect3292"
|
||||
height="20.318001"
|
||||
width="20.32"
|
||||
clip-rule="evenodd"
|
||||
y="10.951"
|
||||
x="-114.388"
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd" />
|
||||
<rect
|
||||
id="rect3294"
|
||||
height="20.318001"
|
||||
width="20.32"
|
||||
clip-rule="evenodd"
|
||||
y="36.349998"
|
||||
x="-114.388"
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd" />
|
||||
<rect
|
||||
id="rect3296"
|
||||
height="20.319"
|
||||
width="20.32"
|
||||
clip-rule="evenodd"
|
||||
y="61.748001"
|
||||
x="-114.388"
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd" />
|
||||
<rect
|
||||
id="rect3298"
|
||||
height="20.318001"
|
||||
width="20.318001"
|
||||
clip-rule="evenodd"
|
||||
y="10.951"
|
||||
x="-139.785"
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd" />
|
||||
<rect
|
||||
id="rect3300"
|
||||
height="20.318001"
|
||||
width="20.318001"
|
||||
clip-rule="evenodd"
|
||||
y="36.349998"
|
||||
x="-139.785"
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd" />
|
||||
<rect
|
||||
id="rect3302"
|
||||
height="20.319"
|
||||
width="20.318001"
|
||||
clip-rule="evenodd"
|
||||
y="61.748001"
|
||||
x="-139.785"
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd" />
|
||||
<rect
|
||||
id="rect3304"
|
||||
height="20.318001"
|
||||
width="20.32"
|
||||
clip-rule="evenodd"
|
||||
y="10.951"
|
||||
x="-165.187"
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd" />
|
||||
<rect
|
||||
id="rect3306"
|
||||
height="20.318001"
|
||||
width="20.32"
|
||||
clip-rule="evenodd"
|
||||
y="36.349998"
|
||||
x="-165.187"
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd" />
|
||||
<rect
|
||||
id="rect3308"
|
||||
height="20.319"
|
||||
width="20.32"
|
||||
clip-rule="evenodd"
|
||||
y="61.748001"
|
||||
x="-165.187"
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd" />
|
||||
</g>
|
||||
<path
|
||||
id="path3310"
|
||||
d="m -175.144,0.991 v 90.855 h 91.032 V 0.991 h -91.032 z m 84.395,84.217 h -77.757 V 7.63 h 77.757 v 77.578 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#464646;fill-opacity:1;fill-rule:evenodd" />
|
||||
</g><g
|
||||
id="g3465"
|
||||
transform="matrix(0.25404736,0,0,0.25404736,140.09745,14.744984)"
|
||||
style="fill:#464646;fill-opacity:1"><g
|
||||
id="g3451"
|
||||
style="fill:#464646;fill-opacity:1">
|
||||
<path
|
||||
id="path3453"
|
||||
d="m 28.793,71.207 c -5.062,-5.065 -7.6,-11.705 -7.62,-18.356 l -6.515,-0.002 c 0.021,8.32 3.193,16.635 9.526,22.967 6.335,6.331 14.647,9.504 22.967,9.526 L 47.15,78.827 C 40.5,78.806 33.856,76.268 28.793,71.207 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#464646;fill-opacity:1" />
|
||||
<path
|
||||
id="path3455"
|
||||
d="M 18.423,81.575 C 10.501,73.654 6.535,63.251 6.514,52.85 L 0,52.846 c 0.02,12.074 4.623,24.145 13.815,33.34 9.193,9.188 21.261,13.796 33.337,13.812 V 93.483 C 36.745,93.467 26.346,89.495 18.423,81.575 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#464646;fill-opacity:1" />
|
||||
</g><path
|
||||
id="path3457"
|
||||
d="M 76.157,43.675 73.294,43.334 C 77.075,38.692 76.803,31.847 72.475,27.523 68.154,23.196 61.309,22.924 56.664,26.705 L 56.325,23.843 32.482,0 11.531,20.949 l 23.842,23.843 2.864,0.341 c -3.779,4.643 -3.506,11.485 0.819,15.811 4.325,4.325 11.167,4.596 15.81,0.819 L 55.205,64.625 79.05,88.466 100,67.519 76.157,43.675 z M 38.384,38.586 20.749,20.949 32.482,9.218 l 17.637,17.636 0.669,5.64 -6.762,6.761 -5.642,-0.669 z M 79.05,79.249 61.412,61.613 l -0.668,-5.64 6.761,-6.761 5.642,0.668 17.633,17.639 -11.73,11.73 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#464646;fill-opacity:1" /></g><g
|
||||
id="g4314"
|
||||
transform="matrix(0.24999998,0,0,0.24999998,200.32251,15.25725)"
|
||||
style="fill:#464646;fill-opacity:1"><path
|
||||
id="path4302"
|
||||
d="M 49.541,0 C 22.198,-0.019 0.027,22.376 0,49.978 0.027,77.621 22.198,100.01 49.541,100 76.894,100.011 99.064,77.621 99.085,49.979 99.064,22.376 76.894,-0.019 49.541,0 z m 0,88.483 C 28.503,88.483 11.445,71.252 11.462,49.971 11.441,28.742 28.503,11.514 49.541,11.52 70.589,11.514 87.65,28.742 87.673,49.978 87.65,71.251 70.589,88.483 49.541,88.483 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#464646;fill-opacity:1" /><path
|
||||
id="path4304"
|
||||
d="m 45.37,64.349 9.073,-0.041 v -7.015 c -0.023,-1.901 0.863,-3.704 3.242,-5.261 2.38,-1.563 9.016,-4.725 9.025,-13.061 C 66.7,30.67 59.73,24.955 53.868,23.72 48.014,22.529 41.665,23.324 37.169,28.281 c -4.042,4.396 -4.892,7.892 -4.905,15.603 h 9.07 v -1.799 c -0.014,-4.103 0.458,-8.438 6.312,-9.64 3.222,-0.631 6.226,0.375 8.018,2.103 2.024,2.007 2.042,6.496 -1.222,8.722 l -5.09,3.465 c -2.959,1.919 -3.977,4.038 -3.983,7.142 v 10.472 l 10e-4,0 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#464646;fill-opacity:1" /><polygon
|
||||
id="polygon4306"
|
||||
points="45.325,67.903 54.484,67.903 54.484,77.194 45.325,77.194 "
|
||||
style="fill:#464646;fill-opacity:1" /></g><g
|
||||
transform="matrix(0.84510875,0,0,0.84510875,246.47145,2.7863074)"
|
||||
id="g4319"
|
||||
style="opacity:0.4"><path
|
||||
style="fill:#464646;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="m 19.02918,27.70898 0,-1.42397 1.52567,0 1.52569,0 0,-4.78047 0,-4.78046 -1.6274,0 -1.62738,0 0,1.52568 0,1.52568 -1.52567,0 -1.52569,0 0,-3.05136 0,-3.05135 7.83182,0 7.83182,0 0,3.05135 0,3.05136 -1.52569,0 -1.52567,0 0,-1.52568 0,-1.52568 -1.62739,0 -1.62739,0 0,4.78046 0,4.78047 1.52568,0 1.52567,0 0,1.42397 0,1.42396 -4.57703,0 -4.57704,0 0,-1.42396 z"
|
||||
id="path4321"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#464646;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="m 19.64356,39.48975 0,-5.51027 1.35498,0 1.35497,0 0,4.15529 0,4.15527 12.64649,0 12.6465,0 0,-9.8462 0,-9.84619 -5.60059,0 -5.60059,0 0,-1.26465 0,-1.26465 6.95558,0 6.95556,0 0,12.46582 0,12.46583 L 35,45 l -15.35644,0 0,-5.51025 z"
|
||||
id="path4323"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
style="opacity:0.4;fill:#464646;fill-opacity:1"
|
||||
transform="matrix(0.24999998,0,0,0.24999998,445.38927,15.676751)"
|
||||
id="g4325"><path
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="M 49.541,0 C 22.198,-0.019 0.027,22.376 0,49.978 0.027,77.621 22.198,100.01 49.541,100 76.894,100.011 99.064,77.621 99.085,49.979 99.064,22.376 76.894,-0.019 49.541,0 z m 0,88.483 C 28.503,88.483 11.445,71.252 11.462,49.971 11.441,28.742 28.503,11.514 49.541,11.52 70.589,11.514 87.65,28.742 87.673,49.978 87.65,71.251 70.589,88.483 49.541,88.483 z"
|
||||
id="path4327" /><path
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 45.37,64.349 9.073,-0.041 v -7.015 c -0.023,-1.901 0.863,-3.704 3.242,-5.261 2.38,-1.563 9.016,-4.725 9.025,-13.061 C 66.7,30.67 59.73,24.955 53.868,23.72 48.014,22.529 41.665,23.324 37.169,28.281 c -4.042,4.396 -4.892,7.892 -4.905,15.603 h 9.07 v -1.799 c -0.014,-4.103 0.458,-8.438 6.312,-9.64 3.222,-0.631 6.226,0.375 8.018,2.103 2.024,2.007 2.042,6.496 -1.222,8.722 l -5.09,3.465 c -2.959,1.919 -3.977,4.038 -3.983,7.142 v 10.472 l 10e-4,0 z"
|
||||
id="path4329" /><polygon
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
points="45.325,67.903 54.484,67.903 54.484,77.194 45.325,77.194 "
|
||||
id="polygon4331" /></g><g
|
||||
style="opacity:0.4;fill:#464646;fill-opacity:1"
|
||||
transform="matrix(0.25404736,0,0,0.25404736,384.37987,15.991112)"
|
||||
id="g4333"><g
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
id="g4335">
|
||||
<path
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 28.793,71.207 c -5.062,-5.065 -7.6,-11.705 -7.62,-18.356 l -6.515,-0.002 c 0.021,8.32 3.193,16.635 9.526,22.967 6.335,6.331 14.647,9.504 22.967,9.526 L 47.15,78.827 C 40.5,78.806 33.856,76.268 28.793,71.207 z"
|
||||
id="path4337" />
|
||||
<path
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="M 18.423,81.575 C 10.501,73.654 6.535,63.251 6.514,52.85 L 0,52.846 c 0.02,12.074 4.623,24.145 13.815,33.34 9.193,9.188 21.261,13.796 33.337,13.812 V 93.483 C 36.745,93.467 26.346,89.495 18.423,81.575 z"
|
||||
id="path4339" />
|
||||
</g><path
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="M 76.157,43.675 73.294,43.334 C 77.075,38.692 76.803,31.847 72.475,27.523 68.154,23.196 61.309,22.924 56.664,26.705 L 56.325,23.843 32.482,0 11.531,20.949 l 23.842,23.843 2.864,0.341 c -3.779,4.643 -3.506,11.485 0.819,15.811 4.325,4.325 11.167,4.596 15.81,0.819 L 55.205,64.625 79.05,88.466 100,67.519 76.157,43.675 z M 38.384,38.586 20.749,20.949 32.482,9.218 l 17.637,17.636 0.669,5.64 -6.762,6.761 -5.642,-0.669 z M 79.05,79.249 61.412,61.613 l -0.668,-5.64 6.761,-6.761 5.642,0.668 17.633,17.639 -11.73,11.73 z"
|
||||
id="path4341" /></g><rect
|
||||
style="opacity:0.8;fill:#464646;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="rect3039"
|
||||
width="250.00003"
|
||||
height="60"
|
||||
x="490"
|
||||
y="-1.7162162e-06" /><g
|
||||
transform="matrix(0.84510875,0,0,0.84510875,492.46665,4.1596899)"
|
||||
id="g3041"
|
||||
style="fill:#ffffff"><path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="m 19.02918,27.70898 0,-1.42397 1.52567,0 1.52569,0 0,-4.78047 0,-4.78046 -1.6274,0 -1.62738,0 0,1.52568 0,1.52568 -1.52567,0 -1.52569,0 0,-3.05136 0,-3.05135 7.83182,0 7.83182,0 0,3.05135 0,3.05136 -1.52569,0 -1.52567,0 0,-1.52568 0,-1.52568 -1.62739,0 -1.62739,0 0,4.78046 0,4.78047 1.52568,0 1.52567,0 0,1.42397 0,1.42396 -4.57703,0 -4.57704,0 0,-1.42396 z"
|
||||
id="path3043"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="m 19.64356,39.48975 0,-5.51027 1.35498,0 1.35497,0 0,4.15529 0,4.15527 12.64649,0 12.6465,0 0,-9.8462 0,-9.84619 -5.60059,0 -5.60059,0 0,-1.26465 0,-1.26465 6.95558,0 6.95556,0 0,12.46582 0,12.46583 L 35,45 l -15.35644,0 0,-5.51025 z"
|
||||
id="path3045"
|
||||
inkscape:connector-curvature="0" /></g><g
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
transform="matrix(0.27873303,0,0,0.27873303,618.96272,15.125216)"
|
||||
id="g3047">
|
||||
<g
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
id="g3049">
|
||||
<rect
|
||||
id="rect3051"
|
||||
height="20.318001"
|
||||
width="20.32"
|
||||
clip-rule="evenodd"
|
||||
y="10.951"
|
||||
x="-114.388"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd" />
|
||||
<rect
|
||||
id="rect3053"
|
||||
height="20.318001"
|
||||
width="20.32"
|
||||
clip-rule="evenodd"
|
||||
y="36.349998"
|
||||
x="-114.388"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd" />
|
||||
<rect
|
||||
id="rect3055"
|
||||
height="20.319"
|
||||
width="20.32"
|
||||
clip-rule="evenodd"
|
||||
y="61.748001"
|
||||
x="-114.388"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd" />
|
||||
<rect
|
||||
id="rect3057"
|
||||
height="20.318001"
|
||||
width="20.318001"
|
||||
clip-rule="evenodd"
|
||||
y="10.951"
|
||||
x="-139.785"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd" />
|
||||
<rect
|
||||
id="rect3059"
|
||||
height="20.318001"
|
||||
width="20.318001"
|
||||
clip-rule="evenodd"
|
||||
y="36.349998"
|
||||
x="-139.785"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd" />
|
||||
<rect
|
||||
id="rect3061"
|
||||
height="20.319"
|
||||
width="20.318001"
|
||||
clip-rule="evenodd"
|
||||
y="61.748001"
|
||||
x="-139.785"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd" />
|
||||
<rect
|
||||
id="rect3063"
|
||||
height="20.318001"
|
||||
width="20.32"
|
||||
clip-rule="evenodd"
|
||||
y="10.951"
|
||||
x="-165.187"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd" />
|
||||
<rect
|
||||
id="rect3065"
|
||||
height="20.318001"
|
||||
width="20.32"
|
||||
clip-rule="evenodd"
|
||||
y="36.349998"
|
||||
x="-165.187"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd" />
|
||||
<rect
|
||||
id="rect3067"
|
||||
height="20.319"
|
||||
width="20.32"
|
||||
clip-rule="evenodd"
|
||||
y="61.748001"
|
||||
x="-165.187"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd" />
|
||||
</g>
|
||||
<path
|
||||
id="path3069"
|
||||
d="m -175.144,0.991 v 90.855 h 91.032 V 0.991 h -91.032 z m 84.395,84.217 h -77.757 V 7.63 h 77.757 v 77.578 z"
|
||||
clip-rule="evenodd"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd" />
|
||||
</g><g
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
transform="matrix(0.25404736,0,0,0.25404736,630.09747,15.002146)"
|
||||
id="g3071"><g
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
id="g3073">
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 28.793,71.207 c -5.062,-5.065 -7.6,-11.705 -7.62,-18.356 l -6.515,-0.002 c 0.021,8.32 3.193,16.635 9.526,22.967 6.335,6.331 14.647,9.504 22.967,9.526 L 47.15,78.827 C 40.5,78.806 33.856,76.268 28.793,71.207 z"
|
||||
id="path3075" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="M 18.423,81.575 C 10.501,73.654 6.535,63.251 6.514,52.85 L 0,52.846 c 0.02,12.074 4.623,24.145 13.815,33.34 9.193,9.188 21.261,13.796 33.337,13.812 V 93.483 C 36.745,93.467 26.346,89.495 18.423,81.575 z"
|
||||
id="path3077" />
|
||||
</g><path
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="M 76.157,43.675 73.294,43.334 C 77.075,38.692 76.803,31.847 72.475,27.523 68.154,23.196 61.309,22.924 56.664,26.705 L 56.325,23.843 32.482,0 11.531,20.949 l 23.842,23.843 2.864,0.341 c -3.779,4.643 -3.506,11.485 0.819,15.811 4.325,4.325 11.167,4.596 15.81,0.819 L 55.205,64.625 79.05,88.466 100,67.519 76.157,43.675 z M 38.384,38.586 20.749,20.949 32.482,9.218 l 17.637,17.636 0.669,5.64 -6.762,6.761 -5.642,-0.669 z M 79.05,79.249 61.412,61.613 l -0.668,-5.64 6.761,-6.761 5.642,0.668 17.633,17.639 -11.73,11.73 z"
|
||||
id="path3079" /></g><g
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
transform="matrix(0.24999998,0,0,0.24999998,690.32253,15.514412)"
|
||||
id="g3081"><path
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="M 49.541,0 C 22.198,-0.019 0.027,22.376 0,49.978 0.027,77.621 22.198,100.01 49.541,100 76.894,100.011 99.064,77.621 99.085,49.979 99.064,22.376 76.894,-0.019 49.541,0 z m 0,88.483 C 28.503,88.483 11.445,71.252 11.462,49.971 11.441,28.742 28.503,11.514 49.541,11.52 70.589,11.514 87.65,28.742 87.673,49.978 87.65,71.251 70.589,88.483 49.541,88.483 z"
|
||||
id="path3083" /><path
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 45.37,64.349 9.073,-0.041 v -7.015 c -0.023,-1.901 0.863,-3.704 3.242,-5.261 2.38,-1.563 9.016,-4.725 9.025,-13.061 C 66.7,30.67 59.73,24.955 53.868,23.72 48.014,22.529 41.665,23.324 37.169,28.281 c -4.042,4.396 -4.892,7.892 -4.905,15.603 h 9.07 v -1.799 c -0.014,-4.103 0.458,-8.438 6.312,-9.64 3.222,-0.631 6.226,0.375 8.018,2.103 2.024,2.007 2.042,6.496 -1.222,8.722 l -5.09,3.465 c -2.959,1.919 -3.977,4.038 -3.983,7.142 v 10.472 l 10e-4,0 z"
|
||||
id="path3085" /><polygon
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
points="45.325,77.194 45.325,67.903 54.484,67.903 54.484,77.194 "
|
||||
id="polygon3087" /></g></svg>
|
||||
|
After Width: | Height: | Size: 21 KiB |
BIN
gui-src/css/maps/images/icons-404040.png
Normal file
|
After Width: | Height: | Size: 849 B |
BIN
gui-src/css/maps/images/icons-404040@2x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
gui-src/css/maps/images/icons-ffffff.png
Normal file
|
After Width: | Height: | Size: 847 B |
BIN
gui-src/css/maps/images/icons-ffffff@2x.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
35
gui-src/css/maps/images/icons.svg
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="26" height="260" viewBox="0 0 26 260" >
|
||||
<g id="sprite" fill="#000000">
|
||||
<path
|
||||
id="zoomIn"
|
||||
d="m 12.5,8.99999 c -0.277,0 -0.5,0.223 -0.5,0.5 l 0,2.50002 -2.5,0 c -0.277,0 -0.5,0.223 -0.5,0.5 l 0,1 c 0,0.277 0.223,0.5 0.5,0.5 l 2.5,0 0,2.5 c 0,0.277 0.223,0.5 0.5,0.5 l 1,0 c 0.277,0 0.5,-0.223 0.5,-0.5 l 0,-2.5 2.5,0 c 0.277,0 0.5,-0.223 0.5,-0.5 l 0,-1 c 0,-0.277 -0.223,-0.5 -0.5,-0.5 l -2.5,0 0,-2.50002 c 0,-0.277 -0.223,-0.5 -0.5,-0.5 z" />
|
||||
<path
|
||||
id="zoomOut"
|
||||
d="M 9.5,38 C 9.223,38 9,38.223 9,38.5 l 0,1 C 9,39.777 9.223,40 9.5,40 l 7,0 c 0.277,0 0.5,-0.223 0.5,-0.5 l 0,-1 C 17,38.223 16.777,38 16.5,38 Z" />
|
||||
<path
|
||||
id="close"
|
||||
d="m 10,61 -1,1 3,3 -3,3 1,1 3,-3 3,3 1,-1 -3,-3 3,-3 -1,-1 -3,3 z" />
|
||||
<path
|
||||
id="info"
|
||||
d="m 13,83.99999 c -3.866,0 -7,3.134 -7,7.00002 0,3.866 3.134,7 7,7 3.8659,0 7,-3.134 7,-7 0,-3.86602 -3.1341,-7.00002 -7,-7.00002 z m -0.5,3 1,0 c 0.277,0 0.5,0.223 0.5,0.5 l 0,1 c 0,0.27702 -0.223,0.50002 -0.5,0.50002 l -1,0 c -0.277,0 -0.5,-0.223 -0.5,-0.50002 l 0,-1 c 0,-0.277 0.223,-0.5 0.5,-0.5 z m 0,3.00002 1,0 c 0.277,0 0.5,0.223 0.5,0.5 l 0,4 c 0,0.277 -0.223,0.5 -0.5,0.5 l -1,0 c -0.277,0 -0.5,-0.223 -0.5,-0.5 l 0,-4 c 0,-0.277 0.223,-0.5 0.5,-0.5 z" />
|
||||
<path
|
||||
id="layers"
|
||||
d="m 13,110.96875 c -0.1012,-5e-4 -0.19265,0.0145 -0.28125,0.0625 L 6,113 l 0,1 6.71875,1.9375 C 12.80675,115.9855 12.8995,116 13,116 c 0.1001,0 0.19325,-0.0145 0.28125,-0.0625 L 20,114 l 0,-1 -6.71875,-1.96875 c -0.088,-0.048 -0.18155,-0.0625 -0.28125,-0.0625 z M 6,118 l 6.71875,1.9375 C 12.80675,119.9855 12.8995,120 13,120 c 0.1001,0 0.19325,-0.0145 0.28125,-0.0625 L 20,118 l 0,-2 -6.71875,1.9375 C 13.19325,117.9855 13.1001,118 13,118 c -0.1005,0 -0.19325,-0.0145 -0.28125,-0.0625 L 6,116 Z m 0,4 6.71875,1.9375 C 12.80675,123.9855 12.8995,124 13,124 c 0.1001,0 0.19325,-0.0145 0.28125,-0.0625 L 20,122 l 0,-2 -6.71875,1.9375 C 13.19325,121.9855 13.1001,122 13,122 c -0.1005,0 -0.19325,-0.0145 -0.28125,-0.0625 L 6,120 Z" />
|
||||
<path
|
||||
id="share"
|
||||
d="m 14.3438,136.99999 2.125,2.125 -4.25,4.25002 1.4062,1.4062 4.25,-4.25002 2.125,2.12502 0,-5.65622 z m -6.3438,1 -1,1 0,9.00002 1,1 10,0 1,-1 0,-4 -1,-1 -1,1 0,3 -8,0 0,-7.00002 4,0 1,-1 -1,-1 z" />
|
||||
<path
|
||||
id="search"
|
||||
d="m 11.5,162.99999 c -2.4853,0 -4.5,2.0147 -4.5,4.50002 0,2.4853 2.0147,4.5 4.5,4.5 0.854,0 1.6635,-0.2431 2.3437,-0.6563 l 3.6563,3.6563 1.5,-1.5 -3.6563,-3.6563 c 0.4132,-0.6802 0.6563,-1.4897 0.6563,-2.3437 0,-2.48532 -2.0147,-4.50002 -4.5,-4.50002 z m 0,1.5 c 1.6568,0 3,1.3431 3,3.00002 0,1.6568 -1.3432,3 -3,3 -1.6569,0 -3,-1.3432 -3,-3 0,-1.65692 1.3431,-3.00002 3,-3.00002 z" />
|
||||
<path
|
||||
id="facebook"
|
||||
d="m 7,186.99998 -1,1 0,12 1,1 6.81812,1e-5 0,-5.00001 -1.8245,0 0,-2 1.8245,0 0,-2.09264 c 0,-1.80824 1.10439,-2.79288 2.7175,-2.79288 0.77272,0 1.09654,0.0575 1.29005,0.0832 l 0,1.80232 -0.77851,5.2e-4 C 16.1699,191.0005 16,191.41736 16,192.0291 l 0,1.97088 2.09228,0 -0.2724,2 -1.81988,0 0,5.00001 3,-1e-5 1,-1 0,-12 -1,-1 z" />
|
||||
<path
|
||||
id="twitter"
|
||||
d="m 19.99957,216.12602 c -0.51509,0.22492 -1.06868,0.37693 -1.64967,0.44524 0.59299,-0.34993 1.04838,-0.90408 1.26288,-1.56444 -0.55499,0.32413 -1.16968,0.55945 -1.82397,0.68616 C 17.26502,215.14343 16.51853,214.8 15.69245,214.8 c -1.58627,0 -2.87235,1.26611 -2.87235,2.82775 0,0.22164 0.025,0.43756 0.075,0.64448 -2.38705,-0.11791 -4.50341,-1.24373 -5.91999,-2.95458 -0.24719,0.41763 -0.38889,0.90338 -0.38889,1.42162 0,0.98111 0.50699,1.84658 1.27768,2.35373 -0.4708,-0.015 -0.91369,-0.14191 -1.30088,-0.35363 -3e-4,0.012 -3e-4,0.024 -3e-4,0.035 0,1.37002 0.99008,2.51291 2.30396,2.77274 -0.241,0.065 -0.49469,0.099 -0.75669,0.099 -0.1851,0 -0.36499,-0.018 -0.54029,-0.051 0.36539,1.1234 1.42607,1.94097 2.68295,1.96377 -0.98298,0.75847 -2.22136,1.21061 -3.56713,1.21061 -0.2318,0 -0.46039,-0.013 -0.68509,-0.04 C 7.27151,225.53176 8.78128,226 10.40325,226 c 5.2831,0 8.17205,-4.30888 8.17205,-8.0457 0,-0.12261 0,-0.24462 -0.01,-0.36585 0.56129,-0.39874 1.04818,-0.89668 1.43327,-1.46383" />
|
||||
<path
|
||||
id="pinterest"
|
||||
d="M 13.50024,238.9996 C 9.35822,238.9996 6,242.35751 6,246.49969 c 0,3.07113 1.84674,5.70949 4.48939,6.86948 -0.0211,-0.5237 -0.004,-1.15239 0.13052,-1.7222 0.14421,-0.60892 0.96507,-4.08682 0.96507,-4.08682 0,0 -0.23961,-0.47889 -0.23961,-1.18669 0,-1.11141 0.64421,-1.94155 1.44648,-1.94155 0.68215,0 1.01169,0.51241 1.01169,1.12601 0,0.68581 -0.43735,1.71156 -0.66231,2.66165 -0.18789,0.79559 0.39892,1.44451 1.1838,1.44451 1.42105,0 2.37808,-1.82512 2.37808,-3.98753 0,-1.64383 -1.10715,-2.87415 -3.12081,-2.87415 -2.27506,0 -3.69243,1.69664 -3.69243,3.59178 0,0.6534 0.19268,1.11426 0.49445,1.47102 0.13874,0.1639 0.15803,0.22983 0.10778,0.418 -0.0359,0.13804 -0.11858,0.47026 -0.15277,0.60191 -0.05,0.18998 -0.20384,0.25786 -0.37553,0.18774 -1.04789,-0.4278 -1.53596,-1.5754 -1.53596,-2.86536 0,-2.13055 1.79685,-4.68521 5.36034,-4.68521 2.86349,0 4.74808,2.0721 4.74808,4.29635 0,2.94222 -1.63569,5.14028 -4.04684,5.14028 -0.8097,0 -1.57134,-0.43774 -1.83228,-0.9349 0,0 -0.43543,1.72808 -0.52766,2.06171 -0.15897,0.57829 -0.47026,1.1562 -0.75486,1.60673 0.67461,0.19909 1.3871,0.30755 2.12562,0.30755 4.1417,0 7.49977,-3.35795 7.49977,-7.50031 0,-4.14218 -3.35807,-7.50009 -7.49977,-7.50009" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.3 KiB |
BIN
gui-src/css/maps/images/spritesheet - Kopie.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
gui-src/css/maps/images/spritesheet-2x.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
gui-src/css/maps/images/spritesheet.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
297
gui-src/css/maps/images/spritesheet.svg
Normal file
@@ -0,0 +1,297 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="1080"
|
||||
height="60"
|
||||
viewBox="0 0 1080 59.999999"
|
||||
enable-background="new 0 0 100 100"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="spritesheet_new.svg"
|
||||
inkscape:export-filename="/Users/aaronr/github/bboxfinder.com/css/maps/images/spritesheet_new.png"
|
||||
inkscape:export-xdpi="45"
|
||||
inkscape:export-ydpi="45"><metadata
|
||||
id="metadata51"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs49"><inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 50 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="100 : 50 : 1"
|
||||
inkscape:persp3d-origin="50 : 33.333333 : 1"
|
||||
id="perspective5373" /></defs><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1226"
|
||||
inkscape:window-height="844"
|
||||
id="namedview47"
|
||||
showgrid="true"
|
||||
inkscape:zoom="0.83039936"
|
||||
inkscape:cx="502.47411"
|
||||
inkscape:cy="27.069218"
|
||||
inkscape:window-x="197"
|
||||
inkscape:window-y="15"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="Layer_1"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
borderlayer="false"><inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid6480"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" /></sodipodi:namedview>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6172"
|
||||
d=""
|
||||
style="fill:#bbbbbb;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6178"
|
||||
d=""
|
||||
style="fill:#bbbbbb;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6184"
|
||||
d=""
|
||||
style="fill:#bbbbbb;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6186"
|
||||
d=""
|
||||
style="fill:#bbbbbb;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6270"
|
||||
d=""
|
||||
style="fill:#bbbbbb;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6288"
|
||||
d=""
|
||||
style="fill:#bbbbbb;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6682"
|
||||
d=""
|
||||
style="fill:#bbbbbb;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path6684"
|
||||
d=""
|
||||
style="fill:#bbbbbb;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none" /><g
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
id="g3558"
|
||||
transform="translate(-1.07,-5e-7)">
|
||||
<path
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 18,36 v 6 h 6 v -6 h -6 z m 4,4 h -2 v -2 h 2 v 2 z"
|
||||
id="path3560" />
|
||||
<path
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 36,18 v 6 h 6 v -6 h -6 z m 4,4 h -2 v -2 h 2 v 2 z"
|
||||
id="path3562" />
|
||||
<polygon
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
points="20.857,36.854 36.857,20.857 39.142,23.142 23.142,39.145 "
|
||||
id="polygon3564" />
|
||||
</g><polygon
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
points="100,24.565 97.904,39.396 83.07,42 76,28.773 86.463,18 "
|
||||
id="polygon3566"
|
||||
transform="translate(-1.07,-5e-7)" /><rect
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
x="138.92999"
|
||||
y="20"
|
||||
width="20"
|
||||
height="20"
|
||||
id="rect3568" /><path
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 219.93,30 c 0,6.078 -4.926,11 -11,11 -6.074,0 -11,-4.922 -11,-11 0,-6.074 4.926,-11 11,-11 6.074,0 11,4.926 11,11 z"
|
||||
id="path3570" /><path
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 268.93,19 c -4.971,0 -9,4.028999 -9,9 0,4.971 5.001,12 9,14 4.001,-2 9,-9.029 9,-14 0,-4.971001 -4.029,-9 -9,-9 z m 0,12.5 c -2.484,0 -4.5,-2.014 -4.5,-4.5 0,-2.484001 2.016,-4.5 4.5,-4.5 2.485,0 4.5,2.015999 4.5,4.5 0,2.486 -2.015,4.5 -4.5,4.5 z"
|
||||
id="path3572" /><g
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
id="g3574"
|
||||
transform="translate(-1.07,-5e-7)">
|
||||
<path
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 337,30.156 v 0.407 5.604 c 0,1.658 -1.344,3 -3,3 h -10 c -1.655,0 -3,-1.342 -3,-3 v -10 c 0,-1.657 1.345,-3 3,-3 h 6.345 l 3.19,-3.17 H 324 c -3.313,0 -6,2.687 -6,6 v 10 c 0,3.313 2.687,6 6,6 h 10 c 3.314,0 6,-2.687 6,-6 v -8.809 l -3,2.968"
|
||||
id="path3576" />
|
||||
<polygon
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
points="335.891,21.809 338.719,24.637 329.828,33.529 327,33.529 327,30.699 "
|
||||
id="polygon3578" />
|
||||
|
||||
<rect
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
x="338.69699"
|
||||
y="17.826"
|
||||
transform="matrix(-0.707,-0.7072,0.7072,-0.707,567.5655,274.7729)"
|
||||
width="4"
|
||||
height="4"
|
||||
id="rect3580" />
|
||||
</g><g
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
id="g3582"
|
||||
transform="translate(-1.07,-5e-7)">
|
||||
<path
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 381,42 h 18 V 24 h -18 v 18 z m 14,-16 h 2 v 14 h -2 V 26 z m -4,0 h 2 v 14 h -2 V 26 z m -4,0 h 2 v 14 h -2 V 26 z m -4,0 h 2 v 14 h -2 V 26 z"
|
||||
id="path3584" />
|
||||
<path
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 395,20 v -2 -2 h -10 v 2 2 h -6 v 2 h 22 v -2 h -6 z m -2,0 h -6 v -2 h 6 v 2 z"
|
||||
id="path3586" />
|
||||
</g><g
|
||||
style="opacity:0.4;fill:#464646;fill-opacity:1"
|
||||
id="g3588"
|
||||
transform="translate(-1.07,-5e-7)">
|
||||
<path
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 458,30.156 v 0.407 5.604 c 0,1.658 -1.344,3 -3,3 h -10 c -1.655,0 -3,-1.342 -3,-3 v -10 c 0,-1.657 1.345,-3 3,-3 h 6.345 l 3.19,-3.17 H 445 c -3.313,0 -6,2.687 -6,6 v 10 c 0,3.313 2.687,6 6,6 h 10 c 3.314,0 6,-2.687 6,-6 v -8.809 l -3,2.968"
|
||||
id="path3590" />
|
||||
<polygon
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
points="456.891,21.809 459.719,24.637 450.828,33.529 448,33.529 448,30.699 "
|
||||
id="polygon3592" />
|
||||
|
||||
<rect
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
x="459.69699"
|
||||
y="17.826"
|
||||
transform="matrix(-0.707,-0.7072,0.7072,-0.707,774.118,360.3402)"
|
||||
width="4"
|
||||
height="4"
|
||||
id="rect3594" />
|
||||
</g><g
|
||||
style="opacity:0.4;fill:#464646;fill-opacity:1"
|
||||
id="g3596"
|
||||
transform="translate(-1.07,-5e-7)">
|
||||
<path
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 501,42 h 18 V 24 h -18 v 18 z m 14,-16 h 2 v 14 h -2 V 26 z m -4,0 h 2 v 14 h -2 V 26 z m -4,0 h 2 v 14 h -2 V 26 z m -4,0 h 2 v 14 h -2 V 26 z"
|
||||
id="path3598" />
|
||||
<path
|
||||
style="fill:#464646;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 515,20 v -2 -2 h -10 v 2 2 h -6 v 2 h 22 v -2 h -6 z m -2,0 h -6 v -2 h 6 v 2 z"
|
||||
id="path3600" />
|
||||
</g><rect
|
||||
style="opacity:0.4;fill:#464646;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="rect3684"
|
||||
width="540"
|
||||
height="60"
|
||||
x="542"
|
||||
y="1.9999995" /><path
|
||||
style="opacity:0.8;fill:#464646;fill-opacity:1;stroke-width:20;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="m 542.50845,29.920029 0,-29.0322577 268.74579,0 268.74576,0 0,29.0322577 0,29.032258 -268.74576,0 -268.74579,0 0,-29.032258 z"
|
||||
id="path3686"
|
||||
inkscape:connector-curvature="0" /><g
|
||||
transform="translate(540,-1.0000005)"
|
||||
id="g3654"
|
||||
style="fill:#ffffff;fill-opacity:1">
|
||||
<path
|
||||
id="path3656"
|
||||
d="m 18,36 v 6 h 6 v -6 h -6 z m 4,4 h -2 v -2 h 2 v 2 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<path
|
||||
id="path3658"
|
||||
d="m 36,18 v 6 h 6 v -6 h -6 z m 4,4 h -2 v -2 h 2 v 2 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<polygon
|
||||
id="polygon3660"
|
||||
points="36.857,20.857 39.142,23.142 23.142,39.145 20.857,36.854 "
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
</g><polygon
|
||||
transform="translate(540,-1.0000005)"
|
||||
id="polygon3662"
|
||||
points="100,24.565 97.904,39.396 83.07,42 76,28.773 86.463,18 "
|
||||
style="fill:#ffffff;fill-opacity:1" /><rect
|
||||
id="rect3664"
|
||||
height="20"
|
||||
width="20"
|
||||
y="19"
|
||||
x="680"
|
||||
style="fill:#ffffff;fill-opacity:1" /><path
|
||||
id="path3666"
|
||||
d="m 761,29 c 0,6.078001 -4.926,11 -11,11 -6.074,0 -11,-4.921999 -11,-11 0,-6.073999 4.926,-10.999999 11,-10.999999 6.074,0 11,4.926 11,10.999999 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff;fill-opacity:1" /><path
|
||||
id="path3668"
|
||||
d="m 810,18.000001 c -4.971,0 -9,4.028999 -9,8.999999 0,4.971001 5.001,12 9,14 4.001,-2 9,-9.028999 9,-14 0,-4.971 -4.029,-8.999999 -9,-8.999999 z M 810,30.5 c -2.484,0 -4.5,-2.013999 -4.5,-4.5 0,-2.483999 2.016,-4.5 4.5,-4.5 2.485,0 4.5,2.016001 4.5,4.5 0,2.486001 -2.015,4.5 -4.5,4.5 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff;fill-opacity:1" /><g
|
||||
transform="translate(540,-1.0000005)"
|
||||
id="g3670"
|
||||
style="fill:#ffffff;fill-opacity:1">
|
||||
<path
|
||||
id="path3672"
|
||||
d="m 337,30.156 v 0.407 5.604 c 0,1.658 -1.344,3 -3,3 h -10 c -1.655,0 -3,-1.342 -3,-3 v -10 c 0,-1.657 1.345,-3 3,-3 h 6.345 l 3.19,-3.17 H 324 c -3.313,0 -6,2.687 -6,6 v 10 c 0,3.313 2.687,6 6,6 h 10 c 3.314,0 6,-2.687 6,-6 v -8.809 l -3,2.968"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<polygon
|
||||
id="polygon3674"
|
||||
points="335.891,21.809 338.719,24.637 329.828,33.529 327,33.529 327,30.699 "
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
|
||||
<rect
|
||||
id="rect3676"
|
||||
height="4"
|
||||
width="4"
|
||||
transform="matrix(-0.707,-0.7072,0.7072,-0.707,567.5655,274.7729)"
|
||||
y="17.826"
|
||||
x="338.69699"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
</g><g
|
||||
transform="translate(540,-1.0000005)"
|
||||
id="g3678"
|
||||
style="fill:#ffffff;fill-opacity:1">
|
||||
<path
|
||||
id="path3680"
|
||||
d="m 381,42 h 18 V 24 h -18 v 18 z m 14,-16 h 2 v 14 h -2 V 26 z m -4,0 h 2 v 14 h -2 V 26 z m -4,0 h 2 v 14 h -2 V 26 z m -4,0 h 2 v 14 h -2 V 26 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<path
|
||||
id="path3682"
|
||||
d="m 395,20 v -2 -2 h -10 v 2 2 h -6 v 2 h 22 v -2 h -6 z m -2,0 h -6 v -2 h 6 v 2 z"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
</g></svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
478
gui-src/css/maps/leaflet.css
Normal file
@@ -0,0 +1,478 @@
|
||||
/* required styles */
|
||||
|
||||
.leaflet-map-pane,
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-tile-pane,
|
||||
.leaflet-tile-container,
|
||||
.leaflet-overlay-pane,
|
||||
.leaflet-shadow-pane,
|
||||
.leaflet-marker-pane,
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-overlay-pane svg,
|
||||
.leaflet-zoom-box,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-layer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-container {
|
||||
overflow: hidden;
|
||||
-ms-touch-action: none;
|
||||
}
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
display: block;
|
||||
}
|
||||
/* map is broken in FF if you have max-width: 100% on tiles */
|
||||
.leaflet-container img {
|
||||
max-width: none !important;
|
||||
}
|
||||
/* stupid Android 2 doesn't understand "max-width: none" properly */
|
||||
.leaflet-container img.leaflet-image-layer {
|
||||
max-width: 15000px !important;
|
||||
}
|
||||
.leaflet-tile {
|
||||
filter: inherit;
|
||||
visibility: hidden;
|
||||
}
|
||||
.leaflet-tile-loaded {
|
||||
visibility: inherit;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
|
||||
.leaflet-overlay-pane svg {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.leaflet-tile-pane { z-index: 2; }
|
||||
.leaflet-objects-pane { z-index: 3; }
|
||||
.leaflet-overlay-pane { z-index: 4; }
|
||||
.leaflet-shadow-pane { z-index: 5; }
|
||||
.leaflet-marker-pane { z-index: 6; }
|
||||
.leaflet-popup-pane { z-index: 7; }
|
||||
|
||||
.leaflet-vml-shape {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
.lvml {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
/* control positioning */
|
||||
|
||||
.leaflet-control {
|
||||
position: relative;
|
||||
z-index: 7;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-top,
|
||||
.leaflet-bottom {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-top {
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-right {
|
||||
right: 0;
|
||||
}
|
||||
.leaflet-bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
.leaflet-left {
|
||||
left: 0;
|
||||
}
|
||||
.leaflet-control {
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
float: right;
|
||||
}
|
||||
.leaflet-top .leaflet-control {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.leaflet-left .leaflet-control {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
|
||||
/* zoom and fade animations */
|
||||
|
||||
.leaflet-fade-anim .leaflet-tile,
|
||||
.leaflet-fade-anim .leaflet-popup {
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
-moz-transition: opacity 0.2s linear;
|
||||
-o-transition: opacity 0.2s linear;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-tile-loaded,
|
||||
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-tile,
|
||||
.leaflet-pan-anim .leaflet-tile,
|
||||
.leaflet-touching .leaflet-zoom-animated {
|
||||
-webkit-transition: none;
|
||||
-moz-transition: none;
|
||||
-o-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-hide {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* cursors */
|
||||
|
||||
.leaflet-clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.leaflet-container {
|
||||
cursor: -webkit-grab;
|
||||
cursor: -moz-grab;
|
||||
}
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-control {
|
||||
cursor: auto;
|
||||
}
|
||||
.leaflet-dragging .leaflet-container,
|
||||
.leaflet-dragging .leaflet-clickable {
|
||||
cursor: move;
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
}
|
||||
|
||||
|
||||
/* visual tweaks */
|
||||
|
||||
.leaflet-container {
|
||||
background: #ddd;
|
||||
outline: 0;
|
||||
}
|
||||
.leaflet-container a {
|
||||
color: #0078A8;
|
||||
}
|
||||
.leaflet-container a.leaflet-active {
|
||||
outline: 2px solid orange;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
border: 2px dotted #38f;
|
||||
background: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
|
||||
/* general typography */
|
||||
.leaflet-container {
|
||||
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
|
||||
/* general toolbar styles */
|
||||
|
||||
.leaflet-bar {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-bar a:hover {
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ccc;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-control-layers-toggle {
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
}
|
||||
.leaflet-bar a:hover {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.leaflet-bar a:first-child {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-bottom: none;
|
||||
}
|
||||
.leaflet-bar a.leaflet-disabled {
|
||||
cursor: default;
|
||||
background-color: #f4f4f4;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-bar a {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
|
||||
/* zoom control */
|
||||
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out {
|
||||
font: bold 18px 'Lucida Console', Monaco, monospace;
|
||||
text-indent: 1px;
|
||||
}
|
||||
.leaflet-control-zoom-out {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-zoom-in {
|
||||
font-size: 22px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-zoom-out {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
|
||||
/* layers control */
|
||||
|
||||
.leaflet-control-layers {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers.png);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
.leaflet-retina .leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers-2x.png);
|
||||
background-size: 26px 26px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers-toggle {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
.leaflet-control-layers .leaflet-control-layers-list,
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
|
||||
display: none;
|
||||
}
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-list {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
.leaflet-control-layers-expanded {
|
||||
padding: 6px 10px 6px 6px;
|
||||
color: #333;
|
||||
background: #fff;
|
||||
}
|
||||
.leaflet-control-layers-selector {
|
||||
margin-top: 2px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
.leaflet-control-layers label {
|
||||
display: block;
|
||||
}
|
||||
.leaflet-control-layers-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
margin: 5px -10px 5px -6px;
|
||||
}
|
||||
|
||||
|
||||
/* attribution and scale controls */
|
||||
|
||||
.leaflet-container .leaflet-control-attribution {
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
margin: 0;
|
||||
}
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale-line {
|
||||
padding: 0 5px;
|
||||
color: #333;
|
||||
}
|
||||
.leaflet-control-attribution a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.leaflet-control-attribution a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.leaflet-container .leaflet-control-attribution,
|
||||
.leaflet-container .leaflet-control-scale {
|
||||
font-size: 11px;
|
||||
}
|
||||
.leaflet-left .leaflet-control-scale {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control-scale {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.leaflet-control-scale-line {
|
||||
border: 2px solid #777;
|
||||
border-top: none;
|
||||
line-height: 1.1;
|
||||
padding: 2px 5px 1px;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child) {
|
||||
border-top: 2px solid #777;
|
||||
border-bottom: none;
|
||||
margin-top: -2px;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
|
||||
border-bottom: 2px solid #777;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-attribution,
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
box-shadow: none;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
border: 2px solid rgba(0,0,0,0.2);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
|
||||
/* popup */
|
||||
|
||||
.leaflet-popup {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
padding: 1px;
|
||||
text-align: left;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.leaflet-popup-content {
|
||||
margin: 13px 19px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.leaflet-popup-content p {
|
||||
margin: 18px 0;
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
margin: 0 auto;
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.leaflet-popup-tip {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
padding: 1px;
|
||||
|
||||
margin: -10px auto 0;
|
||||
|
||||
-webkit-transform: rotate(45deg);
|
||||
-moz-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
-o-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.leaflet-popup-content-wrapper,
|
||||
.leaflet-popup-tip {
|
||||
background: white;
|
||||
|
||||
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 4px 4px 0 0;
|
||||
text-align: center;
|
||||
width: 18px;
|
||||
height: 14px;
|
||||
font: 16px/14px Tahoma, Verdana, sans-serif;
|
||||
color: #c3c3c3;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
background: transparent;
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button:hover {
|
||||
color: #999;
|
||||
}
|
||||
.leaflet-popup-scrolled {
|
||||
overflow: auto;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper {
|
||||
zoom: 1;
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
width: 24px;
|
||||
margin: 0 auto;
|
||||
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
|
||||
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip-container {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-control-zoom,
|
||||
.leaflet-oldie .leaflet-control-layers,
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper,
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
|
||||
/* div icon */
|
||||
|
||||
.leaflet-div-icon {
|
||||
background: #fff;
|
||||
border: 1px solid #666;
|
||||
}
|
||||
248
gui-src/css/maps/leaflet.draw.css
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
/* ================================================================== */
|
||||
/* Toolbars
|
||||
/* ================================================================== */
|
||||
|
||||
.leaflet-draw-section {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.leaflet-draw-toolbar {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.leaflet-draw-toolbar-top {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.leaflet-draw-toolbar-notop a:first-child {
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
.leaflet-draw-toolbar-nobottom a:last-child {
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.leaflet-draw-toolbar a {
|
||||
background-image: url('images/spritesheet.png');
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.leaflet-retina .leaflet-draw-toolbar a {
|
||||
background-image: url('images/spritesheet-2x.png');
|
||||
background-size: 210px 30px;
|
||||
}
|
||||
|
||||
.leaflet-draw a {
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* ================================================================== */
|
||||
/* Toolbar actions menu
|
||||
/* ================================================================== */
|
||||
|
||||
.leaflet-draw-actions {
|
||||
display: none;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
left: 26px; /* leaflet-draw-toolbar.left + leaflet-draw-toolbar.width */
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.leaflet-right .leaflet-draw-actions {
|
||||
right:26px;
|
||||
left:auto;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions li {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* APR */
|
||||
.leaflet-draw-actions li a {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions li:first-child a {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions li:last-child a {
|
||||
-webkit-border-radius: 0 4px 4px 0;
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
.leaflet-right .leaflet-draw-actions li:last-child a {
|
||||
-webkit-border-radius: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.leaflet-right .leaflet-draw-actions li:first-child a {
|
||||
-webkit-border-radius: 4px 0 0 4px;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions a {
|
||||
background-color: #919187;
|
||||
border-left: 1px solid #AAA;
|
||||
color: #FFF;
|
||||
font: 11px/19px "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
line-height: 28px;
|
||||
text-decoration: none;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions-bottom {
|
||||
margin-top: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions-top {
|
||||
margin-top: 1px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions-top a,
|
||||
.leaflet-draw-actions-bottom a {
|
||||
height: 27px;
|
||||
line-height: 27px;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions a:hover {
|
||||
background-color: #A0A098;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions-top.leaflet-draw-actions-bottom a {
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
/* ================================================================== */
|
||||
/* Draw toolbar
|
||||
/* ================================================================== */
|
||||
|
||||
.leaflet-draw-toolbar .leaflet-draw-draw-polyline {
|
||||
background-position: -2px -2px;
|
||||
}
|
||||
|
||||
.leaflet-draw-toolbar .leaflet-draw-draw-polygon {
|
||||
background-position: -31px -2px;
|
||||
}
|
||||
|
||||
.leaflet-draw-toolbar .leaflet-draw-draw-rectangle {
|
||||
background-position: -62px -2px;
|
||||
}
|
||||
|
||||
.leaflet-draw-toolbar .leaflet-draw-draw-circle {
|
||||
background-position: -92px -2px;
|
||||
}
|
||||
|
||||
.leaflet-draw-toolbar .leaflet-draw-draw-marker {
|
||||
background-position: -122px -2px;
|
||||
}
|
||||
|
||||
/* ================================================================== */
|
||||
/* Edit toolbar
|
||||
/* ================================================================== */
|
||||
|
||||
.leaflet-draw-toolbar .leaflet-draw-edit-edit {
|
||||
background-position: -152px -2px;
|
||||
}
|
||||
|
||||
.leaflet-draw-toolbar .leaflet-draw-edit-remove {
|
||||
background-position: -182px -2px;
|
||||
}
|
||||
|
||||
.leaflet-draw-toolbar .leaflet-draw-edit-edit.leaflet-disabled {
|
||||
background-position: -212px -2px;
|
||||
}
|
||||
|
||||
.leaflet-draw-toolbar .leaflet-draw-edit-remove.leaflet-disabled {
|
||||
background-position: -242px -2px;
|
||||
}
|
||||
|
||||
/* ================================================================== */
|
||||
/* Drawing styles
|
||||
/* ================================================================== */
|
||||
|
||||
.leaflet-mouse-marker {
|
||||
background-color: #fff;
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.leaflet-draw-tooltip {
|
||||
background: rgb(54, 54, 54);
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
border: 1px solid transparent;
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
font: 12px/18px "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
margin-left: 20px;
|
||||
margin-top: -21px;
|
||||
padding: 4px 8px;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
z-index: 6;
|
||||
}
|
||||
|
||||
.leaflet-draw-tooltip:before {
|
||||
border-right: 6px solid black;
|
||||
border-right-color: rgba(0, 0, 0, 0.5);
|
||||
border-top: 6px solid transparent;
|
||||
border-bottom: 6px solid transparent;
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
left: -7px;
|
||||
}
|
||||
|
||||
.leaflet-error-draw-tooltip {
|
||||
background-color: #F2DEDE;
|
||||
border: 1px solid #E6B6BD;
|
||||
color: #B94A48;
|
||||
}
|
||||
|
||||
.leaflet-error-draw-tooltip:before {
|
||||
border-right-color: #E6B6BD;
|
||||
}
|
||||
|
||||
.leaflet-draw-tooltip-single {
|
||||
margin-top: -12px
|
||||
}
|
||||
|
||||
.leaflet-draw-tooltip-subtext {
|
||||
color: #f8d5e4;
|
||||
}
|
||||
|
||||
.leaflet-draw-guide-dash {
|
||||
font-size: 1%;
|
||||
opacity: 0.6;
|
||||
position: absolute;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
/* ================================================================== */
|
||||
/* Edit styles
|
||||
/* ================================================================== */
|
||||
|
||||
.leaflet-edit-marker-selected {
|
||||
background: rgba(254, 87, 161, 0.1);
|
||||
border: 4px dashed rgba(254, 87, 161, 0.6);
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.leaflet-edit-move {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.leaflet-edit-resize {
|
||||
cursor: pointer;
|
||||
}
|
||||
49
gui-src/css/maps/leaflet.draw.ie.css
Normal file
@@ -0,0 +1,49 @@
|
||||
/* Conditional stylesheet for IE. */
|
||||
|
||||
.leaflet-draw-toolbar {
|
||||
border: 3px solid #999;
|
||||
}
|
||||
|
||||
.leaflet-draw-toolbar a {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.leaflet-draw-toolbar a:hover {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions {
|
||||
left: 32px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions li {
|
||||
display: inline;
|
||||
zoom: 1;
|
||||
}
|
||||
|
||||
.leaflet-edit-marker-selected {
|
||||
border: 4px dashed #fe93c2;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions a {
|
||||
background-color: #999;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions a:hover {
|
||||
background-color: #a5a5a5;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions-top a {
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions-bottom a {
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.leaflet-draw-actions-top.leaflet-draw-actions-bottom a {
|
||||
height: 27px;
|
||||
line-height: 27px;
|
||||
}
|
||||
51
gui-src/css/maps/leaflet.ie.css
Normal file
@@ -0,0 +1,51 @@
|
||||
.leaflet-vml-shape {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
.lvml {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.leaflet-control {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.leaflet-popup-tip {
|
||||
width: 21px;
|
||||
_width: 27px;
|
||||
margin: 0 auto;
|
||||
_margin-top: -3px;
|
||||
|
||||
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
margin-top: -1px;
|
||||
}
|
||||
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
zoom: 1;
|
||||
}
|
||||
|
||||
.leaflet-control-zoom,
|
||||
.leaflet-control-layers {
|
||||
border: 3px solid #999;
|
||||
}
|
||||
.leaflet-control-layers-toggle {
|
||||
}
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-layers,
|
||||
.leaflet-control-scale-line {
|
||||
background: white;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
filter: alpha(opacity=50);
|
||||
}
|
||||
.leaflet-control-attribution {
|
||||
border-top: 1px solid #bbb;
|
||||
border-left: 1px solid #bbb;
|
||||
}
|
||||
159
gui-src/css/maps/leaflet.sidebar.css
Normal file
@@ -0,0 +1,159 @@
|
||||
.leaflet-sidebar {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
|
||||
z-index: 20000;
|
||||
}
|
||||
|
||||
.leaflet-sidebar.left {
|
||||
left: -700px;
|
||||
transition: left 0.5s, width 0.5s;
|
||||
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.leaflet-sidebar.right {
|
||||
right: -700px;
|
||||
transition: right 0.5s, width 0.5s;
|
||||
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.leaflet-sidebar.left.visible {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.leaflet-sidebar.right.visible {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.leaflet-left {
|
||||
transition: left 0.5s;
|
||||
}
|
||||
|
||||
.leaflet-right {
|
||||
transition: right 0.5s;
|
||||
}
|
||||
|
||||
.leaflet-sidebar > .leaflet-control {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
padding: 8px 24px;
|
||||
|
||||
font-size: 1.1em;
|
||||
|
||||
background: white;
|
||||
box-shadow: 0 1px 7px rgba(0,0,0,0.65);
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@media(max-width:767px){
|
||||
.leaflet-sidebar {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.leaflet-sidebar.left {
|
||||
left: -100%;
|
||||
}
|
||||
|
||||
.leaflet-sidebar.right {
|
||||
right: -100%;
|
||||
}
|
||||
|
||||
.leaflet-sidebar.left.visible {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.leaflet-sidebar.right.visible {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.leaflet-sidebar > .leaflet-control {
|
||||
box-shadow: none;
|
||||
-webkit-border-radius: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.leaflet-sidebar.left.visible ~ .leaflet-left {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.leaflet-sidebar.right.visible ~ .leaflet-right {
|
||||
right: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width:768px) and (max-width:991px){
|
||||
.leaflet-sidebar {
|
||||
width: 505px;
|
||||
}
|
||||
|
||||
.leaflet-sidebar.left.visible ~ .leaflet-left {
|
||||
left: 505px;
|
||||
}
|
||||
|
||||
.leaflet-sidebar.right.visible ~ .leaflet-right {
|
||||
right: 505px;
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width:992px) and (max-width:1199px){
|
||||
.leaflet-sidebar {
|
||||
width: 590px;
|
||||
}
|
||||
|
||||
.leaflet-sidebar.left.visible ~ .leaflet-left {
|
||||
left: 590px;
|
||||
}
|
||||
|
||||
.leaflet-sidebar.right.visible ~ .leaflet-right {
|
||||
right: 590px;
|
||||
}
|
||||
}
|
||||
|
||||
@media(min-width:1200px){
|
||||
.leaflet-sidebar {
|
||||
width: 660px;
|
||||
}
|
||||
|
||||
.leaflet-sidebar.left.visible ~ .leaflet-left {
|
||||
left: 660px;
|
||||
}
|
||||
|
||||
.leaflet-sidebar.right.visible ~ .leaflet-right {
|
||||
right: 660px;
|
||||
}
|
||||
}
|
||||
|
||||
.leaflet-sidebar .close {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
width: 31px;
|
||||
height: 31px;
|
||||
|
||||
color: #333;
|
||||
font-size: 25pt;
|
||||
line-height: 1em;
|
||||
text-align: center;
|
||||
background: white;
|
||||
-webkit-border-radius: 16px;
|
||||
border-radius: 16px;
|
||||
cursor: pointer;
|
||||
|
||||
z-index: 8;
|
||||
}
|
||||
757
gui-src/css/maps/mapbox.standalone.css
Normal file
@@ -0,0 +1,757 @@
|
||||
/* general typography */
|
||||
.leaflet-container {
|
||||
background:#fff;
|
||||
font:15px/25px 'Helvetica Neue', Arial, Helvetica, sans-serif;
|
||||
color:#404040;
|
||||
color:rgba(0,0,0,0.75);
|
||||
outline:0;
|
||||
overflow:hidden;
|
||||
-ms-touch-action:none;
|
||||
}
|
||||
.leaflet-container *,
|
||||
.leaflet-container *:after,
|
||||
.leaflet-container *:before {
|
||||
-webkit-box-sizing:border-box;
|
||||
-moz-box-sizing:border-box;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
|
||||
.leaflet-container h1,
|
||||
.leaflet-container h2,
|
||||
.leaflet-container h3,
|
||||
.leaflet-container h4,
|
||||
.leaflet-container h5,
|
||||
.leaflet-container h6,
|
||||
.leaflet-container p {
|
||||
font-size:15px;
|
||||
line-height:25px;
|
||||
margin:0 0 10px;
|
||||
}
|
||||
.mapbox-small,
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale,
|
||||
.leaflet-container input,
|
||||
.leaflet-container textarea,
|
||||
.leaflet-container label,
|
||||
.leaflet-container small {
|
||||
font-size:12px;
|
||||
line-height:20px;
|
||||
}
|
||||
|
||||
.leaflet-container a {
|
||||
color:#3887BE;
|
||||
font-weight:normal;
|
||||
text-decoration:none;
|
||||
}
|
||||
.leaflet-container a:hover { color:#63b6e5; }
|
||||
.leaflet-container.dark a { color:#63b6e5; }
|
||||
.leaflet-container.dark a:hover { color:#8fcaec; }
|
||||
|
||||
.leaflet-container.dark .mapbox-button,
|
||||
.leaflet-container .mapbox-button {
|
||||
background-color:#3887be;
|
||||
display:inline-block;
|
||||
height:40px;
|
||||
line-height:40px;
|
||||
text-decoration:none;
|
||||
color:#fff;
|
||||
font-size:12px;
|
||||
white-space:nowrap;
|
||||
text-overflow:ellipsis;
|
||||
}
|
||||
.leaflet-container.dark .mapbox-button:hover,
|
||||
.leaflet-container .mapbox-button:hover {
|
||||
color:#fff;
|
||||
background-color:#3bb2d0;
|
||||
}
|
||||
|
||||
/* Base Leaflet
|
||||
------------------------------------------------------- */
|
||||
.leaflet-map-pane,
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-tile-pane,
|
||||
.leaflet-tile-container,
|
||||
.leaflet-overlay-pane,
|
||||
.leaflet-shadow-pane,
|
||||
.leaflet-marker-pane,
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-overlay-pane svg,
|
||||
.leaflet-zoom-box,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-layer {
|
||||
position:absolute;
|
||||
left:0;
|
||||
top:0;
|
||||
}
|
||||
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
-webkit-user-drag:none;
|
||||
-webkit-user-select:none;
|
||||
-moz-user-select:none;
|
||||
user-select:none;
|
||||
}
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.leaflet-tile {
|
||||
filter:inherit;
|
||||
visibility:hidden;
|
||||
}
|
||||
.leaflet-tile-loaded {
|
||||
visibility:inherit;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
width:0;
|
||||
height:0;
|
||||
}
|
||||
|
||||
.leaflet-tile-pane { z-index:2; }
|
||||
.leaflet-objects-pane { z-index:3; }
|
||||
.leaflet-overlay-pane { z-index:4; }
|
||||
.leaflet-shadow-pane { z-index:5; }
|
||||
.leaflet-marker-pane { z-index:6; }
|
||||
.leaflet-popup-pane { z-index:7; }
|
||||
|
||||
.leaflet-control {
|
||||
position:relative;
|
||||
z-index:7;
|
||||
pointer-events:auto;
|
||||
float:left;
|
||||
clear:both;
|
||||
}
|
||||
.leaflet-right .leaflet-control { float:right; }
|
||||
.leaflet-top .leaflet-control { margin-top:10px; }
|
||||
.leaflet-bottom .leaflet-control { margin-bottom:10px; }
|
||||
.leaflet-left .leaflet-control { margin-left:10px; }
|
||||
.leaflet-right .leaflet-control { margin-right:10px; }
|
||||
|
||||
.leaflet-top,
|
||||
.leaflet-bottom {
|
||||
position:absolute;
|
||||
z-index:1000;
|
||||
pointer-events:none;
|
||||
}
|
||||
.leaflet-top { top:0; }
|
||||
.leaflet-right { right:0; }
|
||||
.leaflet-bottom { bottom:0; }
|
||||
.leaflet-left { left:0; }
|
||||
|
||||
/* zoom and fade animations */
|
||||
.leaflet-fade-anim .leaflet-tile,
|
||||
.leaflet-fade-anim .leaflet-popup {
|
||||
opacity:0;
|
||||
-webkit-transition:opacity 0.2s linear;
|
||||
-moz-transition:opacity 0.2s linear;
|
||||
-o-transition:opacity 0.2s linear;
|
||||
transition:opacity 0.2s linear;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-tile-loaded,
|
||||
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
-webkit-transition:-webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-tile,
|
||||
.leaflet-pan-anim .leaflet-tile,
|
||||
.leaflet-touching .leaflet-zoom-animated {
|
||||
-webkit-transition:none;
|
||||
-moz-transition:none;
|
||||
-o-transition:none;
|
||||
transition:none;
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-zoom-hide { visibility: hidden; }
|
||||
|
||||
/* cursors */
|
||||
.map-clickable,
|
||||
.leaflet-clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-control {
|
||||
cursor:auto;
|
||||
}
|
||||
.leaflet-container {
|
||||
cursor:-webkit-grab;
|
||||
cursor: -moz-grab;
|
||||
}
|
||||
.leaflet-dragging,
|
||||
.leaflet-dragging .map-clickable,
|
||||
.leaflet-dragging .leaflet-clickable,
|
||||
.leaflet-dragging .leaflet-container {
|
||||
cursor:move;
|
||||
cursor:-webkit-grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
}
|
||||
|
||||
.leaflet-zoom-box {
|
||||
background:#fff;
|
||||
border:2px dotted #202020;
|
||||
opacity:0.5;
|
||||
}
|
||||
|
||||
/* general toolbar styles */
|
||||
.leaflet-control-layers,
|
||||
.leaflet-bar {
|
||||
background-color:#fff;
|
||||
border:1px solid #999;
|
||||
border-color:rgba(0,0,0,0.4);
|
||||
border-radius:3px;
|
||||
box-shadow:none;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-bar a:hover {
|
||||
color:#404040;
|
||||
color:rgba(0,0,0,0.75);
|
||||
border-bottom:1px solid #ddd;
|
||||
border-bottom-color:rgba(0,0,0,0.10);
|
||||
}
|
||||
.leaflet-bar a:hover,
|
||||
.leaflet-bar a:active {
|
||||
background-color:#f8f8f8;
|
||||
cursor:pointer;
|
||||
}
|
||||
.leaflet-bar a:first-child {
|
||||
border-radius:3px 3px 0 0;
|
||||
}
|
||||
.leaflet-bar a:last-child {
|
||||
border-bottom:none;
|
||||
border-radius:0 0 3px 3px;
|
||||
}
|
||||
.leaflet-bar a:only-of-type {
|
||||
border-radius:3px;
|
||||
}
|
||||
|
||||
.leaflet-bar .leaflet-disabled {
|
||||
cursor:default;
|
||||
opacity:0.75;
|
||||
}
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out {
|
||||
display:block;
|
||||
content:'';
|
||||
text-indent:-999em;
|
||||
}
|
||||
|
||||
.leaflet-control-layers .leaflet-control-layers-list,
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
|
||||
display:none;
|
||||
}
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-list {
|
||||
display:block;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.leaflet-control-layers-expanded {
|
||||
background:#fff;
|
||||
padding:6px 10px 6px 6px;
|
||||
color:#404040;
|
||||
color:rgba(0,0,0,0.75);
|
||||
}
|
||||
.leaflet-control-layers-selector {
|
||||
margin-top:2px;
|
||||
position:relative;
|
||||
top:1px;
|
||||
}
|
||||
.leaflet-control-layers label {
|
||||
display: block;
|
||||
}
|
||||
.leaflet-control-layers-separator {
|
||||
height:0;
|
||||
border-top:1px solid #ddd;
|
||||
border-top-color:rgba(0,0,0,0.10);
|
||||
margin:5px -10px 5px -6px;
|
||||
}
|
||||
|
||||
.leaflet-container .leaflet-control-attribution {
|
||||
background-color:rgba(255,255,255,0.25);
|
||||
margin:0;
|
||||
box-shadow:none;
|
||||
}
|
||||
.leaflet-control-attribution a:hover,
|
||||
.map-info-container a:hover {
|
||||
color:inherit;
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale-line {
|
||||
padding:0 5px;
|
||||
}
|
||||
.leaflet-left .leaflet-control-scale { margin-left:5px; }
|
||||
.leaflet-bottom .leaflet-control-scale { margin-bottom:5px; }
|
||||
|
||||
.leaflet-control-scale-line {
|
||||
background-color:rgba(255,255,255,0.5);
|
||||
border:1px solid #999;
|
||||
border-color:rgba(0,0,0,0.4);
|
||||
border-top:none;
|
||||
padding:2px 5px 1px;
|
||||
white-space:nowrap;
|
||||
overflow:hidden;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child) {
|
||||
border-top:2px solid #ddd;
|
||||
border-top-color:rgba(0,0,0,0.10);
|
||||
border-bottom:none;
|
||||
margin-top:-2px;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
|
||||
border-bottom:2px solid #777;
|
||||
}
|
||||
|
||||
/* popup */
|
||||
.leaflet-popup {
|
||||
position:absolute;
|
||||
text-align:center;
|
||||
pointer-events:none;
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
padding:1px;
|
||||
text-align:left;
|
||||
pointer-events:all;
|
||||
}
|
||||
.leaflet-popup-content {
|
||||
padding:10px 10px 15px;
|
||||
margin:0;
|
||||
line-height:inherit;
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
width:20px;
|
||||
height:20px;
|
||||
margin:0 auto;
|
||||
position:relative;
|
||||
}
|
||||
.leaflet-popup-tip {
|
||||
width:0;
|
||||
height:0;
|
||||
margin:0;
|
||||
border-left:10px solid transparent;
|
||||
border-right:10px solid transparent;
|
||||
border-top:10px solid #fff;
|
||||
box-shadow:none;
|
||||
}
|
||||
.leaflet-popup-close-button {
|
||||
text-indent:-999em;
|
||||
position:absolute;
|
||||
top:0;right:0;
|
||||
pointer-events:all;
|
||||
}
|
||||
.leaflet-popup-close-button:hover {
|
||||
background-color:#f8f8f8;
|
||||
}
|
||||
|
||||
.leaflet-popup-scrolled {
|
||||
overflow:auto;
|
||||
border-bottom:1px solid #ddd;
|
||||
border-top:1px solid #ddd;
|
||||
}
|
||||
|
||||
/* div icon */
|
||||
.leaflet-div-icon {
|
||||
background:#fff;
|
||||
border:1px solid #999;
|
||||
border-color:rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-editing-icon {
|
||||
border-radius:3px;
|
||||
}
|
||||
|
||||
/* Leaflet + Mapbox
|
||||
------------------------------------------------------- */
|
||||
.leaflet-bar a,
|
||||
.mapbox-icon,
|
||||
.map-tooltip.closable .close,
|
||||
.leaflet-control-layers-toggle,
|
||||
.leaflet-popup-close-button,
|
||||
.mapbox-button-icon:before {
|
||||
content:'';
|
||||
display:inline-block;
|
||||
width:26px;
|
||||
height:26px;
|
||||
vertical-align:middle;
|
||||
background-repeat:no-repeat;
|
||||
}
|
||||
.leaflet-bar a {
|
||||
display:block;
|
||||
}
|
||||
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out,
|
||||
.leaflet-popup-close-button,
|
||||
.leaflet-control-layers-toggle,
|
||||
.leaflet-container.dark .map-tooltip .close,
|
||||
.map-tooltip .close,
|
||||
.mapbox-icon {
|
||||
background-image:url(./images/icons-404040.png);
|
||||
background-repeat:no-repeat;
|
||||
background-size:26px 260px;
|
||||
}
|
||||
.mapbox-button-icon:before,
|
||||
.leaflet-container.dark .leaflet-control-zoom-in,
|
||||
.leaflet-container.dark .leaflet-control-zoom-out,
|
||||
.leaflet-container.dark .leaflet-control-layers-toggle,
|
||||
.leaflet-container.dark .mapbox-icon {
|
||||
background-image:url(./images/icons-ffffff.png);
|
||||
background-size:26px 260px;
|
||||
}
|
||||
.leaflet-bar .leaflet-control-zoom-in { background-position:0 0; }
|
||||
.leaflet-bar .leaflet-control-zoom-out { background-position:0 -26px; }
|
||||
.map-tooltip .close, .leaflet-popup-close-button { background-position:0 -52px; }
|
||||
.mapbox-icon-info { background-position:0 -78px; }
|
||||
.leaflet-control-layers-toggle { background-position:0 -104px; }
|
||||
.mapbox-icon-share:before, .mapbox-icon-share { background-position:0 -130px; }
|
||||
.mapbox-icon-geocoder:before, .mapbox-icon-geocoder { background-position:0 -156px; }
|
||||
.mapbox-icon-facebook:before, .mapbox-icon-facebook { background-position:0 -182px; }
|
||||
.mapbox-icon-twitter:before, .mapbox-icon-twitter { background-position:0 -208px; }
|
||||
.mapbox-icon-pinterest:before, .mapbox-icon-pinterest { background-position:0 -234px; }
|
||||
|
||||
@media
|
||||
(-webkit-min-device-pixel-ratio:2),
|
||||
(min-resolution:192dpi) {
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out,
|
||||
.leaflet-popup-close-button,
|
||||
.leaflet-control-layers-toggle,
|
||||
.mapbox-icon {
|
||||
background-image:url(./images/icons-404040@2x.png);
|
||||
}
|
||||
.mapbox-button-icon:before,
|
||||
.leaflet-container.dark .leaflet-control-zoom-in,
|
||||
.leaflet-container.dark .leaflet-control-zoom-out,
|
||||
.leaflet-container.dark .leaflet-control-layers-toggle,
|
||||
.leaflet-container.dark .mapbox-icon {
|
||||
background-image:url(./images/icons-ffffff@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
.leaflet-popup-content-wrapper,
|
||||
.map-legends,
|
||||
.map-tooltip {
|
||||
background:#fff;
|
||||
border-radius:3px;
|
||||
box-shadow:0 1px 2px rgba(0,0,0,0.10);
|
||||
}
|
||||
.map-legends,
|
||||
.map-tooltip {
|
||||
max-width:300px;
|
||||
}
|
||||
.map-legends .map-legend {
|
||||
padding:10px;
|
||||
}
|
||||
.map-tooltip {
|
||||
z-index:999999;
|
||||
padding:10px;
|
||||
min-width:180px;
|
||||
max-height:400px;
|
||||
overflow:auto;
|
||||
opacity:1;
|
||||
-webkit-transition:opacity 150ms;
|
||||
-moz-transition:opacity 150ms;
|
||||
-o-transition:opacity 150ms;
|
||||
transition:opacity 150ms;
|
||||
}
|
||||
|
||||
.map-tooltip .close {
|
||||
text-indent:-999em;
|
||||
overflow:hidden;
|
||||
display:none;
|
||||
}
|
||||
.map-tooltip.closable .close {
|
||||
position:absolute;
|
||||
top:0;right:0;
|
||||
border-radius:3px;
|
||||
}
|
||||
.map-tooltip.closable .close:active {
|
||||
background-color:#f8f8f8;
|
||||
}
|
||||
|
||||
.leaflet-control-interaction {
|
||||
position:absolute;
|
||||
top:10px;
|
||||
right:10px;
|
||||
width:300px;
|
||||
}
|
||||
.leaflet-popup-content .marker-title {
|
||||
font-weight:bold;
|
||||
}
|
||||
.leaflet-control .mapbox-button {
|
||||
background-color:#fff;
|
||||
border:1px solid #ddd;
|
||||
border-color:rgba(0,0,0,0.10);
|
||||
padding:5px 10px;
|
||||
border-radius:3px;
|
||||
}
|
||||
|
||||
/* Share modal
|
||||
------------------------------------------------------- */
|
||||
.mapbox-modal > div {
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
width:100%;
|
||||
height:100%;
|
||||
z-index:-1;
|
||||
overflow-y:auto;
|
||||
}
|
||||
.mapbox-modal.active > div {
|
||||
z-index:99999;
|
||||
transition:all .2s, z-index 0 0;
|
||||
}
|
||||
|
||||
.mapbox-modal .mapbox-modal-mask {
|
||||
background:rgba(0,0,0,0.5);
|
||||
opacity:0;
|
||||
}
|
||||
.mapbox-modal.active .mapbox-modal-mask { opacity:1; }
|
||||
|
||||
.mapbox-modal .mapbox-modal-content {
|
||||
-webkit-transform:translateY(-100%);
|
||||
-moz-transform:translateY(-100%);
|
||||
-ms-transform:translateY(-100%);
|
||||
transform:translateY(-100%);
|
||||
}
|
||||
.mapbox-modal.active .mapbox-modal-content {
|
||||
-webkit-transform:translateY(0);
|
||||
-moz-transform:translateY(0);
|
||||
-ms-transform:translateY(0);
|
||||
transform:translateY(0);
|
||||
}
|
||||
|
||||
.mapbox-modal-body {
|
||||
position:relative;
|
||||
background:#fff;
|
||||
padding:20px;
|
||||
z-index:1000;
|
||||
width:50%;
|
||||
margin:20px 0 20px 25%;
|
||||
}
|
||||
.mapbox-share-buttons {
|
||||
margin:0 0 20px;
|
||||
}
|
||||
.mapbox-share-buttons a {
|
||||
width:33.3333%;
|
||||
border-left:1px solid #fff;
|
||||
text-align:center;
|
||||
border-radius:0;
|
||||
}
|
||||
.mapbox-share-buttons a:last-child { border-radius:0 3px 3px 0; }
|
||||
.mapbox-share-buttons a:first-child { border:none; border-radius:3px 0 0 3px; }
|
||||
|
||||
.mapbox-modal input {
|
||||
width:100%;
|
||||
height:40px;
|
||||
padding:10px;
|
||||
border:1px solid #ddd;
|
||||
border-color:rgba(0,0,0,0.10);
|
||||
color:rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
/* Info Control
|
||||
------------------------------------------------------- */
|
||||
.leaflet-control.mapbox-control-info {
|
||||
margin:5px 30px 10px 10px;
|
||||
min-height:26px;
|
||||
}
|
||||
.leaflet-control.mapbox-control-info-right {
|
||||
margin:5px 10px 10px 30px;
|
||||
}
|
||||
|
||||
.mapbox-info-toggle {
|
||||
background-color:#fff;
|
||||
background-color:rgba(255,255,255,0.25);
|
||||
border-radius:50%;
|
||||
position:absolute;
|
||||
bottom:0;left:0;
|
||||
z-index:1;
|
||||
}
|
||||
.mapbox-control-info-right .mapbox-info-toggle { left:auto; right:0; }
|
||||
.mapbox-control-info.active .mapbox-info-toggle { background-color:#fff; }
|
||||
.mapbox-info-toggle:hover { background-color:rgba(255,255,255,0.5); }
|
||||
|
||||
.map-info-container {
|
||||
background:#fff;
|
||||
background:rgba(255,255,255,0.75);
|
||||
padding:3px 5px 3px 15px;
|
||||
display:none;
|
||||
position:relative;
|
||||
bottom:0;
|
||||
left:13px;
|
||||
border-radius:3px;
|
||||
}
|
||||
.mapbox-control-info.active .map-info-container { display:inline-block; }
|
||||
.mapbox-control-info-right .map-info-container {
|
||||
left:auto;
|
||||
right:13px;
|
||||
padding:3px 15px 3px 5px;
|
||||
}
|
||||
|
||||
/* Geocoder
|
||||
------------------------------------------------------- */
|
||||
.leaflet-control-mapbox-geocoder {
|
||||
position:relative;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder.searching {
|
||||
opacity:0.75;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder .leaflet-control-mapbox-geocoder-wrap {
|
||||
background:#fff;
|
||||
position:absolute;
|
||||
border:1px solid #999;
|
||||
border-color:rgba(0,0,0,0.4);
|
||||
border-bottom-width:0;
|
||||
overflow:hidden;
|
||||
left:26px;
|
||||
height:27px;
|
||||
width:0;
|
||||
top:-1px;
|
||||
border-radius:0 3px 3px 0;
|
||||
opacity:0;
|
||||
-webkit-transition:opacity 100ms;
|
||||
-moz-transition:opacity 100ms;
|
||||
-o-transition:opacity 100ms;
|
||||
transition:opacity 100ms;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder.active .leaflet-control-mapbox-geocoder-wrap {
|
||||
width:180px;
|
||||
opacity:1;
|
||||
}
|
||||
.leaflet-bar .leaflet-control-mapbox-geocoder-toggle,
|
||||
.leaflet-bar .leaflet-control-mapbox-geocoder-toggle:hover {
|
||||
border-bottom:none;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder-toggle {
|
||||
border-radius:3px;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder.active,
|
||||
.leaflet-control-mapbox-geocoder.active .leaflet-control-mapbox-geocoder-toggle {
|
||||
border-top-right-radius:0;
|
||||
border-bottom-right-radius:0;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder .leaflet-control-mapbox-geocoder-form input {
|
||||
background:transparent;
|
||||
border:0;
|
||||
width:180px;
|
||||
padding:0 0 0 10px;
|
||||
height:26px;
|
||||
outline:none;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder-results {
|
||||
width:180px;
|
||||
position:absolute;
|
||||
left:26px;
|
||||
top:25px;
|
||||
border-radius:0 0 3px 3px;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder.active .leaflet-control-mapbox-geocoder-results {
|
||||
background:#fff;
|
||||
border:1px solid #999;
|
||||
border-color:rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
.leaflet-control-mapbox-geocoder-results a,
|
||||
.leaflet-control-mapbox-geocoder-results span {
|
||||
padding:0 10px;
|
||||
text-overflow:ellipsis;
|
||||
white-space:nowrap;
|
||||
display:block;
|
||||
width:100%;
|
||||
font-size:12px;
|
||||
line-height:26px;
|
||||
text-align:left;
|
||||
overflow:hidden;
|
||||
}
|
||||
.leaflet-control-mapbox-geocoder-results a:first-child {
|
||||
border-top:1px solid #999;
|
||||
border-top-color:rgba(0,0,0,0.4);
|
||||
border-radius:0;
|
||||
}
|
||||
.leaflet-container.dark .leaflet-control .leaflet-control-mapbox-geocoder-results a:hover,
|
||||
.leaflet-control-mapbox-geocoder-results a:hover {
|
||||
background:#f8f8f8;
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
/* Dark Theme
|
||||
------------------------------------------------------- */
|
||||
.leaflet-container.dark .leaflet-bar {
|
||||
background-color:#404040;
|
||||
border-color:#202020;
|
||||
border-color:rgba(0,0,0,0.75);
|
||||
}
|
||||
.leaflet-container.dark .leaflet-bar a {
|
||||
color:#404040;
|
||||
border-color:rgba(0,0,0,0.5);
|
||||
}
|
||||
.leaflet-container.dark .leaflet-bar a:active,
|
||||
.leaflet-container.dark .leaflet-bar a:hover {
|
||||
background-color:#505050;
|
||||
}
|
||||
|
||||
.leaflet-container.dark .mapbox-info-toggle,
|
||||
.leaflet-container.dark .map-info-container,
|
||||
.leaflet-container.dark .leaflet-control-attribution {
|
||||
background-color:rgba(0,0,0,0.25);
|
||||
color:#f8f8f8;
|
||||
}
|
||||
.leaflet-container.dark .leaflet-bar a.leaflet-disabled,
|
||||
.leaflet-container.dark .leaflet-control .mapbox-button.disabled {
|
||||
background-color:#252525;
|
||||
color:#404040;
|
||||
}
|
||||
.leaflet-container.dark .leaflet-control-mapbox-geocoder > div {
|
||||
border-color:#202020;
|
||||
border-color:rgba(0,0,0,0.75);
|
||||
}
|
||||
.leaflet-container.dark .leaflet-control .leaflet-control-mapbox-geocoder-results a {
|
||||
border-color:#ddd #202020;
|
||||
border-color:rgba(0,0,0,0.10) rgba(0,0,0,0.75);
|
||||
}
|
||||
.leaflet-container.dark .leaflet-control .leaflet-control-mapbox-geocoder-results span {
|
||||
border-color:#202020;
|
||||
border-color:rgba(0,0,0,0.75);
|
||||
}
|
||||
|
||||
/* Larger Screens
|
||||
------------------------------------------------------- */
|
||||
@media only screen and (max-width:800px) {
|
||||
.mapbox-modal-body {
|
||||
width:83.3333%;
|
||||
margin-left:8.3333%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Smaller Screens
|
||||
------------------------------------------------------- */
|
||||
@media only screen and (max-width:640px) {
|
||||
.mapbox-modal-body {
|
||||
width:100%;
|
||||
height:100%;
|
||||
margin:0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Browser Fixes
|
||||
------------------------------------------------------- */
|
||||
/* Map is broken in FF if you have max-width: 100% on tiles */
|
||||
.leaflet-container img { max-width:none!important; }
|
||||
/* Stupid Android 2 doesn't understand "max-width: none" properly */
|
||||
.leaflet-container img.leaflet-image-layer { max-width:15000px!important; }
|
||||
/* Android chrome makes tiles disappear without this */
|
||||
.leaflet-tile-container img { -webkit-backface-visibility:hidden; }
|
||||
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
|
||||
.leaflet-overlay-pane svg { -moz-user-select:none; }
|
||||
/* Older IEs don't support the translateY property for display animation */
|
||||
.leaflet-oldie .mapbox-modal .mapbox-modal-content { display:none; }
|
||||
.leaflet-oldie .mapbox-modal.active .mapbox-modal-content { display:block; }
|
||||
.map-tooltip { width:280px\8; /* < IE9 */ }
|
||||
1
gui-src/css/maps/mapbox.v3.2.0.css
Normal file
241
gui-src/css/styles.css
Normal file
@@ -0,0 +1,241 @@
|
||||
:root {
|
||||
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 400;
|
||||
color: #0f0f0f;
|
||||
background-color: #f6f6f6;
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #ececec;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin: 0;
|
||||
padding-top: 1vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: 0.75s;
|
||||
}
|
||||
|
||||
.logo.arnis:hover {
|
||||
filter: drop-shadow(0 0 2em #b3b3b3);
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
.flex-container {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
justify-content: center;
|
||||
align-items: stretch; /* Ensures both sections take full height */
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.section {
|
||||
background: #575757;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.map-box,
|
||||
.controls-box {
|
||||
width: 45%;
|
||||
background: #575757;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
/* No display: flex here, so buttons and content aren't stretched */
|
||||
}
|
||||
|
||||
.controls-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.controls-box .progress-section {
|
||||
margin-top: auto; /* Keeps the progress section at the bottom */
|
||||
}
|
||||
|
||||
.map-container {
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.section h2 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #d6d6d6;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
color: #0f0f0f;
|
||||
background-color: #ffffff;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
|
||||
margin-top: 10px;
|
||||
width: auto; /* Ensures buttons don’t stretch */
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #396cd8;
|
||||
}
|
||||
|
||||
#selected-directory {
|
||||
font-size: 1em;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.progress-section {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.progress-section h2 {
|
||||
margin-bottom: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.progress-bar-container {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
background-color: #e0e0e0;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
background-color: #4caf50;
|
||||
transition: width 0.4s;
|
||||
}
|
||||
|
||||
/* Left and right alignment for "Saving world..." text */
|
||||
.progress-status {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 0.9em;
|
||||
margin-top: 8px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.footer-link {
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.footer-link:hover {
|
||||
color: #b3b3b3;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
color: #f6f6f6;
|
||||
background-color: #2f2f2f;
|
||||
}
|
||||
|
||||
p {
|
||||
color: #ececec;
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
color: #ffffff;
|
||||
background-color: #0f0f0f98;
|
||||
}
|
||||
button:active {
|
||||
background-color: #0f0f0f69;
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tooltip button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tooltip .tooltiptext {
|
||||
visibility: hidden;
|
||||
width: 90%;
|
||||
background-color: #808080;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
padding: 5px 0;
|
||||
border-radius: 6px;
|
||||
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
bottom: -100%;
|
||||
left: 5%;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.tooltip .tooltiptext::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
left: 50%;
|
||||
margin-left: -5px;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
border-color: transparent transparent #808080 transparent;
|
||||
}
|
||||
|
||||
.tooltip:hover .tooltiptext {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.controls-box button {
|
||||
width: 100%;
|
||||
}
|
||||
BIN
gui-src/images/crosshair.png
Normal file
|
After Width: | Height: | Size: 487 B |
BIN
gui-src/images/logo.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
gui-src/images/tile.png
Normal file
|
After Width: | Height: | Size: 811 B |
80
gui-src/index.html
Normal file
@@ -0,0 +1,80 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="stylesheet" href="./css/styles.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Arnis</title>
|
||||
<script type="module" src="./js/main.js" defer></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main class="container">
|
||||
<div class="row">
|
||||
<a href="https://github.com/louis-e/arnis" target="_blank">
|
||||
<img src="./images/logo.png" class="logo arnis" alt="Arnis Logo" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="flex-container">
|
||||
<!-- Left Box: Map and BBox Input -->
|
||||
<section class="section map-box" style="margin-bottom: 0; padding-bottom: 0;">
|
||||
<h2>Select Location</h2>
|
||||
<span id="bbox-text" style="font-size: 1.0em; display: block; margin-top: -8px; margin-bottom: 3px;">
|
||||
Zoom in and choose your area using the rectangle tool
|
||||
</span>
|
||||
<iframe src="maps.html" width="100%" height="300" class="map-container" title="Map Picker"></iframe>
|
||||
|
||||
<span id="bbox-info"
|
||||
style="font-size: 0.75em; color: #7bd864; display: block; margin-bottom: 4px; font-weight: bold; min-height: 2em;"></span>
|
||||
</section>
|
||||
|
||||
<!-- Right Box: Directory Selection, Start Button, and Progress Bar -->
|
||||
<section class="section controls-box">
|
||||
<div class="controls-content">
|
||||
<h2>Select World</h2>
|
||||
|
||||
<!-- Updated Tooltip Structure -->
|
||||
<div class="tooltip" style="width: 100%;">
|
||||
<button type="button" onclick="pickDirectory()" style="padding: 10px; line-height: 1.2; width: 100%;">
|
||||
Choose World
|
||||
<br>
|
||||
<span id="selected-world" style="font-size: 0.8em; color: #fecc44; display: block; margin-top: 4px;">
|
||||
No world selected
|
||||
</span>
|
||||
</button>
|
||||
<span class="tooltiptext" style="font-size: 0.8em; line-height: 1.2;">
|
||||
Please select a Minecraft world that can be overwritten, as the generation process will replace existing structures in the chosen world!
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<button type="button" onclick="startGeneration()">Start Generation</button>
|
||||
<br><br>
|
||||
|
||||
<div class="progress-section">
|
||||
<h2>Progress</h2>
|
||||
<div class="progress-bar-container">
|
||||
<div class="progress-bar" id="progress-bar"></div>
|
||||
</div>
|
||||
<div class="progress-status">
|
||||
<span id="progress-message"></span>
|
||||
<span id="progress-detail">0%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="footer">
|
||||
<a href="https://github.com/louis-e/arnis" target="_blank" class="footer-link">
|
||||
© <span id="current-year"></span> Arnis v<span id="version-placeholder">x.x.x</span> by louis-e
|
||||
</a>
|
||||
</footer>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
657
gui-src/js/bbox.js
Normal file
@@ -0,0 +1,657 @@
|
||||
var map, rsidebar, lsidebar, drawControl, drawnItems = null;
|
||||
|
||||
// Where we keep the big list of proj defs from the server
|
||||
var proj4defs = null;
|
||||
// Where we keep the proj objects we are using in this session
|
||||
var projdefs = { "4326": L.CRS.EPSG4326, "3857": L.CRS.EPSG3857 };
|
||||
var currentproj = "3857";
|
||||
var currentmouse = L.latLng(0, 0);
|
||||
|
||||
/*
|
||||
**
|
||||
** override L.Rectangle
|
||||
** to fire an event after setting
|
||||
**
|
||||
** the base parent object L.Path
|
||||
** includes the L.Mixin.Events
|
||||
**
|
||||
** ensures bbox box is always
|
||||
** the topmost SVG feature
|
||||
**
|
||||
*/
|
||||
L.Rectangle.prototype.setBounds = function (latLngBounds) {
|
||||
|
||||
this.setLatLngs(this._boundsToLatLngs(latLngBounds));
|
||||
this.fire('bounds-set');
|
||||
}
|
||||
|
||||
|
||||
var FormatSniffer = (function () { // execute immediately
|
||||
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
**
|
||||
** constructor
|
||||
**
|
||||
*/
|
||||
var FormatSniffer = function (options) {
|
||||
|
||||
options || (options = {});
|
||||
|
||||
if (!this || !(this instanceof FormatSniffer)) {
|
||||
return new FormatSniffer(options);
|
||||
}
|
||||
|
||||
|
||||
this.regExes = {
|
||||
ogrinfoExtent: /Extent\:\s\((.*)\)/,
|
||||
bbox: /^\(([\s|\-|0-9]*\.[0-9]*,[\s|\-|0-9]*\.[0-9]*,[\s|\-|0-9]*\.[0-9]*,[\s|\-|0-9]*\.[0-9|\s]*)\)$/
|
||||
};
|
||||
this.data = options.data || "";
|
||||
this.parse_type = null;
|
||||
};
|
||||
|
||||
/*
|
||||
**
|
||||
** functions
|
||||
**
|
||||
*/
|
||||
FormatSniffer.prototype.sniff = function () {
|
||||
return this._sniffFormat();
|
||||
};
|
||||
|
||||
FormatSniffer.prototype._is_ogrinfo = function () {
|
||||
var match = this.regExes.ogrinfoExtent.exec(this.data.trim());
|
||||
var extent = [];
|
||||
if (match) {
|
||||
var pairs = match[1].split(") - (");
|
||||
for (var indx = 0; indx < pairs.length; indx++) {
|
||||
var coords = pairs[indx].trim().split(",");
|
||||
extent = (extent.concat([parseFloat(coords[0].trim()), parseFloat(coords[1].trim())]));
|
||||
}
|
||||
}
|
||||
this.parse_type = "ogrinfo";
|
||||
return extent;
|
||||
};
|
||||
|
||||
FormatSniffer.prototype._is_normal_bbox = function () {
|
||||
var match = this.regExes.bbox.exec(this.data.trim());
|
||||
var extent = [];
|
||||
if (match) {
|
||||
var bbox = match[1].split(",");
|
||||
for (var indx = 0; indx < bbox.length; indx++) {
|
||||
var coord = bbox[indx].trim();
|
||||
extent = (extent.concat([parseFloat(coord)]));
|
||||
}
|
||||
}
|
||||
this.parse_type = "bbox";
|
||||
return extent;
|
||||
};
|
||||
|
||||
FormatSniffer.prototype._is_geojson = function () {
|
||||
try {
|
||||
// try JSON
|
||||
var json = JSON.parse(this.data);
|
||||
|
||||
// try GeoJSON
|
||||
var parsed_data = new L.geoJson(json)
|
||||
|
||||
} catch (err) {
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
this.parse_type = "geojson";
|
||||
return parsed_data;
|
||||
};
|
||||
|
||||
FormatSniffer.prototype._is_wkt = function () {
|
||||
if (this.data === "") {
|
||||
throw new Error("empty -- nothing to parse");
|
||||
}
|
||||
|
||||
try {
|
||||
var parsed_data = new Wkt.Wkt(this.data);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.parse_type = "wkt";
|
||||
return parsed_data;
|
||||
};
|
||||
|
||||
FormatSniffer.prototype._sniffFormat = function () {
|
||||
|
||||
var parsed_data = null;
|
||||
var fail = false;
|
||||
try {
|
||||
var next = true;
|
||||
|
||||
// try ogrinfo
|
||||
parsed_data = this._is_ogrinfo()
|
||||
if (parsed_data.length > 0) {
|
||||
next = false;
|
||||
}
|
||||
|
||||
// try normal bbox
|
||||
if (next) {
|
||||
parsed_data = this._is_normal_bbox();
|
||||
if (parsed_data.length > 0) next = false;
|
||||
}
|
||||
|
||||
// try GeoJSON
|
||||
if (next) {
|
||||
parsed_data = this._is_geojson();
|
||||
if (parsed_data) next = false;
|
||||
}
|
||||
|
||||
// try WKT
|
||||
if (next) {
|
||||
parsed_data = this._is_wkt();
|
||||
if (parsed_data) next = false;
|
||||
}
|
||||
|
||||
// no matches, throw error
|
||||
if (next) {
|
||||
fail = true;
|
||||
/*
|
||||
** sorry, this block needs to be left aligned
|
||||
** to make the alert more readable
|
||||
** which means, we probably shouldn't use alerts ;-)
|
||||
*/
|
||||
throw {
|
||||
"name": "NoTypeMatchError",
|
||||
"message": "The data is not a recognized format:\n \
|
||||
1. ogrinfo extent output\n \
|
||||
2. bbox as (xMin,yMin,xMax,yMax )\n \
|
||||
3. GeoJSON\n \
|
||||
4. WKT\n\n "
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} catch (err) {
|
||||
|
||||
alert("Your paste is not parsable:\n" + err.message);
|
||||
fail = true;
|
||||
|
||||
}
|
||||
|
||||
// delegate to format handler
|
||||
if (!fail) {
|
||||
|
||||
this._formatHandler[this.parse_type].call(this._formatHandler, parsed_data);
|
||||
|
||||
}
|
||||
|
||||
return (fail ? false : true);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
** an object with functions as property names.
|
||||
** if we need to add another format
|
||||
** we can do so here as a property name
|
||||
** to enforce reusability
|
||||
**
|
||||
** to add different formats as L.FeatureGroup layer
|
||||
** so they work with L.Draw edit and delete options
|
||||
** we fake passing event information
|
||||
** and triggering draw:created for L.Draw
|
||||
*/
|
||||
FormatSniffer.prototype._formatHandler = {
|
||||
|
||||
|
||||
// coerce event objects to work with L.Draw types
|
||||
coerce: function (lyr, type_obj) {
|
||||
|
||||
var event_obj = {
|
||||
layer: lyr,
|
||||
layerType: null,
|
||||
}
|
||||
|
||||
// coerce to L.Draw types
|
||||
if (/point/i.test(type_obj)) {
|
||||
event_obj.layerType = "marker";
|
||||
}
|
||||
else if (/linestring/i.test(type_obj)) {
|
||||
event_obj.layerType = "polyline";
|
||||
}
|
||||
else if (/polygon/i.test(type_obj)) {
|
||||
event_obj.layerType = "polygon";
|
||||
}
|
||||
|
||||
return event_obj;
|
||||
|
||||
},
|
||||
|
||||
reduce_layers: function (lyr) {
|
||||
var lyr_parts = [];
|
||||
if (typeof lyr['getLayers'] === 'undefined') {
|
||||
return [lyr];
|
||||
}
|
||||
else {
|
||||
var all_layers = lyr.getLayers();
|
||||
for (var i = 0; i < all_layers.length; i++) {
|
||||
lyr_parts = lyr_parts.concat(this.reduce_layers(all_layers[i]));
|
||||
}
|
||||
}
|
||||
return lyr_parts;
|
||||
},
|
||||
|
||||
get_leaflet_bounds: function (data) {
|
||||
/*
|
||||
** data comes in an extent ( xMin,yMin,xMax,yMax )
|
||||
** we need to swap lat/lng positions
|
||||
** because leaflet likes it hard
|
||||
*/
|
||||
var sw = [data[1], data[0]];
|
||||
var ne = [data[3], data[2]];
|
||||
return new L.LatLngBounds(sw, ne);
|
||||
},
|
||||
|
||||
wkt: function (data) {
|
||||
var wkt_layer = data.construct[data.type].call(data);
|
||||
var all_layers = this.reduce_layers(wkt_layer);
|
||||
for (var indx = 0; indx < all_layers.length; indx++) {
|
||||
var lyr = all_layers[indx];
|
||||
var evt = this.coerce(lyr, data.type);
|
||||
|
||||
// call L.Draw.Feature.prototype._fireCreatedEvent
|
||||
map.fire('draw:created', evt);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
geojson: function (geojson_layer) {
|
||||
var all_layers = this.reduce_layers(geojson_layer);
|
||||
for (var indx = 0; indx < all_layers.length; indx++) {
|
||||
var lyr = all_layers[indx];
|
||||
|
||||
var geom_type = geojson_layer.getLayers()[0].feature.geometry.type;
|
||||
var evt = this.coerce(lyr, geom_type);
|
||||
|
||||
// call L.Draw.Feature.prototype._fireCreatedEvent
|
||||
map.fire('draw:created', evt);
|
||||
}
|
||||
},
|
||||
|
||||
ogrinfo: function (data) {
|
||||
var lBounds = this.get_leaflet_bounds(data);
|
||||
// create a rectangle layer
|
||||
var lyr = new L.Rectangle(lBounds);
|
||||
var evt = this.coerce(lyr, 'polygon');
|
||||
|
||||
// call L.Draw.Feature.prototype._fireCreatedEvent
|
||||
map.fire('draw:created', evt);
|
||||
},
|
||||
|
||||
bbox: function (data) {
|
||||
var lBounds = this.get_leaflet_bounds(data);
|
||||
// create a rectangle layer
|
||||
var lyr = new L.Rectangle(lBounds);
|
||||
var evt = this.coerce(lyr, 'polygon');
|
||||
|
||||
// call L.Draw.Feature.prototype._fireCreatedEvent
|
||||
map.fire('draw:created', evt);
|
||||
}
|
||||
};
|
||||
|
||||
return FormatSniffer; // return class def
|
||||
|
||||
})(); // end FormatSniffer
|
||||
|
||||
|
||||
function addLayer(layer, name, title, zIndex, on) {
|
||||
if (on) {
|
||||
layer.setZIndex(zIndex).addTo(map);
|
||||
} else {
|
||||
layer.setZIndex(zIndex);
|
||||
}
|
||||
// Create a simple layer switcher that toggles layers on and off.
|
||||
var ui = document.getElementById('map-ui');
|
||||
var item = document.createElement('li');
|
||||
var link = document.createElement('a');
|
||||
link.href = '#';
|
||||
if (on) {
|
||||
link.className = 'enabled';
|
||||
} else {
|
||||
link.className = '';
|
||||
}
|
||||
link.innerHTML = name;
|
||||
link.title = title;
|
||||
link.onclick = function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
if (map.hasLayer(layer)) {
|
||||
map.removeLayer(layer);
|
||||
this.className = '';
|
||||
} else {
|
||||
map.addLayer(layer);
|
||||
this.className = 'enabled';
|
||||
}
|
||||
};
|
||||
item.appendChild(link);
|
||||
ui.appendChild(item);
|
||||
};
|
||||
|
||||
function formatBounds(bounds, proj) {
|
||||
var gdal = $("input[name='gdal-checkbox']").prop('checked');
|
||||
var lngLat = $("input[name='coord-order']").prop('checked');
|
||||
|
||||
var formattedBounds = '';
|
||||
var southwest = bounds.getSouthWest();
|
||||
var northeast = bounds.getNorthEast();
|
||||
var xmin = 0;
|
||||
var ymin = 0;
|
||||
var xmax = 0;
|
||||
var ymax = 0;
|
||||
if (proj == '4326') {
|
||||
xmin = southwest.lng.toFixed(6);
|
||||
ymin = southwest.lat.toFixed(6);
|
||||
xmax = northeast.lng.toFixed(6);
|
||||
ymax = northeast.lat.toFixed(6);
|
||||
} else {
|
||||
var proj_to_use = null;
|
||||
if (typeof (projdefs[proj]) !== 'undefined') {
|
||||
// we have it already, then grab it and use it...
|
||||
proj_to_use = projdefs[proj];
|
||||
} else {
|
||||
// We have not used this one yet... make it and store it...
|
||||
projdefs[proj] = new L.Proj.CRS(proj, proj4defs[proj][1]);
|
||||
proj_to_use = projdefs[proj];
|
||||
}
|
||||
southwest = proj_to_use.project(southwest)
|
||||
northeast = proj_to_use.project(northeast)
|
||||
xmin = southwest.x.toFixed(4);
|
||||
ymin = southwest.y.toFixed(4);
|
||||
xmax = northeast.x.toFixed(4);
|
||||
ymax = northeast.y.toFixed(4);
|
||||
}
|
||||
|
||||
if (gdal) {
|
||||
if (lngLat) {
|
||||
formattedBounds = xmin + ',' + ymin + ',' + xmax + ',' + ymax;
|
||||
} else {
|
||||
formattedBounds = ymin + ',' + xmin + ',' + ymax + ',' + xmax;
|
||||
}
|
||||
} else {
|
||||
if (lngLat) {
|
||||
formattedBounds = xmin + ' ' + ymin + ' ' + xmax + ' ' + ymax;
|
||||
} else {
|
||||
formattedBounds = ymin + ' ' + xmin + ' ' + ymax + ' ' + xmax;
|
||||
}
|
||||
}
|
||||
return formattedBounds
|
||||
}
|
||||
|
||||
function formatTile(point, zoom) {
|
||||
var xTile = Math.floor((point.lng + 180) / 360 * Math.pow(2, zoom));
|
||||
var yTile = Math.floor((1 - Math.log(Math.tan(point.lat * Math.PI / 180) + 1 / Math.cos(point.lat * Math.PI / 180)) / Math.PI) / 2 * Math.pow(2, zoom));
|
||||
return xTile.toString() + ',' + yTile.toString();
|
||||
}
|
||||
|
||||
function formatPoint(point, proj) {
|
||||
var gdal = $("input[name='gdal-checkbox']").prop('checked');
|
||||
var lngLat = $("input[name='coord-order']").prop('checked');
|
||||
|
||||
var formattedPoint = '';
|
||||
if (proj == '4326') {
|
||||
x = point.lng.toFixed(6);
|
||||
y = point.lat.toFixed(6);
|
||||
} else {
|
||||
var proj_to_use = null;
|
||||
if (typeof (projdefs[proj]) !== 'undefined') {
|
||||
// we have it already, then grab it and use it...
|
||||
proj_to_use = projdefs[proj];
|
||||
} else {
|
||||
// We have not used this one yet... make it and store it...
|
||||
projdefs[proj] = new L.Proj.CRS(proj, proj4defs[proj][1]);
|
||||
proj_to_use = projdefs[proj];
|
||||
}
|
||||
point = proj_to_use.project(point)
|
||||
x = point.x.toFixed(4);
|
||||
y = point.y.toFixed(4);
|
||||
}
|
||||
if (gdal) {
|
||||
if (lngLat) {
|
||||
formattedBounds = x + ',' + y;
|
||||
} else {
|
||||
formattedBounds = y + ',' + x;
|
||||
}
|
||||
} else {
|
||||
if (lngLat) {
|
||||
formattedBounds = x + ' ' + y;
|
||||
} else {
|
||||
formattedBounds = y + ' ' + x;
|
||||
}
|
||||
}
|
||||
return formattedBounds
|
||||
}
|
||||
|
||||
function validateStringAsBounds(bounds) {
|
||||
var splitBounds = bounds ? bounds.split(',') : null;
|
||||
return ((splitBounds !== null) &&
|
||||
(splitBounds.length == 4) &&
|
||||
((-90.0 <= parseFloat(splitBounds[0]) <= 90.0) &&
|
||||
(-180.0 <= parseFloat(splitBounds[1]) <= 180.0) &&
|
||||
(-90.0 <= parseFloat(splitBounds[2]) <= 90.0) &&
|
||||
(-180.0 <= parseFloat(splitBounds[3]) <= 180.0)) &&
|
||||
(parseFloat(splitBounds[0]) < parseFloat(splitBounds[2]) &&
|
||||
parseFloat(splitBounds[1]) < parseFloat(splitBounds[3])))
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
/*
|
||||
**
|
||||
** make sure all textarea inputs
|
||||
** are selected once they are clicked
|
||||
** because some people might not
|
||||
** have flash enabled or installed
|
||||
** and yes...
|
||||
** there's a fucking Flash movie floating
|
||||
** on top of your DOM
|
||||
**
|
||||
*/
|
||||
$('input[type="textarea"]').on('click', function (evt) { this.select() });
|
||||
|
||||
// Have to init the projection input box as it is used to format the initial values
|
||||
$("#projection").val(currentproj);
|
||||
|
||||
L.mapbox.accessToken = 'pk.eyJ1IjoiY3Vnb3MiLCJhIjoiY2p4Nm43MzA3MDFmZDQwcGxsMjB4Z3hnNiJ9.SQbnMASwdqZe6G4n6OMvVw';
|
||||
map = L.mapbox.map('map').setView([50.114768, 8.687322], 4).addLayer(L.mapbox.styleLayer('mapbox://styles/mapbox/streets-v11'));
|
||||
|
||||
rsidebar = L.control.sidebar('rsidebar', {
|
||||
position: 'right',
|
||||
closeButton: true
|
||||
});
|
||||
rsidebar.on("sidebar-show", function (e) {
|
||||
$("#map .leaflet-tile-loaded").addClass("blurred");
|
||||
});
|
||||
rsidebar.on("sidebar-hide", function (e) {
|
||||
$('#map .leaflet-tile-loaded').removeClass('blurred');
|
||||
$('#map .leaflet-tile-loaded').addClass('unblurred');
|
||||
setTimeout(function () {
|
||||
$('#map .leaflet-tile-loaded').removeClass('unblurred');
|
||||
}, 7000);
|
||||
});
|
||||
|
||||
map.addControl(rsidebar);
|
||||
|
||||
lsidebar = L.control.sidebar('lsidebar', {
|
||||
position: 'left'
|
||||
});
|
||||
|
||||
map.addControl(lsidebar);
|
||||
|
||||
// Add in a crosshair for the map
|
||||
var crosshairIcon = L.icon({
|
||||
iconUrl: 'images/crosshair.png',
|
||||
iconSize: [20, 20], // size of the icon
|
||||
iconAnchor: [10, 10], // point of the icon which will correspond to marker's location
|
||||
});
|
||||
crosshair = new L.marker(map.getCenter(), { icon: crosshairIcon, clickable: false });
|
||||
crosshair.addTo(map);
|
||||
|
||||
// Initialize the FeatureGroup to store editable layers
|
||||
drawnItems = new L.FeatureGroup();
|
||||
map.addLayer(drawnItems);
|
||||
|
||||
// Initialize the draw control and pass it the FeatureGroup of editable layers
|
||||
drawControl = new L.Control.Draw({
|
||||
edit: {
|
||||
featureGroup: drawnItems
|
||||
},
|
||||
draw: {
|
||||
polyline: false,
|
||||
polygon: false,
|
||||
circle: false,
|
||||
marker: false
|
||||
}
|
||||
});
|
||||
map.addControl(drawControl);
|
||||
|
||||
/*
|
||||
**
|
||||
** create bounds layer
|
||||
** and default it at first
|
||||
** to draw on null island
|
||||
** so it's not seen onload
|
||||
**
|
||||
*/
|
||||
startBounds = new L.LatLngBounds([0.0, 0.0], [0.0, 0.0]);
|
||||
var bounds = new L.Rectangle(startBounds,
|
||||
{
|
||||
fill: false,
|
||||
opacity: 1.0,
|
||||
color: '#000'
|
||||
}
|
||||
);
|
||||
bounds.on('bounds-set', function (e) {
|
||||
// move it to the end of the parent
|
||||
var parent = e.target._renderer._container.parentElement;
|
||||
$(parent).append(e.target._renderer._container);
|
||||
// Set the hash
|
||||
var southwest = this.getBounds().getSouthWest();
|
||||
var northeast = this.getBounds().getNorthEast();
|
||||
var xmin = southwest.lng.toFixed(6);
|
||||
var ymin = southwest.lat.toFixed(6);
|
||||
var xmax = northeast.lng.toFixed(6);
|
||||
var ymax = northeast.lat.toFixed(6);
|
||||
location.hash = ymin + ',' + xmin + ',' + ymax + ',' + xmax;
|
||||
});
|
||||
map.addLayer(bounds)
|
||||
map.on('draw:created', function (e) {
|
||||
drawnItems.addLayer(e.layer);
|
||||
bounds.setBounds(drawnItems.getBounds())
|
||||
$('#boxbounds').text(formatBounds(bounds.getBounds(), '4326'));
|
||||
$('#boxboundsmerc').text(formatBounds(bounds.getBounds(), currentproj));
|
||||
notifyBboxUpdate();
|
||||
if (!e.geojson &&
|
||||
!((drawnItems.getLayers().length == 1) && (drawnItems.getLayers()[0] instanceof L.Marker))) {
|
||||
map.fitBounds(bounds.getBounds());
|
||||
} else {
|
||||
if ((drawnItems.getLayers().length == 1) && (drawnItems.getLayers()[0] instanceof L.Marker)) {
|
||||
map.panTo(drawnItems.getLayers()[0].getLatLng());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
map.on('draw:deleted', function (e) {
|
||||
e.layers.eachLayer(function (l) {
|
||||
drawnItems.removeLayer(l);
|
||||
});
|
||||
if (drawnItems.getLayers().length > 0 &&
|
||||
!((drawnItems.getLayers().length == 1) && (drawnItems.getLayers()[0] instanceof L.Marker))) {
|
||||
bounds.setBounds(drawnItems.getBounds())
|
||||
$('#boxbounds').text(formatBounds(bounds.getBounds(), '4326'));
|
||||
$('#boxboundsmerc').text(formatBounds(bounds.getBounds(), currentproj));
|
||||
notifyBboxUpdate();
|
||||
map.fitBounds(bounds.getBounds());
|
||||
} else {
|
||||
bounds.setBounds(new L.LatLngBounds([0.0, 0.0], [0.0, 0.0]));
|
||||
$('#boxbounds').text(formatBounds(bounds.getBounds(), '4326'));
|
||||
$('#boxboundsmerc').text(formatBounds(bounds.getBounds(), currentproj));
|
||||
notifyBboxUpdate();
|
||||
if (drawnItems.getLayers().length == 1) {
|
||||
map.panTo(drawnItems.getLayers()[0].getLatLng());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
map.on('draw:edited', function (e) {
|
||||
bounds.setBounds(drawnItems.getBounds())
|
||||
$('#boxbounds').text(formatBounds(bounds.getBounds(), '4326'));
|
||||
$('#boxboundsmerc').text(formatBounds(bounds.getBounds(), currentproj));
|
||||
notifyBboxUpdate();
|
||||
map.fitBounds(bounds.getBounds());
|
||||
});
|
||||
|
||||
function display() {
|
||||
$('#boxbounds').text(formatBounds(bounds.getBounds(), '4326'));
|
||||
$('#boxboundsmerc').text(formatBounds(bounds.getBounds(), currentproj));
|
||||
notifyBboxUpdate();
|
||||
}
|
||||
display();
|
||||
|
||||
map.on('move', function (e) {
|
||||
crosshair.setLatLng(map.getCenter());
|
||||
});
|
||||
|
||||
// handle geolocation click events
|
||||
$('#geolocation').click(function () {
|
||||
map.locate({ setView: true, maxZoom: 8 });
|
||||
$('#geolocation a').toggleClass('active');
|
||||
$('#geolocation a').toggleClass('active', 350);
|
||||
});
|
||||
|
||||
|
||||
|
||||
$('button#add').on('click', function (evt) {
|
||||
var sniffer = FormatSniffer({ data: $('div#rsidebar textarea').val() });
|
||||
var is_valid = sniffer.sniff();
|
||||
if (is_valid) {
|
||||
rsidebar.hide();
|
||||
$('#create-geojson a').toggleClass('enabled');
|
||||
map.fitBounds(bounds.getBounds());
|
||||
}
|
||||
});
|
||||
$('button#clear').on('click', function (evt) {
|
||||
$('div#rsidebar textarea').val('');
|
||||
});
|
||||
|
||||
var initialBBox = location.hash ? location.hash.replace(/^#/, '') : null;
|
||||
if (initialBBox) {
|
||||
if (validateStringAsBounds(initialBBox)) {
|
||||
var splitBounds = initialBBox.split(',');
|
||||
startBounds = new L.LatLngBounds([splitBounds[0], splitBounds[1]],
|
||||
[splitBounds[2], splitBounds[3]]);
|
||||
var lyr = new L.Rectangle(startBounds);
|
||||
var evt = {
|
||||
layer: lyr,
|
||||
layerType: "polygon",
|
||||
}
|
||||
map.fire('draw:created', evt);
|
||||
//map.fitBounds(bounds.getBounds());
|
||||
} else {
|
||||
// This will reset the hash if the original hash was not valid
|
||||
bounds.setBounds(bounds.getBounds());
|
||||
}
|
||||
} else {
|
||||
// Initially set the hash if there was not one set by the user
|
||||
bounds.setBounds(bounds.getBounds());
|
||||
}
|
||||
|
||||
$("input").click(function (e) {
|
||||
display();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function notifyBboxUpdate() {
|
||||
const bboxText = document.getElementById('boxbounds').textContent;
|
||||
window.parent.postMessage({ bboxText: bboxText }, '*');
|
||||
}
|
||||
9597
gui-src/js/libs/jquery-1.9.1.js
vendored
Normal file
5
gui-src/js/libs/jquery-1.9.1.min.js
vendored
Normal file
14971
gui-src/js/libs/jquery-ui-1.10.3.custom.js
vendored
Normal file
7
gui-src/js/libs/jquery-ui-1.10.3.custom.min.js
vendored
Normal file
170
gui-src/js/main.js
Normal file
@@ -0,0 +1,170 @@
|
||||
const { invoke } = window.__TAURI__.core;
|
||||
|
||||
// Initialize elements and start the demo progress
|
||||
window.addEventListener("DOMContentLoaded", async () => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
document.getElementById("current-year").textContent = currentYear;
|
||||
|
||||
// Update displayed version
|
||||
try {
|
||||
const version = await invoke('gui_get_version');
|
||||
const footerLink = document.querySelector(".footer-link");
|
||||
footerLink.textContent = `© ${currentYear} Arnis v${version} by louis-e`;
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch version:", error);
|
||||
}
|
||||
|
||||
// Check for updates
|
||||
try {
|
||||
const isUpdateAvailable = await invoke('gui_check_for_updates');
|
||||
if (isUpdateAvailable) {
|
||||
const footer = document.querySelector(".footer");
|
||||
const updateMessage = document.createElement("a");
|
||||
updateMessage.href = "https://github.com/louis-e/arnis/releases";
|
||||
updateMessage.target = "_blank";
|
||||
updateMessage.style.color = "#fecc44";
|
||||
updateMessage.style.marginTop = "-5px";
|
||||
updateMessage.style.fontSize = "0.95em";
|
||||
updateMessage.style.display = "block";
|
||||
updateMessage.style.textDecoration = "none";
|
||||
|
||||
updateMessage.textContent = "There's a new version available! Click here to download it.";
|
||||
footer.style.marginTop = "15px";
|
||||
footer.appendChild(updateMessage);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to check for updates: ", error);
|
||||
}
|
||||
|
||||
// Register bbox update event for iframe map
|
||||
window.addEventListener('message', function (event) {
|
||||
const bboxText = event.data.bboxText;
|
||||
|
||||
if (bboxText) {
|
||||
console.log("Updated BBOX Coordinates:", bboxText);
|
||||
displayBboxInfoText(bboxText);
|
||||
}
|
||||
});
|
||||
|
||||
window.pickDirectory = pickDirectory;
|
||||
window.startGeneration = startGeneration;
|
||||
|
||||
const progressBar = document.getElementById("progress-bar");
|
||||
const progressMessage = document.getElementById("progress-message");
|
||||
const progressDetail = document.getElementById("progress-detail");
|
||||
|
||||
// Listen for progress-update events
|
||||
window.__TAURI__.event.listen("progress-update", (event) => {
|
||||
const { progress, message } = event.payload;
|
||||
|
||||
if (progress != -1) {
|
||||
progressBar.style.width = `${progress}%`;
|
||||
progressDetail.textContent = `${Math.round(progress)}%`;
|
||||
}
|
||||
|
||||
if (message != "") {
|
||||
progressMessage.textContent = message;
|
||||
|
||||
if (message.startsWith("Error!")) {
|
||||
progressMessage.style.color = "#fa7878";
|
||||
} else {
|
||||
progressMessage.style.color = "";
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Function to calculate the bounding box "size" in square meters based on latitude and longitude
|
||||
function calculateBBoxSize(lng1, lat1, lng2, lat2) {
|
||||
// Approximate distance calculation using Haversine formula or geodesic formula
|
||||
const toRad = (angle) => (angle * Math.PI) / 180;
|
||||
const R = 6371000; // Earth radius in meters
|
||||
|
||||
const latDistance = toRad(lat2 - lat1);
|
||||
const lngDistance = toRad(lng2 - lng1);
|
||||
|
||||
const a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2) +
|
||||
Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) *
|
||||
Math.sin(lngDistance / 2) * Math.sin(lngDistance / 2);
|
||||
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
|
||||
// Width and height of the box
|
||||
const height = R * latDistance;
|
||||
const width = R * lngDistance;
|
||||
|
||||
return Math.abs(width * height);
|
||||
}
|
||||
|
||||
const threshold1 = 12332660.00;
|
||||
const threshold2 = 36084700.00;
|
||||
let selectedBBox = "";
|
||||
|
||||
// Function to handle incoming bbox data
|
||||
function displayBboxInfoText(bboxText) {
|
||||
selectedBBox = bboxText;
|
||||
|
||||
const [lng1, lat1, lng2, lat2] = bboxText.split(" ").map(Number);
|
||||
const bboxInfo = document.getElementById("bbox-info");
|
||||
|
||||
// Reset the info text if the bbox is 0,0,0,0
|
||||
if (lng1 === 0 && lat1 === 0 && lng2 === 0 && lat2 === 0) {
|
||||
bboxInfo.textContent = "";
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the size of the selected bbox
|
||||
const selectedSize = calculateBBoxSize(lng1, lat1, lng2, lat2);
|
||||
|
||||
if (selectedSize > threshold2) {
|
||||
bboxInfo.textContent = "This area is very large and could exceed typical computing limits.";
|
||||
bboxInfo.style.color = "#fa7878";
|
||||
} else if (selectedSize > threshold1) {
|
||||
bboxInfo.textContent = "The area is quite extensive and may take significant time and resources.";
|
||||
bboxInfo.style.color = "#fecc44";
|
||||
} else {
|
||||
bboxInfo.textContent = "Selection confirmed!";
|
||||
bboxInfo.style.color = "#7bd864";
|
||||
}
|
||||
}
|
||||
|
||||
let worldPath = "";
|
||||
|
||||
async function pickDirectory() {
|
||||
try {
|
||||
const worldName = await invoke('gui_pick_directory');
|
||||
if (worldName) {
|
||||
worldPath = worldName;
|
||||
const lastSegment = worldName.split(/[\\/]/).pop();
|
||||
document.getElementById('selected-world').textContent = lastSegment;
|
||||
document.getElementById('selected-world').style.color = "#fecc44";
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
document.getElementById('selected-world').textContent = error;
|
||||
document.getElementById('selected-world').style.color = "#fa7878";
|
||||
}
|
||||
}
|
||||
|
||||
async function startGeneration() {
|
||||
try {
|
||||
if (worldPath === "No world selected" || worldPath == "Invalid Minecraft world" || worldPath === "") {
|
||||
document.getElementById('selected-world').textContent = "Select a Minecraft world first!";
|
||||
document.getElementById('selected-world').style.color = "#fa7878";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selectedBBox || selectedBBox == "0.000000 0.000000 0.000000 0.000000") {
|
||||
document.getElementById('bbox-info').textContent = "Select a location firsta using the rectangle tool!";
|
||||
document.getElementById('bbox-info').style.color = "#fa7878";
|
||||
return;
|
||||
}
|
||||
|
||||
// Pass the bounding box and selected world to the Rust backend
|
||||
await invoke("gui_start_generation", { bboxText: selectedBBox, selectedWorld: worldPath });
|
||||
|
||||
// Update the UI or show a loading/progress message if needed
|
||||
console.log("Generation process started.");
|
||||
} catch (error) {
|
||||
console.error("Error starting generation:", error);
|
||||
}
|
||||
}
|
||||
9180
gui-src/js/maps/leaflet-src.js
Normal file
2766
gui-src/js/maps/leaflet.draw-src.js
vendored
Normal file
10
gui-src/js/maps/leaflet.draw.js
Normal file
9
gui-src/js/maps/leaflet.js
Normal file
122
gui-src/js/maps/leaflet.sidebar.js
Normal file
@@ -0,0 +1,122 @@
|
||||
L.Control.Sidebar = L.Control.extend({
|
||||
includes: L.Mixin.Events,
|
||||
|
||||
options: {
|
||||
closeButton: true,
|
||||
position: 'left'
|
||||
},
|
||||
|
||||
initialize: function (placeholder, options) {
|
||||
L.setOptions(this, options);
|
||||
|
||||
// Find content container
|
||||
var content = this._contentContainer = L.DomUtil.get(placeholder);
|
||||
|
||||
// Remove the content container from its original parent
|
||||
content.parentNode.removeChild(content);
|
||||
|
||||
// Make sure we don't drag the map when we interact with the content
|
||||
var stop = L.DomEvent.stopPropagation;
|
||||
L.DomEvent
|
||||
.on(content, 'click', stop)
|
||||
.on(content, 'mousedown', stop)
|
||||
.on(content, 'touchstart', stop)
|
||||
.on(content, 'dblclick', stop)
|
||||
.on(content, 'mousewheel', stop)
|
||||
.on(content, 'MozMousePixelScroll', stop);
|
||||
},
|
||||
|
||||
addTo: function (map) {
|
||||
var sidebar = this;
|
||||
var l = 'leaflet-';
|
||||
|
||||
// Create sidebar container
|
||||
var container = this._container =
|
||||
L.DomUtil.create('div', l + 'sidebar ' + this.options.position);
|
||||
|
||||
// Style and attach content container
|
||||
var content = this._contentContainer;
|
||||
L.DomUtil.addClass(content, l + 'control');
|
||||
container.appendChild(content);
|
||||
|
||||
// Create close button and attach it if configured
|
||||
if (this.options.closeButton) {
|
||||
var close = L.DomUtil.create('a', 'close', container);
|
||||
close.innerHTML = '×';
|
||||
|
||||
L.DomEvent.on(close, 'click', function (e) {
|
||||
sidebar.hide();
|
||||
L.DomEvent.stopPropagation(e);
|
||||
});
|
||||
}
|
||||
|
||||
// Attach sidebar container to controls container
|
||||
var controlContainer = map._controlContainer;
|
||||
controlContainer.insertBefore(container, controlContainer.firstChild);
|
||||
|
||||
this._map = map;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
removeFrom: function (map) {
|
||||
// Remove sidebar container from controls container
|
||||
var controlContainer = map._controlContainer;
|
||||
controlContainer.removeChild(this._container);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
isVisible: function () {
|
||||
return L.DomUtil.hasClass(this._container, 'visible');
|
||||
},
|
||||
|
||||
show: function () {
|
||||
if (!this.isVisible()) {
|
||||
L.DomUtil.addClass(this._container, 'visible');
|
||||
//this._map.panBy([-this.getOffset() / 2, 0], {
|
||||
// duration: 0.5
|
||||
//});
|
||||
this.fire("sidebar-show");
|
||||
}
|
||||
},
|
||||
|
||||
hide: function () {
|
||||
if (this.isVisible()) {
|
||||
L.DomUtil.removeClass(this._container, 'visible');
|
||||
//this._map.panBy([this.getOffset() / 2, 0], {
|
||||
// duration: 0.5
|
||||
//});
|
||||
this.fire("sidebar-hide");
|
||||
}
|
||||
},
|
||||
|
||||
toggle: function () {
|
||||
if (this.isVisible()) {
|
||||
this.hide();
|
||||
} else {
|
||||
this.show();
|
||||
}
|
||||
},
|
||||
|
||||
getContainer: function () {
|
||||
return this._contentContainer;
|
||||
},
|
||||
|
||||
setContent: function (content) {
|
||||
this.getContainer().innerHTML = content;
|
||||
return this;
|
||||
},
|
||||
|
||||
getOffset: function () {
|
||||
if (this.options.position === 'right') {
|
||||
return -this._container.offsetWidth;
|
||||
} else {
|
||||
return this._container.offsetWidth;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
L.control.sidebar = function (placeholder, options) {
|
||||
return new L.Control.Sidebar(placeholder, options);
|
||||
};
|
||||
3
gui-src/js/maps/mapbox.standalone.js
Normal file
66
gui-src/js/maps/mapbox.v3.2.0.js
Normal file
5733
gui-src/js/maps/proj4-src.js
Normal file
3
gui-src/js/maps/proj4.js
Normal file
227
gui-src/js/maps/proj4leaflet.js
Normal file
@@ -0,0 +1,227 @@
|
||||
(function (factory) {
|
||||
var L, proj4;
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD
|
||||
define(['leaflet', 'proj4'], factory);
|
||||
} else if (typeof module !== 'undefined') {
|
||||
// Node/CommonJS
|
||||
L = require('leaflet');
|
||||
proj4 = require('proj4');
|
||||
module.exports = factory(L, proj4);
|
||||
} else {
|
||||
// Browser globals
|
||||
if (typeof window.L === 'undefined' || typeof window.proj4 === 'undefined')
|
||||
throw "Leaflet and proj4 must be loaded first";
|
||||
factory(window.L, window.proj4);
|
||||
}
|
||||
}(function (L, proj4) {
|
||||
|
||||
L.Proj = {};
|
||||
|
||||
L.Proj._isProj4Obj = function(a) {
|
||||
return (typeof a['inverse'] !== 'undefined'
|
||||
&& typeof a['forward'] !== 'undefined');
|
||||
};
|
||||
|
||||
L.Proj.ScaleDependantTransformation = function(scaleTransforms) {
|
||||
this.scaleTransforms = scaleTransforms;
|
||||
}
|
||||
|
||||
L.Proj.ScaleDependantTransformation.prototype.transform = function(point, scale) {
|
||||
return this.scaleTransforms[scale].transform(point, scale);
|
||||
};
|
||||
|
||||
L.Proj.ScaleDependantTransformation.prototype.untransform = function(point, scale) {
|
||||
return this.scaleTransforms[scale].untransform(point, scale);
|
||||
};
|
||||
|
||||
L.Proj.Projection = L.Class.extend({
|
||||
initialize: function(a, def) {
|
||||
if (L.Proj._isProj4Obj(a)) {
|
||||
this._proj = a;
|
||||
} else {
|
||||
var code = a;
|
||||
if (def) {
|
||||
proj4.defs(code, def);
|
||||
} else if (proj4.defs[code] === undefined) {
|
||||
var urn = code.split(':');
|
||||
if (urn.length > 3)
|
||||
code = urn[urn.length - 3] + ':' + urn[urn.length - 1];
|
||||
if (proj4.defs[code] === undefined)
|
||||
throw "No projection definition for code " + code;
|
||||
}
|
||||
this._proj = proj4(code);
|
||||
}
|
||||
},
|
||||
|
||||
project: function (latlng) {
|
||||
var point = this._proj.forward([latlng.lng, latlng.lat]);
|
||||
return new L.Point(point[0], point[1]);
|
||||
},
|
||||
|
||||
unproject: function (point, unbounded) {
|
||||
var point2 = this._proj.inverse([point.x, point.y]);
|
||||
return new L.LatLng(point2[1], point2[0], unbounded);
|
||||
}
|
||||
});
|
||||
|
||||
L.Proj.CRS = L.Class.extend({
|
||||
includes: L.CRS,
|
||||
|
||||
options: {
|
||||
transformation: new L.Transformation(1, 0, -1, 0)
|
||||
},
|
||||
|
||||
initialize: function(a, b, c) {
|
||||
var code, proj, def, options;
|
||||
|
||||
if (L.Proj._isProj4Obj(a)) {
|
||||
proj = a;
|
||||
code = proj.srsCode;
|
||||
options = b || {};
|
||||
|
||||
this.projection = new L.Proj.Projection(proj);
|
||||
} else {
|
||||
code = a;
|
||||
def = b;
|
||||
options = c || {};
|
||||
this.projection = new L.Proj.Projection(code, def);
|
||||
}
|
||||
|
||||
L.Util.setOptions(this, options);
|
||||
this.code = code;
|
||||
this.transformation = this.options.transformation;
|
||||
|
||||
if (this.options.origin) {
|
||||
this.transformation =
|
||||
new L.Transformation(1, -this.options.origin[0],
|
||||
-1, this.options.origin[1]);
|
||||
}
|
||||
|
||||
if (this.options.scales) {
|
||||
this.scale = function(zoom) {
|
||||
return this.options.scales[zoom];
|
||||
}
|
||||
} else if (this.options.resolutions) {
|
||||
this.scale = function(zoom) {
|
||||
return 1 / this.options.resolutions[zoom];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
L.Proj.CRS.TMS = L.Proj.CRS.extend({
|
||||
initialize: function(a, b, c, d) {
|
||||
if (L.Proj._isProj4Obj(a)) {
|
||||
var proj = a,
|
||||
projectedBounds = b,
|
||||
options = c || {};
|
||||
options.origin = [projectedBounds[0], projectedBounds[3]];
|
||||
L.Proj.CRS.prototype.initialize.call(this, proj, options);
|
||||
} else {
|
||||
var code = a,
|
||||
def = b,
|
||||
projectedBounds = c,
|
||||
options = d || {};
|
||||
options.origin = [projectedBounds[0], projectedBounds[3]];
|
||||
L.Proj.CRS.prototype.initialize.call(this, code, def, options);
|
||||
}
|
||||
|
||||
this.projectedBounds = projectedBounds;
|
||||
}
|
||||
});
|
||||
|
||||
L.Proj.TileLayer = {};
|
||||
|
||||
L.Proj.TileLayer.TMS = L.TileLayer.extend({
|
||||
options: {
|
||||
tms: true,
|
||||
continuousWorld: true
|
||||
},
|
||||
|
||||
initialize: function(urlTemplate, crs, options) {
|
||||
var boundsMatchesGrid = true,
|
||||
scaleTransforms,
|
||||
upperY,
|
||||
crsBounds;
|
||||
|
||||
if (!(crs instanceof L.Proj.CRS.TMS)) {
|
||||
throw new Error("CRS is not L.Proj.CRS.TMS.");
|
||||
}
|
||||
|
||||
L.TileLayer.prototype.initialize.call(this, urlTemplate, options);
|
||||
this.crs = crs;
|
||||
crsBounds = this.crs.projectedBounds;
|
||||
|
||||
// Verify grid alignment
|
||||
for (var i = this.options.minZoom; i < this.options.maxZoom && boundsMatchesGrid; i++) {
|
||||
var gridHeight = (crsBounds[3] - crsBounds[1]) /
|
||||
this._projectedTileSize(i);
|
||||
boundsMatchesGrid = Math.abs(gridHeight - Math.round(gridHeight)) > 1e-3;
|
||||
}
|
||||
|
||||
if (!boundsMatchesGrid) {
|
||||
scaleTransforms = {};
|
||||
for (var i = this.options.minZoom; i < this.options.maxZoom; i++) {
|
||||
upperY = crsBounds[1] + Math.ceil((crsBounds[3] - crsBounds[1]) /
|
||||
this._projectedTileSize(i)) * this._projectedTileSize(i);
|
||||
scaleTransforms[this.crs.scale(i)] = new L.Transformation(1, -crsBounds[0], -1, upperY);
|
||||
}
|
||||
|
||||
this.crs = new L.Proj.CRS.TMS(this.crs.projection._proj, crsBounds, this.crs.options);
|
||||
this.crs.transformation = new L.Proj.ScaleDependantTransformation(scaleTransforms);
|
||||
}
|
||||
},
|
||||
|
||||
getTileUrl: function(tilePoint, zoom) {
|
||||
var gridHeight = Math.ceil(
|
||||
(this.crs.projectedBounds[3] - this.crs.projectedBounds[1]) /
|
||||
this._projectedTileSize(zoom)
|
||||
);
|
||||
|
||||
return L.Util.template(this._url, L.Util.extend({
|
||||
s: this._getSubdomain(tilePoint),
|
||||
z: zoom,
|
||||
x: tilePoint.x,
|
||||
y: gridHeight - tilePoint.y - 1
|
||||
}, this.options));
|
||||
},
|
||||
|
||||
_projectedTileSize: function(zoom) {
|
||||
return (this.options.tileSize / this.crs.scale(zoom));
|
||||
}
|
||||
});
|
||||
|
||||
L.Proj.GeoJSON = L.GeoJSON.extend({
|
||||
initialize: function(geojson, options) {
|
||||
if (geojson.crs && geojson.crs.type == 'name') {
|
||||
var crs = new L.Proj.CRS(geojson.crs.properties.name)
|
||||
options = options || {};
|
||||
options.coordsToLatLng = function(coords) {
|
||||
var point = L.point(coords[0], coords[1]);
|
||||
return crs.projection.unproject(point);
|
||||
};
|
||||
}
|
||||
L.GeoJSON.prototype.initialize.call(this, geojson, options);
|
||||
}
|
||||
});
|
||||
|
||||
L.Proj.geoJson = function(geojson, options) {
|
||||
return new L.Proj.GeoJSON(geojson, options);
|
||||
};
|
||||
|
||||
if (typeof L.CRS !== 'undefined') {
|
||||
// This is left here for backwards compatibility
|
||||
L.CRS.proj4js = (function () {
|
||||
return function (code, def, transformation, options) {
|
||||
options = options || {};
|
||||
if (transformation) options.transformation = transformation;
|
||||
|
||||
return new L.Proj.CRS(code, def, options);
|
||||
};
|
||||
}());
|
||||
}
|
||||
|
||||
return L.Proj;
|
||||
|
||||
}));
|
||||
158
gui-src/js/maps/test.runner.js
Normal file
@@ -0,0 +1,158 @@
|
||||
(function( definition ) { // execute immeidately
|
||||
|
||||
if ( typeof module !== 'undefined' &&
|
||||
typeof module.exports !== 'undefined' ) {
|
||||
module.exports = definition();
|
||||
}
|
||||
else if ( typeof window === "object" ) {
|
||||
// example run syntax: BBOX_T( { 'url' : '/js/maps/testdata.js' } );
|
||||
window.BBOX_T = definition();
|
||||
}
|
||||
|
||||
|
||||
})( function() {
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
**
|
||||
** constructor
|
||||
**
|
||||
*/
|
||||
var TestRunner = function( options ) {
|
||||
options || ( options = {} );
|
||||
|
||||
if( !this || !(this instanceof TestRunner )){
|
||||
return new TestRunner( options );
|
||||
}
|
||||
|
||||
this.test_url = options.url || "";
|
||||
|
||||
this.global_setup(); // execute immediately
|
||||
};
|
||||
|
||||
/*
|
||||
**
|
||||
** functions
|
||||
**
|
||||
*/
|
||||
TestRunner.prototype.global_setup = function() {
|
||||
|
||||
var self = this; // hold ref to instance
|
||||
|
||||
$.ajax({
|
||||
'url' : this.test_url ,
|
||||
'dataType' : 'json'
|
||||
})
|
||||
.done( function( json_data ) {
|
||||
self.run_this_mother.call( self, json_data );
|
||||
})
|
||||
.fail( function( error ) {
|
||||
console.log( "The test data didn't load: ", error );
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
TestRunner.prototype.single_setup = function() {
|
||||
this.get_layer_count();
|
||||
};
|
||||
|
||||
TestRunner.prototype.tear_down = function() {
|
||||
if( this._draw_delete_handler ){
|
||||
this._draw_delete_handler.off('draw:deleted');
|
||||
}
|
||||
};
|
||||
|
||||
TestRunner.prototype.run_this_mother = function( json_data ) {
|
||||
for( var key in json_data ){
|
||||
console.log( "[ RUNNING ]: test " + json_data[key]['type'] + "->" + "simple=" + json_data[key]['simple'] );
|
||||
var data = json_data[key]['data'];
|
||||
if( json_data[key]['type'] === 'geojson' ) {
|
||||
data = JSON.stringify( data );
|
||||
}
|
||||
|
||||
/*
|
||||
** run different tests
|
||||
** the context here is jQuery, so change
|
||||
** to reference the instance
|
||||
*/
|
||||
this.single_setup();
|
||||
|
||||
this.test_parsing( data, json_data );
|
||||
this.test_add2map( json_data );
|
||||
this.test_deletable( json_data );
|
||||
|
||||
this.tear_down();
|
||||
}
|
||||
};
|
||||
|
||||
TestRunner.prototype.test_deletable = function(identifier){ // TODO: this needs work
|
||||
var toolbar = null;
|
||||
// get the right toolbar, depending on attributes
|
||||
for( var key in drawControl._toolbars ){
|
||||
var tbar = drawControl._toolbars[key];
|
||||
if ( !(tbar instanceof L.EditToolbar ) ){
|
||||
continue;
|
||||
}
|
||||
|
||||
toolbar = tbar; // set the right one;
|
||||
}
|
||||
|
||||
// create delete handler that makes sure things are deleted
|
||||
this._draw_delete_handler = map.on('draw:deleted', function (e) {
|
||||
try {
|
||||
e.layers.eachLayer(function (l) {
|
||||
drawnItems.removeLayer(l);
|
||||
});
|
||||
console.warn( "[ PASSED ]: test_deletable" );
|
||||
}
|
||||
catch ( err ) {
|
||||
console.error( "[ DELETE TEST FAIL ]: ", err.message, identifier );
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// loop through this toolbars featureGroup, delete layers
|
||||
if ( !toolbar._activeMode ) {
|
||||
toolbar._modes['remove'].button.click(); // enable deletable
|
||||
}
|
||||
for( var indx in toolbar.options['featureGroup']._layers ) {
|
||||
try {
|
||||
var lyr = toolbar.options['featureGroup']._layers[indx];
|
||||
lyr.fire( 'click' ); // triggers delete
|
||||
}
|
||||
catch ( err ){
|
||||
console.error( "[ DELETE TEST FAIL ]: ", err.message, identifier );
|
||||
}
|
||||
}
|
||||
// WTF?
|
||||
$('a[title="Save changes."]')[0].click(); // disable deletable
|
||||
|
||||
};
|
||||
|
||||
TestRunner.prototype.test_add2map = function(identifier){
|
||||
var current_num = Object.keys( map._layers ).length;
|
||||
if( current_num <= this.num_layers_before_parse ){
|
||||
console.error( "[ ADD2MAP TEST FAIL ]: ", identifier );
|
||||
}
|
||||
else {
|
||||
console.warn( "[ PASSED ]: test_add2map" );
|
||||
}
|
||||
};
|
||||
|
||||
TestRunner.prototype.get_layer_count = function(){
|
||||
this.num_layers_before_parse = Object.keys( map._layers ).length;
|
||||
};
|
||||
|
||||
TestRunner.prototype.test_parsing = function( data, identifier ){
|
||||
var is_valid = FormatSniffer( { data : data } ).sniff();
|
||||
if ( !is_valid ) {
|
||||
console.error( "[ PARSE TEST FAIL ]: ", identifier );
|
||||
}
|
||||
else {
|
||||
console.warn( "[ PASSED ]: test_parsing" );
|
||||
}
|
||||
};
|
||||
|
||||
return TestRunner; // return class def
|
||||
|
||||
});
|
||||
549
gui-src/js/maps/wkt.parser.js
Normal file
@@ -0,0 +1,549 @@
|
||||
/*
|
||||
**
|
||||
** taking only necessary pieces from
|
||||
** https://raw.github.com/arthur-e/Wicket/master/wicket.src.js
|
||||
**
|
||||
*/
|
||||
var Wkt = (function () { // Execute function immediately
|
||||
var beginsWith, endsWith;
|
||||
|
||||
/**
|
||||
* Returns true if the substring is found at the beginning of the string.
|
||||
* @param str {String} The String to search
|
||||
* @param sub {String} The substring of interest
|
||||
* @return {Boolean}
|
||||
* @private
|
||||
*/
|
||||
beginsWith = function (str, sub) {
|
||||
return str.substring(0, sub.length) === sub;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the substring is found at the end of the string.
|
||||
* @param str {String} The String to search
|
||||
* @param sub {String} The substring of interest
|
||||
* @return {Boolean}
|
||||
* @private
|
||||
*/
|
||||
endsWith = function (str, sub) {
|
||||
return str.substring(str.length - sub.length) === sub;
|
||||
};
|
||||
|
||||
return {
|
||||
/**
|
||||
* The default delimiter for separating components of atomic geometry (coordinates)
|
||||
* @ignore
|
||||
*/
|
||||
delimiter: ' ',
|
||||
|
||||
/**
|
||||
* Determines whether or not the passed Object is an Array.
|
||||
* @param obj {Object} The Object in question
|
||||
* @return {Boolean}
|
||||
* @member Wkt.isArray
|
||||
* @method
|
||||
*/
|
||||
isArray: function (obj) {
|
||||
return !!(obj && obj.constructor === Array);
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes given character String(s) from a String.
|
||||
* @param str {String} The String to search
|
||||
* @param sub {String} The String character(s) to trim
|
||||
* @return {String} The trimmed string
|
||||
* @member Wkt.trim
|
||||
* @method
|
||||
*/
|
||||
trim: function (str, sub) {
|
||||
sub = sub || ' '; // Defaults to trimming spaces
|
||||
// Trim beginning spaces
|
||||
while (beginsWith(str, sub)) {
|
||||
str = str.substring(1);
|
||||
}
|
||||
// Trim ending spaces
|
||||
while (endsWith(str, sub)) {
|
||||
str = str.substring(0, str.length - 1);
|
||||
}
|
||||
return str;
|
||||
},
|
||||
|
||||
/**
|
||||
* An object for reading WKT strings and writing geographic features
|
||||
* @constructor Wkt.Wkt
|
||||
* @param initializer {String} An optional WKT string for immediate read
|
||||
* @property {Array} components - Holder for atomic geometry objects (internal representation of geometric components)
|
||||
* @property {String} delimiter - The default delimiter for separating components of atomic geometry (coordinates)
|
||||
* @property {Object} regExes - Some regular expressions copied from OpenLayers.Format.WKT.js
|
||||
* @property {String} type - The Well-Known Text name (e.g. 'point') of the geometry
|
||||
* @property {Boolean} wrapVerticies - True to wrap vertices in MULTIPOINT geometries; If true: MULTIPOINT((30 10),(10 30),(40 40)); If false: MULTIPOINT(30 10,10 30,40 40)
|
||||
* @return {Wkt.Wkt}
|
||||
* @memberof Wkt
|
||||
*/
|
||||
Wkt: function (initializer) {
|
||||
|
||||
/**
|
||||
* The default delimiter between X and Y coordinates.
|
||||
* @ignore
|
||||
*/
|
||||
this.delimiter = Wkt.delimiter;
|
||||
|
||||
/**
|
||||
* Configuration parameter for controlling how Wicket seralizes
|
||||
* MULTIPOINT strings. Examples; both are valid WKT:
|
||||
* If true: MULTIPOINT((30 10),(10 30),(40 40))
|
||||
* If false: MULTIPOINT(30 10,10 30,40 40)
|
||||
* @ignore
|
||||
*/
|
||||
this.wrapVertices = true;
|
||||
|
||||
/**
|
||||
* Some regular expressions copied from OpenLayers.Format.WKT.js
|
||||
* @ignore
|
||||
*/
|
||||
this.regExes = {
|
||||
'typeStr': /^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/,
|
||||
'spaces': /\s+|\+/, // Matches the '+' or the empty space
|
||||
'numeric': /-*\d+(\.*\d+)?/,
|
||||
'comma': /\s*,\s*/,
|
||||
'parenComma': /\)\s*,\s*\(/,
|
||||
'coord': /-*\d+\.*\d+ -*\d+\.*\d+/, // e.g. "24 -14"
|
||||
'doubleParenComma': /\)\s*\)\s*,\s*\(\s*\(/,
|
||||
'trimParens': /^\s*\(?(.*?)\)?\s*$/
|
||||
};
|
||||
|
||||
/**
|
||||
* The internal representation of geometry--the "components" of geometry.
|
||||
* @ignore
|
||||
*/
|
||||
this.components = undefined;
|
||||
|
||||
// An initial WKT string may be provided
|
||||
if (initializer && typeof initializer === 'string') {
|
||||
this.read(initializer);
|
||||
} else if (initializer && typeof initializer !== undefined) {
|
||||
this.fromObject(initializer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}());
|
||||
|
||||
/**
|
||||
* Returns true if the internal geometry is a collection of geometries.
|
||||
* @return {Boolean} Returns true when it is a collection
|
||||
* @memberof Wkt.Wkt
|
||||
* @method
|
||||
*/
|
||||
Wkt.Wkt.prototype.isCollection = function () {
|
||||
switch (this.type.slice(0, 5)) {
|
||||
case 'multi':
|
||||
// Trivial; any multi-geometry is a collection
|
||||
return true;
|
||||
case 'polyg':
|
||||
// Polygons with holes are "collections" of rings
|
||||
return true;
|
||||
default:
|
||||
// Any other geometry is not a collection
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Compares two x,y coordinates for equality.
|
||||
* @param a {Object} An object with x and y properties
|
||||
* @param b {Object} An object with x and y properties
|
||||
* @return {Boolean}
|
||||
* @memberof Wkt.Wkt
|
||||
* @method
|
||||
*/
|
||||
Wkt.Wkt.prototype.sameCoords = function (a, b) {
|
||||
return (a.x === b.x && a.y === b.y);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets internal geometry (components) from framework geometry (e.g.
|
||||
* Google Polygon objects or google.maps.Polygon).
|
||||
* @param obj {Object} The framework-dependent geometry representation
|
||||
* @return {Wkt.Wkt} The object itself
|
||||
* @memberof Wkt.Wkt
|
||||
* @method
|
||||
*/
|
||||
Wkt.Wkt.prototype.fromObject = function (obj) {
|
||||
var result = this.deconstruct.call(this, obj);
|
||||
this.components = result.components;
|
||||
this.isRectangle = result.isRectangle || false;
|
||||
this.type = result.type;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates external geometry objects based on a plug-in framework's
|
||||
* construction methods and available geometry classes.
|
||||
* @param config {Object} An optional framework-dependent properties specification
|
||||
* @return {Object} The framework-dependent geometry representation
|
||||
* @memberof Wkt.Wkt
|
||||
* @method
|
||||
*/
|
||||
Wkt.Wkt.prototype.toObject = function (config) {
|
||||
return this.construct[this.type].call(this, config);
|
||||
};
|
||||
|
||||
/**
|
||||
* Absorbs the geometry of another Wkt.Wkt instance, merging it with its own,
|
||||
* creating a collection (MULTI-geometry) based on their types, which must agree.
|
||||
* For example, creates a MULTIPOLYGON from a POLYGON type merged with another
|
||||
<<<<<<< HEAD
|
||||
* POLYGON type.
|
||||
=======
|
||||
* POLYGON type, or adds a POLYGON instance to a MULTIPOLYGON instance.
|
||||
>>>>>>> dev
|
||||
* @memberof Wkt.Wkt
|
||||
* @method
|
||||
*/
|
||||
Wkt.Wkt.prototype.merge = function (wkt) {
|
||||
var prefix = this.type.slice(0, 5);
|
||||
|
||||
if (this.type !== wkt.type) {
|
||||
if (this.type.slice(5, this.type.length) !== wkt.type) {
|
||||
throw TypeError('The input geometry types must agree or the calling Wkt.Wkt instance must be a multigeometry of the other');
|
||||
}
|
||||
}
|
||||
|
||||
switch (prefix) {
|
||||
|
||||
case 'point':
|
||||
this.components = [this.components.concat(wkt.components)];
|
||||
break;
|
||||
|
||||
case 'multi':
|
||||
this.components = this.components.concat((wkt.type.slice(0, 5) === 'multi') ? wkt.components : [wkt.components]);
|
||||
break;
|
||||
|
||||
default:
|
||||
this.components = [
|
||||
this.components,
|
||||
wkt.components
|
||||
]
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (prefix !== 'multi') {
|
||||
this.type = 'multi' + this.type;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reads a WKT string, validating and incorporating it.
|
||||
* @param wkt {String} A WKT string
|
||||
* @return {Array} An Array of internal geometry objects
|
||||
* @memberof Wkt.Wkt
|
||||
* @method
|
||||
*/
|
||||
Wkt.Wkt.prototype.read = function (wkt) {
|
||||
var matches;
|
||||
matches = this.regExes.typeStr.exec(wkt);
|
||||
if (matches) {
|
||||
this.type = matches[1].toLowerCase();
|
||||
this.base = matches[2];
|
||||
if (this.ingest[this.type]) {
|
||||
this.components = this.ingest[this.type].apply(this, [this.base]);
|
||||
}
|
||||
} else {
|
||||
console.log("Invalid WKT string provided to read()");
|
||||
throw {
|
||||
name: "WKTError",
|
||||
message: "Invalid WKT string provided to read()"
|
||||
};
|
||||
}
|
||||
return this.components;
|
||||
}; // eo readWkt
|
||||
|
||||
|
||||
/**
|
||||
* This object contains functions as property names that ingest WKT
|
||||
* strings into the internal representation.
|
||||
* @memberof Wkt.Wkt
|
||||
* @namespace Wkt.Wkt.ingest
|
||||
* @instance
|
||||
*/
|
||||
Wkt.Wkt.prototype.ingest = {
|
||||
|
||||
/**
|
||||
* Return point feature given a point WKT fragment.
|
||||
* @param str {String} A WKT fragment representing the point
|
||||
* @memberof Wkt.Wkt.ingest
|
||||
* @instance
|
||||
*/
|
||||
point: function (str) {
|
||||
var coords = Wkt.trim(str).split(this.regExes.spaces);
|
||||
// In case a parenthetical group of coordinates is passed...
|
||||
return [{ // ...Search for numeric substrings
|
||||
x: parseFloat(this.regExes.numeric.exec(coords[0])[0]),
|
||||
y: parseFloat(this.regExes.numeric.exec(coords[1])[0])
|
||||
}];
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a multipoint feature given a multipoint WKT fragment.
|
||||
* @param str {String} A WKT fragment representing the multipoint
|
||||
* @memberof Wkt.Wkt.ingest
|
||||
* @instance
|
||||
*/
|
||||
multipoint: function (str) {
|
||||
var i, components, points;
|
||||
components = [];
|
||||
points = Wkt.trim(str).split(this.regExes.comma);
|
||||
for (i = 0; i < points.length; i += 1) {
|
||||
components.push(this.ingest.point.apply(this, [points[i]]));
|
||||
}
|
||||
return components;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a linestring feature given a linestring WKT fragment.
|
||||
* @param str {String} A WKT fragment representing the linestring
|
||||
* @memberof Wkt.Wkt.ingest
|
||||
* @instance
|
||||
*/
|
||||
linestring: function (str) {
|
||||
var i, multipoints, components;
|
||||
|
||||
// In our x-and-y representation of components, parsing
|
||||
// multipoints is the same as parsing linestrings
|
||||
multipoints = this.ingest.multipoint.apply(this, [str]);
|
||||
|
||||
// However, the points need to be joined
|
||||
components = [];
|
||||
for (i = 0; i < multipoints.length; i += 1) {
|
||||
components = components.concat(multipoints[i]);
|
||||
}
|
||||
return components;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a multilinestring feature given a multilinestring WKT fragment.
|
||||
* @param str {String} A WKT fragment representing the multilinestring
|
||||
* @memberof Wkt.Wkt.ingest
|
||||
* @instance
|
||||
*/
|
||||
multilinestring: function (str) {
|
||||
var i, components, line, lines;
|
||||
components = [];
|
||||
|
||||
lines = Wkt.trim(str).split(this.regExes.doubleParenComma);
|
||||
if (lines.length === 1) { // If that didn't work...
|
||||
lines = Wkt.trim(str).split(this.regExes.parenComma);
|
||||
}
|
||||
|
||||
for (i = 0; i < lines.length; i += 1) {
|
||||
line = lines[i].replace(this.regExes.trimParens, '$1');
|
||||
components.push(this.ingest.linestring.apply(this, [line]));
|
||||
}
|
||||
|
||||
return components;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a polygon feature given a polygon WKT fragment.
|
||||
* @param str {String} A WKT fragment representing the polygon
|
||||
* @memberof Wkt.Wkt.ingest
|
||||
* @instance
|
||||
*/
|
||||
polygon: function (str) {
|
||||
var i, j, components, subcomponents, ring, rings;
|
||||
rings = Wkt.trim(str).split(this.regExes.parenComma);
|
||||
components = []; // Holds one or more rings
|
||||
for (i = 0; i < rings.length; i += 1) {
|
||||
ring = rings[i].replace(this.regExes.trimParens, '$1').split(this.regExes.comma);
|
||||
subcomponents = []; // Holds the outer ring and any inner rings (holes)
|
||||
for (j = 0; j < ring.length; j += 1) {
|
||||
// Split on the empty space or '+' character (between coordinates)
|
||||
subcomponents.push({
|
||||
x: parseFloat(ring[j].split(this.regExes.spaces)[0]),
|
||||
y: parseFloat(ring[j].split(this.regExes.spaces)[1])
|
||||
});
|
||||
}
|
||||
components.push(subcomponents);
|
||||
}
|
||||
return components;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a multipolygon feature given a multipolygon WKT fragment.
|
||||
* @param str {String} A WKT fragment representing the multipolygon
|
||||
* @memberof Wkt.Wkt.ingest
|
||||
* @instance
|
||||
*/
|
||||
multipolygon: function (str) {
|
||||
var i, components, polygon, polygons;
|
||||
components = [];
|
||||
polygons = Wkt.trim(str).split(this.regExes.doubleParenComma);
|
||||
for (i = 0; i < polygons.length; i += 1) {
|
||||
polygon = polygons[i].replace(this.regExes.trimParens, '$1');
|
||||
components.push(this.ingest.polygon.apply(this, [polygon]));
|
||||
}
|
||||
return components;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return an array of features given a geometrycollection WKT fragment.
|
||||
* @param str {String} A WKT fragment representing the geometry collection
|
||||
* @memberof Wkt.Wkt.ingest
|
||||
* @instance
|
||||
*/
|
||||
geometrycollection: function (str) {
|
||||
console.log('The geometrycollection WKT type is not yet supported.');
|
||||
}
|
||||
|
||||
}; // eo ingest
|
||||
|
||||
/**
|
||||
* @augments Wkt.Wkt
|
||||
* Truncates an Array of coordinates by the closing coordinate when it is
|
||||
* equal to the first coordinate given--this is only to be used for closed
|
||||
* geometries in order to provide merely an "implied" closure to Leaflet.
|
||||
* @param coords {Array} An Array of x,y coordinates (objects)
|
||||
* @return {Array}
|
||||
*/
|
||||
Wkt.Wkt.prototype.trunc = function (coords) {
|
||||
var i, verts = [];
|
||||
|
||||
for (i = 0; i < coords.length; i += 1) {
|
||||
if (Wkt.isArray(coords[i])) {
|
||||
verts.push(this.trunc(coords[i]));
|
||||
|
||||
} else {
|
||||
|
||||
// Add the first coord, but skip the last if it is identical
|
||||
if (i === 0 || !this.sameCoords(coords[0], coords[i])) {
|
||||
verts.push(coords[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return verts;
|
||||
};
|
||||
|
||||
/**
|
||||
* @augments Wkt.Wkt
|
||||
* An object of framework-dependent construction methods used to generate
|
||||
* objects belonging to the various geometry classes of the framework.
|
||||
*/
|
||||
Wkt.Wkt.prototype.construct = {
|
||||
/**
|
||||
* Creates the framework's equivalent point geometry object.
|
||||
* @param config {Object} An optional properties hash the object should use
|
||||
* @param component {Object} An optional component to build from
|
||||
* @return {L.marker}
|
||||
*/
|
||||
point: function (config, component) {
|
||||
var coord = component || this.components;
|
||||
if (coord instanceof Array) {
|
||||
coord = coord[0];
|
||||
}
|
||||
|
||||
return L.marker(this.coordsToLatLng(coord), config);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the framework's equivalent multipoint geometry object.
|
||||
* @param config {Object} An optional properties hash the object should use
|
||||
* @return {L.featureGroup}
|
||||
*/
|
||||
multipoint: function (config) {
|
||||
var i,
|
||||
layers = [],
|
||||
coords = this.components;
|
||||
|
||||
for (i = 0; i < coords.length; i += 1) {
|
||||
layers.push(this.construct.point.call(this, config, coords[i]));
|
||||
}
|
||||
|
||||
return L.featureGroup(layers, config);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the framework's equivalent linestring geometry object.
|
||||
* @param config {Object} An optional properties hash the object should use
|
||||
* @param component {Object} An optional component to build from
|
||||
* @return {L.polyline}
|
||||
*/
|
||||
linestring: function (config, component) {
|
||||
var coords = component || this.components,
|
||||
latlngs = this.coordsToLatLngs(coords);
|
||||
|
||||
return L.polyline(latlngs, config);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the framework's equivalent multilinestring geometry object.
|
||||
* @param config {Object} An optional properties hash the object should use
|
||||
* @return {L.multiPolyline}
|
||||
*/
|
||||
multilinestring: function (config) {
|
||||
var coords = this.components,
|
||||
latlngs = this.coordsToLatLngs(coords, 1);
|
||||
|
||||
return L.multiPolyline(latlngs, config);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the framework's equivalent polygon geometry object.
|
||||
* @param config {Object} An optional properties hash the object should use
|
||||
* @return {L.multiPolygon}
|
||||
*/
|
||||
polygon: function (config) {
|
||||
// Truncate the coordinates to remove the closing coordinate
|
||||
var coords = this.trunc(this.components),
|
||||
latlngs = this.coordsToLatLngs(coords, 1);
|
||||
return L.polygon(latlngs, config);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the framework's equivalent multipolygon geometry object.
|
||||
* @param config {Object} An optional properties hash the object should use
|
||||
* @return {L.multiPolygon}
|
||||
*/
|
||||
multipolygon: function (config) {
|
||||
// Truncate the coordinates to remove the closing coordinate
|
||||
var coords = this.trunc(this.components),
|
||||
latlngs = this.coordsToLatLngs(coords, 2);
|
||||
|
||||
return L.multiPolygon(latlngs, config);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the framework's equivalent collection of geometry objects.
|
||||
* @param config {Object} An optional properties hash the object should use
|
||||
* @return {L.featureGroup}
|
||||
*/
|
||||
geometrycollection: function (config) {
|
||||
var comps, i, layers;
|
||||
|
||||
comps = this.trunc(this.components);
|
||||
layers = [];
|
||||
for (i = 0; i < this.components.length; i += 1) {
|
||||
layers.push(this.construct[comps[i].type].call(this, comps[i]));
|
||||
}
|
||||
|
||||
return L.featureGroup(layers, config);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
L.Util.extend(Wkt.Wkt.prototype, {
|
||||
coordsToLatLngs: L.GeoJSON.coordsToLatLngs,
|
||||
// TODO Why doesn't the coordsToLatLng function in L.GeoJSON already suffice?
|
||||
coordsToLatLng: function (coords, reverse) {
|
||||
var lat = reverse ? coords.x : coords.y,
|
||||
lng = reverse ? coords.y : coords.x;
|
||||
|
||||
return L.latLng(lat, lng, true);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
60
gui-src/maps.html
Normal file
@@ -0,0 +1,60 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Map View</title>
|
||||
|
||||
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
|
||||
|
||||
<link rel="stylesheet" href="css/maps/leaflet.css" />
|
||||
<link rel="stylesheet" href="css/maps/leaflet.draw.css" />
|
||||
<link rel="stylesheet" href="css/maps/leaflet.sidebar.css" />
|
||||
<link rel="stylesheet" href="css/maps/mapbox.v3.2.0.css" />
|
||||
<link rel="stylesheet" href="css/bbox.css" />
|
||||
|
||||
<script src="js/libs/jquery-1.9.1.min.js"></script>
|
||||
<script src="js/libs/jquery-ui-1.10.3.custom.js"></script>
|
||||
<script src="js/maps/leaflet.js"></script>
|
||||
<script src="js/maps/mapbox.v3.2.0.js"></script>
|
||||
<script src="js/maps/leaflet.draw.js"></script>
|
||||
<script src="js/maps/leaflet.sidebar.js"></script>
|
||||
<script src="js/maps/wkt.parser.js"></script>
|
||||
<script src="js/maps/proj4-src.js"></script>
|
||||
<script src="js/maps/proj4leaflet.js"></script>
|
||||
<script src="js/bbox.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<div id="rsidebar" >
|
||||
<button id="add">Add</button>
|
||||
<button id="clear">Clear</button>
|
||||
</div>
|
||||
<div id="lsidebar">
|
||||
</div>
|
||||
|
||||
<section id="info-box">
|
||||
<div id="info">
|
||||
<div id="wgscoords" class="coords">
|
||||
<div id="bbounds">
|
||||
<span id="bbboundslabel" class="bboxlabel">BBOX</span>
|
||||
<span id="boxbounds" class="bboxllpos"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="projcoords" class="coords">
|
||||
<div id="bbounds">
|
||||
<span id="bbboundslabel" class="bboxlabel">BBOX</span>
|
||||
<span id="boxboundsmerc" class="bboxprojpos"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<div id="ocontainer" class="ocontainer" style="display:none;">
|
||||
<textarea rows="25" cols="100" ></textarea>
|
||||
<div id="submit-buttons">
|
||||
<button id="cancel">Cancel</button>
|
||||
<button id="add">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
icons/128x128.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
icons/128x128@2x.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
icons/32x32.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
icons/icon.icns
Normal file
BIN
icons/icon.ico
Normal file
|
After Width: | Height: | Size: 221 KiB |
BIN
icons/icon.png
Normal file
|
After Width: | Height: | Size: 232 KiB |
@@ -145,31 +145,31 @@ impl Block {
|
||||
pub fn properties(&self) -> Option<Value> {
|
||||
match self.id {
|
||||
105 => Some(Value::Compound({
|
||||
let mut map = HashMap::new();
|
||||
let mut map: HashMap<String, Value> = HashMap::new();
|
||||
map.insert("age".to_string(), Value::String("7".to_string()));
|
||||
map
|
||||
})),
|
||||
|
||||
106 => Some(Value::Compound({
|
||||
let mut map = HashMap::new();
|
||||
let mut map: HashMap<String, Value> = HashMap::new();
|
||||
map.insert("half".to_string(), Value::String("lower".to_string()));
|
||||
map
|
||||
})),
|
||||
|
||||
107 => Some(Value::Compound({
|
||||
let mut map = HashMap::new();
|
||||
let mut map: HashMap<String, Value> = HashMap::new();
|
||||
map.insert("half".to_string(), Value::String("upper".to_string()));
|
||||
map
|
||||
})),
|
||||
|
||||
108 => Some(Value::Compound({
|
||||
let mut map = HashMap::new();
|
||||
let mut map: HashMap<String, Value> = HashMap::new();
|
||||
map.insert("age".to_string(), Value::String("7".to_string()));
|
||||
map
|
||||
})),
|
||||
|
||||
109 => Some(Value::Compound({
|
||||
let mut map = HashMap::new();
|
||||
let mut map: HashMap<String, Value> = HashMap::new();
|
||||
map.insert("age".to_string(), Value::String("7".to_string()));
|
||||
map
|
||||
})),
|
||||
|
||||
@@ -19,29 +19,29 @@ pub fn color_text_to_rgb_tuple(text: &str) -> Option<RGBTuple> {
|
||||
fn full_hex_color_to_rgb_tuple(text: &str) -> Option<RGBTuple> {
|
||||
if text.len() != 7
|
||||
|| !text.starts_with("#")
|
||||
|| !text.chars().skip(1).all(|c| c.is_ascii_hexdigit())
|
||||
|| !text.chars().skip(1).all(|c: char| c.is_ascii_hexdigit())
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let r = u8::from_str_radix(&text[1..3], 16).unwrap();
|
||||
let g = u8::from_str_radix(&text[3..5], 16).unwrap();
|
||||
let b = u8::from_str_radix(&text[5..7], 16).unwrap();
|
||||
let r: u8 = u8::from_str_radix(&text[1..3], 16).unwrap();
|
||||
let g: u8 = u8::from_str_radix(&text[3..5], 16).unwrap();
|
||||
let b: u8 = u8::from_str_radix(&text[5..7], 16).unwrap();
|
||||
Some((r, g, b))
|
||||
}
|
||||
|
||||
fn short_hex_color_to_rgb_tuple(text: &str) -> Option<RGBTuple> {
|
||||
if text.len() != 4
|
||||
|| !text.starts_with("#")
|
||||
|| text.chars().skip(1).all(|c| c.is_ascii_hexdigit())
|
||||
|| text.chars().skip(1).all(|c: char| c.is_ascii_hexdigit())
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let r = u8::from_str_radix(&text[1..2], 16).unwrap();
|
||||
let r = r | r << 4;
|
||||
let g = u8::from_str_radix(&text[2..3], 16).unwrap();
|
||||
let g = g | g << 4;
|
||||
let b = u8::from_str_radix(&text[3..4], 16).unwrap();
|
||||
let b = b | b << 4;
|
||||
let r: u8 = u8::from_str_radix(&text[1..2], 16).unwrap();
|
||||
let r: u8 = r | r << 4;
|
||||
let g: u8 = u8::from_str_radix(&text[2..3], 16).unwrap();
|
||||
let g: u8 = g | g << 4;
|
||||
let b: u8 = u8::from_str_radix(&text[3..4], 16).unwrap();
|
||||
let b: u8 = b | b << 4;
|
||||
Some((r, g, b))
|
||||
}
|
||||
|
||||
@@ -78,11 +78,11 @@ fn color_name_to_rgb_tuple(text: &str) -> Option<RGBTuple> {
|
||||
|
||||
pub fn rgb_distance(from: &RGBTuple, to: &RGBTuple) -> u32 {
|
||||
// i32 because .pow(2) returns the same data type as self and 255^2 wouldn't fit
|
||||
let difference = (
|
||||
let difference: (i32, i32, i32) = (
|
||||
from.0 as i32 - to.0 as i32,
|
||||
from.1 as i32 - to.1 as i32,
|
||||
from.2 as i32 - to.2 as i32,
|
||||
);
|
||||
let distance = difference.0.pow(2) + difference.1.pow(2) + difference.2.pow(2);
|
||||
let distance: i32 = difference.0.pow(2) + difference.1.pow(2) + difference.2.pow(2);
|
||||
distance as u32
|
||||
}
|
||||
|
||||
@@ -1,37 +1,45 @@
|
||||
use crate::args::Args;
|
||||
use crate::block_definitions::{BEDROCK, DIRT, GRASS_BLOCK, STONE};
|
||||
use crate::block_definitions::{DIRT, GRASS_BLOCK};
|
||||
use crate::element_processing::*;
|
||||
use crate::osm_parser::ProcessedElement;
|
||||
use crate::progress::emit_gui_progress_update;
|
||||
use crate::world_editor::WorldEditor;
|
||||
use colored::Colorize;
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
|
||||
const MIN_Y: i32 = -64;
|
||||
const MAX_Y: i32 = 256;
|
||||
const GROUND_LEVEL: i32 = 65;
|
||||
const GROUND_LEVEL: i32 = -62;
|
||||
|
||||
pub fn generate_world(
|
||||
elements: Vec<ProcessedElement>,
|
||||
args: &Args,
|
||||
scale_factor_x: f64,
|
||||
scale_factor_z: f64,
|
||||
) {
|
||||
) -> Result<(), String> {
|
||||
println!("{} Processing data...", "[3/5]".bold());
|
||||
emit_gui_progress_update(10.0, "Processing data...");
|
||||
|
||||
let region_dir: String = format!("{}/region", args.path);
|
||||
|
||||
let mut editor: WorldEditor =
|
||||
WorldEditor::new(®ion_dir, scale_factor_x, scale_factor_z, args);
|
||||
|
||||
// Process data
|
||||
let process_pb: ProgressBar = ProgressBar::new(elements.len() as u64);
|
||||
let elements_count: usize = elements.len();
|
||||
let process_pb: ProgressBar = ProgressBar::new(elements_count as u64);
|
||||
process_pb.set_style(ProgressStyle::default_bar()
|
||||
.template("{spinner:.green} [{elapsed_precise}] [{bar:45.white/black}] {pos}/{len} elements ({eta}) {msg}")
|
||||
.unwrap()
|
||||
.progress_chars("█▓░"));
|
||||
|
||||
let progress_increment_prcs: f64 = 50.0 / elements_count as f64;
|
||||
let mut current_progress_prcs: f64 = 10.0;
|
||||
let mut last_emitted_progress: f64 = current_progress_prcs;
|
||||
for element in &elements {
|
||||
process_pb.inc(1);
|
||||
current_progress_prcs += progress_increment_prcs;
|
||||
if (current_progress_prcs - last_emitted_progress).abs() > 0.25 {
|
||||
emit_gui_progress_update(current_progress_prcs, "");
|
||||
last_emitted_progress = current_progress_prcs;
|
||||
}
|
||||
|
||||
if args.debug {
|
||||
process_pb.set_message(format!(
|
||||
@@ -149,6 +157,8 @@ pub fn generate_world(
|
||||
let mut block_counter: u64 = 0;
|
||||
|
||||
println!("{} Generating ground layer...", "[4/5]".bold());
|
||||
emit_gui_progress_update(60.0, "Generating ground layer...");
|
||||
|
||||
let ground_pb: ProgressBar = ProgressBar::new(total_blocks);
|
||||
ground_pb.set_style(
|
||||
ProgressStyle::default_bar()
|
||||
@@ -157,34 +167,26 @@ pub fn generate_world(
|
||||
.progress_chars("█▓░"),
|
||||
);
|
||||
|
||||
let mut gui_progress_grnd: f64 = 60.0;
|
||||
let mut last_emitted_progress: f64 = gui_progress_grnd;
|
||||
let total_iterations_grnd: f64 = (scale_factor_x + 1.0) * (scale_factor_z + 1.0);
|
||||
let progress_increment_grnd: f64 = 30.0 / total_iterations_grnd;
|
||||
|
||||
for x in 0..=(scale_factor_x as i32) {
|
||||
for z in 0..=(scale_factor_z as i32) {
|
||||
// Use the smaller of [current block y, ground level y]
|
||||
let max_y = (MIN_Y..MAX_Y)
|
||||
.find(|y| editor.block_at(x, *y, z))
|
||||
.unwrap_or(MAX_Y)
|
||||
.min(GROUND_LEVEL);
|
||||
|
||||
// 1 layer of grass
|
||||
editor.set_block(GRASS_BLOCK, x, max_y, z, None, None);
|
||||
|
||||
// 3 layers of dirt
|
||||
for y in (max_y - 3)..max_y {
|
||||
editor.set_block(DIRT, x, y, z, None, None);
|
||||
}
|
||||
|
||||
// n - 1 layers of stone
|
||||
for y in (MIN_Y + 1)..(max_y - 3) {
|
||||
editor.set_block(STONE, x, y, z, None, None);
|
||||
}
|
||||
|
||||
// 1 layer of bedrock
|
||||
editor.set_block(BEDROCK, x, MIN_Y, z, None, None);
|
||||
editor.set_block(GRASS_BLOCK, x, GROUND_LEVEL, z, None, None);
|
||||
editor.set_block(DIRT, x, GROUND_LEVEL - 1, z, None, None);
|
||||
|
||||
block_counter += 1;
|
||||
if block_counter % batch_size == 0 {
|
||||
ground_pb.inc(batch_size);
|
||||
}
|
||||
|
||||
gui_progress_grnd += progress_increment_grnd;
|
||||
if (gui_progress_grnd - last_emitted_progress).abs() > 0.25 {
|
||||
emit_gui_progress_update(gui_progress_grnd, "");
|
||||
last_emitted_progress = gui_progress_grnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,5 +196,7 @@ pub fn generate_world(
|
||||
// Save world
|
||||
editor.save();
|
||||
|
||||
println!("{}", "Done! World generation complete.".green().bold());
|
||||
emit_gui_progress_update(100.0, "Done! World generation completed.");
|
||||
println!("{}", "Done! World generation completed.".green().bold());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -26,7 +26,10 @@ pub fn generate_amenities(
|
||||
}
|
||||
|
||||
if let Some(amenity_type) = element.tags().get("amenity") {
|
||||
let first_node = element.nodes().map(|n| (n.x, n.z)).next();
|
||||
let first_node: Option<(i32, i32)> = element
|
||||
.nodes()
|
||||
.map(|n: &crate::osm_parser::ProcessedNode| (n.x, n.z))
|
||||
.next();
|
||||
match amenity_type.as_str() {
|
||||
"waste_disposal" | "waste_basket" => {
|
||||
// Place a cauldron for waste disposal or waste basket
|
||||
@@ -41,10 +44,13 @@ pub fn generate_amenities(
|
||||
}
|
||||
}
|
||||
"bicycle_parking" => {
|
||||
let ground_block = OAK_PLANKS;
|
||||
let roof_block = STONE_BLOCK_SLAB;
|
||||
let ground_block: Block = OAK_PLANKS;
|
||||
let roof_block: Block = STONE_BLOCK_SLAB;
|
||||
|
||||
let polygon_coords: Vec<(i32, i32)> = element.nodes().map(|n| (n.x, n.z)).collect();
|
||||
let polygon_coords: Vec<(i32, i32)> = element
|
||||
.nodes()
|
||||
.map(|n: &crate::osm_parser::ProcessedNode| (n.x, n.z))
|
||||
.collect();
|
||||
let floor_area: Vec<(i32, i32)> =
|
||||
flood_fill_area(&polygon_coords, floodfill_timeout);
|
||||
|
||||
@@ -55,8 +61,8 @@ pub fn generate_amenities(
|
||||
|
||||
// Place fences and roof slabs at each corner node directly
|
||||
for node in element.nodes() {
|
||||
let x = node.x;
|
||||
let z = node.z;
|
||||
let x: i32 = node.x;
|
||||
let z: i32 = node.z;
|
||||
|
||||
for y in 1..=4 {
|
||||
editor.set_block(ground_block, x, ground_level, z, None, None);
|
||||
@@ -98,8 +104,8 @@ pub fn generate_amenities(
|
||||
_ => GRAY_CONCRETE,
|
||||
};
|
||||
for node in element.nodes() {
|
||||
let x = node.x;
|
||||
let z = node.z;
|
||||
let x: i32 = node.x;
|
||||
let z: i32 = node.z;
|
||||
|
||||
if let Some(prev) = previous_node {
|
||||
// Create borders for fountain or parking area
|
||||
|
||||
@@ -28,13 +28,13 @@ pub fn generate_barriers(editor: &mut WorldEditor, element: &ProcessedElement, g
|
||||
|
||||
// Process nodes to create the barrier wall
|
||||
for i in 1..way.nodes.len() {
|
||||
let prev = &way.nodes[i - 1];
|
||||
let x1 = prev.x;
|
||||
let z1 = prev.z;
|
||||
let prev: &crate::osm_parser::ProcessedNode = &way.nodes[i - 1];
|
||||
let x1: i32 = prev.x;
|
||||
let z1: i32 = prev.z;
|
||||
|
||||
let cur = &way.nodes[i];
|
||||
let x2 = cur.x;
|
||||
let z2 = cur.z;
|
||||
let cur: &crate::osm_parser::ProcessedNode = &way.nodes[i];
|
||||
let x2: i32 = cur.x;
|
||||
let z2: i32 = cur.z;
|
||||
|
||||
// Generate the line of coordinates between the two nodes
|
||||
let bresenham_points: Vec<(i32, i32, i32)> =
|
||||
|
||||
@@ -15,27 +15,27 @@ pub fn generate_bridges(editor: &mut WorldEditor, element: &ProcessedWay, ground
|
||||
let total_steps: usize = element
|
||||
.nodes
|
||||
.windows(2)
|
||||
.map(|nodes| {
|
||||
let x1 = nodes[0].x;
|
||||
let z1 = nodes[0].z;
|
||||
let x2 = nodes[1].x;
|
||||
let z2 = nodes[1].z;
|
||||
.map(|nodes: &[crate::osm_parser::ProcessedNode]| {
|
||||
let x1: i32 = nodes[0].x;
|
||||
let z1: i32 = nodes[0].z;
|
||||
let x2: i32 = nodes[1].x;
|
||||
let z2: i32 = nodes[1].z;
|
||||
|
||||
bresenham_line(x1, ground_level, z1, x2, ground_level, z2).len()
|
||||
})
|
||||
.sum();
|
||||
|
||||
let half_steps = total_steps / 2; // Calculate midpoint for descending after rising
|
||||
let mut current_step = 0;
|
||||
let half_steps: usize = total_steps / 2; // Calculate midpoint for descending after rising
|
||||
let mut current_step: usize = 0;
|
||||
|
||||
for i in 1..element.nodes.len() {
|
||||
let prev = &element.nodes[i - 1];
|
||||
let x1 = prev.x;
|
||||
let z1 = prev.z;
|
||||
let prev: &crate::osm_parser::ProcessedNode = &element.nodes[i - 1];
|
||||
let x1: i32 = prev.x;
|
||||
let z1: i32 = prev.z;
|
||||
|
||||
let cur = &element.nodes[i];
|
||||
let x2 = cur.x;
|
||||
let z2 = cur.z;
|
||||
let cur: &crate::osm_parser::ProcessedNode = &element.nodes[i];
|
||||
let x2: i32 = cur.x;
|
||||
let z2: i32 = cur.z;
|
||||
|
||||
// Generate the line of coordinates between the two nodes
|
||||
let bresenham_points: Vec<(i32, i32, i32)> =
|
||||
|
||||
@@ -24,26 +24,28 @@ pub fn generate_buildings(
|
||||
let variation_index_wall: usize = rng.gen_range(0..building_wall_variations().len());
|
||||
let variation_index_floor: usize = rng.gen_range(0..building_floor_variations().len());
|
||||
|
||||
let corner_block = building_corner_variations()[variation_index_corner];
|
||||
let wall_block = element
|
||||
let corner_block: Block = building_corner_variations()[variation_index_corner];
|
||||
let wall_block: Block = element
|
||||
.tags
|
||||
.get("building:colour")
|
||||
.and_then(|building_colour| {
|
||||
color_text_to_rgb_tuple(building_colour)
|
||||
.map(|rgb| find_nearest_block_in_color_map(&rgb, building_wall_color_map()))
|
||||
.and_then(|building_colour: &String| {
|
||||
color_text_to_rgb_tuple(building_colour).map(|rgb: (u8, u8, u8)| {
|
||||
find_nearest_block_in_color_map(&rgb, building_wall_color_map())
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
.unwrap_or_else(|| building_wall_variations()[variation_index_wall]);
|
||||
let floor_block = element
|
||||
let floor_block: Block = element
|
||||
.tags
|
||||
.get("roof:colour")
|
||||
.and_then(|roof_colour| {
|
||||
color_text_to_rgb_tuple(roof_colour)
|
||||
.map(|rgb| find_nearest_block_in_color_map(&rgb, building_floor_color_map()))
|
||||
.and_then(|roof_colour: &String| {
|
||||
color_text_to_rgb_tuple(roof_colour).map(|rgb: (u8, u8, u8)| {
|
||||
find_nearest_block_in_color_map(&rgb, building_floor_color_map())
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
.unwrap_or_else(|| building_floor_variations()[variation_index_floor]);
|
||||
let window_block = WHITE_STAINED_GLASS;
|
||||
let window_block: Block = WHITE_STAINED_GLASS;
|
||||
|
||||
// Set to store processed flood fill points
|
||||
let mut processed_points: HashSet<(i32, i32)> = HashSet::new();
|
||||
@@ -84,11 +86,14 @@ pub fn generate_buildings(
|
||||
building_height = 2;
|
||||
|
||||
if element.tags.contains_key("bicycle_parking") {
|
||||
let ground_block = OAK_PLANKS;
|
||||
let roof_block = STONE_BLOCK_SLAB;
|
||||
let ground_block: Block = OAK_PLANKS;
|
||||
let roof_block: Block = STONE_BLOCK_SLAB;
|
||||
|
||||
let polygon_coords: Vec<(i32, i32)> =
|
||||
element.nodes.iter().map(|n| (n.x, n.z)).collect();
|
||||
let polygon_coords: Vec<(i32, i32)> = element
|
||||
.nodes
|
||||
.iter()
|
||||
.map(|n: &crate::osm_parser::ProcessedNode| (n.x, n.z))
|
||||
.collect();
|
||||
let floor_area: Vec<(i32, i32)> =
|
||||
flood_fill_area(&polygon_coords, floodfill_timeout);
|
||||
|
||||
@@ -99,8 +104,8 @@ pub fn generate_buildings(
|
||||
|
||||
// Place fences and roof slabs at each corner node directly
|
||||
for node in &element.nodes {
|
||||
let x = node.x;
|
||||
let z = node.z;
|
||||
let x: i32 = node.x;
|
||||
let z: i32 = node.z;
|
||||
|
||||
for y in 1..=4 {
|
||||
editor.set_block(ground_block, x, ground_level, z, None, None);
|
||||
@@ -118,12 +123,12 @@ pub fn generate_buildings(
|
||||
return;
|
||||
}
|
||||
} else if building_type == "roof" {
|
||||
let roof_height = ground_level + 5;
|
||||
let roof_height: i32 = ground_level + 5;
|
||||
|
||||
// Iterate through the nodes to create the roof edges using Bresenham's line algorithm
|
||||
for node in &element.nodes {
|
||||
let x = node.x;
|
||||
let z = node.z;
|
||||
let x: i32 = node.x;
|
||||
let z: i32 = node.z;
|
||||
|
||||
if let Some(prev) = previous_node {
|
||||
let bresenham_points: Vec<(i32, i32, i32)> =
|
||||
@@ -142,8 +147,11 @@ pub fn generate_buildings(
|
||||
}
|
||||
|
||||
// Use flood-fill to fill the interior of the roof
|
||||
let polygon_coords: Vec<(i32, i32)> =
|
||||
element.nodes.iter().map(|node| (node.x, node.z)).collect();
|
||||
let polygon_coords: Vec<(i32, i32)> = element
|
||||
.nodes
|
||||
.iter()
|
||||
.map(|node: &crate::osm_parser::ProcessedNode| (node.x, node.z))
|
||||
.collect();
|
||||
let roof_area: Vec<(i32, i32)> = flood_fill_area(&polygon_coords, floodfill_timeout); // Use flood-fill to determine the area
|
||||
|
||||
// Fill the interior of the roof with STONE_BRICK_SLAB
|
||||
@@ -171,8 +179,8 @@ pub fn generate_buildings(
|
||||
|
||||
// Process nodes to create walls and corners
|
||||
for node in &element.nodes {
|
||||
let x = node.x;
|
||||
let z = node.z;
|
||||
let x: i32 = node.x;
|
||||
let z: i32 = node.z;
|
||||
|
||||
if let Some(prev) = previous_node {
|
||||
// Calculate walls and corners using Bresenham line
|
||||
@@ -211,7 +219,11 @@ pub fn generate_buildings(
|
||||
|
||||
// Flood-fill interior with floor variation
|
||||
if corner_addup != (0, 0, 0) {
|
||||
let polygon_coords: Vec<(i32, i32)> = element.nodes.iter().map(|n| (n.x, n.z)).collect();
|
||||
let polygon_coords: Vec<(i32, i32)> = element
|
||||
.nodes
|
||||
.iter()
|
||||
.map(|n: &crate::osm_parser::ProcessedNode| (n.x, n.z))
|
||||
.collect();
|
||||
let floor_area: Vec<(i32, i32)> = flood_fill_area(&polygon_coords, floodfill_timeout);
|
||||
|
||||
for (x, z) in floor_area {
|
||||
@@ -264,21 +276,21 @@ fn generate_bridge(
|
||||
floodfill_timeout: Option<&Duration>,
|
||||
) {
|
||||
// Calculate the bridge level
|
||||
let mut bridge_level = base_level;
|
||||
let mut bridge_level: i32 = base_level;
|
||||
if let Some(level_str) = element.tags.get("level") {
|
||||
if let Ok(level) = level_str.parse::<i32>() {
|
||||
bridge_level += (level * 3) + 1; // Adjust height by levels
|
||||
}
|
||||
}
|
||||
|
||||
let floor_block = STONE;
|
||||
let railing_block = STONE_BRICKS;
|
||||
let floor_block: Block = STONE;
|
||||
let railing_block: Block = STONE_BRICKS;
|
||||
|
||||
// Process the nodes to create bridge pathways and railings
|
||||
let mut previous_node: Option<(i32, i32)> = None;
|
||||
for node in &element.nodes {
|
||||
let x = node.x;
|
||||
let z = node.z;
|
||||
let x: i32 = node.x;
|
||||
let z: i32 = node.z;
|
||||
|
||||
// Create bridge path using Bresenham's line
|
||||
if let Some(prev) = previous_node {
|
||||
@@ -293,7 +305,11 @@ fn generate_bridge(
|
||||
}
|
||||
|
||||
// Flood fill the area between the bridge path nodes
|
||||
let polygon_coords: Vec<(i32, i32)> = element.nodes.iter().map(|n| (n.x, n.z)).collect();
|
||||
let polygon_coords: Vec<(i32, i32)> = element
|
||||
.nodes
|
||||
.iter()
|
||||
.map(|n: &crate::osm_parser::ProcessedNode| (n.x, n.z))
|
||||
.collect();
|
||||
let bridge_area: Vec<(i32, i32)> = flood_fill_area(&polygon_coords, floodfill_timeout);
|
||||
for (x, z) in bridge_area {
|
||||
editor.set_block(floor_block, x, bridge_level, z, None, None);
|
||||
|
||||
@@ -14,8 +14,8 @@ pub fn generate_doors(editor: &mut WorldEditor, element: &ProcessedNode, ground_
|
||||
}
|
||||
}
|
||||
|
||||
let x = element.x;
|
||||
let z = element.z;
|
||||
let x: i32 = element.x;
|
||||
let z: i32 = element.z;
|
||||
|
||||
// Set the ground block and the door blocks
|
||||
editor.set_block(GRAY_CONCRETE, x, ground_level, z, None, None);
|
||||
|
||||
@@ -16,8 +16,8 @@ pub fn generate_highways(
|
||||
if highway_type == "street_lamp" {
|
||||
// Handle street lamps
|
||||
if let ProcessedElement::Node(first_node) = element {
|
||||
let x = first_node.x;
|
||||
let z = first_node.z;
|
||||
let x: i32 = first_node.x;
|
||||
let z: i32 = first_node.z;
|
||||
for y in 1..=4 {
|
||||
editor.set_block(OAK_FENCE, x, ground_level + y, z, None, None);
|
||||
}
|
||||
@@ -28,8 +28,8 @@ pub fn generate_highways(
|
||||
if let Some(crossing_type) = element.tags().get("crossing") {
|
||||
if crossing_type == "traffic_signals" {
|
||||
if let ProcessedElement::Node(node) = element {
|
||||
let x = node.x;
|
||||
let z = node.z;
|
||||
let x: i32 = node.x;
|
||||
let z: i32 = node.z;
|
||||
for y in 1..=3 {
|
||||
editor.set_block(COBBLESTONE_WALL, x, ground_level + y, z, None, None);
|
||||
}
|
||||
@@ -43,8 +43,8 @@ pub fn generate_highways(
|
||||
} else if highway_type == "bus_stop" {
|
||||
// Handle bus stops
|
||||
if let ProcessedElement::Node(node) = element {
|
||||
let x = node.x;
|
||||
let z = node.z;
|
||||
let x: i32 = node.x;
|
||||
let z: i32 = node.z;
|
||||
for y in 1..=3 {
|
||||
editor.set_block(COBBLESTONE_WALL, x, ground_level + y, z, None, None);
|
||||
}
|
||||
@@ -52,13 +52,17 @@ pub fn generate_highways(
|
||||
editor.set_block(WHITE_WOOL, x, ground_level + 4, z, None, None);
|
||||
editor.set_block(WHITE_WOOL, x + 1, ground_level + 4, z, None, None);
|
||||
}
|
||||
} else if element.tags().get("area").map_or(false, |v| v == "yes") {
|
||||
} else if element
|
||||
.tags()
|
||||
.get("area")
|
||||
.map_or(false, |v: &String| v == "yes")
|
||||
{
|
||||
let ProcessedElement::Way(way) = element else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Handle areas like pedestrian plazas
|
||||
let mut surface_block = STONE; // Default block
|
||||
let mut surface_block: Block = STONE; // Default block
|
||||
|
||||
// Determine the block type based on the 'surface' tag
|
||||
if let Some(surface) = element.tags().get("surface") {
|
||||
@@ -77,8 +81,12 @@ pub fn generate_highways(
|
||||
}
|
||||
|
||||
// Fill the area using flood fill or by iterating through the nodes
|
||||
let polygon_coords: Vec<(i32, i32)> = way.nodes.iter().map(|n| (n.x, n.z)).collect();
|
||||
let filled_area = flood_fill_area(&polygon_coords, floodfill_timeout);
|
||||
let polygon_coords: Vec<(i32, i32)> = way
|
||||
.nodes
|
||||
.iter()
|
||||
.map(|n: &crate::osm_parser::ProcessedNode| (n.x, n.z))
|
||||
.collect();
|
||||
let filled_area: Vec<(i32, i32)> = flood_fill_area(&polygon_coords, floodfill_timeout);
|
||||
|
||||
for (x, z) in filled_area {
|
||||
editor.set_block(surface_block, x, ground_level, z, None, None);
|
||||
@@ -144,17 +152,17 @@ pub fn generate_highways(
|
||||
for node in &way.nodes {
|
||||
if let Some(prev) = previous_node {
|
||||
let (x1, z1) = prev;
|
||||
let x2 = node.x;
|
||||
let z2 = node.z;
|
||||
let x2: i32 = node.x;
|
||||
let z2: i32 = node.z;
|
||||
|
||||
// Generate the line of coordinates between the two nodes
|
||||
let bresenham_points: Vec<(i32, i32, i32)> =
|
||||
bresenham_line(x1, ground_level, z1, x2, ground_level, z2);
|
||||
|
||||
// Variables to manage dashed line pattern
|
||||
let mut stripe_length = 0;
|
||||
let dash_length = 5; // Length of the solid part of the stripe
|
||||
let gap_length = 5; // Length of the gap part of the stripe
|
||||
let mut stripe_length: i32 = 0;
|
||||
let dash_length: i32 = 5; // Length of the solid part of the stripe
|
||||
let gap_length: i32 = 5; // Length of the gap part of the stripe
|
||||
|
||||
for (x, _, z) in bresenham_points {
|
||||
// Draw the road surface for the entire width
|
||||
@@ -253,11 +261,11 @@ pub fn generate_highways(
|
||||
/// Generates a siding using stone brick slabs
|
||||
pub fn generate_siding(editor: &mut WorldEditor, element: &ProcessedWay, ground_level: i32) {
|
||||
let mut previous_node: Option<(i32, i32)> = None;
|
||||
let siding_block = STONE_BRICK_SLAB;
|
||||
let siding_block: Block = STONE_BRICK_SLAB;
|
||||
|
||||
for node in &element.nodes {
|
||||
let x = node.x;
|
||||
let z = node.z;
|
||||
let x: i32 = node.x;
|
||||
let z: i32 = node.z;
|
||||
|
||||
// Draw the siding using Bresenham's line algorithm between nodes
|
||||
if let Some(prev) = previous_node {
|
||||
|
||||
@@ -41,8 +41,8 @@ pub fn generate_landuse(
|
||||
|
||||
// Process landuse nodes to fill the area
|
||||
for node in &element.nodes {
|
||||
let x = node.x;
|
||||
let z = node.z;
|
||||
let x: i32 = node.x;
|
||||
let z: i32 = node.z;
|
||||
|
||||
if let Some(prev) = previous_node {
|
||||
// Generate the line of coordinates between the two nodes
|
||||
@@ -166,7 +166,7 @@ pub fn generate_landuse(
|
||||
if random_choice == 20 {
|
||||
create_tree(editor, x, ground_level + 1, z, rng.gen_range(1..=3));
|
||||
} else if random_choice == 2 {
|
||||
let flower_block = match rng.gen_range(1..=4) {
|
||||
let flower_block: Block = match rng.gen_range(1..=4) {
|
||||
1 => RED_FLOWER,
|
||||
2 => BLUE_FLOWER,
|
||||
3 => YELLOW_FLOWER,
|
||||
@@ -198,7 +198,7 @@ pub fn generate_landuse(
|
||||
|
||||
// If a random condition is met, place a special object
|
||||
if rng.gen_range(0..76) == 0 {
|
||||
let special_choice = rng.gen_range(1..=10);
|
||||
let special_choice: i32 = rng.gen_range(1..=10);
|
||||
if special_choice <= 2 {
|
||||
create_tree(
|
||||
editor,
|
||||
@@ -271,7 +271,7 @@ pub fn generate_landuse(
|
||||
);
|
||||
}
|
||||
} else if random_choice < 30 {
|
||||
let construction_items = [
|
||||
let construction_items: [Block; 11] = [
|
||||
OAK_LOG,
|
||||
COBBLESTONE,
|
||||
GRAVEL,
|
||||
|
||||
@@ -20,7 +20,7 @@ pub fn generate_leisure(
|
||||
let mut current_leisure: Vec<(i32, i32)> = vec![];
|
||||
|
||||
// Determine block type based on leisure type
|
||||
let block_type = match leisure_type.as_str() {
|
||||
let block_type: Block = match leisure_type.as_str() {
|
||||
"park" => GRASS_BLOCK,
|
||||
"playground" | "recreation_ground" | "pitch" => {
|
||||
if let Some(surface) = element.tags.get("surface") {
|
||||
@@ -73,8 +73,11 @@ pub fn generate_leisure(
|
||||
|
||||
// Flood-fill the interior of the leisure area
|
||||
if corner_addup != (0, 0, 0) {
|
||||
let polygon_coords: Vec<(i32, i32)> =
|
||||
element.nodes.iter().map(|n| (n.x, n.z)).collect();
|
||||
let polygon_coords: Vec<(i32, i32)> = element
|
||||
.nodes
|
||||
.iter()
|
||||
.map(|n: &crate::osm_parser::ProcessedNode| (n.x, n.z))
|
||||
.collect();
|
||||
let filled_area: Vec<(i32, i32)> = flood_fill_area(&polygon_coords, floodfill_timeout);
|
||||
|
||||
for (x, z) in filled_area {
|
||||
|
||||
@@ -17,8 +17,8 @@ pub fn generate_natural(
|
||||
if let Some(natural_type) = element.tags().get("natural") {
|
||||
if natural_type == "tree" {
|
||||
if let ProcessedElement::Node(node) = element {
|
||||
let x = node.x;
|
||||
let z = node.z;
|
||||
let x: i32 = node.x;
|
||||
let z: i32 = node.z;
|
||||
|
||||
let mut rng: rand::prelude::ThreadRng = rand::thread_rng();
|
||||
create_tree(editor, x, ground_level + 1, z, rng.gen_range(1..=3));
|
||||
@@ -29,7 +29,7 @@ pub fn generate_natural(
|
||||
let mut current_natural: Vec<(i32, i32)> = vec![];
|
||||
|
||||
// Determine block type based on natural tag
|
||||
let block_type = match natural_type.as_str() {
|
||||
let block_type: Block = match natural_type.as_str() {
|
||||
"scrub" | "grassland" | "wood" => GRASS_BLOCK,
|
||||
"beach" | "sand" => SAND,
|
||||
"tree_row" => GRASS_BLOCK,
|
||||
@@ -43,8 +43,8 @@ pub fn generate_natural(
|
||||
|
||||
// Process natural nodes to fill the area
|
||||
for node in &way.nodes {
|
||||
let x = node.x;
|
||||
let z = node.z;
|
||||
let x: i32 = node.x;
|
||||
let z: i32 = node.z;
|
||||
|
||||
if let Some(prev) = previous_node {
|
||||
// Generate the line of coordinates between the two nodes
|
||||
@@ -63,8 +63,11 @@ pub fn generate_natural(
|
||||
|
||||
// If there are natural nodes, flood-fill the area
|
||||
if corner_addup != (0, 0, 0) {
|
||||
let polygon_coords: Vec<(i32, i32)> =
|
||||
way.nodes.iter().map(|n| (n.x, n.z)).collect();
|
||||
let polygon_coords: Vec<(i32, i32)> = way
|
||||
.nodes
|
||||
.iter()
|
||||
.map(|n: &crate::osm_parser::ProcessedNode| (n.x, n.z))
|
||||
.collect();
|
||||
let filled_area: Vec<(i32, i32)> =
|
||||
flood_fill_area(&polygon_coords, floodfill_timeout);
|
||||
|
||||
|
||||
@@ -22,13 +22,13 @@ pub fn generate_railways(editor: &mut WorldEditor, element: &ProcessedWay, groun
|
||||
}
|
||||
|
||||
for i in 1..element.nodes.len() {
|
||||
let prev = &element.nodes[i - 1];
|
||||
let x1 = prev.x;
|
||||
let z1 = prev.z;
|
||||
let prev: &crate::osm_parser::ProcessedNode = &element.nodes[i - 1];
|
||||
let x1: i32 = prev.x;
|
||||
let z1: i32 = prev.z;
|
||||
|
||||
let cur = &element.nodes[i];
|
||||
let x2 = cur.x;
|
||||
let z2 = cur.z;
|
||||
let cur: &crate::osm_parser::ProcessedNode = &element.nodes[i];
|
||||
let x2: i32 = cur.x;
|
||||
let z2: i32 = cur.z;
|
||||
|
||||
// Generate the line of coordinates between the two nodes
|
||||
let bresenham_points: Vec<(i32, i32, i32)> =
|
||||
|
||||
@@ -17,11 +17,11 @@ pub fn generate_tourisms(editor: &mut WorldEditor, element: &ProcessedNode, grou
|
||||
}
|
||||
|
||||
if let Some(tourism_type) = element.tags.get("tourism") {
|
||||
let x = element.x;
|
||||
let z = element.z;
|
||||
let x: i32 = element.x;
|
||||
let z: i32 = element.z;
|
||||
|
||||
if tourism_type == "information" {
|
||||
if let Some("board") = element.tags.get("information").map(|x| x.as_str()) {
|
||||
if let Some("board") = element.tags.get("information").map(|x: &String| x.as_str()) {
|
||||
// TODO draw a sign
|
||||
editor.set_block(OAK_PLANKS, x, ground_level + 1, z, None, None);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ fn round3(editor: &mut WorldEditor, material: Block, x: i32, y: i32, z: i32) {
|
||||
|
||||
/// Function to create different types of trees.
|
||||
pub fn create_tree(editor: &mut WorldEditor, x: i32, y: i32, z: i32, typetree: u8) {
|
||||
let mut blacklist = Vec::new();
|
||||
let mut blacklist: Vec<Block> = Vec::new();
|
||||
blacklist.extend(building_corner_variations());
|
||||
blacklist.extend(building_wall_variations());
|
||||
blacklist.extend(building_floor_variations());
|
||||
|
||||
@@ -22,8 +22,8 @@ pub fn generate_water_areas(
|
||||
}
|
||||
}
|
||||
|
||||
let mut outers = vec![];
|
||||
let mut inners = vec![];
|
||||
let mut outers: Vec<Vec<ProcessedNode>> = vec![];
|
||||
let mut inners: Vec<Vec<ProcessedNode>> = vec![];
|
||||
|
||||
for mem in &element.members {
|
||||
match mem.role {
|
||||
@@ -43,13 +43,21 @@ pub fn generate_water_areas(
|
||||
}
|
||||
|
||||
let (max_x, max_z) = editor.get_max_coords();
|
||||
let outers = outers
|
||||
let outers: Vec<Vec<(f64, f64)>> = outers
|
||||
.iter()
|
||||
.map(|x| x.iter().map(|y| (y.x as f64, y.z as f64)).collect())
|
||||
.map(|x: &Vec<ProcessedNode>| {
|
||||
x.iter()
|
||||
.map(|y: &ProcessedNode| (y.x as f64, y.z as f64))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
let inners = inners
|
||||
let inners: Vec<Vec<(f64, f64)>> = inners
|
||||
.iter()
|
||||
.map(|x| x.iter().map(|y| (y.x as f64, y.z as f64)).collect())
|
||||
.map(|x: &Vec<ProcessedNode>| {
|
||||
x.iter()
|
||||
.map(|y: &ProcessedNode| (y.x as f64, y.z as f64))
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
|
||||
inverse_floodfill(max_x, max_z, outers, inners, editor, ground_level);
|
||||
@@ -57,8 +65,8 @@ pub fn generate_water_areas(
|
||||
|
||||
// Merges ways that share nodes into full loops
|
||||
fn merge_loopy_loops(loops: &mut Vec<Vec<ProcessedNode>>) {
|
||||
let mut removed = vec![];
|
||||
let mut merged = vec![];
|
||||
let mut removed: Vec<usize> = vec![];
|
||||
let mut merged: Vec<Vec<ProcessedNode>> = vec![];
|
||||
|
||||
for i in 0..loops.len() {
|
||||
for j in 0..loops.len() {
|
||||
@@ -70,8 +78,8 @@ fn merge_loopy_loops(loops: &mut Vec<Vec<ProcessedNode>>) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let x = &loops[i];
|
||||
let y = &loops[j];
|
||||
let x: &Vec<ProcessedNode> = &loops[i];
|
||||
let y: &Vec<ProcessedNode> = &loops[j];
|
||||
|
||||
// it's looped already
|
||||
if x[0].id == x.last().unwrap().id {
|
||||
@@ -87,7 +95,7 @@ fn merge_loopy_loops(loops: &mut Vec<Vec<ProcessedNode>>) {
|
||||
removed.push(i);
|
||||
removed.push(j);
|
||||
|
||||
let mut x = x.clone();
|
||||
let mut x: Vec<ProcessedNode> = x.clone();
|
||||
x.reverse();
|
||||
x.extend(y.iter().skip(1).cloned());
|
||||
merged.push(x);
|
||||
@@ -95,7 +103,7 @@ fn merge_loopy_loops(loops: &mut Vec<Vec<ProcessedNode>>) {
|
||||
removed.push(i);
|
||||
removed.push(j);
|
||||
|
||||
let mut x = x.clone();
|
||||
let mut x: Vec<ProcessedNode> = x.clone();
|
||||
x.extend(y.iter().rev().skip(1).cloned());
|
||||
|
||||
merged.push(x);
|
||||
@@ -103,7 +111,7 @@ fn merge_loopy_loops(loops: &mut Vec<Vec<ProcessedNode>>) {
|
||||
removed.push(i);
|
||||
removed.push(j);
|
||||
|
||||
let mut y = y.clone();
|
||||
let mut y: Vec<ProcessedNode> = y.clone();
|
||||
y.extend(x.iter().skip(1).cloned());
|
||||
|
||||
merged.push(y);
|
||||
@@ -117,7 +125,7 @@ fn merge_loopy_loops(loops: &mut Vec<Vec<ProcessedNode>>) {
|
||||
loops.remove(*r);
|
||||
}
|
||||
|
||||
let merged_len = merged.len();
|
||||
let merged_len: usize = merged.len();
|
||||
for m in merged {
|
||||
loops.push(m);
|
||||
}
|
||||
@@ -128,7 +136,7 @@ fn merge_loopy_loops(loops: &mut Vec<Vec<ProcessedNode>>) {
|
||||
}
|
||||
|
||||
fn verify_loopy_loops(loops: &[Vec<ProcessedNode>]) -> bool {
|
||||
let mut valid = true;
|
||||
let mut valid: bool = true;
|
||||
for l in loops {
|
||||
if l[0].id != l.last().unwrap().id {
|
||||
eprintln!("WARN: Disconnected loop");
|
||||
@@ -150,17 +158,17 @@ fn inverse_floodfill(
|
||||
editor: &mut WorldEditor,
|
||||
ground_level: i32,
|
||||
) {
|
||||
let min_x = 0;
|
||||
let min_z = 0;
|
||||
let min_x: i32 = 0;
|
||||
let min_z: i32 = 0;
|
||||
|
||||
let inners: Vec<_> = inners
|
||||
.into_iter()
|
||||
.map(|x| Polygon::new(LineString::from(x), vec![]))
|
||||
.map(|x: Vec<(f64, f64)>| Polygon::new(LineString::from(x), vec![]))
|
||||
.collect();
|
||||
|
||||
let outers: Vec<_> = outers
|
||||
.into_iter()
|
||||
.map(|x| Polygon::new(LineString::from(x), vec![]))
|
||||
.map(|x: Vec<(f64, f64)>| Polygon::new(LineString::from(x), vec![]))
|
||||
.collect();
|
||||
|
||||
inverse_floodfill_recursive(
|
||||
@@ -193,9 +201,9 @@ fn inverse_floodfill_recursive(
|
||||
return;
|
||||
}
|
||||
|
||||
let center_x = (min.0 + max.0) / 2;
|
||||
let center_z = (min.1 + max.1) / 2;
|
||||
let quadrants = [
|
||||
let center_x: i32 = (min.0 + max.0) / 2;
|
||||
let center_z: i32 = (min.1 + max.1) / 2;
|
||||
let quadrants: [(i32, i32, i32, i32); 4] = [
|
||||
(min.0, center_x, min.1, center_z),
|
||||
(center_x, max.0, min.1, center_z),
|
||||
(min.0, center_x, center_z, max.1),
|
||||
@@ -203,13 +211,13 @@ fn inverse_floodfill_recursive(
|
||||
];
|
||||
|
||||
for (min_x, max_x, min_z, max_z) in quadrants {
|
||||
let rect = Rect::new(
|
||||
let rect: Rect = Rect::new(
|
||||
Point::new(min_x as f64, min_z as f64),
|
||||
Point::new(max_x as f64, max_z as f64),
|
||||
);
|
||||
|
||||
if outers.iter().any(|outer| outer.contains(&rect))
|
||||
&& !inners.iter().any(|inner| inner.intersects(&rect))
|
||||
if outers.iter().any(|outer: &Polygon| outer.contains(&rect))
|
||||
&& !inners.iter().any(|inner: &Polygon| inner.intersects(&rect))
|
||||
{
|
||||
// every block in rect is water
|
||||
// so we can safely just set the whole thing to water
|
||||
@@ -223,7 +231,7 @@ fn inverse_floodfill_recursive(
|
||||
// This saves on processing time
|
||||
let outers_intersects: Vec<_> = outers
|
||||
.iter()
|
||||
.filter(|poly| poly.intersects(&rect))
|
||||
.filter(|poly: &&Polygon| poly.intersects(&rect))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
@@ -231,7 +239,7 @@ fn inverse_floodfill_recursive(
|
||||
// I assume it changes how the compiler is able to optimize it
|
||||
let inners_intersects: Vec<_> = inners
|
||||
.iter()
|
||||
.filter(|poly| poly.intersects(&rect))
|
||||
.filter(|poly: &&Polygon| poly.intersects(&rect))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
@@ -261,10 +269,10 @@ fn inverse_floodfill_iterative(
|
||||
) {
|
||||
for x in min.0..max.0 {
|
||||
for z in min.1..max.1 {
|
||||
let p = Point::new(x as f64, z as f64);
|
||||
let p: Point = Point::new(x as f64, z as f64);
|
||||
|
||||
if outers.iter().any(|poly| poly.contains(&p))
|
||||
&& inners.iter().all(|poly| !poly.contains(&p))
|
||||
if outers.iter().any(|poly: &Polygon| poly.contains(&p))
|
||||
&& inners.iter().all(|poly: &Polygon| !poly.contains(&p))
|
||||
{
|
||||
editor.set_block(WATER, x, ground_level, z, None, None);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ pub fn flood_fill_area(
|
||||
return vec![]; // Not a valid polygon
|
||||
}
|
||||
|
||||
let start_time = Instant::now();
|
||||
let start_time: Instant = Instant::now();
|
||||
|
||||
// Calculate bounding box of the polygon using itertools
|
||||
let (min_x, max_x) = polygon_coords
|
||||
@@ -41,8 +41,8 @@ pub fn flood_fill_area(
|
||||
let polygon: Polygon<f64> = Polygon::new(exterior, vec![]); // Create Polygon using LineString
|
||||
|
||||
// Determine safe step sizes for grid sampling
|
||||
let step_x = ((max_x - min_x) / 10).max(1); // Ensure step is at least 1
|
||||
let step_z = ((max_z - min_z) / 10).max(1); // Ensure step is at least 1
|
||||
let step_x: i32 = ((max_x - min_x) / 10).max(1); // Ensure step is at least 1
|
||||
let step_z: i32 = ((max_z - min_z) / 10).max(1); // Ensure step is at least 1
|
||||
|
||||
// Sample multiple starting points within the bounding box
|
||||
let mut candidate_points: VecDeque<(i32, i32)> = VecDeque::new();
|
||||
|
||||
246
src/main.rs
@@ -1,3 +1,5 @@
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
mod args;
|
||||
mod block_definitions;
|
||||
mod bresenham;
|
||||
@@ -6,6 +8,7 @@ mod data_processing;
|
||||
mod element_processing;
|
||||
mod floodfill;
|
||||
mod osm_parser;
|
||||
mod progress;
|
||||
mod retrieve_data;
|
||||
mod version_check;
|
||||
mod world_editor;
|
||||
@@ -13,8 +16,10 @@ mod world_editor;
|
||||
use args::Args;
|
||||
use clap::Parser;
|
||||
use colored::*;
|
||||
use rfd::FileDialog;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::{env, path::PathBuf};
|
||||
|
||||
fn print_banner() {
|
||||
let version: &str = env!("CARGO_PKG_VERSION");
|
||||
@@ -40,58 +45,211 @@ fn print_banner() {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
print_banner();
|
||||
// Parse arguments to decide whether to launch the UI or CLI
|
||||
let raw_args: Vec<String> = std::env::args().collect();
|
||||
|
||||
// Check for updates
|
||||
if let Err(e) = version_check::check_for_updates() {
|
||||
eprintln!(
|
||||
"{}: {}",
|
||||
"Error checking for version updates".red().bold(),
|
||||
e
|
||||
);
|
||||
// Check if either `--help` or `--path` is present to run command-line mode
|
||||
let is_help: bool = raw_args.iter().any(|arg: &String| arg == "--help");
|
||||
let is_path_provided: bool = raw_args
|
||||
.iter()
|
||||
.any(|arg: &String| arg.starts_with("--path"));
|
||||
|
||||
if is_help || is_path_provided {
|
||||
print_banner();
|
||||
|
||||
// Check for updates
|
||||
if let Err(e) = version_check::check_for_updates() {
|
||||
eprintln!(
|
||||
"{}: {}",
|
||||
"Error checking for version updates".red().bold(),
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
// Parse input arguments
|
||||
let args: Args = Args::parse();
|
||||
args.run();
|
||||
|
||||
let bbox: Vec<f64> = args
|
||||
.bbox
|
||||
.as_ref()
|
||||
.expect("Bounding box is required")
|
||||
.split(',')
|
||||
.map(|s: &str| s.parse::<f64>().expect("Invalid bbox coordinate"))
|
||||
.collect::<Vec<f64>>();
|
||||
|
||||
let bbox_tuple: (f64, f64, f64, f64) = (bbox[0], bbox[1], bbox[2], bbox[3]);
|
||||
|
||||
// Fetch data
|
||||
let raw_data: serde_json::Value =
|
||||
retrieve_data::fetch_data(bbox_tuple, args.file.as_deref(), args.debug, "requests")
|
||||
.expect("Failed to fetch data");
|
||||
|
||||
// Parse raw data
|
||||
let (mut parsed_elements, scale_factor_x, scale_factor_z) =
|
||||
osm_parser::parse_osm_data(&raw_data, bbox_tuple, &args);
|
||||
parsed_elements.sort_by_key(|element: &osm_parser::ProcessedElement| {
|
||||
osm_parser::get_priority(element)
|
||||
});
|
||||
|
||||
// Write the parsed OSM data to a file for inspection
|
||||
if args.debug {
|
||||
let mut output_file: File =
|
||||
File::create("parsed_osm_data.txt").expect("Failed to create output file");
|
||||
for element in &parsed_elements {
|
||||
writeln!(
|
||||
output_file,
|
||||
"Element ID: {}, Type: {}, Tags: {:?}",
|
||||
element.id(),
|
||||
element.kind(),
|
||||
element.tags(),
|
||||
)
|
||||
.expect("Failed to write to output file");
|
||||
}
|
||||
}
|
||||
|
||||
// Generate world
|
||||
let _ =
|
||||
data_processing::generate_world(parsed_elements, &args, scale_factor_x, scale_factor_z);
|
||||
} else {
|
||||
// Launch the UI
|
||||
println!("Launching UI...");
|
||||
tauri::Builder::default()
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
gui_pick_directory,
|
||||
gui_start_generation,
|
||||
gui_get_version,
|
||||
gui_check_for_updates
|
||||
])
|
||||
.setup(|app| {
|
||||
let app_handle = app.handle();
|
||||
let main_window = tauri::Manager::get_webview_window(app_handle, "main")
|
||||
.expect("Failed to get main window");
|
||||
progress::set_main_window(main_window);
|
||||
Ok(())
|
||||
})
|
||||
.run(tauri::generate_context!())
|
||||
.expect("Error while starting the application UI (Tauri)");
|
||||
}
|
||||
}
|
||||
|
||||
// Parse input arguments
|
||||
let args: Args = Args::parse();
|
||||
args.run();
|
||||
#[tauri::command]
|
||||
fn gui_pick_directory() -> Result<String, String> {
|
||||
// Determine the default Minecraft 'saves' directory based on the OS
|
||||
let default_dir: Option<PathBuf> = if cfg!(target_os = "windows") {
|
||||
env::var("APPDATA")
|
||||
.ok()
|
||||
.map(|appdata: String| PathBuf::from(appdata).join(".minecraft").join("saves"))
|
||||
} else if cfg!(target_os = "macos") {
|
||||
dirs::home_dir().map(|home: PathBuf| {
|
||||
home.join("Library/Application Support/minecraft")
|
||||
.join("saves")
|
||||
})
|
||||
} else if cfg!(target_os = "linux") {
|
||||
dirs::home_dir().map(|home: PathBuf| home.join(".minecraft").join("saves"))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let bbox: Vec<f64> = args
|
||||
.bbox
|
||||
.as_ref()
|
||||
.expect("Bounding box is required")
|
||||
.split(',')
|
||||
.map(|s: &str| s.parse::<f64>().expect("Invalid bbox coordinate"))
|
||||
.collect::<Vec<f64>>();
|
||||
// Check if the default directory exists
|
||||
let starting_directory: Option<PathBuf> = default_dir.filter(|dir: &PathBuf| dir.exists());
|
||||
|
||||
let bbox_tuple: (f64, f64, f64, f64) = (bbox[0], bbox[1], bbox[2], bbox[3]);
|
||||
// Open the directory picker dialog
|
||||
let dialog: FileDialog = FileDialog::new();
|
||||
let dialog: FileDialog = if let Some(start_dir) = starting_directory {
|
||||
dialog.set_directory(start_dir)
|
||||
} else {
|
||||
dialog
|
||||
};
|
||||
|
||||
// Fetch data
|
||||
let raw_data: serde_json::Value =
|
||||
retrieve_data::fetch_data(bbox_tuple, args.file.as_deref(), args.debug, "requests")
|
||||
.expect("Failed to fetch data");
|
||||
if let Some(path) = dialog.pick_folder() {
|
||||
// Print the full path to the console
|
||||
println!("Selected world path: {}", path.display());
|
||||
|
||||
// Parse raw data
|
||||
let (mut parsed_elements, scale_factor_x, scale_factor_z) =
|
||||
osm_parser::parse_osm_data(&raw_data, bbox_tuple, &args);
|
||||
parsed_elements
|
||||
.sort_by_key(|element: &osm_parser::ProcessedElement| osm_parser::get_priority(element));
|
||||
|
||||
// Write the parsed OSM data to a file for inspection
|
||||
if args.debug {
|
||||
let mut output_file: File =
|
||||
File::create("parsed_osm_data.txt").expect("Failed to create output file");
|
||||
for element in &parsed_elements {
|
||||
writeln!(
|
||||
output_file,
|
||||
"Element ID: {}, Type: {}, Tags: {:?}",
|
||||
element.id(),
|
||||
element.kind(),
|
||||
element.tags(),
|
||||
)
|
||||
.expect("Failed to write to output file");
|
||||
// Check if the "region" folder exists within the selected directory
|
||||
if path.join("region").exists() {
|
||||
return Ok(path.display().to_string());
|
||||
} else {
|
||||
// Notify the frontend that no valid Minecraft world was found
|
||||
return Err("Invalid Minecraft world".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// Generate world
|
||||
data_processing::generate_world(parsed_elements, &args, scale_factor_x, scale_factor_z);
|
||||
// If no folder was selected, return an error message
|
||||
Err("No world selected".to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn gui_get_version() -> String {
|
||||
env!("CARGO_PKG_VERSION").to_string()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn gui_check_for_updates() -> Result<bool, String> {
|
||||
match version_check::check_for_updates() {
|
||||
Ok(is_newer) => Ok(is_newer),
|
||||
Err(e) => Err(format!("Error checking for updates: {}", e)),
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn gui_start_generation(bbox_text: String, selected_world: String) -> Result<(), String> {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
if let Err(e) = tokio::task::spawn_blocking(move || {
|
||||
// Utility function to reorder bounding box coordinates
|
||||
fn reorder_bbox(bbox: &[f64]) -> (f64, f64, f64, f64) {
|
||||
(bbox[1], bbox[0], bbox[3], bbox[2])
|
||||
}
|
||||
|
||||
// Parse bounding box string and validate it
|
||||
let bbox: Vec<f64> = bbox_text
|
||||
.split_whitespace()
|
||||
.map(|s| s.parse::<f64>().expect("Invalid bbox coordinate"))
|
||||
.collect();
|
||||
|
||||
if bbox.len() != 4 {
|
||||
return Err("Invalid bounding box format".to_string());
|
||||
}
|
||||
|
||||
// Create an Args instance with the chosen bounding box and world directory path
|
||||
let args: Args = Args {
|
||||
bbox: Some(bbox_text),
|
||||
file: None,
|
||||
path: selected_world,
|
||||
downloader: "requests".to_string(),
|
||||
scale: 1.0,
|
||||
debug: false,
|
||||
timeout: None,
|
||||
};
|
||||
|
||||
// Reorder bounding box coordinates for further processing
|
||||
let reordered_bbox: (f64, f64, f64, f64) = reorder_bbox(&bbox);
|
||||
|
||||
// Run data fetch and world generation
|
||||
match retrieve_data::fetch_data(reordered_bbox, None, args.debug, "requests") {
|
||||
Ok(raw_data) => {
|
||||
let (mut parsed_elements, scale_factor_x, scale_factor_z) =
|
||||
osm_parser::parse_osm_data(&raw_data, reordered_bbox, &args);
|
||||
parsed_elements.sort_by_key(|element: &osm_parser::ProcessedElement| {
|
||||
osm_parser::get_priority(element)
|
||||
});
|
||||
|
||||
let _ = data_processing::generate_world(
|
||||
parsed_elements,
|
||||
&args,
|
||||
scale_factor_x,
|
||||
scale_factor_z,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => Err(format!("Failed to start generation: {}", e)),
|
||||
}
|
||||
})
|
||||
.await
|
||||
{
|
||||
eprintln!("Error in blocking task: {}", e);
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::args::Args;
|
||||
use crate::{args::Args, progress::emit_gui_progress_update};
|
||||
use colored::Colorize;
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
@@ -39,7 +39,7 @@ pub struct ProcessedNode {
|
||||
pub id: u64,
|
||||
pub tags: HashMap<String, String>,
|
||||
|
||||
// minecraft coords
|
||||
// Minecraft coordinates
|
||||
pub x: i32,
|
||||
pub z: i32,
|
||||
}
|
||||
@@ -138,6 +138,7 @@ pub fn parse_osm_data(
|
||||
args: &Args,
|
||||
) -> (Vec<ProcessedElement>, f64, f64) {
|
||||
println!("{} Parsing data...", "[2/5]".bold());
|
||||
emit_gui_progress_update(5.0, "Parsing data...");
|
||||
|
||||
// Deserialize the JSON data into the OSMData structure
|
||||
let data: OsmData =
|
||||
@@ -145,16 +146,16 @@ pub fn parse_osm_data(
|
||||
|
||||
// Determine which dimension is larger and assign scale factors accordingly
|
||||
let (scale_factor_z, scale_factor_x) = geo_distance(bbox.1, bbox.3, bbox.0, bbox.2);
|
||||
let scale_factor_z = scale_factor_z.floor() * args.scale;
|
||||
let scale_factor_x = scale_factor_x.floor() * args.scale;
|
||||
let scale_factor_z: f64 = scale_factor_z.floor() * args.scale;
|
||||
let scale_factor_x: f64 = scale_factor_x.floor() * args.scale;
|
||||
|
||||
if args.debug {
|
||||
println!("Scale factor X: {}", scale_factor_x);
|
||||
println!("Scale factor Z: {}", scale_factor_z);
|
||||
}
|
||||
|
||||
let mut nodes_map = HashMap::new();
|
||||
let mut ways_map = HashMap::new();
|
||||
let mut nodes_map: HashMap<u64, ProcessedNode> = HashMap::new();
|
||||
let mut ways_map: HashMap<u64, ProcessedWay> = HashMap::new();
|
||||
|
||||
let mut processed_elements: Vec<ProcessedElement> = Vec::new();
|
||||
|
||||
@@ -165,7 +166,7 @@ pub fn parse_osm_data(
|
||||
let (x, z) =
|
||||
lat_lon_to_minecraft_coords(lat, lon, bbox, scale_factor_z, scale_factor_x);
|
||||
|
||||
let processed = ProcessedNode {
|
||||
let processed: ProcessedNode = ProcessedNode {
|
||||
id: element.id,
|
||||
tags: element.tags.clone().unwrap_or_default(),
|
||||
x,
|
||||
@@ -190,7 +191,7 @@ pub fn parse_osm_data(
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut nodes = vec![];
|
||||
let mut nodes: Vec<ProcessedNode> = vec![];
|
||||
if let Some(node_ids) = &element.nodes {
|
||||
for &node_id in node_ids {
|
||||
if let Some(node) = nodes_map.get(&node_id) {
|
||||
@@ -199,7 +200,7 @@ pub fn parse_osm_data(
|
||||
}
|
||||
}
|
||||
|
||||
let processed = ProcessedWay {
|
||||
let processed: ProcessedWay = ProcessedWay {
|
||||
id: element.id,
|
||||
tags: element.tags.clone().unwrap_or_default(),
|
||||
nodes,
|
||||
@@ -223,14 +224,14 @@ pub fn parse_osm_data(
|
||||
};
|
||||
|
||||
// Only process multipolygons for now
|
||||
if tags.get("type").map(|x| x.as_str()) != Some("multipolygon") {
|
||||
if tags.get("type").map(|x: &String| x.as_str()) != Some("multipolygon") {
|
||||
continue;
|
||||
};
|
||||
|
||||
let members = element
|
||||
let members: Vec<ProcessedMember> = element
|
||||
.members
|
||||
.iter()
|
||||
.filter_map(|mem| {
|
||||
.filter_map(|mem: &OsmMember| {
|
||||
if mem.r#type != "way" {
|
||||
eprintln!("WARN: Unknown relation type {}", mem.r#type);
|
||||
return None;
|
||||
@@ -247,7 +248,7 @@ pub fn parse_osm_data(
|
||||
}
|
||||
};
|
||||
|
||||
let way = ways_map
|
||||
let way: ProcessedWay = ways_map
|
||||
.get(&mem.r#ref)
|
||||
.expect("Missing a way referenced by a rel")
|
||||
.clone();
|
||||
@@ -263,6 +264,8 @@ pub fn parse_osm_data(
|
||||
}));
|
||||
}
|
||||
|
||||
emit_gui_progress_update(10.0, "");
|
||||
|
||||
(processed_elements, scale_factor_x, scale_factor_z)
|
||||
}
|
||||
|
||||
@@ -284,10 +287,10 @@ pub fn get_priority(element: &ProcessedElement) -> usize {
|
||||
|
||||
// (lat meters, lon meters)
|
||||
fn geo_distance(lat1: f64, lat2: f64, lon1: f64, lon2: f64) -> (f64, f64) {
|
||||
let z = lat_distance(lat1, lat2);
|
||||
let z: f64 = lat_distance(lat1, lat2);
|
||||
|
||||
// distance between two lons depends on their latitude. In this case we'll just average them
|
||||
let x = lon_distance((lat1 + lat2) / 2.0, lon1, lon2);
|
||||
let x: f64 = lon_distance((lat1 + lat2) / 2.0, lon1, lon2);
|
||||
|
||||
(z, x)
|
||||
}
|
||||
@@ -296,10 +299,10 @@ fn geo_distance(lat1: f64, lat2: f64, lon1: f64, lon2: f64) -> (f64, f64) {
|
||||
// returns meters
|
||||
fn lon_distance(lat: f64, lon1: f64, lon2: f64) -> f64 {
|
||||
const R: f64 = 6_371_000.0;
|
||||
let d_lon = (lon2 - lon1).to_radians();
|
||||
let a =
|
||||
let d_lon: f64 = (lon2 - lon1).to_radians();
|
||||
let a: f64 =
|
||||
lat.to_radians().cos() * lat.to_radians().cos() * (d_lon / 2.0).sin() * (d_lon / 2.0).sin();
|
||||
let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());
|
||||
let c: f64 = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());
|
||||
|
||||
R * c
|
||||
}
|
||||
@@ -308,9 +311,9 @@ fn lon_distance(lat: f64, lon1: f64, lon2: f64) -> f64 {
|
||||
// returns meters
|
||||
fn lat_distance(lat1: f64, lat2: f64) -> f64 {
|
||||
const R: f64 = 6_371_000.0;
|
||||
let d_lat = (lat2 - lat1).to_radians();
|
||||
let a = (d_lat / 2.0).sin() * (d_lat / 2.0).sin();
|
||||
let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());
|
||||
let d_lat: f64 = (lat2 - lat1).to_radians();
|
||||
let a: f64 = (d_lat / 2.0).sin() * (d_lat / 2.0).sin();
|
||||
let c: f64 = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());
|
||||
|
||||
R * c
|
||||
}
|
||||
|
||||
46
src/progress.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
use once_cell::sync::OnceCell;
|
||||
use serde_json::json;
|
||||
use tauri::{Emitter, WebviewWindow};
|
||||
|
||||
pub static MAIN_WINDOW: OnceCell<WebviewWindow> = OnceCell::new();
|
||||
|
||||
pub fn set_main_window(window: WebviewWindow) {
|
||||
MAIN_WINDOW.set(window).ok();
|
||||
}
|
||||
|
||||
pub fn get_main_window() -> Option<&'static WebviewWindow> {
|
||||
MAIN_WINDOW.get()
|
||||
}
|
||||
|
||||
/// This function checks if the program is running with a GUI window.
|
||||
/// Returns `true` if a GUI window is initialized, `false` otherwise.
|
||||
pub fn is_running_with_gui() -> bool {
|
||||
get_main_window().is_some()
|
||||
}
|
||||
|
||||
/// This code manages a multi-step process with a progress bar indicating the overall completion.
|
||||
/// The progress updates are mapped to specific steps in the pipeline:
|
||||
///
|
||||
/// [1/5] Fetching data... - Starts at: 0% / Completes at: 5%
|
||||
/// [2/5] Parsing data... - Starts at: 5% / Completes at: 10%
|
||||
/// [3/5] Processing data... - Starts at: 10% / Completes at: 60%
|
||||
/// [4/5] Generating ground layer... - Starts at: 60% / Completes at: 90%
|
||||
/// [5/5] Saving world... - Starts at: 90% / Completes at: 100%
|
||||
///
|
||||
/// The function `emit_gui_progress_update` is used to send real-time progress updates to the UI.
|
||||
pub fn emit_gui_progress_update(progress: f64, message: &str) {
|
||||
if let Some(window) = get_main_window() {
|
||||
let payload = json!({
|
||||
"progress": progress,
|
||||
"message": message
|
||||
});
|
||||
|
||||
if let Err(e) = window.emit("progress-update", payload) {
|
||||
eprintln!("Failed to emit progress event: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit_gui_error(message: &str) {
|
||||
emit_gui_progress_update(0.0, &format!("Error! {}", message));
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::progress::{emit_gui_error, emit_gui_progress_update, is_running_with_gui};
|
||||
use colored::Colorize;
|
||||
use rand::seq::SliceRandom;
|
||||
use reqwest::blocking::Client;
|
||||
@@ -14,7 +15,8 @@ fn download_with_reqwest(url: &str, query: &str) -> Result<String, Box<dyn std::
|
||||
.timeout(Duration::from_secs(1800))
|
||||
.build()?;
|
||||
|
||||
let response = client.get(url).query(&[("data", query)]).send();
|
||||
let response: Result<reqwest::blocking::Response, reqwest::Error> =
|
||||
client.get(url).query(&[("data", query)]).send();
|
||||
|
||||
match response {
|
||||
Ok(resp) => {
|
||||
@@ -32,10 +34,17 @@ fn download_with_reqwest(url: &str, query: &str) -> Result<String, Box<dyn std::
|
||||
.red()
|
||||
.bold()
|
||||
);
|
||||
emit_gui_error("Request timed out. Try selecting a smaller area.");
|
||||
} else {
|
||||
eprintln!("{}", format!("Error! {}", e).red().bold());
|
||||
emit_gui_error(&e.to_string());
|
||||
}
|
||||
|
||||
if !is_running_with_gui() {
|
||||
std::process::exit(1);
|
||||
} else {
|
||||
Ok("".to_string())
|
||||
}
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,6 +85,7 @@ pub fn fetch_data(
|
||||
download_method: &str,
|
||||
) -> Result<Value, Box<dyn std::error::Error>> {
|
||||
println!("{} Fetching data...", "[1/5]".bold());
|
||||
emit_gui_progress_update(1.0, "Fetching data...");
|
||||
|
||||
// List of Overpass API servers
|
||||
let api_servers: Vec<&str> = vec![
|
||||
@@ -146,22 +156,33 @@ pub fn fetch_data(
|
||||
// Check if the remark mentions memory or other runtime errors
|
||||
if remark.contains("runtime error") && remark.contains("out of memory") {
|
||||
eprintln!("{}", "Error! The query ran out of memory on the Overpass API server. Try using a smaller area.".red().bold());
|
||||
emit_gui_error("Try using a smaller area.");
|
||||
} else {
|
||||
// Handle other Overpass API errors if present in the remark field
|
||||
eprintln!(
|
||||
"{}",
|
||||
format!("Error! API returned: {}", remark).red().bold()
|
||||
);
|
||||
emit_gui_error(&format!("API returned: {}", remark));
|
||||
}
|
||||
} else {
|
||||
// General case for when there are no elements and no specific remark
|
||||
eprintln!("{}", "Error! No data available.".red().bold());
|
||||
eprintln!(
|
||||
"{}",
|
||||
"Error! No data available in this region.".red().bold()
|
||||
);
|
||||
emit_gui_error("No data available in this region.");
|
||||
}
|
||||
|
||||
if debug {
|
||||
println!("Additional debug information: {}", data);
|
||||
}
|
||||
std::process::exit(1);
|
||||
|
||||
if !is_running_with_gui() {
|
||||
std::process::exit(1);
|
||||
} else {
|
||||
return Err("Data fetch failed".into());
|
||||
}
|
||||
}
|
||||
|
||||
// If debug is enabled, write data to file
|
||||
@@ -170,6 +191,8 @@ pub fn fetch_data(
|
||||
file.write_all(response.as_bytes())?;
|
||||
}
|
||||
|
||||
emit_gui_progress_update(5.0, "");
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ const REMOTE_CARGO_TOML_URL: &str =
|
||||
"https://raw.githubusercontent.com/louis-e/arnis/main/Cargo.toml";
|
||||
|
||||
/// Fetches the latest version from the remote Cargo.toml file and compares it with the local version.
|
||||
/// If a newer version is available, prints a message.
|
||||
pub fn check_for_updates() -> Result<(), Box<dyn Error>> {
|
||||
/// Returns `true` if a newer version is available, `false` otherwise.
|
||||
pub fn check_for_updates() -> Result<bool, Box<dyn Error>> {
|
||||
let client: Client = Client::new();
|
||||
|
||||
// Fetch the remote Cargo.toml file with a User-Agent header
|
||||
@@ -24,7 +24,7 @@ pub fn check_for_updates() -> Result<(), Box<dyn Error>> {
|
||||
// If the response status is not 200 OK, handle it as an HTTP error
|
||||
if !res.status().is_success() {
|
||||
handle_http_error(res.status());
|
||||
return Ok(());
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let response_text: String = res.text()?;
|
||||
@@ -40,12 +40,16 @@ pub fn check_for_updates() -> Result<(), Box<dyn Error>> {
|
||||
local_version,
|
||||
remote_version
|
||||
);
|
||||
return Ok(true); // Newer version is available
|
||||
}
|
||||
}
|
||||
Err(err) => handle_request_error(err),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(false) // Local version is up-to-date
|
||||
}
|
||||
Err(err) => {
|
||||
handle_request_error(err);
|
||||
Ok(false) // Treat request failures as no new version available
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts the version from the contents of a Cargo.toml file.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::args::Args;
|
||||
use crate::block_definitions::*;
|
||||
use crate::progress::emit_gui_progress_update;
|
||||
use colored::Colorize;
|
||||
use fastanvil::Region;
|
||||
use fastnbt::{LongArray, Value};
|
||||
@@ -192,11 +193,11 @@ impl WorldToModify {
|
||||
fn get_block(&self, x: i32, y: i32, z: i32) -> Option<Block> {
|
||||
let chunk_x: i32 = x >> 4;
|
||||
let chunk_z: i32 = z >> 4;
|
||||
let region_x = chunk_x >> 5;
|
||||
let region_z = chunk_z >> 5;
|
||||
let region_x: i32 = chunk_x >> 5;
|
||||
let region_z: i32 = chunk_z >> 5;
|
||||
|
||||
let region = self.get_region(region_x, region_z)?;
|
||||
let chunk = region.get_chunk(chunk_x & 31, chunk_z & 31)?;
|
||||
let region: &RegionToModify = self.get_region(region_x, region_z)?;
|
||||
let chunk: &ChunkToModify = region.get_chunk(chunk_x & 31, chunk_z & 31)?;
|
||||
|
||||
chunk.get_block(
|
||||
(x & 15).try_into().unwrap(),
|
||||
@@ -208,11 +209,11 @@ impl WorldToModify {
|
||||
fn set_block(&mut self, x: i32, y: i32, z: i32, block: Block) {
|
||||
let chunk_x: i32 = x >> 4;
|
||||
let chunk_z: i32 = z >> 4;
|
||||
let region_x = chunk_x >> 5;
|
||||
let region_z = chunk_z >> 5;
|
||||
let region_x: i32 = chunk_x >> 5;
|
||||
let region_z: i32 = chunk_z >> 5;
|
||||
|
||||
let region = self.get_or_create_region(region_x, region_z);
|
||||
let chunk = region.get_or_create_chunk(chunk_x & 31, chunk_z & 31);
|
||||
let region: &mut RegionToModify = self.get_or_create_region(region_x, region_z);
|
||||
let chunk: &mut ChunkToModify = region.get_or_create_chunk(chunk_x & 31, chunk_z & 31);
|
||||
|
||||
chunk.set_block(
|
||||
(x & 15).try_into().unwrap(),
|
||||
@@ -249,7 +250,7 @@ impl<'a> WorldEditor<'a> {
|
||||
|
||||
const REGION_TEMPLATE: &[u8] = include_bytes!("region.template");
|
||||
|
||||
let mut region_file = File::options()
|
||||
let mut region_file: File = File::options()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
@@ -268,9 +269,10 @@ impl<'a> WorldEditor<'a> {
|
||||
(self.scale_factor_x as i32, self.scale_factor_x as i32)
|
||||
}
|
||||
|
||||
pub fn block_at(&self, x: i32, y: i32, z: i32) -> bool {
|
||||
// Unused and not tested
|
||||
/*pub fn block_at(&self, x: i32, y: i32, z: i32) -> bool {
|
||||
self.world.get_block(x, y, z).is_some()
|
||||
}
|
||||
}*/
|
||||
|
||||
/// Sets a block of the specified type at the given coordinates.
|
||||
pub fn set_block(
|
||||
@@ -292,11 +294,11 @@ impl<'a> WorldEditor<'a> {
|
||||
if let Some(whitelist) = override_whitelist {
|
||||
whitelist
|
||||
.iter()
|
||||
.any(|whitelisted_block| whitelisted_block.id() == existing_block.id())
|
||||
.any(|whitelisted_block: &Block| whitelisted_block.id() == existing_block.id())
|
||||
} else if let Some(blacklist) = override_blacklist {
|
||||
!blacklist
|
||||
.iter()
|
||||
.any(|blacklisted_block| blacklisted_block.id() == existing_block.id())
|
||||
.any(|blacklisted_block: &Block| blacklisted_block.id() == existing_block.id())
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@@ -351,7 +353,7 @@ impl<'a> WorldEditor<'a> {
|
||||
if let Some(whitelist) = whitelist {
|
||||
if whitelist
|
||||
.iter()
|
||||
.any(|whitelisted_block| whitelisted_block.id() == existing_block.id())
|
||||
.any(|whitelisted_block: &Block| whitelisted_block.id() == existing_block.id())
|
||||
{
|
||||
return true; // Block is in whitelist
|
||||
}
|
||||
@@ -359,7 +361,7 @@ impl<'a> WorldEditor<'a> {
|
||||
if let Some(blacklist) = blacklist {
|
||||
if blacklist
|
||||
.iter()
|
||||
.any(|blacklisted_block| blacklisted_block.id() == existing_block.id())
|
||||
.any(|blacklisted_block: &Block| blacklisted_block.id() == existing_block.id())
|
||||
{
|
||||
return true; // Block is in blacklist
|
||||
}
|
||||
@@ -372,6 +374,7 @@ impl<'a> WorldEditor<'a> {
|
||||
/// Saves all changes made to the world by writing modified chunks to the appropriate region files.
|
||||
pub fn save(&mut self) {
|
||||
println!("{} Saving world...", "[5/5]".bold());
|
||||
emit_gui_progress_update(90.0, "Saving world...");
|
||||
|
||||
let _debug: bool = self.args.debug;
|
||||
let total_regions: u64 = self.world.regions.len() as u64;
|
||||
@@ -386,12 +389,17 @@ impl<'a> WorldEditor<'a> {
|
||||
.progress_chars("█▓░"),
|
||||
);
|
||||
|
||||
let total_steps: f64 = 10.0;
|
||||
let progress_increment_save: f64 = total_steps / total_regions as f64;
|
||||
let mut current_progress_save: f64 = 90.0;
|
||||
let mut last_emitted_progress: f64 = current_progress_save;
|
||||
|
||||
for ((region_x, region_z), region_to_modify) in &self.world.regions {
|
||||
let mut region = self.create_region(*region_x, *region_z);
|
||||
let mut region: Region<File> = self.create_region(*region_x, *region_z);
|
||||
|
||||
for chunk_x in 0..32 {
|
||||
for chunk_z in 0..32 {
|
||||
let data = region
|
||||
let data: Vec<u8> = region
|
||||
.read_chunk(chunk_x as usize, chunk_z as usize)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
@@ -418,6 +426,12 @@ impl<'a> WorldEditor<'a> {
|
||||
}
|
||||
|
||||
save_pb.inc(1);
|
||||
|
||||
current_progress_save += progress_increment_save;
|
||||
if (current_progress_save - last_emitted_progress).abs() > 0.25 {
|
||||
emit_gui_progress_update(current_progress_save, "Saving world...");
|
||||
last_emitted_progress = current_progress_save;
|
||||
}
|
||||
}
|
||||
|
||||
save_pb.finish();
|
||||
|
||||
36
tauri.conf.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "Arnis",
|
||||
"version": "2.1.0",
|
||||
"identifier": "com.louisdev.arnis",
|
||||
"build": {
|
||||
"frontendDist": "gui-src"
|
||||
},
|
||||
"app": {
|
||||
"withGlobalTauri": true,
|
||||
"windows": [
|
||||
{
|
||||
"title": "Arnis",
|
||||
"width": 1000,
|
||||
"height": 650,
|
||||
"resizable": false,
|
||||
"transparent": true,
|
||||
"center": true
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": null
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
]
|
||||
}
|
||||
}
|
||||