Skip to content

Commit

Permalink
DB inegrity check: add test if all mesh faces are triangles
Browse files Browse the repository at this point in the history
This is run now by default for the catmaid_check_db_integrity management
command.

The --tracing [true|false] and --volumes [true|false] command line
parameters now allow to explicitly test only some parts of the database.
By default all is tested.  Please enter the commit message for your
changes. Lines starting

See #1765
  • Loading branch information
tomka committed Oct 17, 2018
1 parent 341164d commit dce6ccc
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 5 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ Miscellaneous:
- Admin: a user import view is now available to import users from other CATMAID
instances. It requires superuser permissions on the remote instance.

- DB integrity check management command: volumes are now checked to make sure
all faces are triangles. The --tracing [true|false] and --volumes [true|false]
command line parameters now allow to explicitly test only some parts of the
database. By default all is tested.


### Bug fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django.core.management.base import BaseCommand, CommandError
from django.db import connection
from catmaid.models import Project
from catmaid.util import str2bool

class Command(BaseCommand):
help = '''
Expand All @@ -15,6 +16,10 @@ class Command(BaseCommand):

def add_arguments(self, parser):
parser.add_argument('--project_id', nargs='*', type=int, default=[])
parser.add_argument("--tracing", type=str2bool, nargs='?',
const=True, default=True, help="Check tracing data.")
parser.add_argument("--volumes", type=str2bool, nargs='?',
const=True, default=True, help="Check volumes data.")

def handle(self, *args, **options):
project_ids = options['project_id']
Expand All @@ -23,17 +28,29 @@ def handle(self, *args, **options):

passed = True
for project_id in project_ids:
passed = passed and self.check_project(project_id)
passed = passed and self.check_project(project_id, options)

if not passed:
sys.exit(1)

def check_project(self, project_id):
def check_project(self, project_id, options):
if not Project.objects.filter(id=project_id).exists():
raise CommandError('Project with id %s does not exist.' % project_id)
project_passed = True
self.stdout.write('Checking integrity of project %s' % project_id)

passed = True
if options['tracing']:
passed = passed and self.check_tracing_data(project_id)

if options['volumes']:
passed = passed and self.check_volumes(project_id)

self.stdout.write('')

return passed


def check_tracing_data(self, project_id):
self.stdout.write('Check that no connected treenodes are in different skeletons...', ending='')
cursor = connection.cursor()
cursor.execute('''
Expand Down Expand Up @@ -102,9 +119,34 @@ def check_project(self, project_id):
project_passed = False
row = cursor.fetchone()
self.stdout.write('FAILED: node %s in skeleton %s has no path to root' % row)

if test_passed:
self.stdout.write('OK')

self.stdout.write('')

return project_passed
def check_volumes(self, project_id):
passed = True
self.stdout.write('Check if all meshes consist only of triangles...', ending='')
cursor = connection.cursor()
cursor.execute("""
SELECT g.volume_id,
(g.gdump).path[1] as triangle_id,
COUNT(*) as n_points
FROM (
SELECT v.id AS volume_id,
ST_DumpPoints(geometry) AS gdump
FROM catmaid_volume v
) AS g
GROUP BY volume_id, (g.gdump).path[1]
HAVING COUNT(*) <> 4;
""")
n_non_triangles = len(list(cursor.fetchall()))
if n_non_triangles > 0:
self.stdout.write('FAILED: found {} non-triangle meshes in project {}'.format(
n_non_triangles, project_id))
passed = False
else:
self.stdout.write('OK')
passed = passed and True

return passed
9 changes: 9 additions & 0 deletions django/applications/catmaid/util.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-

import argparse
import math

from django.utils.encoding import python_2_unicode_compatible
Expand Down Expand Up @@ -72,3 +73,11 @@ def is_collinear(a, b, c, between=False, eps=epsilon):
return not (min(tx, ty, tz) < 0.0 or max(tx, ty, tz) > 1.0)
else:
return True

def str2bool(v):
if v.lower() in ('yes', 'true', 't', 'y', '1'):
return True
elif v.lower() in ('no', 'false', 'f', 'n', '0'):
return False
else:
raise argparse.ArgumentTypeError('Boolean value expected.')

0 comments on commit dce6ccc

Please sign in to comment.