Skip to content

Commit

Permalink
Represent volumes as TIN geometry in the database
Browse files Browse the repository at this point in the history
All geometries in the back-end are now stored as PostGIS TIN Geometry.
This allows for more consistency and a cleaner API. Implemented together
with @aschampion, @clbarnes, @Willp24.

See #1765
Fixes #1581
  • Loading branch information
tomka committed Jul 17, 2018
1 parent ccfc5bf commit c69462d
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 13 deletions.
39 changes: 26 additions & 13 deletions django/applications/catmaid/control/volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,19 +167,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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
]

0 comments on commit c69462d

Please sign in to comment.