feat: AR-GPS initial commit — Python + JavaScript PyQt5 (standalone desktop app) + FastAPI (charts REST router) + OpenLayers (frontend map)
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
"""SQLite persistence for waypoints and routes."""
|
||||
import sqlite3, json, uuid
|
||||
from pathlib import Path
|
||||
from datetime import datetime, timezone
|
||||
|
||||
|
||||
def _conn(db_path: Path):
|
||||
con = sqlite3.connect(db_path)
|
||||
con.row_factory = sqlite3.Row
|
||||
return con
|
||||
|
||||
|
||||
def init_db(db_path: Path):
|
||||
db_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
con = _conn(db_path)
|
||||
con.executescript("""
|
||||
CREATE TABLE IF NOT EXISTS waypoints (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
lat REAL NOT NULL,
|
||||
lon REAL NOT NULL,
|
||||
notes TEXT,
|
||||
mark_type TEXT DEFAULT '',
|
||||
locked INTEGER DEFAULT 0,
|
||||
created_at TEXT
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS routes (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
wpt_ids TEXT NOT NULL, -- JSON array of waypoint ids in order
|
||||
created_at TEXT
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS track_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
lat REAL,
|
||||
lon REAL,
|
||||
sog REAL,
|
||||
cog REAL,
|
||||
alt REAL,
|
||||
hdop REAL,
|
||||
ts TEXT
|
||||
);
|
||||
""")
|
||||
con.commit()
|
||||
# Migration: add mark_type column to existing DBs that don't have it
|
||||
try:
|
||||
con.execute("ALTER TABLE waypoints ADD COLUMN mark_type TEXT DEFAULT ''")
|
||||
con.commit()
|
||||
except Exception:
|
||||
pass # column already exists
|
||||
try:
|
||||
con.execute("ALTER TABLE waypoints ADD COLUMN locked INTEGER DEFAULT 0")
|
||||
con.commit()
|
||||
except Exception:
|
||||
pass
|
||||
con.close()
|
||||
|
||||
|
||||
# ── Waypoints ─────────────────────────────────────────────────────────────────
|
||||
|
||||
def get_waypoints(db_path: Path) -> list:
|
||||
con = _conn(db_path)
|
||||
rows = con.execute("SELECT * FROM waypoints ORDER BY created_at").fetchall()
|
||||
con.close()
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
|
||||
def save_waypoint(db_path: Path, data: dict) -> dict:
|
||||
wid = data.get("id") or str(uuid.uuid4())[:8].upper()
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
con = _conn(db_path)
|
||||
con.execute("""
|
||||
INSERT INTO waypoints (id, name, lat, lon, notes, mark_type, locked, created_at)
|
||||
VALUES (?,?,?,?,?,?,?,?)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
name=excluded.name, lat=excluded.lat, lon=excluded.lon,
|
||||
notes=excluded.notes, mark_type=excluded.mark_type,
|
||||
locked=excluded.locked
|
||||
""", (wid, data["name"], data["lat"], data["lon"],
|
||||
data.get("notes", ""), data.get("mark_type", ""),
|
||||
int(data.get("locked", 0)),
|
||||
data.get("created_at", now)))
|
||||
con.commit()
|
||||
con.close()
|
||||
return {**data, "id": wid, "created_at": now}
|
||||
|
||||
|
||||
def delete_waypoint(db_path: Path, wid: str):
|
||||
con = _conn(db_path)
|
||||
con.execute("DELETE FROM waypoints WHERE id=?", (wid,))
|
||||
con.commit()
|
||||
con.close()
|
||||
|
||||
|
||||
# ── Routes ────────────────────────────────────────────────────────────────────
|
||||
|
||||
def get_routes(db_path: Path) -> list:
|
||||
con = _conn(db_path)
|
||||
rows = con.execute("SELECT * FROM routes ORDER BY created_at").fetchall()
|
||||
con.close()
|
||||
result = []
|
||||
for r in rows:
|
||||
d = dict(r)
|
||||
d["wpt_ids"] = json.loads(d["wpt_ids"])
|
||||
result.append(d)
|
||||
return result
|
||||
|
||||
|
||||
def save_route(db_path: Path, data: dict) -> dict:
|
||||
rid = data.get("id") or str(uuid.uuid4())[:8].upper()
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
con = _conn(db_path)
|
||||
con.execute("""
|
||||
INSERT INTO routes (id, name, wpt_ids, created_at)
|
||||
VALUES (?,?,?,?)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
name=excluded.name, wpt_ids=excluded.wpt_ids
|
||||
""", (rid, data["name"], json.dumps(data.get("wpt_ids", [])),
|
||||
data.get("created_at", now)))
|
||||
con.commit()
|
||||
con.close()
|
||||
return {**data, "id": rid, "wpt_ids": data.get("wpt_ids", []), "created_at": now}
|
||||
|
||||
|
||||
def delete_route(db_path: Path, rid: str):
|
||||
con = _conn(db_path)
|
||||
con.execute("DELETE FROM routes WHERE id=?", (rid,))
|
||||
con.commit()
|
||||
con.close()
|
||||
|
||||
|
||||
# ── Track log ─────────────────────────────────────────────────────────────────
|
||||
|
||||
def log_position(db_path: Path, fix: dict):
|
||||
con = _conn(db_path)
|
||||
con.execute(
|
||||
"INSERT INTO track_log (lat,lon,sog,cog,alt,hdop,ts) VALUES (?,?,?,?,?,?,?)",
|
||||
(fix.get("lat"), fix.get("lon"), fix.get("sog"), fix.get("cog"),
|
||||
fix.get("altitude"), fix.get("hdop"),
|
||||
datetime.now(timezone.utc).isoformat())
|
||||
)
|
||||
con.commit()
|
||||
con.close()
|
||||
|
||||
|
||||
def get_track(db_path: Path, limit: int = 2000) -> list:
|
||||
con = _conn(db_path)
|
||||
rows = con.execute(
|
||||
"SELECT lat,lon,sog,cog,alt,hdop,ts FROM track_log ORDER BY id DESC LIMIT ?",
|
||||
(limit,)
|
||||
).fetchall()
|
||||
con.close()
|
||||
return [dict(r) for r in reversed(rows)]
|
||||
|
||||
|
||||
def clear_track(db_path: Path):
|
||||
con = _conn(db_path)
|
||||
con.execute("DELETE FROM track_log")
|
||||
con.commit()
|
||||
con.close()
|
||||
Reference in New Issue
Block a user