#!/usr/bin/python
# -*- coding: utf-8 -*-
# ---------------------------------------------------------------------
# Copyright (c) 2012 Michael Hull.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# - Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------
import os
from morphforge.morphology.importer.import_array_swc import NewSWCLoader
from morphforgecontrib.indev.highqualitymesh.create_mesh import MeshFromGTS
from morphforge.morphology.mesh.writer_ply import MeshWriterPLY
from morphforge.morphology.mesh.mesh import TriangleMesh
from morphforge.core.mgrs.locmgr import LocMgr
from morphforgecontrib.morphology.util.axontrimmer import AxonTrimmer
from morphforgecontrib.morphology.util.morphologytranslator import MorphologyTranslator
from morphforgecontrib.morphology.util.minimum_diameter import MorphologyMinimumDiameter
[docs]class MeshGenerationOptions:
minimum_diameter = 'MinimumDiameter'
[docs]class Context(object):
[docs] def __init__(self, src_zip_file, dst_zip_file):
self.color_aliases = {}
self.region_color_defaults = {}
self.currentplyscope = None
self.global_options = {
#MeshGenerationOptions.minimum_diameter: 1.0
}
self.src_zip_file = src_zip_file
self.dst_zip_file = dst_zip_file
self.op_files = []
self.op_dir = '/tmp/mf/meshbuilder/'
LocMgr.ensure_dir_exists(self.op_dir)
[docs] def has_option_set(self, key):
return key in self.global_options
[docs] def get_option(self, key):
return self.global_options[key]
[docs] def get_color(self, alias):
return self.color_aliases[alias]
[docs] def add_alias(self, id, color):
assert not id in self.color_aliases
self.color_aliases[id] = color
[docs] def set_default_region_color(self, rgn_id, color):
self.region_color_defaults[rgn_id] = color
[docs] def new_ply_block(self):
assert self.currentplyscope is None
self.currentplyscope = PlyScope(global_scope=self)
[docs] def close_ply_block(self, plyfilename):
self.currentplyscope.finalise(plyfilename=plyfilename)
self.currentplyscope = None
for f in self.op_files:
self.dst_zip_file.write(f)
self.op_files = []
[docs] def getFileObjRead(self, filename):
possible_filenames = [filename, 'src/' + filename]
for pf in possible_filenames:
try:
return self.src_zip_file.open(pf, 'r')
except KeyError:
pass
raise ValueError("Can't find file: %s" % filename)
[docs] def getFileObjWrite(self, filename):
filename = os.path.join(self.op_dir, filename)
d = os.path.dirname(filename)
if not os.path.exists(d):
os.makedirs(d)
self.op_files.append(filename)
return open(filename, 'w')
[docs]class PlyScope(object):
[docs] def __init__(self, global_scope):
self.global_scope = global_scope
self.region_colors = {}
self.meshes = []
[docs] def get_region_color(self, rgn):
assert isinstance(rgn, int)
# Local colors?
if rgn in self.region_colors:
return self.region_colors[rgn]
if None in self.region_colors:
return self.region_colors[None]
# Global colors?:
if rgn in self.global_scope.region_color_defaults:
return self.global_scope.region_color_defaults[rgn]
if None in self.global_scope.region_color_defaults:
return self.global_scope.region_color_defaults[None]
assert False, 'What do I do with region: %d ' % rgn
# return ColorDef(200,50, np.min((rgn*20,255)))
[docs] def include_file(self, filename, options):
src_obj = self.global_scope.getFileObjRead(filename)
morphs = NewSWCLoader.load_swc_set(src=src_obj)
# Hack: only first:
# morphs = [morphs[0]]
for m in morphs:
m = m.to_tree()
# Create the color LUT:
bi_dict = m.region_number_to_name_bidict
rgn_colors = {}
for rgn in m.get_regions():
rgn_name = rgn.name
rgn_int = bi_dict.region_name_to_int(rgn_name)
rgn_color = self.get_region_color(rgn_int)
print '%s -> %s' % (rgn_name, rgn_int), rgn_color
rgn_colors[rgn_name] = rgn_color
# Check for ignored Region:
if None in rgn_colors.values():
for v in rgn_colors.values():
if v is not None:
print 'Partly ignoring Structure:',
for (k, v) in rgn_colors.iteritems():
print k, v
assert False, 'Partly ignored structure!'
continue
# Apply the options:
if 'trim' in options:
m = AxonTrimmer.trim_axon_from_morphology(m,
max_dist_to_parent=options['trim'])
if 'offset' in options:
m = MorphologyTranslator.translate(morphology=m,
offset=options['offset'])
if self.global_scope.has_option_set(MeshGenerationOptions.minimum_diameter):
m = MorphologyMinimumDiameter.ensure(m,
min_diameter=self.global_scope.get_option(MeshGenerationOptions.minimum_diameter))
mesh = MeshFromGTS.build(m, plot=False,
region_color_map=rgn_colors)
self.meshes.append(mesh)
[docs] def set_region_color(self, region, color):
self.region_colors[region] = color
[docs] def finalise(self, plyfilename):
m = TriangleMesh.merge(meshes=self.meshes)
ply = MeshWriterPLY.build_string(m)
with self.global_scope.getFileObjWrite(plyfilename) as f:
f.write(ply)
[docs]class ColorDef(object):
[docs] def __init__(self, r, g, b):
self.r = r
self.g = g
self.b = b
[docs] def __str__(self):
return '<ColorDef: (%d,%d,%d)>' % (self.r, self.g, self.b)
[docs]class RegionColorDef(object):
[docs] def __init__(self, rgn, color_def):
assert isinstance(rgn, int)
assert isinstance(color_def, ColorDef)
self.rgn = rgn
self.color_def = color_def