332 lines
12 KiB
Python
332 lines
12 KiB
Python
# Copyright (c) 2025 Martin Kayser (tebarius)
|
|
# Licensed under the MIT License. See LICENSE file in the project root.
|
|
import math
|
|
from re import match # für unkennify
|
|
import streamlit as st
|
|
from streamlit_folium import st_folium
|
|
import folium
|
|
import os
|
|
|
|
|
|
# ***recursive quersummenfunktion***
|
|
def q_sum(n):
|
|
if n < 10:
|
|
return n
|
|
else:
|
|
n = q_sum(n // 10) + n % 10
|
|
return n
|
|
|
|
# ***recursive iterierte quersummenfunktion***
|
|
def iq_sum(n):
|
|
if n < 10:
|
|
return n
|
|
else:
|
|
n = iq_sum(q_sum(n))
|
|
return n
|
|
|
|
# ***produziert eine Liste mit Primzahlen kleiner als grenze***
|
|
# ***nach dem Prinzip des "Sieb des Eratosthenes"***
|
|
@st.cache_resource
|
|
def primzahlliste(grenze):
|
|
primes = []
|
|
is_prime = [True] * grenze
|
|
is_prime[0] = False
|
|
is_prime[1] = False
|
|
for i in range(2, int(math.sqrt(grenze))):
|
|
if is_prime[i]:
|
|
for j in range((i * i), grenze, i):
|
|
is_prime[j] = False
|
|
for i in range(len(is_prime)):
|
|
if is_prime[i]:
|
|
primes.append(i)
|
|
return primes
|
|
|
|
# ***alle permutationen generieren***
|
|
def all_perms(liste):
|
|
if len(liste) <= 1:
|
|
yield liste
|
|
else:
|
|
for perm in all_perms(liste[1:]):
|
|
for i in range(len(perm) + 1):
|
|
yield perm[:i] + liste[0:1] + perm[i:]
|
|
|
|
# ***zählfunktionen für anagramm suche
|
|
def buchstabenzaehl(buchstabe, anzahl):
|
|
if buchstabe in anzahl:
|
|
anzahl[buchstabe] = anzahl[buchstabe] + 1
|
|
else:
|
|
anzahl[buchstabe] = 1
|
|
|
|
def wortzaehl(wort):
|
|
anzahl = {}
|
|
for buchstabe in wort:
|
|
buchstabenzaehl(buchstabe.upper(), anzahl)
|
|
return anzahl
|
|
|
|
# ***Funktionen für Kachelkoordinaten/Maptiles-Funktion
|
|
def dec_to_maptiles(lat_deg, lon_deg, zoom):
|
|
lat_rad = math.radians(lat_deg)
|
|
n = 2.0 ** zoom
|
|
xtile = int((lon_deg + 180.0) / 360.0 * n)
|
|
ytile = int((1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n)
|
|
return xtile, ytile
|
|
|
|
def maptiles_to_dec(xtile, ytile, zoom):
|
|
n = 2.0 ** zoom
|
|
lon_dec = xtile / n * 360.0 - 180.0
|
|
lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * ytile / n)))
|
|
lat_dec = math.degrees(lat_rad)
|
|
return lat_dec, lon_dec
|
|
|
|
# ***Dezimalgrad in Dezimalminuten (Ausgabe als String)
|
|
def dec_to_deg(lat_dec, lon_dec):
|
|
if lat_dec < 0:
|
|
lat_pre = "S"
|
|
else:
|
|
lat_pre = "N"
|
|
if lon_dec < 0:
|
|
lon_pre = "W"
|
|
else:
|
|
lon_pre = "E"
|
|
lat = abs(lat_dec)
|
|
lon = abs(lon_dec)
|
|
lat_degree = int(lat)
|
|
lon_degree = int(lon)
|
|
lat_minutes = (lat - lat_degree) * 60
|
|
lon_minutes = (lon - lon_degree) * 60
|
|
return ("{}{} {:.3f} {}{} {:.3f}".format(lat_pre, lat_degree, round(lat_minutes, 3), lon_pre, lon_degree,
|
|
round(lon_minutes, 3)))
|
|
|
|
# ***ReverseWherIGo zu Dezimalgrad
|
|
def rwig_to_coords(a, b, c):
|
|
lat, lon = 0, 0
|
|
a = int(a)
|
|
b = int(b)
|
|
c = int(c)
|
|
if (a % 1000 - a % 100) / 100 == 1:
|
|
lat_sign = 1
|
|
lon_sign = 1
|
|
elif (a % 1000 - a % 100) / 100 == 2:
|
|
lat_sign = -1
|
|
lon_sign = 1
|
|
elif (a % 1000 - a % 100) / 100 == 3:
|
|
lat_sign = 1
|
|
lon_sign = -1
|
|
elif (a % 1000 - a % 100) / 100 == 4:
|
|
lat_sign = -1
|
|
lon_sign = -1
|
|
else:
|
|
return 0, 0
|
|
if ((c % 100000 - c % 10000) / 10000 + (c % 100 - c % 10) / 10) % 2 == 0:
|
|
lat = lat_sign * (
|
|
(a % 10000 - a % 1000) / 100
|
|
+ (b % 100 - b % 10) / 10
|
|
+ (b % 100000 - b % 10000) / 100000
|
|
+ (c % 1000 - c % 100) / 10000
|
|
+ (a % 1000000 - a % 100000) / 100000000
|
|
+ (c % 100 - c % 10) / 100000
|
|
+ a % 10 * 1.0E-5)
|
|
elif ((c % 100000 - c % 10000) / 10000 + (c % 100 - c % 10) / 10) % 2 != 0:
|
|
lat = lat_sign * (
|
|
(b % 1000000 - b % 100000) / 10000
|
|
+ a % 10 + (a % 10000 - a % 1000) / 10000
|
|
+ (c % 1000000 - c % 100000) / 10000000
|
|
+ (c % 1000 - c % 100) / 100000
|
|
+ (c % 100 - c % 10) / 100000
|
|
+ (a % 1000000 - a % 100000) / 10000000000)
|
|
if ((c % 100000 - c % 10000) / 10000 + (c % 100 - c % 10) / 10) % 2 == 0:
|
|
lon = lon_sign * (
|
|
(a % 100000 - a % 10000) / 100
|
|
+ (c % 1000000 - c % 100000) / 10000
|
|
+ c % 10 + (b % 1000 - b % 100) / 1000
|
|
+ (b % 1000000 - b % 100000) / 10000000
|
|
+ (a % 100 - a % 10) / 10000
|
|
+ (c % 100000 - c % 10000) / 100000000
|
|
+ b % 10 * 1.0E-5)
|
|
elif ((c % 100000 - c % 10000) / 10000 + (c % 100 - c % 10) / 10) % 2 != 0:
|
|
lon = lon_sign * (
|
|
(b % 100 - b % 10) * 10
|
|
+ c % 10 * 10
|
|
+ (a % 100 - a % 10) / 10
|
|
+ (a % 100000 - a % 10000) / 100000
|
|
+ (b % 1000 - b % 100) / 10000
|
|
+ b % 10 * 0.001
|
|
+ (c % 100000 - c % 10000) / 100000000
|
|
+ (b % 100000 - b % 10000) / 1000000000)
|
|
return round(lat, 5), round(lon, 5)
|
|
|
|
def unkennify(text):
|
|
# Funktion hier entnommen und angepasst: https://www.namesuppressed.com/software/kenny.py
|
|
decoded = ''
|
|
codemap = str.maketrans('MmPpFf', '001122')
|
|
n_len = len(text)
|
|
i = 0
|
|
while i + 3 <= n_len:
|
|
if match('[MmPpFf]{3,}', text[i:i + 3]):
|
|
num = int(text[i:i + 3].translate(codemap), 3) # 'mpf' -> '012' -> 5
|
|
cypher = chr(num + ord('a')) # 5 -> 'f'
|
|
if text[i].isupper():
|
|
cypher = cypher.upper()
|
|
decoded = decoded + cypher
|
|
i = i + 3
|
|
else:
|
|
decoded = decoded + text[i]
|
|
i = i + 1
|
|
if i < n_len:
|
|
decoded = decoded + text[i:]
|
|
return decoded
|
|
|
|
def generate_special_files():
|
|
out="\n\n\n"
|
|
if os.path.exists("./data/morse-de.dic"):
|
|
pass
|
|
else:
|
|
remorse_generate_morsede()
|
|
out+=":blue[deutsches Re-Morse-Wörterbuch wurde generiert] \n"
|
|
if os.path.exists("./data/t9-de.dic"):
|
|
pass
|
|
else:
|
|
t9_generate_t9de()
|
|
out+=":blue[deutsches T9-Wörterbuch wurde generiert] \n"
|
|
return out
|
|
|
|
def remorse_generate_morsede():
|
|
alphabet = {'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.', 'G': '--.',
|
|
'H': '....', 'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..', 'M': '--', 'N': '-.',
|
|
'O': '---', 'P': '.--.', 'Q': '--.-', 'R': '.-.', 'S': '...', 'T': '-', 'U': '..-',
|
|
'V': '...-', 'W': '.--', 'X': '-..-', 'Y': '-.--', 'Z': '--..', '1': '.----',
|
|
'2': '..---', '3': '...--', '4': '....-', '5': '.....', '6': '-....', '7': '--...',
|
|
'8': '---..', '9': '----.', '0': '-----', 'Ñ': '--.--', 'É': '..-..', 'È': '.-..-',
|
|
'À': '.--.-', 'Ü': '..--', 'Ö': '---.', 'Ä': '.-.-', '_': '..--.-', '@': '.--.-.',
|
|
'?': '..--..', '=': '-...-', ';': '-.-.-.', ':': '---...', '/': '-..-.',
|
|
'.': '.-.-.-', '-': '-....-', ',': '--..--', '+': '.-.-.', ')': '-.--.-',
|
|
'(': '-.--.', "'": '.----.', 'SS': '...--..'}
|
|
with open("./data/morse-de.dic", "w", encoding="iso-8859-1") as ofile:
|
|
for symbol, morse in alphabet.items():
|
|
ofile.write(f"{morse},{symbol}\n")
|
|
with open("./data/german.dic", "r", encoding="iso-8859-1") as infile:
|
|
for line in infile:
|
|
word = line.strip()
|
|
try:
|
|
morse_word = ''.join(alphabet[char.upper()] for char in word)
|
|
ofile.write(f"{morse_word},{word}\n")
|
|
except KeyError:
|
|
# Überspringe Wörter mit nicht-unterstützten Zeichen
|
|
continue
|
|
infile.close()
|
|
ofile.close()
|
|
|
|
def t9_generate_t9de():
|
|
alphabet = {'A': '2', 'B': '2', 'C': '2', 'D': '3', 'E': '3', 'F': '3', 'G': '4',
|
|
'H': '4', 'I': '4', 'J': '5', 'K': '5', 'L': '5', 'M': '6', 'N': '6',
|
|
'O': '6', 'P': '7', 'Q': '7', 'R': '7', 'S': '7', 'T': '8', 'U': '8',
|
|
'V': '8', 'W': '9', 'X': '9', 'Y': '9', 'Z': '9', '1': '1', '2': '2',
|
|
'3': '3', '4': '4', '5': '5', '6': '6', '7': '7', '8': '8', '9': '9',
|
|
'0': '0', 'Ñ': '6', 'É': '3', 'È': '3', 'À': '2', 'Ü': '8', 'Ö': '6',
|
|
'Ä': '2', '@': '1', '?': '1', '=': '0', ':': '1', '/': '1', '.': '1',
|
|
'-': '1', ',': '1', '+': '0', ')': '1', '(': '1', 'SS': '7'}
|
|
ofile = open("./data/t9-de.dic", "a", encoding="iso-8859-15")
|
|
file = open("./data/german.dic", "r", encoding="iso-8859-15")
|
|
for zeile in file:
|
|
omsg = ""
|
|
zeile = zeile.rstrip()
|
|
try:
|
|
for char in zeile:
|
|
omsg = omsg + alphabet[char.upper()]
|
|
except KeyError:
|
|
continue
|
|
else:
|
|
ofile.write(omsg + "," + zeile + "\n")
|
|
file.close()
|
|
ofile.close()
|
|
|
|
def rail_encrypt(plain_text: str, rails: int):
|
|
arr = [["" for _ in range(len(plain_text))] for _ in range(rails)]
|
|
r = 0
|
|
z = 0
|
|
plus = True
|
|
for b in plain_text:
|
|
arr[r][z] = b
|
|
z += 1
|
|
if r + 1 == rails and plus:
|
|
plus = False
|
|
r -= 1
|
|
elif r - 1 < 0 and not plus:
|
|
plus = True
|
|
r += 1
|
|
elif plus:
|
|
r += 1
|
|
else:
|
|
r -= 1
|
|
out = ""
|
|
for i in range(rails):
|
|
for j in range(len(plain_text)):
|
|
out += arr[i][j]
|
|
return out
|
|
|
|
def rail_decrypt(cipher: str, rails: int):
|
|
arr = [["_" for _ in range(len(cipher))] for _ in range(rails)]
|
|
# cipher ins array reinbasteln
|
|
x, y = 0, 0
|
|
first_x = True
|
|
for b in cipher:
|
|
if x >= len(cipher) and y < rails:
|
|
y += 1
|
|
x = y
|
|
first_x = True
|
|
arr[y][x] = b
|
|
if y == 0 or (first_x and y != rails - 1):
|
|
x = x + (rails - y - 1) * 2
|
|
first_x = False
|
|
elif y == rails - 1 or first_x is False:
|
|
x = x + (y * 2)
|
|
first_x = True
|
|
# dekodierten Text aus array holen
|
|
out = ""
|
|
x, y = 0, 0
|
|
down = True
|
|
for _ in range(len(cipher)):
|
|
out += arr[y][x]
|
|
x += 1
|
|
if down and y + 1 == rails:
|
|
down = False
|
|
y -= 1
|
|
elif down:
|
|
y += 1
|
|
elif down is False and y == 0:
|
|
down = True
|
|
y += 1
|
|
elif down is False:
|
|
y -= 1
|
|
return out
|
|
#from folium.map import DivIcon
|
|
def show_map_folium(df):
|
|
if not df.empty:
|
|
# Schritt 1: Bestimme die südwestliche und nordöstliche Ecke
|
|
sw = df[['lat', 'lon']].min().values.tolist() # Südwesten
|
|
ne = df[['lat', 'lon']].max().values.tolist() # Nordosten
|
|
# Schritt 2: Initialisiere Karte (Ort egal, wird überschrieben, zoom wird bei mehreren Koordinaten überschrieben)
|
|
m = folium.Map(location=df[["lat", "lon"]].mean().values.tolist(), zoom_start=15)
|
|
# Schritt 3: Marker hinzufügen
|
|
for _, row in df.iterrows():
|
|
if 'label' in row:
|
|
folium.Marker(
|
|
location=[row["lat"], row["lon"]],
|
|
popup=f"<b>{int(row['label'])}</b><br> Lat:{round(row['lat'], 5)}, Lon:{round(row['lon'], 5)}",
|
|
tooltip=f"<b>{int(row['label'])}</b><br> Lat:{round(row['lat'], 5)}, Lon:{round(row['lon'], 5)}",
|
|
icon = folium.Icon(color="red", icon="map-marker")
|
|
).add_to(m)
|
|
else:
|
|
folium.Marker(
|
|
location=[row["lat"], row["lon"]],
|
|
popup=f"Lat:{round(row['lat'], 5)}, Lon:{round(row['lon'], 5)}",
|
|
tooltip=f"Lat:{round(row['lat'], 5)}, Lon:{round(row['lon'], 5)}",
|
|
icon = folium.Icon(color="red", icon="map-marker")
|
|
).add_to(m)
|
|
if len(df) != 1:
|
|
# Schritt 4: Zoom anpassen bei mehr als einer Koordinate
|
|
m.fit_bounds([sw, ne])
|
|
# Schritt 5: In Streamlit anzeigen
|
|
st_folium(m, use_container_width=True)
|
|
else:
|
|
st.markdown(":red[Keine sinnvoll darstellbaren Koordinaten gefunden]") |