test openlayers, adjust geofeature models for openlayers

This commit is contained in:
Cyberes 2024-09-29 20:52:36 -06:00
parent 328d2e8684
commit b476272808
7 changed files with 166 additions and 47 deletions

View File

@ -1,4 +1,3 @@
Django backend, vue.js frontend
Tagging support (tag roads, trails, etc)
Sharing (share individual items or select items or tags to include)
Organization by folder

View File

@ -47,7 +47,7 @@ def process_feature(converted_kml) -> Tuple[list, ImportLog]:
for i, timestamp_str in enumerate(feature['properties']['times']):
timestamp = int(parse(timestamp_str).timestamp() * 1000)
feature['geometry']['coordinates'][i].append(timestamp)
feature['properties'] = GeojsonRawProperty(**feature['properties']).dict()
feature['properties'] = GeojsonRawProperty(**feature['properties']).model_dump()
features.append(feature)
else:
# Log the error
@ -78,5 +78,4 @@ def load_geojson_type(data: dict) -> dict:
'coordinates': item.pop('coordinates'),
}
item['type'] = 'Feature'
item['properties']['title'] = item['properties'].pop('name')
return geojson_dict

View File

@ -1,12 +1,11 @@
from datetime import datetime
import json
from enum import Enum
from typing import Optional, List, Union, Tuple
from typing import List, Tuple, Optional
from typing import Union
import pytz
from pydantic import Field, BaseModel
from pydantic import BaseModel, Field
from geo_lib.daemon.workers.workers_lib.importer.logging import ImportLog
from geo_lib.geo_backend import SOFTWARE_NAME, SOFTWARE_VERSION
class GeoFeatureType(str, Enum):
@ -15,42 +14,54 @@ class GeoFeatureType(str, Enum):
POLYGON = 'Polygon'
class GeoFeatureProperties(BaseModel):
tags: List[str] = Field(default_factory=list)
created: datetime = datetime.utcnow().replace(tzinfo=pytz.utc)
software: str = Field(SOFTWARE_NAME, frozen=True)
software_version: str = Field(SOFTWARE_VERSION, frozen=True)
class Rendering(BaseModel):
stroke_width: int = Field(2, alias='strokeWidth')
stroke_color: Tuple[int, int, int, float] = Field((255, 0, 0, 1.0), alias='strokeColor')
fill_color: Optional[Tuple[int, int, int, float]] = Field((255, 0, 0, 0.2), alias='fillColor')
class GeoFeature(BaseModel):
"""
A thing that's shown on the map.
Can be a point, linestring, or polygon.
"""
class Properties(BaseModel):
name: str
id: int # From the database
type: GeoFeatureType
id: Optional[int] = -1
description: Optional[str] = None
geometry: List
properties: GeoFeatureProperties = Field(default_factory=GeoFeatureProperties)
tags: Optional[List[str]] = Field(default_factory=list)
rendering: Optional[Rendering] = Field(default_factory=Rendering)
class GeoPoint(GeoFeature):
class PointFeatureGeometry(BaseModel):
type: GeoFeatureType = GeoFeatureType.POINT
geometry: List[float]
coordinates: Union[Tuple[float, float], Tuple[float, float, float]]
class GeoLineString(GeoFeature):
class LineStringGeometry(BaseModel):
type: GeoFeatureType = GeoFeatureType.LINESTRING
geometry: List[List[float]]
coordinates: List[Union[Tuple[float, float], Tuple[float, float, float], Tuple[float, float, float, int]]]
class GeoPolygon(GeoFeature):
class PolygonGeometry(BaseModel):
type: GeoFeatureType = GeoFeatureType.POLYGON
geometry: List[List[List[float]]]
coordinates: List[List[Union[Tuple[float, float], Tuple[float, float, float]]]]
GeoFeatureSupported = Union[GeoPoint, GeoLineString, GeoPolygon]
class Feature(BaseModel):
type: str = 'Feature'
geometry: Union[PointFeatureGeometry, LineStringGeometry, PolygonGeometry]
properties: Properties
class PointFeature(Feature):
geometry: PointFeatureGeometry
class LineStringFeature(Feature):
geometry: LineStringGeometry
class PolygonFeature(Feature):
geometry: PolygonGeometry
GeoFeatureSupported = Union[PointFeature, LineStringFeature, PolygonFeature]
def geojson_to_geofeature(geojson: dict) -> Tuple[List[GeoFeatureSupported], ImportLog]:
@ -59,20 +70,32 @@ def geojson_to_geofeature(geojson: dict) -> Tuple[List[GeoFeatureSupported], Imp
for item in geojson['features']:
match item['geometry']['type'].lower():
case 'point':
c = GeoPoint
c = PointFeature
case 'linestring':
c = GeoLineString
c = LineStringFeature
case 'polygon':
c = GeoPolygon
c = PolygonFeature
case _:
import_log.add(f'Feature named "{item["properties"]["title"]}" had unsupported type "{item["geometry"]["type"]}".')
continue
result.append(c(
name=item['properties']['title'],
id=-1, # This will be updated after it's added to the main data store.
description=item['properties']['description'],
tags=item['properties']['feature_tags'],
geometry=item['geometry']['coordinates']
))
f = c(**item)
if isinstance(f, (PointFeature, LineStringFeature)):
del f.properties.rendering.fill_color
# TODO: do this shit
f.properties.id = -1 # This will be updated after it's added to the main data store.
result.append(f)
return result, import_log
def geofeature_to_geojson(feature: Union[GeoFeatureSupported, list]) -> str:
if isinstance(feature, list):
return json.dumps({
'type': 'FeatureCollection',
'features': [json.loads(x.model_dump_json(by_alias=True)) for x in feature]
})
else:
return feature.model_dump_json(by_alias=True)

View File

@ -7,4 +7,4 @@ class GeojsonRawProperty(BaseModel):
# A class to whitelist these properties.
name: str
description: Optional[str] = None
feature_tags: List[str] = Field(default_factory=list)
tags: List[str] = Field(default_factory=list, alias='feature_tags') # kml2geojson calls this field `feature_tags`

View File

@ -0,0 +1,19 @@
import argparse
import sys
from pathlib import Path
sys.path.append(str(list(Path(__file__).parents)[1]))
from geo_lib.daemon.workers.workers_lib.importer.kml import kml_to_geojson
from geo_lib.types.feature import geojson_to_geofeature, geofeature_to_geojson
parser = argparse.ArgumentParser()
parser.add_argument('kml_path')
args = parser.parse_args()
raw_kml = Path(args.kml_path).expanduser().absolute().resolve().read_text()
geojson_data, kml_conv_messages = kml_to_geojson(raw_kml)
geofetures, typing_messages = geojson_to_geofeature(geojson_data)
print(geofeature_to_geojson(geofetures))

View File

@ -1,7 +1 @@
1. Style main import page
2. Fix created field reset on edit imported
3. Implement refresh on edit imported
4. Style messages/log on edit imported
5. Implement upload working animation on edit imported
- For tracks, set the created date to the timestamp of the first point in the track
- For tracks, set the created date to the timestamp of the first point in the track

View File

@ -0,0 +1,85 @@
<!DOCTYPE html>
<html style="width: 100%; height: 100%;">
<head>
<title>OpenLayers LineString Example</title>
<link href="https://openlayers.org/en/v6.5.0/css/ol.css" rel="stylesheet" type="text/css">
<script src="https://openlayers.org/en/v6.5.0/build/ol.js"></script>
</head>
<body style="width: 100%; height: 100%; margin:0">
<div id="map" style="width: 100%; height: 100%;"></div>
<script>
const geojsonData = {
"type": "FeatureCollection",
"features": []
};
const features = new ol.format.GeoJSON().readFeatures(geojsonData, {
featureProjection: 'EPSG:3857',
dataProjection: 'EPSG:4326'
});
const vectorSource = new ol.source.Vector({
features: features
});
const vectorLayer = new ol.layer.Vector({
source: vectorSource,
style: function (feature) {
const rendering = feature.get('rendering');
const geometryType = feature.getGeometry().getType();
if (geometryType === 'Point') {
return new ol.style.Style({
image: new ol.style.Circle({
radius: 6,
fill: new ol.style.Fill({
color: rendering.strokeColor
}),
stroke: new ol.style.Stroke({
color: rendering.strokeColor,
width: rendering.strokeWidth
})
})
});
} else if (geometryType === 'LineString') {
return new ol.style.Style({
stroke: new ol.style.Stroke({
color: rendering.strokeColor,
width: rendering.strokeWidth
})
});
} else if (geometryType === 'Polygon') {
return new ol.style.Style({
stroke: new ol.style.Stroke({
color: rendering.strokeColor,
width: rendering.strokeWidth
}),
fill: new ol.style.Fill({
color: rendering.fillColor
})
});
}
}
});
const map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayer
],
view: new ol.View({
center: ol.proj.fromLonLat([-104.692626, 38.881215]),
zoom: 10
})
});
</script>
<style>
.ol-attribution {
display: none;
}
</style>
</body>
</html>