Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ jobs
bin/shptree
bin/gdalwarp
bin/ogr2ogr
/lib/python3.12
pyvenv.cfg
lib64
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,24 @@ These are named volumes inside your docker service.
This directory caches all the data from the data repository. WARNING: This
volume can take up a lot of space (100GB).

Note: To mount those volumes into a local directory to keep them if the containers are dropped, update the docker compose (change the path as needed):

```bash
volumes:
mapgen-data:
driver: local
driver_opts:
type: none
o: bind
device: /home/user/xcsoar_mapgen/mapgen-data
mapgen-jobs:
driver: local
driver_opts:
type: none
o: bind
device: /home/user/xcsoar_mapgen/mapgen-jobs
```

### Ports

```bash
Expand Down Expand Up @@ -83,3 +101,26 @@ docker-compose build \
```bash
docker-compose up -d
```

### Mounting the source files into the containers

To speed up the development process, it's possible to mount the folders with the Python sources into the container, which allow automatic reload by CherryPy.
Update the docker-compose:

```bash
...
services:
mapgen-frontend:
...
volumes:
- mapgen-jobs:/opt/mapgen/jobs
- ./lib:/opt/mapgen/lib
- ./bin:/opt/mapgen/bin
mapgen-worker:
...
volumes:
- mapgen-jobs:/opt/mapgen/jobs
- mapgen-data:/opt/mapgen/data
- ./lib:/opt/mapgen/lib
- ./bin:/opt/mapgen/bin
```
12 changes: 7 additions & 5 deletions lib/xcsoar/mapgen/server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,21 +83,23 @@ def index(self, **params):

try:
filename = waypoint_file.filename.lower()
if not filename.endswith(".dat") and (
filename.endswith(".dat") or not filename.endswith(".cup")
):

if not (filename.endswith(".dat") or filename.endswith(".cup")):
raise RuntimeError(
"Waypoint file {} has an unsupported format.".format(
waypoint_file.filename
)
)

waypoint_file.file.seek(0)

desc.bounds = parse_waypoint_file(
waypoint_file.filename, waypoint_file.file
).get_bounds()
desc.waypoint_file = (
"waypoints.cup" if filename.endswith(".cup") else "waypoints.dat"
)
except:
except Exception as e:
return view.render(
error="Unsupported waypoint file " + waypoint_file.filename
) | HTMLFormFiller(data=params)
Expand Down Expand Up @@ -134,7 +136,7 @@ def index(self, **params):

if desc.waypoint_file:
waypoint_file.file.seek(0)
f = open(job.file_path(desc.waypoint_file), "w")
f = open(job.file_path(desc.waypoint_file), "wb")
try:
shutil.copyfileobj(fsrc=waypoint_file.file, fdst=f, length=1024 * 64)
finally:
Expand Down
92 changes: 59 additions & 33 deletions lib/xcsoar/mapgen/waypoints/seeyou_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,59 +76,85 @@ def __parse_length(str):
def parse_seeyou_waypoints(lines, bounds=None):
waypoint_list = WaypointList()

first = True
for line in lines:
if first:
first = False
continue

line = line.strip()
if line == "name,code,country,lat,lon,elev,style,rwdir,rwlen,freq,desc":
continue
header = None
columns = {}

for raw_line in lines:
if isinstance(raw_line, bytes):
try:
line = raw_line.decode("utf-8")
except UnicodeDecodeError:
line = raw_line.decode("windows-1252")
line = line.strip()
else:
line = raw_line.strip()

if line == "" or line.startswith("*"):
if not line or line.startswith("*"):
continue

if line == "-----Related Tasks-----":
break
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# Parse CSV
fields = []
line = __CSVLine(line)
while line.has_next():
fields.append(next(line))

if len(fields) < 6:
csv_line = __CSVLine(line)
while csv_line.has_next():
fields.append(next(csv_line))

# First non-comment line is the header
if header is None:
header = [f.strip().lower() for f in fields]
columns = {name: idx for idx, name in enumerate(header)}
continue

lat = __parse_coordinate(fields[3])
if bounds and (lat > bounds.top or lat < bounds.bottom):
continue
def get(name, default=""):
idx = columns.get(name)
if idx is None or idx >= len(fields):
return default
return fields[idx]

lon = __parse_coordinate(fields[4])
if bounds and (lon > bounds.right or lon < bounds.left):
try:
lat = __parse_coordinate(get("lat"))
lon = __parse_coordinate(get("lon"))
except Exception:
continue

if bounds:
if lat > bounds.top or lat < bounds.bottom:
continue
if lon > bounds.right or lon < bounds.left:
continue

wp = Waypoint()
wp.lat = lat
wp.lon = lon
wp.altitude = __parse_altitude(fields[5])
wp.name = fields[0].strip()
wp.country_code = fields[2].strip()

if len(fields) > 6 and len(fields[6]) > 0:
wp.cup_type = int(fields[6])
wp.name = get("name").strip()
wp.country_code = get("country").strip()

elev = get("elev")
if elev:
wp.altitude = __parse_altitude(elev)

style = get("style")
if style:
wp.cup_type = int(style)

if len(fields) > 7 and len(fields[7]) > 0:
wp.runway_dir = int(fields[7])
rwdir = get("rwdir")
if rwdir:
wp.runway_dir = int(rwdir)

if len(fields) > 8 and len(fields[8]) > 0:
wp.runway_len = __parse_length(fields[8])
rwlen = get("rwlen")
if rwlen:
wp.runway_len = __parse_length(rwlen)

if len(fields) > 9 and len(fields[9]) > 0:
wp.freq = float(fields[9])
freq = get("freq")
if freq:
wp.freq = float(freq)

if len(fields) > 10 and len(fields[10]) > 0:
wp.comment = fields[10].strip()
desc = get("desc")
if desc:
wp.comment = desc.strip()

waypoint_list.append(wp)

Expand Down