diff --git a/docs/developers/install.md b/docs/developers/install.md index 49d78048..65f80712 100644 --- a/docs/developers/install.md +++ b/docs/developers/install.md @@ -94,16 +94,16 @@ psql -U postgres -d oldinsurancemaps -c "CREATE EXTENSION PostGIS;" Run migrations and create admin user to access the Django admin panel (and login to the site once it's running) ```bash -python manage.py migrate -python manage.py createsuperuser +uv run manage.py migrate +uv run manage.py createsuperuser ``` Load a few other fixtures with some default objects: ```bash -python manage.py loaddata default-region-categories -python manage.py loaddata default-layerset-categories -python manage.py loaddata default-navbar +uv run manage.py loaddata default-region-categories +uv run manage.py loaddata default-layerset-categories +uv run manage.py loaddata default-navbar ``` Alternatively, if you have set all of the `DATABASE_*` variables in `.env`, you can use the included script to perform all of the actions described above: @@ -125,7 +125,7 @@ source ./scripts/load_dev_data.sh There are a few js and css plugins that must be downloaded to the local static directory: ```bash -python manage.py get-plugins +uv run manage.py get-plugins ``` The frontend uses a suite of independently built svelte components. First install `pnpm`: https://pnpm.io/installation. Then: @@ -153,7 +153,7 @@ In production, use the `build` command instead, and then Django's `collectstatic ```bash pnpm run build cd ../../.. -python manage.py collectstatic --noinput +uv run manage.py collectstatic --noinput ``` This bash script combines all steps into one: @@ -168,7 +168,7 @@ You can now activate the virtual environment and then run the django dev server: ```bash source .venv/bin/activate -python manage.py runserver +uv run manage.py runserver ``` and view the site at `http://localhost:8000`. @@ -259,13 +259,13 @@ In production, you will already be using a webserver for static files so you wil All tests are stored in `ohmg/tests`. Make sure you have installed dev requirements, then run: ```bash -python manage.py test +uv run manage.py test ``` To skip the tests that make external calls to the LOC API, use the following command. Keep in mind that coverage numbers will be lower when you skip tests. ```bash -python manage.py test --exclude-tag=loc +uv run manage.py test --exclude-tag=loc ``` ## Load the Place scaffolding @@ -273,7 +273,7 @@ python manage.py test --exclude-tag=loc Load all the place objects to create geography scaffolding (this will take a minute or two) ```bash -python manage.py place import-all +uv run manage.py place import-all ``` ## Environment variables diff --git a/ohmg/conf/settings.py b/ohmg/conf/settings.py index 6bae135c..73ebb726 100644 --- a/ohmg/conf/settings.py +++ b/ohmg/conf/settings.py @@ -13,7 +13,7 @@ # set BASE_DIR which is used to locate log, cache, temp, static, and uploaded dirs BASE_DIR = PROJECT_DIR.parent -# the build file is generated and updated with python manage.py update_build +# the build file is generated and updated with ./manage.py update_build BUILD_FILE = BASE_DIR / ".build" BUILD_NUMBER = "" if BUILD_FILE.is_file(): diff --git a/ohmg/extensions/iiif.py b/ohmg/extensions/iiif.py index f1d0c492..14b3c37e 100644 --- a/ohmg/extensions/iiif.py +++ b/ohmg/extensions/iiif.py @@ -34,35 +34,35 @@ def get_target(self): wgs84.ImportFromEPSG(4326) mask_geojson = json.loads(self.layer.mask.geojson) coords = mask_geojson["coordinates"][0] - ct = CoordTransform(SpatialReference("WGS84"), SpatialReference("EPSG:3857")) + + target_crs = f"EPSG:{self.region.gcpgroup.crs_epsg}" + ct = CoordTransform(SpatialReference("WGS84"), SpatialReference(target_crs)) polygon = Polygon(coords) polygon.transform(ct) - g = Georeferencer( - crs=f"EPSG:{self.region.gcpgroup.crs_epsg}", - transformation=self.region.gcpgroup.transformation, - gcps_geojson=self.region.gcpgroup.as_geojson, - ) in_path = ( self.region.file.url if self.region.file.url.startswith("http") else self.region.file.path ) + + g = Georeferencer( + crs=target_crs, + transformation=self.region.gcpgroup.transformation, + gcps_geojson=self.region.gcpgroup.as_geojson, + ) g.make_gcps_vrt(in_path) ds = gdal.Open(g.gcps_vrt.get_vsi_url()) transformer = gdal.Transformer( # Source datasource - None, - # Target datasource ds, + # Target datasource + None, # Transformer options that are ultimately passed to 'GDALCreateGenImgProjTransformer2()' # https://gdal.org/api/gdal_alg.html#_CPPv432GDALCreateGenImgProjTransformer212GDALDatasetH12GDALDatasetHPPc - [ - ## need to update this, different number if thin plate spline - "MAX_GCP_ORDER=1", - ], + g.make_transformer_options(), ) - transposed, status = transformer.TransformPoints(False, polygon.coords[0]) + transposed, status = transformer.TransformPoints(True, polygon.coords[0]) coords_str = [f"{i[0]},{i[1]}" for i in transposed] coords_join = " ".join(coords_str) @@ -114,14 +114,15 @@ def get_gcps(self): return features def get_body(self): - if self.region.gcpgroup.transformation == "poly1": - transformation = {"type": "polynomial", "options": {"order": 1}} - elif self.region.gcpgroup.transformation == "tps": - transformation = { - "type": "thinPlateSpline", - } - else: - raise Exception("invalid transformation", self.region.gcpgroup.transformation) + match t := self.region.gcpgroup.transformation: + case "poly1": + transformation = {"type": "polynomial", "options": {"order": 1}} + case "tps": + transformation = {"type": "thinPlateSpline"} + case "helmert": + transformation = {"type": "helmert"} + case _: + raise Exception(f"invalid transformation: {t}") body = { "id": full_reverse("iiif_gcps_view", args=(self.layerid,)), diff --git a/ohmg/extensions/urls.py b/ohmg/extensions/urls.py index 65408ed4..e85ebc56 100644 --- a/ohmg/extensions/urls.py +++ b/ohmg/extensions/urls.py @@ -1,5 +1,6 @@ from django.urls import path, register_converter +from ohmg.extensions.feeds import PlaceFeed from ohmg.places.converters import PlaceConverter from .views import ( @@ -9,7 +10,6 @@ IIIFResourceView, IIIFSelectorView, ) -from ohmg.extensions.feeds import PlaceFeed register_converter(PlaceConverter, "place-slug") diff --git a/ohmg/frontend/svelte_components/src/components/interfaces/Georeferencer.svelte b/ohmg/frontend/svelte_components/src/components/interfaces/Georeferencer.svelte index 73a53141..1785c5fe 100644 --- a/ohmg/frontend/svelte_components/src/components/interfaces/Georeferencer.svelte +++ b/ohmg/frontend/svelte_components/src/components/interfaces/Georeferencer.svelte @@ -173,21 +173,6 @@ available: CONTEXT.user.perms.includes("core.use_helmert") }, ]; - $: { - if (gcpList.length == 3 && currentTransformation == "helmert") { - currentTransformation = "poly1" - } - if (currentTransformation == "helmert") { - minGCPs = 2; - } else { - minGCPs = 3; - } - } - $: { - if (gcpList.length <= 2 && currentTransformation != "helmert") { - previewMode = "n/a" - } - } let currentTargetProjection = 'EPSG:3857'; const availableProjections = [ @@ -590,6 +575,19 @@ note: props.note, }); }); + + // special handling for helmert, do this before the preview is regenerated + if (gcpList.length == 3 && currentTransformation == "helmert") { + currentTransformation = "poly1"; + } + if (currentTransformation == "helmert") { + minGCPs = 2; + } else { + minGCPs = 3; + } + if (gcpList.length <= 2 && currentTransformation != "helmert") { + previewMode = "n/a" + } getPreview(); } @@ -736,6 +734,16 @@ return featureCollection; }; + const preparePayload = function () { + return { + gcp_geojson: asGeoJSON(), + transformation: currentTransformation, + projection: currentTargetProjection, + sesh_id: sessionId, + last_preview_id: currentPreviewId, + } + } + function getPreview() { if (currentTransformation == "helmert") { minGCPs = 2; @@ -750,13 +758,7 @@ `/georeference/${REGION.id}/`, CONTEXT.ohmg_post_headers, 'preview', - { - gcp_geojson: asGeoJSON(), - transformation: currentTransformation, - projection: currentTargetProjection, - sesh_id: sessionId, - last_preview_id: currentPreviewId, - }, + preparePayload(), (result) => { previewMode = previewMode == 'n/a' ? 'transparent' : previewMode; // updating this variable will trigger the preview layer to be @@ -779,13 +781,7 @@ `/georeference/${REGION.id}/`, CONTEXT.ohmg_post_headers, 'submit', - { - gcp_geojson: asGeoJSON(), - transformation: currentTransformation, - projection: currentTargetProjection, - sesh_id: sessionId, - last_preview_id: currentPreviewId, - }, + preparePayload(), () => { window.location.href = `/map/${REGION.map}`; }, @@ -901,17 +897,23 @@ }} on:unload={cancelSession} /> -
- You have only two GCPs, but it is highly advisable to have three or more. - Please add more, unless you are unable to do so. + You have only created two GCPs, but we recommend having three or more. + If possible, please add more before submitting your work.