fucking hell
This commit is contained in:
commit
5b949b892c
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"python.REPL.enableREPLSmartSend": false
|
||||
}
|
209
Cargo.lock
generated
Normal file
209
Cargo.lock
generated
Normal file
@ -0,0 +1,209 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "Froggy"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bmp",
|
||||
"rand",
|
||||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||
|
||||
[[package]]
|
||||
name = "bmp"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69985ff4f58085ac696454692d0b646a66ad1f9cc9be294c91dc51bb5df511ae"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.158"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "Froggy"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.86"
|
||||
bmp = "0.5.0"
|
||||
rand = "0.8.5"
|
||||
rayon = "1.10.0"
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
113
find.py
Normal file
113
find.py
Normal file
@ -0,0 +1,113 @@
|
||||
import json
|
||||
import random
|
||||
import functools
|
||||
import datetime
|
||||
import multiprocessing
|
||||
from math import sqrt, acos, cos, sin, radians, degrees
|
||||
from PIL import Image
|
||||
|
||||
img_north_border = radians(54.8364)
|
||||
img_west_border = radians(14.1229)
|
||||
img_south_border = radians(49.0024)
|
||||
img_east_border = radians(24.1455)
|
||||
img_path = "poland.bmp"
|
||||
|
||||
img = Image.open(img_path)
|
||||
print(img.size)
|
||||
|
||||
p_horiz_scale = img.width / (img_east_border - img_west_border)
|
||||
p_verti_scale = img.height / (img_north_border - img_south_border)
|
||||
|
||||
with open("pos.json") as df:
|
||||
data = json.loads(df.read())
|
||||
frog_shop_positions = [(radians(x['lat']), radians(x['lon'])) for x in data]
|
||||
|
||||
# @functools.cache
|
||||
# def dist(lat, lon):
|
||||
# return min([sqrt((lat-i[0])**2 + (lon-i[1])**2) for i in frog_shop_positions])
|
||||
|
||||
|
||||
def gcd(a: tuple[float, float], b: tuple[float, float]) -> float:
|
||||
return acos(sin(a[0])*sin(b[0]) + cos(a[0])*cos(b[0])*cos(abs(a[1]-b[1])))
|
||||
|
||||
def dist(lat, lon):
|
||||
return min([gcd((lat, lon), i) for i in frog_shop_positions])
|
||||
|
||||
def in_poland(lat, lon, im):
|
||||
if lat < img_south_border or lat >= img_north_border or lon < img_west_border or lon >= img_east_border:
|
||||
return False
|
||||
offlat = lat - img_south_border
|
||||
offlon = lon - img_west_border
|
||||
ppos = (offlon * p_horiz_scale, offlat * p_verti_scale)
|
||||
ppos = (ppos[0], img.height - ppos[1] - 1)
|
||||
# try:
|
||||
return im.getpixel(ppos) == (0, 0, 0)
|
||||
# except Exception as e:
|
||||
# print("FUCK")
|
||||
# print(e)
|
||||
# print(lat, lon)
|
||||
# exit(1)
|
||||
|
||||
def start_point(im):
|
||||
lat, lon = 0, 0
|
||||
while not in_poland(lat, lon, im):
|
||||
lat = random.uniform(img_south_border, img_north_border)
|
||||
lon = random.uniform(img_west_border, img_east_border)
|
||||
return (lat, lon)
|
||||
|
||||
epsilon = 0.00005
|
||||
|
||||
def get_next_point(curr, im):
|
||||
point_candidates = [
|
||||
(curr[0] + epsilon, curr[1]),
|
||||
(curr[0] - epsilon, curr[1]),
|
||||
(curr[0], curr[1] + epsilon),
|
||||
(curr[0], curr[1] - epsilon),
|
||||
]
|
||||
points = [x for x in point_candidates if in_poland(x[0], x[1], im)]
|
||||
best_dist = dist(curr[0], curr[1])
|
||||
best = curr
|
||||
for point in points:
|
||||
d = dist(point[0], point[1])
|
||||
if d > best_dist:
|
||||
best = point
|
||||
return best
|
||||
|
||||
def find_local_best(start, im):
|
||||
iters = 0
|
||||
curr = None
|
||||
next = start
|
||||
start_time = datetime.datetime.now()
|
||||
while curr != next:
|
||||
curr = next
|
||||
print(curr)
|
||||
iters += 1
|
||||
next = get_next_point(curr, im)
|
||||
print(f"Local minimum at {next}, {dist(next[0], next[1])} ({datetime.datetime.now() - start_time})")
|
||||
return next
|
||||
|
||||
def search(id):
|
||||
best_point = None
|
||||
best_dist = 0
|
||||
img = Image.open(img_path)
|
||||
for i in range(2000):
|
||||
print(f"Runner {id} at attempt {i}")
|
||||
start = start_point(img)
|
||||
local = find_local_best(start, img)
|
||||
if dist(local[0], local[1]) > best_dist:
|
||||
best_point = local
|
||||
best_dist = dist(local[0], local[1])
|
||||
print(f"Better than previous, new best for {id} is {best_point} with {best_dist}")
|
||||
return (best_point, best_dist)
|
||||
|
||||
# with multiprocessing.Pool(16) as p:
|
||||
# found = p.map(search, range(40))
|
||||
# best_overall = max(found, key=lambda x: x[1])
|
||||
# print(f"Found best point at {degrees(best_overall[0][0]), degrees(best_overall[0][1])} with distance {degrees(best_overall[1])}")
|
||||
|
||||
#print(degrees(dist(radians(49.92), radians(14.19))))
|
||||
|
||||
fuck = find_local_best(
|
||||
(radians(52), radians(19)), img
|
||||
)
|
||||
print(degrees(fuck[0]), degrees(fuck[1]))
|
96
flake.lock
Normal file
96
flake.lock
Normal file
@ -0,0 +1,96 @@
|
||||
{
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1724015816,
|
||||
"narHash": "sha256-hVESnM7Eiz93+4DeiE0a1TwMeaeph1ytRJ5QtqxYRWg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9aa35efbea27d320d0cdc5f922f0890812affb60",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1718428119,
|
||||
"narHash": "sha256-WdWDpNaq6u1IPtxtYHHWpl5BmabtpmLnMAx0RdJ/vo8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e6cea36f83499eb4e9cd184c8a8e823296b50ad5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay",
|
||||
"utils": "utils"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1724120436,
|
||||
"narHash": "sha256-/MvfxTjco5UDBF6SEvwyeXrXwZG7nz7/mDVreQNKsWg=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "48e61fe824f5823e4f3f15dd9a75c19c63649269",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
27
flake.nix
Normal file
27
flake.nix
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
utils.url = "github:numtide/flake-utils";
|
||||
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, utils, rust-overlay }:
|
||||
utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
overlays = [ (import rust-overlay) ];
|
||||
pkgs = import nixpkgs { inherit system overlays; };
|
||||
in {
|
||||
devShell = with pkgs; mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
python312 python312Packages.decorator python312Packages.pillow
|
||||
perf-tools
|
||||
linuxPackages_latest.perf
|
||||
(rust-bin.stable.latest.default.override {
|
||||
extensions = [ "rust-src" ];
|
||||
targets = ["x86_64-unknown-linux-gnu"];
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
BIN
poland.bmp
Normal file
BIN
poland.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.7 MiB |
6
poland.bpw
Normal file
6
poland.bpw
Normal file
@ -0,0 +1,6 @@
|
||||
0.00084698025551684
|
||||
0
|
||||
0
|
||||
-0.00084698025551684
|
||||
14.12177084785133729
|
||||
54.83555301974448071
|
BIN
poland2.bmp
Normal file
BIN
poland2.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.7 MiB |
6
polang.pgw
Normal file
6
polang.pgw
Normal file
@ -0,0 +1,6 @@
|
||||
0.00577623762376237
|
||||
0
|
||||
0
|
||||
-0.00577623762376237
|
||||
14.12620198019802054
|
||||
54.83062376237623425
|
BIN
polang.png
Normal file
BIN
polang.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
8
preprocess.py
Normal file
8
preprocess.py
Normal file
@ -0,0 +1,8 @@
|
||||
import json
|
||||
|
||||
with open("raw.json", "r") as f:
|
||||
string = f.read()
|
||||
rawls = json.loads(string)
|
||||
latlons = [{'lat': x['lat'], 'lon': x['lon']} for x in rawls if x['lon'] != None]
|
||||
with open("pos.json", "w") as w:
|
||||
w.write(json.dumps(latlons))
|
5
refrogger.js
Normal file
5
refrogger.js
Normal file
@ -0,0 +1,5 @@
|
||||
const frogs = require('./pos.json');
|
||||
|
||||
for (let { lat, lon } of frogs) {
|
||||
process.stdout.write(`${lat} ${lon}\n`);
|
||||
}
|
1
sample.json
Normal file
1
sample.json
Normal file
@ -0,0 +1 @@
|
||||
[{"lat": 52.444686, "lon": 16.881193}, {"lat": 52.411081, "lon": 16.926432}, {"lat": 52.410221, "lon": 17.078734}, {"lat": 52.385385, "lon": 16.914945}, {"lat": 50.326686, "lon": 19.186558}, {"lat": 53.234833, "lon": 20.175232}, {"lat": 52.094746, "lon": 17.020672}, {"lat": 51.878283, "lon": 17.016359}, {"lat": 50.334049, "lon": 18.886466}, {"lat": 52.408623, "lon": 16.941987}, {"lat": 52.392868, "lon": 16.889022}, {"lat": 50.364616, "lon": 19.036451}, {"lat": 50.3688, "lon": 18.849958}, {"lat": 52.894126, "lon": 16.171218}, {"lat": 51.42558, "lon": 17.932531}]
|
200
src/main.rs
Normal file
200
src/main.rs
Normal file
@ -0,0 +1,200 @@
|
||||
use anyhow::Result;
|
||||
use bmp::Image;
|
||||
use std::{fs::File, io::{self, BufRead, Cursor}};
|
||||
use rand::prelude::*;
|
||||
use rayon::prelude::*;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
|
||||
struct Radians(f64);
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
|
||||
struct Degrees(f64);
|
||||
|
||||
impl From<Degrees> for Radians {
|
||||
fn from(value: Degrees) -> Self {
|
||||
Radians(value.0 * std::f64::consts::PI / 180f64)
|
||||
}
|
||||
}
|
||||
impl Into<f64> for Radians {
|
||||
fn into(self) -> f64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
impl From<Radians> for Degrees {
|
||||
fn from(value: Radians) -> Self {
|
||||
Degrees(value.0 * (180f64 / std::f64::consts::PI))
|
||||
}
|
||||
}
|
||||
impl Into<f64> for Degrees {
|
||||
fn into(self) -> f64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
struct Location {
|
||||
lat: Radians,
|
||||
lon: Radians,
|
||||
}
|
||||
impl From<(Degrees, Degrees)> for Location {
|
||||
fn from(value: (Degrees, Degrees)) -> Self {
|
||||
Location {
|
||||
lat: value.0.into(),
|
||||
lon: value.1.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const IMG_NORTH_BORDER: Radians = Radians(0.9570757299); // Degrees(54.8364);
|
||||
const IMG_WEST_BORDER: Radians = Radians(0.2464911049); // Degrees(14.1229);
|
||||
const IMG_SOUTH_BORDER: Radians = Radians(0.8552532214); // Degrees(49.0024);
|
||||
const IMG_EAST_BORDER: Radians = Radians(0.4214184745); // Degrees(24.1455);
|
||||
const EPSILON: f64 = 0.00001f64;
|
||||
|
||||
struct ImageMeta {
|
||||
image: Image,
|
||||
horizontal_scale: f64,
|
||||
vertical_scale: f64
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn gcd(a: &Location, b: &Location) -> f64 {
|
||||
return f64::acos(
|
||||
f64::sin(a.lat.into())*f64::sin(b.lat.into()) +
|
||||
f64::cos(a.lat.into())*f64::cos(b.lat.into())*f64::cos(
|
||||
f64::abs(a.lon.0 - b.lon.0)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fn dist(location: &Location, shops: &Vec<Location>) -> f64 {
|
||||
shops.into_iter().map(|a| {
|
||||
gcd(a, &location)
|
||||
}).min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Greater)).unwrap()
|
||||
}
|
||||
|
||||
fn in_poland(
|
||||
location: &Location,
|
||||
im: &ImageMeta,
|
||||
) -> bool {
|
||||
if location.lat < IMG_SOUTH_BORDER ||
|
||||
location.lat >= IMG_NORTH_BORDER ||
|
||||
location.lon < IMG_WEST_BORDER ||
|
||||
location.lon >= IMG_EAST_BORDER {
|
||||
return false
|
||||
}
|
||||
|
||||
let offlat = location.lat.0 - IMG_SOUTH_BORDER.0;
|
||||
let offlon = location.lon.0 - IMG_WEST_BORDER.0;
|
||||
let ppos: (f64, f64) = (offlon * im.horizontal_scale, offlat * im.vertical_scale);
|
||||
let ppos = (ppos.0 as u32, im.image.get_height() - (ppos.1 as u32) - 1);
|
||||
|
||||
return im.image.get_pixel(ppos.0, ppos.1) == bmp::consts::BLACK;
|
||||
}
|
||||
|
||||
fn start_point(
|
||||
im: &ImageMeta
|
||||
) -> Location {
|
||||
loop {
|
||||
let loc = Location {
|
||||
lat: Radians(rand::thread_rng().gen_range(IMG_SOUTH_BORDER.0 .. IMG_NORTH_BORDER.0)),
|
||||
lon: Radians(rand::thread_rng().gen_range(IMG_WEST_BORDER.0 .. IMG_EAST_BORDER.0) )
|
||||
};
|
||||
if in_poland(&loc, im) {
|
||||
return loc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_next_point(curr: Location, im: &ImageMeta, shops: &Vec<Location>) -> (f64, Location) {
|
||||
[
|
||||
Location {lat: Radians(curr.lat.0 + EPSILON), lon: Radians(curr.lon.0)},
|
||||
Location {lat: Radians(curr.lat.0 - EPSILON), lon: Radians(curr.lon.0)},
|
||||
Location {lat: Radians(curr.lat.0), lon: Radians(curr.lon.0 + EPSILON)},
|
||||
Location {lat: Radians(curr.lat.0), lon: Radians(curr.lon.0 - EPSILON)},
|
||||
Location {lat: Radians(curr.lat.0 + EPSILON), lon: Radians(curr.lon.0 + EPSILON)},
|
||||
Location {lat: Radians(curr.lat.0 + EPSILON), lon: Radians(curr.lon.0 - EPSILON)},
|
||||
Location {lat: Radians(curr.lat.0 - EPSILON), lon: Radians(curr.lon.0 - EPSILON)},
|
||||
Location {lat: Radians(curr.lat.0 - EPSILON), lon: Radians(curr.lon.0 + EPSILON)},
|
||||
curr
|
||||
].into_iter().filter(|loc| {
|
||||
in_poland(loc, im)
|
||||
}).map(|loc| {
|
||||
(dist(&loc, shops), loc)
|
||||
}).max_by(|x, y| {
|
||||
x.0.partial_cmp(&y.0).unwrap()
|
||||
}).unwrap()
|
||||
}
|
||||
|
||||
fn find_local_best(start: Location, im: &ImageMeta, shops: &Vec<Location>) -> (f64, Location) {
|
||||
let mut curr = start;
|
||||
loop {
|
||||
let next = get_next_point(curr.clone(), im, shops);
|
||||
if curr == next.1 {
|
||||
return next;
|
||||
}
|
||||
|
||||
curr = next.1;
|
||||
}
|
||||
}
|
||||
|
||||
fn search(im: &ImageMeta, shops: &Vec<Location>) -> (Location, f64) {
|
||||
let mut best_dist = 0f64;
|
||||
let mut best_point = Location {lat: Radians(0f64), lon: Radians(0f64)};
|
||||
for iter in 0..3000 {
|
||||
let start = start_point(im);
|
||||
let local = find_local_best(start, im, shops);
|
||||
if local.0 > best_dist {
|
||||
best_dist = local.0;
|
||||
best_point = local.1.clone();
|
||||
println!("At iter {}, new best", iter);
|
||||
}
|
||||
}
|
||||
|
||||
return (best_point, best_dist);
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let file = File::open("./pos.txt")?;
|
||||
let mut frog_shops: Vec<Location> = Vec::with_capacity(10778);
|
||||
for line in io::BufReader::new(file).lines() {
|
||||
let line = line?;
|
||||
let numbers: Vec<f64> = line.split(" ").map(str::parse::<f64>).map(Result::unwrap).collect();
|
||||
frog_shops.push(Location {
|
||||
lat: Degrees(numbers[0]).into(),
|
||||
lon: Degrees(numbers[1]).into()
|
||||
});
|
||||
}
|
||||
|
||||
let poland = include_bytes!("../poland.bmp");
|
||||
let mut cursor = Cursor::new(poland);
|
||||
let img = bmp::from_reader(&mut cursor)?;
|
||||
// println!("{:?}", img);
|
||||
|
||||
// println!("{:?}", dist((
|
||||
// radians!(52f64), radians!(19f64)
|
||||
// ), &frog_shops));
|
||||
|
||||
// println!("{:?}", in_poland((radians!(52f64), radians!(19f64)), &img, p_horiz_scale, p_verti_scale));
|
||||
// println!("{:?}", degrees_but_tuple!(start_point(&img, p_horiz_scale, p_verti_scale)));
|
||||
// println!("{:?}", degrees_but_tuple!(find_local_best(
|
||||
// (radians!(52f64), radians!(19f64)), &img, p_horiz_scale, p_verti_scale, &frog_shops
|
||||
// )));
|
||||
let imagemeta = ImageMeta {
|
||||
horizontal_scale: (img.get_width() as f64) / (IMG_EAST_BORDER.0 - IMG_WEST_BORDER.0),
|
||||
vertical_scale: (img.get_height() as f64) / (IMG_NORTH_BORDER.0 - IMG_SOUTH_BORDER.0),
|
||||
image: img
|
||||
};
|
||||
// let result = (0..100)
|
||||
// .into_iter()
|
||||
// .into_par_iter()
|
||||
// .map(|_| search(&imagemeta, &frog_shops))
|
||||
// .max_by(|a, b| {
|
||||
// a.1.partial_cmp(&b.1).unwrap()
|
||||
// }).unwrap();
|
||||
let result = search(&imagemeta, &frog_shops);
|
||||
|
||||
let best_point: (Degrees, Degrees) = (result.0.lat.into(), result.0.lon.into());
|
||||
println!("Found best point at ({}, {}); Distance is {}", best_point.0.0, best_point.1.0, result.1);
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue
Block a user