Skip to content
Merged
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
23 changes: 22 additions & 1 deletion ohmg/core/admin.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.contrib import admin
from django.http import HttpResponseRedirect
from django.utils.safestring import mark_safe

from ohmg.core.models import (
Expand Down Expand Up @@ -70,8 +71,9 @@ def document_link(self, obj):
class LayerAdmin(admin.ModelAdmin):
search_fields = ("title",)
raw_id_fields = ("region", "layerset2")
readonly_fields = ("title",)
readonly_fields = ("title", "gcp_count", "transformation", "rmse", "skew", "anisotropy")
list_display = ("title", "created_by", "region_link", "map_link", "layerset_link")
actions = ("recalculate_measures",)

@admin.display(description="Map")
def map_link(self, obj):
Expand All @@ -87,6 +89,25 @@ def layerset_link(self, obj):
f'<a href="/admin/core/layerset/{obj.layerset2.pk}">{obj.layerset2.category}</a>'
)

# handles custom button in object change page
def response_change(self, request, obj):
if "_recalculate-measures" in request.POST:
msg = "Measures recalculated"
try:
obj.update_georeferencing_measures()
except Exception as e:
msg = f"Error calculating measures: {e}"
self.message_user(request, msg)
return HttpResponseRedirect(".")
return super().response_change(request, obj)

# handles bulk updates through select/list page
@admin.action(description="Recalculate measures for selected layers")
def recalculate_measures(self, request, queryset):
for obj in queryset:
obj.update_georeferencing_measures()
self.message_user(request, f"{queryset.count()} updated")


admin.site.register(MapGroup)
admin.site.register(Map, MapAdmin)
Expand Down
12 changes: 12 additions & 0 deletions ohmg/core/management/commands/oneoffs.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def add_arguments(self, parser):
"set-tilejson",
"delete-duplicate-regions",
"add-masks-to-layers",
"set-measures-on-layers",
],
help="Choose what operation to run.",
)
Expand Down Expand Up @@ -430,3 +431,14 @@ def old_ds_to_new(file_set):
print(" -> setting mask to None")
layer.mask = None
layer.save(skip_map_lookup_update=True, set_extent=False)

## Sept 25th, 2026
## set the new metrics on all layers using the new method that has been added to Layer
elif operation == "set-measures-on-layers":
from ohmg.core.models import Layer

layers = Layer.objects.all()
layers_ct = layers.count()
for n, layer in enumerate(Layer.objects.all(), start=1):
print(f"{n}/{layers_ct}: {layer.title}")
layer.update_georeferencing_measures()
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Generated by Django 4.2.27 on 2026-09-24 14:57

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('core', '0015_remove_layerset_mosaic_geotiff_date_and_more'),
]

operations = [
migrations.AddField(
model_name='layer',
name='anisotropy',
field=models.FloatField(blank=True, null=True),
),
migrations.AddField(
model_name='layer',
name='gcp_count',
field=models.IntegerField(blank=True, null=True, verbose_name='GCP Count'),
),
migrations.AddField(
model_name='layer',
name='rmse',
field=models.FloatField(blank=True, null=True, verbose_name='RMSE'),
),
migrations.AddField(
model_name='layer',
name='skew',
field=models.FloatField(blank=True, null=True),
),
migrations.AddField(
model_name='layer',
name='transformation',
field=models.CharField(blank=True, null=True),
),
]
29 changes: 29 additions & 0 deletions ohmg/core/models/layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ class Meta:
on_delete=models.SET_NULL,
)
tilejson = models.JSONField(null=True, blank=True)
gcp_count = models.IntegerField("GCP Count", null=True, blank=True)
transformation = models.CharField(null=True, blank=True)
rmse = models.FloatField("RMSE", null=True, blank=True)
skew = models.FloatField(null=True, blank=True)
anisotropy = models.FloatField(null=True, blank=True)

def __str__(self):
return self.title
Expand Down Expand Up @@ -117,6 +122,30 @@ def mask_geojson_feature(self) -> Union[dict | None]:
else None
)

def get_gcp_group(self):
from ohmg.georeference.models import GCPGroup

try:
return GCPGroup.objects.get(region2=self.region)
except Exception as e:
logger.error(e)

def update_georeferencing_measures(self):
"""Saves a suite of georeferencing-related data directly to this Layer instance."""

gcp_group = self.get_gcp_group()
if gcp_group:
rmse, _, _, skew, aniso = gcp_group.get_georeferencer().get_measures()
self.rmse = rmse
self.skew = skew
self.anisotropy = aniso
self.transformation = gcp_group.transformation
self.gcp_count = gcp_group.gcps.count()
self.save(
skip_map_lookup_update=True,
update_fields=["rmse", "skew", "anisotropy", "transformation", "gcp_count"],
)

def create_xyz_url(self) -> Union[str, None]:
file_url = get_file_url(self)
if file_url:
Expand Down
7 changes: 1 addition & 6 deletions ohmg/extensions/iiif.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

from ohmg.core.models import Layer
from ohmg.core.utils import full_reverse
from ohmg.georeference.georeferencer import Georeferencer


class IIIFResource:
Expand Down Expand Up @@ -46,11 +45,7 @@ def get_target(self):
else self.region.file.path
)

g = Georeferencer(
crs=target_crs,
transformation=self.region.gcpgroup.transformation,
gcps_geojson=self.region.gcpgroup.as_geojson,
)
g = self.region.gcpgroup.get_georeferencer()
g.make_gcps_vrt(in_path)
ds = gdal.Open(g.gcps_vrt.get_vsi_url())
transformer = gdal.Transformer(
Expand Down
Loading
Loading