diff --git a/django/applications/catmaid/control/volume.py b/django/applications/catmaid/control/volume.py index 6f9ed45fa3..3918a9854b 100644 --- a/django/applications/catmaid/control/volume.py +++ b/django/applications/catmaid/control/volume.py @@ -166,19 +166,32 @@ def __init__(self, project_id, user_id, options): self.max_z = get_req_coordinate(options, "max_z") def get_geometry(self): - return """ST_GeomFromEWKT('POLYHEDRALSURFACE ( - ((%(lx)s %(ly)s %(lz)s, %(lx)s %(hy)s %(lz)s, %(hx)s %(hy)s %(lz)s, - %(hx)s %(ly)s %(lz)s, %(lx)s %(ly)s %(lz)s)), - ((%(lx)s %(ly)s %(lz)s, %(lx)s %(hy)s %(lz)s, %(lx)s %(hy)s %(hz)s, - %(lx)s %(ly)s %(hz)s, %(lx)s %(ly)s %(lz)s)), - ((%(lx)s %(ly)s %(lz)s, %(hx)s %(ly)s %(lz)s, %(hx)s %(ly)s %(hz)s, - %(lx)s %(ly)s %(hz)s, %(lx)s %(ly)s %(lz)s)), - ((%(hx)s %(hy)s %(hz)s, %(hx)s %(ly)s %(hz)s, %(lx)s %(ly)s %(hz)s, - %(lx)s %(hy)s %(hz)s, %(hx)s %(hy)s %(hz)s)), - ((%(hx)s %(hy)s %(hz)s, %(hx)s %(ly)s %(hz)s, %(hx)s %(ly)s %(lz)s, - %(hx)s %(hy)s %(lz)s, %(hx)s %(hy)s %(hz)s)), - ((%(hx)s %(hy)s %(hz)s, %(hx)s %(hy)s %(lz)s, %(lx)s %(hy)s %(lz)s, - %(lx)s %(hy)s %(hz)s, %(hx)s %(hy)s %(hz)s)))')""" + return """ST_GeomFromEWKT('TIN ( + (({0}, {2}, {1}, {0})), + (({1}, {2}, {3}, {1})), + + (({0}, {1}, {5}, {0})), + (({0}, {5}, {4}, {0})), + + (({2}, {6}, {7}, {2})), + (({2}, {7}, {3}, {2})), + + (({4}, {7}, {6}, {4})), + (({4}, {5}, {7}, {4})), + + (({0}, {6}, {2}, {0})), + (({0}, {4}, {6}, {0})), + + (({1}, {3}, {5}, {1})), + (({3}, {7}, {5}, {3})))') + """.format(*[ + '%({a})s %({b})s %({c})s'.format(**{ + 'a': 'hx' if i & 0b001 else 'lx', + 'b': 'hy' if i & 0b010 else 'ly', + 'c': 'hz' if i & 0b100 else 'lz', + }) + for i in range(8) + ]) def get_params(self): return { diff --git a/django/applications/catmaid/migrations/0042_volume_tin_representation.py b/django/applications/catmaid/migrations/0042_volume_tin_representation.py new file mode 100644 index 0000000000..575c5c1564 --- /dev/null +++ b/django/applications/catmaid/migrations/0042_volume_tin_representation.py @@ -0,0 +1,124 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.13 on 2018-07-17 15:45 +from __future__ import unicode_literals + +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion + + +# Construct a PostGIS TIN representation of a bounding box +bb_vertices = """ + (({0}, {2}, {1}, {0})), + (({1}, {2}, {3}, {1})), + + (({0}, {1}, {5}, {0})), + (({0}, {5}, {4}, {0})), + + (({2}, {6}, {7}, {2})), + (({2}, {7}, {3}, {2})), + + (({4}, {7}, {6}, {4})), + (({4}, {5}, {7}, {4})), + + (({0}, {6}, {2}, {0})), + (({0}, {4}, {6}, {0})), + + (({1}, {3}, {5}, {1})), + (({3}, {7}, {5}, {3})) +""".format(*[ + '%{a}$s %{b}$s %{c}$s'.format(**{ + 'a': 1 if i & 0b001 else 2, + 'b': 3 if i & 0b010 else 4, + 'c': 5 if i & 0b100 else 6, + }) + for i in range(8) +]) + +forward = """ + DO $$ + BEGIN + -- Make sure we only deal with polyhedeal surfaces and TINs + IF (SELECT COUNT(*) FROM catmaid_volume + WHERE ST_GeometryType(geometry) NOT IN ('ST_PolyhedralSurface', 'ST_Tin') + LIMIT 1) <> 0 + THEN + RAISE EXCEPTION 'Only geometries of type ST_PolyhedralSurface and ' + 'ST_Tin are supported by CATMAID. Please fix volumes manually.'; + END IF; + + -- Make sure that all polyhedral surfaces have 30 vertices and six faces, + -- in which case we assume it is a simple box. + IF (SELECT COUNT(*) FROM catmaid_volume + WHERE ST_GeometryType(geometry) = 'ST_PolyhedralSurface' + AND (ST_NPoints(geometry) <> 30 OR ST_NumGeometries(geometry) <> 6) + LIMIT 1) <> 0 + THEN + RAISE EXCEPTION 'All polyhedral surfaces need to be boxes, i.e. ' + 'have 30 vertices and 6 faces. Please fix volumes manually.'; + END IF; + END + $$; + + SELECT disable_history_tracking_for_table('catmaid_volume'::regclass, + get_history_table_name('catmaid_volume'::regclass)); + SELECT drop_history_view_for_table('catmaid_volume'::regclass); + + -- Convert polyhedral surfaces to TINs, assuming that we only deal with + -- boxes. + UPDATE catmaid_volume + SET geometry = ST_GeomFromEWKT(FORMAT('TINZ ({bb_vertices})', + ST_XMax(geometry), + ST_XMin(geometry), + ST_YMax(geometry), + ST_YMin(geometry), + ST_ZMax(geometry), + ST_ZMin(geometry))) + WHERE ST_GeometryType(geometry) = 'ST_PolyhedralSurface'; + + UPDATE catmaid_volume__history + SET geometry = ST_GeomFromEWKT(FORMAT('TINZ ({bb_vertices})', + ST_XMax(geometry), + ST_XMin(geometry), + ST_YMax(geometry), + ST_YMin(geometry), + ST_ZMax(geometry), + ST_ZMin(geometry))) + WHERE ST_GeometryType(geometry) = 'ST_PolyhedralSurface'; + + ALTER TABLE catmaid_volume + ALTER COLUMN geometry TYPE Geometry(TINZ); + + ALTER TABLE catmaid_volume__history + ALTER COLUMN geometry TYPE Geometry(TINZ); + + SELECT create_history_view_for_table('catmaid_volume'::regclass); + SELECT enable_history_tracking_for_table('catmaid_volume'::regclass, + get_history_table_name('catmaid_volume'::regclass), FALSE); +""".format(bb_vertices=bb_vertices) + +backward = """ + SELECT disable_history_tracking_for_table('catmaid_volume'::regclass, + get_history_table_name('catmaid_volume'::regclass)); + SELECT drop_history_view_for_table('catmaid_volume'::regclass); + + ALTER TABLE catmaid_volume + ALTER COLUMN geometry TYPE Geometry(GeometryZ); + + ALTER TABLE catmaid_volume__history + ALTER COLUMN geometry TYPE Geometry(GeometryZ); + + SELECT create_history_view_for_table('catmaid_volume'::regclass); + SELECT enable_history_tracking_for_table('catmaid_volume'::regclass, + get_history_table_name('catmaid_volume'::regclass), FALSE); +""" + +class Migration(migrations.Migration): + + dependencies = [ + ('catmaid', '0041_add_sampler_column_leaf_handling'), + ] + + operations = [ + migrations.RunSQL(forward, backward) + ]