Loading autocnet/io/db/model.py +4 −2 Original line number Diff line number Diff line Loading @@ -193,7 +193,7 @@ class Images(BaseMixin, Base): name = Column(String) path = Column(String) serial = Column(String, unique=True) active = Column(Boolean) active = Column(Boolean, default=True) _footprint_latlon = Column("footprint_latlon", Geometry('MultiPolygon', srid=srid, dimension=2, spatial_index=True)) footprint_bodyfixed = Column(Geometry('MULTIPOLYGON', dimension=2)) #footprint_bodyfixed = Column(Geometry('POLYGON',dimension=3)) Loading Loading @@ -330,7 +330,7 @@ class Measures(BaseMixin, Base): self._measuretype = v if Session: from autocnet.io.db.triggers import valid_point_function, valid_point_trigger from autocnet.io.db.triggers import valid_point_function, valid_point_trigger, valid_geom_function, valid_geom_trigger # Create the database if not database_exists(engine.url): create_database(engine.url, template='template_postgis') # This is a hardcode to the local template Loading @@ -339,6 +339,8 @@ if Session: # based on the point count. event.listen(Base.metadata, 'before_create', valid_point_function) event.listen(Measures.__table__, 'after_create', valid_point_trigger) event.listen(Base.metadata, 'before_create', valid_geom_function) event.listen(Images.__table__, 'after_create', valid_geom_trigger) Base.metadata.bind = engine # If the table does not exist, this will create it. This is used in case a Loading autocnet/io/db/tests/test_model.py +17 −1 Original line number Diff line number Diff line Loading @@ -5,7 +5,7 @@ import numpy as np import pandas as pd import pytest import sqlalchemy from shapely.geometry import Polygon, Point from shapely.geometry import MultiPolygon, Polygon, Point from unittest.mock import MagicMock, patch from autocnet.io.db import model Loading Loading @@ -168,3 +168,19 @@ def test_jigsaw_append(mockFunc, session, measure_data, point_data, image_data): resp = session.query(model.Measures).filter(model.Measures.id == 1).first() assert resp.liner == 0.1 assert resp.sampler == 0.1 def test_broken_bad_geom(session): # An irreperablly damaged poly geom = MultiPolygon([Polygon([(0,0), (1,1), (1,2), (1,1), (0,0)])]) i = model.Images.create(session, footprint_latlon=geom, serial = 'serial') resp = session.query(model.Images).filter(model.Images.id==i.id).one() assert resp.active == False def test_fix_bad_geom(session): geom = MultiPolygon([Polygon([(0,0), (0,1), (1,1), (0,1), (1,1), (1,0), (0,0) ])]) i = model.Images.create(session, footprint_latlon=geom, serial = 'serial' ) resp = session.query(model.Images).filter(model.Images.id==i.id).one() assert resp.active == True assert resp.footprint_latlon == MultiPolygon([Polygon([(0,0), (0,1), (1,1), (1,0), (0,0) ])]) autocnet/io/db/triggers.py +25 −0 Original line number Diff line number Diff line from sqlalchemy.schema import DDL valid_geom_function = DDL(""" CREATE OR REPLACE FUNCTION validate_geom() RETURNS trigger AS $BODY$ BEGIN NEW.footprint_latlon = ST_MAKEVALID(NEW.footprint_latlon); RETURN NEW; EXCEPTION WHEN OTHERS THEN NEW.active = false; RETURN NEW; END; $BODY$ LANGUAGE plpgsql VOLATILE -- Says the function is implemented in the plpgsql language; VOLATILE says the function has side effects. COST 100; -- Estimated execution cost of the function. """) valid_geom_trigger = DDL(""" CREATE TRIGGER image_inserted BEFORE INSERT OR UPDATE ON images FOR EACH ROW EXECUTE PROCEDURE validate_geom(); """) valid_point_function = DDL(""" CREATE OR REPLACE FUNCTION validate_points() RETURNS trigger AS Loading Loading
autocnet/io/db/model.py +4 −2 Original line number Diff line number Diff line Loading @@ -193,7 +193,7 @@ class Images(BaseMixin, Base): name = Column(String) path = Column(String) serial = Column(String, unique=True) active = Column(Boolean) active = Column(Boolean, default=True) _footprint_latlon = Column("footprint_latlon", Geometry('MultiPolygon', srid=srid, dimension=2, spatial_index=True)) footprint_bodyfixed = Column(Geometry('MULTIPOLYGON', dimension=2)) #footprint_bodyfixed = Column(Geometry('POLYGON',dimension=3)) Loading Loading @@ -330,7 +330,7 @@ class Measures(BaseMixin, Base): self._measuretype = v if Session: from autocnet.io.db.triggers import valid_point_function, valid_point_trigger from autocnet.io.db.triggers import valid_point_function, valid_point_trigger, valid_geom_function, valid_geom_trigger # Create the database if not database_exists(engine.url): create_database(engine.url, template='template_postgis') # This is a hardcode to the local template Loading @@ -339,6 +339,8 @@ if Session: # based on the point count. event.listen(Base.metadata, 'before_create', valid_point_function) event.listen(Measures.__table__, 'after_create', valid_point_trigger) event.listen(Base.metadata, 'before_create', valid_geom_function) event.listen(Images.__table__, 'after_create', valid_geom_trigger) Base.metadata.bind = engine # If the table does not exist, this will create it. This is used in case a Loading
autocnet/io/db/tests/test_model.py +17 −1 Original line number Diff line number Diff line Loading @@ -5,7 +5,7 @@ import numpy as np import pandas as pd import pytest import sqlalchemy from shapely.geometry import Polygon, Point from shapely.geometry import MultiPolygon, Polygon, Point from unittest.mock import MagicMock, patch from autocnet.io.db import model Loading Loading @@ -168,3 +168,19 @@ def test_jigsaw_append(mockFunc, session, measure_data, point_data, image_data): resp = session.query(model.Measures).filter(model.Measures.id == 1).first() assert resp.liner == 0.1 assert resp.sampler == 0.1 def test_broken_bad_geom(session): # An irreperablly damaged poly geom = MultiPolygon([Polygon([(0,0), (1,1), (1,2), (1,1), (0,0)])]) i = model.Images.create(session, footprint_latlon=geom, serial = 'serial') resp = session.query(model.Images).filter(model.Images.id==i.id).one() assert resp.active == False def test_fix_bad_geom(session): geom = MultiPolygon([Polygon([(0,0), (0,1), (1,1), (0,1), (1,1), (1,0), (0,0) ])]) i = model.Images.create(session, footprint_latlon=geom, serial = 'serial' ) resp = session.query(model.Images).filter(model.Images.id==i.id).one() assert resp.active == True assert resp.footprint_latlon == MultiPolygon([Polygon([(0,0), (0,1), (1,1), (1,0), (0,0) ])])
autocnet/io/db/triggers.py +25 −0 Original line number Diff line number Diff line from sqlalchemy.schema import DDL valid_geom_function = DDL(""" CREATE OR REPLACE FUNCTION validate_geom() RETURNS trigger AS $BODY$ BEGIN NEW.footprint_latlon = ST_MAKEVALID(NEW.footprint_latlon); RETURN NEW; EXCEPTION WHEN OTHERS THEN NEW.active = false; RETURN NEW; END; $BODY$ LANGUAGE plpgsql VOLATILE -- Says the function is implemented in the plpgsql language; VOLATILE says the function has side effects. COST 100; -- Estimated execution cost of the function. """) valid_geom_trigger = DDL(""" CREATE TRIGGER image_inserted BEFORE INSERT OR UPDATE ON images FOR EACH ROW EXECUTE PROCEDURE validate_geom(); """) valid_point_function = DDL(""" CREATE OR REPLACE FUNCTION validate_points() RETURNS trigger AS Loading