# -*- coding: utf-8 -*- #~ from traits.etsconfig.api import ETSConfig #~ ETSConfig.toolkit = 'qt4' from enthought.mayavi import mlab import datetime import logging import time import thread import threading from collections import namedtuple, defaultdict import math import cPickle as pickle from contextlib import contextmanager import numpy as np import scipy from matplotlib.figure import Figure from ansistrm import ColorizingStreamHandler as StreamHandler from enthought.traits.api import HasTraits, Instance, on_trait_change, HasStrictTraits, DelegatesTo from enthought.traits.api import Enum, Range, List, Bool, Str, Int, Float, Event, Dict, File, Any, Date, Instance, Property, Set, Tuple from enthought.traits.ui.api import (Handler, View, Item, Group, VGroup, HGroup, TextEditor, ButtonEditor, HSplit, HFlow, VFold, VGrid, EnumEditor, ListEditor, BooleanEditor, ShellEditor, FileEditor, Tabbed, CodeEditor, RangeEditor) from enthought.traits.ui.key_bindings import KeyBinding, KeyBindings from enthought.tvtk.pyface.scene_editor import SceneEditor from enthought.mayavi.core.ui.mayavi_scene import MayaviScene from enthought.mayavi.tools.mlab_scene_model import MlabSceneModel from enthought.traits.ui.api import View, Item, TableEditor, TabularEditor from enthought.traits.ui.extras.checkbox_column import CheckboxColumn from enthought.traits.ui.table_column import ObjectColumn from enthought.traits.ui.tabular_adapter import TabularAdapter from utils.traitsmpl import MPLFigureEditor from utils.path import path from utils import cython_annotate from utils.objparser import Mesh from utils.xml import FileToTree, subelement, TreeToFile, prettyPrint, TreeToString, StringToTree from utils.volumeimage import VolumeImage from utils.materials import loadMaterials, Brdf, materialsAsXml from utils.url import urlopen from utils.accelerated import toNormalizedDecibelwithDeviceAdaption import lws.localize as localizer log = logging.getLogger() gui = None UN_SELECTED_MEASUREMENT = 0.5 CLAMP = -130 HTTP_AVAILABLE = True from utils.url import getOpener mpart_opener = getOpener(enableMultipart=True) opener = getOpener() BASE_URL = 'http://nostromo.informatik.rwth-aachen.de:20080' #BASE_URL = 'http://loco.visual-library.de' #~ BASE_URL = 'http://localhost:42777' gui_lock = threading.Lock() class LoggingHandler(logging.Handler): def __init__(self): logging.Handler.__init__(self) self.level = logging.DEBUG formatter = logging.Formatter("%(asctime)s.%(msecs)03d " "%(name)s %(levelname)s %(message)s", "%H:%M:%S") self.setFormatter(formatter) def emit(self, record): msg = self.format(record) gui.loggingout = msg + '\n' + gui.loggingout class Material(HasStrictTraits): name = Str reflect = Float(0.5) alpha = Float(0.5) ior = Float(1.0) def _reflect_changed(self): if sceneloader.materials is not None and self.name in sceneloader.materials: sceneloader.materials[self.name].reflect = self.reflect def _alpha_changed(self): if sceneloader.materials is not None and self.name in sceneloader.materials: sceneloader.materials[self.name].alpha = self.alpha materials_table = TableEditor( sortable = False, configurable = False, columns = [ObjectColumn(name ='name'), ObjectColumn(name='reflect', format_func = lambda x: '%.3f' % x), ObjectColumn(name='alpha', format_func = lambda x: '%.3f' % x), ], ) class SceneObjectColumn (ObjectColumn): # Override some default settings for the column: width = 0.08 horizontal_alignment = 'center' editable = False def get_text_color(self, object): return [ 'light grey', 'black' ][1] objects_table = TableEditor( sortable = False, configurable = False, #~ auto_size = False, columns = [CheckboxColumn(name ='visible', label='View'), CheckboxColumn(name ='used', label='Used'), SceneObjectColumn(name='name'), SceneObjectColumn(name='matname'), ], ) class SceneObject(HasStrictTraits): # Trait definitions: name = Str matname = Str visible = Bool(True) used = Bool(False) reflect = Float alpha = Float ior = Float display_color = Tuple # the mayavi mesh color mlab_mesh = Any(None) # the mayavi mesh def _visible_changed(self): if _LOADING: return if hasattr(self.mlab_mesh, '__call__'): if self.visible: # create mesh lazy self.mlab_mesh = self.mlab_mesh() else: self.mlab_mesh.visible = self.visible class MeasurementColumn(ObjectColumn): def get_text_color(self, m): if self.name == 'rssi_norm' and m.rssi_norm == m.rssi_sim: return 'light grey' else: return 'black' if m.available else 'light grey' objectsgroups_table = TableEditor( sortable = False, configurable = False, columns = [CheckboxColumn(name ='visible', label='View'), ObjectColumn(name='name'), ], ) class SceneObjectGroup(HasStrictTraits): name = Str visible = Bool(False) filter = List def _visible_changed(self): if not _LOADING: for f in self.filter: for sceneobject in gui.scene_objects: if f in sceneobject.name: sceneobject.visible = self.visible class Location(HasTraits): locid = Int x = Float y = Float z = Float class Measurement(HasStrictTraits): location = Instance(Location) locid = DelegatesTo('location') x = DelegatesTo('location') y = DelegatesTo('location') z = DelegatesTo('location') rssi = Float rssi_sim = Float rssi_norm = Float rssis = List delta = Float # delta between measured and simulated rssi distance = Float # distance to ap available = Bool(False) class MeasurementTableAdapter(TabularAdapter): columns = [ ('id', 'locid'), ('x', 'x'), ('y', 'y'), ('z', 'z'), ('Dist', 'distance'), ('meas', 'rssi'), ('sim', 'rssi_sim'), ('norm', 'rssi_norm'), ('delta', 'delta') ] distance_format = Str('%.1f') rssi_format = Str('%.1f') rssi_sim_format = Str('%.1f') rssi_norm_format = Str('%.1f') delta_format = Str('%.1f') value_text = Property def _get_value_text ( self ): return self.item measurements_table = TabularEditor( auto_update = True, editable = False, selected = 'selected_measurement', adapter = MeasurementTableAdapter() ) class AccessPoint(HasStrictTraits): id = Str x = Float y = Float z = Float power = Float used = Bool powid = Str avg_delta = Float # raytracer results - loaded lazy data_in_db = Any normalized_data_in_db = Any vi = Any def __str__(self): return '%s at (%.1f,%.1f,%.1f)' % (self.id, self.x, self.y, self.z) def reset(self): self.data_in_db = None self.normalized_data_in_db = None self.vi = None ap_table = TableEditor( columns = [ObjectColumn(name='id', editable=False), ObjectColumn(name='x'), ObjectColumn(name='y'), ObjectColumn(name='z'), ObjectColumn(name='powid'), ObjectColumn(name='power', format_func = lambda x: ('%.1f' if x > 0.1 else '%.1e') % x), CheckboxColumn(name ='used', label='Used'), ObjectColumn(name='avg_delta', format_func = lambda x: '%.1f' % x), ], dclick = 'doubleclicked_ap', selected = 'selected_ap' ) class OptimizeRun(HasStrictTraits): date = Date minavgdelta = Float session = Str scene = Str density = Float numphotons = Int materials = Dict # key matname, value: Brdf powers = Dict # key powid, value power resolution = Str # store only string form "320,90,50" bbox = Str # store only string form rssieq = Float # normalization via normalizeLogarithmic davalues = Dict # normalization via normalizeDeviceAdaption devices = List # list of included devices in optrun opt_runs_table = TableEditor( columns = [ObjectColumn(name='date', editable=False, format_func = lambda x: x.strftime("%m-%d %H:%M:%S")), ObjectColumn(name='minavgdelta', editable=False), ObjectColumn(name='session', editable=False), ObjectColumn(name='density', editable=False), ObjectColumn(name='numphotons', editable=False), ObjectColumn(name='devices', editable=False, format_func = lambda x: ','.join(x)), ], dclick = 'doubleclicked_optrun', ) def updateRes(): if gui is not None: gui.res_dx = round((gui.bbox.x2 - gui.bbox.x1) / gui.resolution.x, 6) gui.res_dy = round((gui.bbox.y2 - gui.bbox.y1) / gui.resolution.y, 6) gui.res_dz = round((gui.bbox.z2 - gui.bbox.z1) / gui.resolution.z, 6) gui.cube_res_x = gui.res_x / gui.cube_width gui.cube_res_y = gui.res_y / gui.cube_width gui.cube_res_z = gui.res_z / gui.cube_width total = gui.cube_res_x * gui.cube_res_y * gui.cube_res_z gui.cube_width_display = '%s, %s, %s [%.2fk states]' % (gui.cube_res_x, gui.cube_res_y, gui.cube_res_z, total / 1000.0) class _BBox(HasStrictTraits): x1 = Float x2 = Float y1 = Float y2 = Float z1 = Float z2 = Float @on_trait_change('anytrait') def _update(self, x): updateRes() class Resolution(HasStrictTraits): x = Int y = Int z = Int @on_trait_change('anytrait') def _update(self, x): updateRes() class SceneLoader(object): ''' pretty much obsolete now''' def __init__(self): self.mesh = None self.materials = {} def loadMesh(self, objfile): objfile = path(objfile) self.mesh = Mesh() t = time.time() self.mesh.parseObjFile(objfile) log.debug('parsed %s vertices in %.3f seconds' % (len(self.mesh.vertices[0]), time.time() - t)) def loadMaterials(self, materialfile): materialfile = path(materialfile) log.info('loading materials from %s' % materialfile.normpath()) self.setMaterials(loadMaterials(materialfile)) def setMaterials(self, materials): gui.materials[:] = [] self.materials.clear() for matname, brdf in materials.items(): # convert Brdf() to traits representation m = Material(name=matname, reflect=brdf.reflect, alpha=brdf.alpha) self.materials[matname] = m gui.materials.append(m) sceneloader = SceneLoader() path_pos_table = TableEditor( columns = [ObjectColumn(name='id', editable=False), ObjectColumn(name='x', format_func=lambda x: '%.1f' % x), ObjectColumn(name='y', format_func=lambda x: '%.1f' % x), ObjectColumn(name='z', format_func=lambda x: '%.1f' % x), ObjectColumn(name='distance', label='dist', format_func=lambda x: '%.1f' % x, editable=False), ObjectColumn(name='total_distance', label='total', format_func=lambda x: '%.1f' % x, editable=False), ], selected = 'selected_path_pos' ) class PathPosition(HasStrictTraits): id = Int x = Float y = Float z = Float distance = Float total_distance = Float @on_trait_change('x,y,z') def _update(self, v): if _LOADING: return gui._localization_path_changed() path_table = TableEditor( columns = [ObjectColumn(name='id', label='id', editable=False), ObjectColumn(name='length', label='l', editable=False), ObjectColumn(name='collect_runs', label='runs', editable=False), ], selected = 'selected_path_sequence' ) class MeasurementRun(HasStrictTraits): id = Int measurements = Str locations = Str class PathSequence(HasStrictTraits): id = Str length = Int collect_runs = Int locs = List # either [int locids] or [PathPosition] runs = List(MeasurementRun) _LOADING = False @contextmanager def LOADING(): global _LOADING try: _LOADING = True yield None finally: _LOADING = False class Gui(HasTraits): # The scene model. scene = Instance(MlabSceneModel, ()) # Trait definitions: scene_objects = List(SceneObject) # different blender objects as trait definition load_scene_objects = Event clear_scene_objects = Event retrieve_scene_object = Event scene_object_groups = List(SceneObjectGroup) toogle_object_groups = Event plane_cursor_coords = Str('') plane_state_coords = Str state_x = Int(0) state_y = Int(0) state_z = Int(0) avg_ap_delta = Float total_avg_ap_delta = Float sum_ap_delta = Float measurements_mean = Float measurements_stddev = Float locations = List(Location) measurements = List(Measurement) # measured db/rssi values at different coords measurements_points = None # points3d instance clear_locations = Event load_locations = Event retrieve_measurements = Event retrieve_measurements_overlay = Event aps = List(AccessPoint) #different access points powids = Set load_aps = Event clear_aps = Event reload_ap_data = Event toggle_ap_used = Event evaluate_all_aps = Event run_device_adaption = Event clear_cached_ap = Event show_ap_data_at_cursor = Event load_all = Event load_scene_config = Event scene_name = Str('new_scene') device_name = Str('device') device_names = List(Str) device_davalues = Str() #~ objfile = File(r'D:\loco-dev\maps\onewall\One-Wall.obj') objfile = File() materials = List(Material) retrieve_materials = Event load_materials = Event materialfile = File #~ materialfile = File(r'D:\loco-dev\maps\onewall\materials.xml') measurementfile = File() tmpdir = path('_tmp').abspath() run_simulation = Event shell = Dict loggingout = Str ap_power = Float ap_x = Float ap_y = Float ap_z = Float apdatafiles = Str doubleclicked_ap = Any # tuple (AccessPoint, clicked Colum) selected_ap = Any # Instance of AccessPoint loaded_ap_id = None selected_measurement = Any opt_runs = List(OptimizeRun) optrun_session = Str('default') load_opt_runs = Event doubleclicked_optrun = Any # tuple (OptimizeRun, clicked Column) bbox = _BBox(x1=-1, x2=1, y1=-1, y2=1, z1=-1, z2=1) #~ bbox = _BBox(x1=-10.0, x2=10, y1=-10.0, y2=10.0, z1=-5, z2=4.0) bb_x1 = DelegatesTo('bbox', prefix='x1') bb_x2 = DelegatesTo('bbox', prefix='x2') bb_y1 = DelegatesTo('bbox', prefix='y1') bb_y2 = DelegatesTo('bbox', prefix='y2') bb_z1 = DelegatesTo('bbox', prefix='z1') bb_z2 = DelegatesTo('bbox', prefix='z2') resolution = Resolution(x=32, y=32, z=32) res_x = DelegatesTo('resolution', prefix='x') res_y = DelegatesTo('resolution', prefix='y') res_z = DelegatesTo('resolution', prefix='z') cube_resolution = Resolution(x=0, y=0, z=0) cube_res_x = DelegatesTo('cube_resolution', prefix='x') cube_res_y = DelegatesTo('cube_resolution', prefix='y') cube_res_z = DelegatesTo('cube_resolution', prefix='z') res_dx = Float res_dy = Float res_dz = Float # normalization param davalues = Dict rssieq = Float(0.0) plot = Instance(Figure, ()) view_normalized_data = Bool(False) sim_waiting = Set sim_running = Set sim_finished = Set numphotons = Int(300000) density = Float(0.1) localizer = Any localization_paths = List(PathSequence) localization_path = List(PathPosition) custom_path = PathSequence do_localizeHMM = Event do_localizePF = Event do_localizeLMSE = Event localize_range = Str('0:') # slice notation do_viewblocked = Event do_viewpftrans = Event do_viewgradients = Event do_record_path = Bool do_delete_path_segment = Event do_draw_path = Event do_load_paths = Event selected_path_pos = Any selected_path_sequence = Any do_viewhistory = Event do_viewhistory_prev = Event pruning_idx = Int(0) pruning_step_width = Int(1) pruning_visible_count = Int(1000) do_generate_synthetic_measurements = Event do_generate_synthetic_measurements_cubes = Event synthetic_measurements = Str synthetic_measurements_noise = Float(5) synthetic_measurements_speed = Float(1.5) synthetic_measurements_granularity = Float(2.0) do_load_measurement_run = Event measurement_runid = Str measurement_runs = List(Str) cube_width = Int(3) cube_width_display = Str prune_to = Int(3000) threads = Int(4) freespace_scan = Int(-1) show_scalar_bar = Event toggle_ipw_z = Event toggle_surfaceview = Event ipw_vmin = Range(-100, 10) ipw_vmax = Range(-100, 10) surface_number_of_contours = Range(5, 150, 8) do_current_ap_surface_plot = Event do_thesis_pruning_plot = Event do_thesis_path_info = Event do_thesis_localization_plot = Event do_thesis_pruning_scatter = Event do_3dmodel_latextable = Event do_device2measurements_latextable = Event do_generate_synthetic_paths = Event do_plot_apcoverage = Event ###################### def __init__(self, **traits): HasTraits.__init__(self, **traits) self.setupLogging() self.mlab_aps = None # holds mlab ap geometry self.scalar_field = None # holds mlab volume image data self.ipw_z = None self.surface_view = None self.mlab_locations = None # holds mlab locations geometry self.vi = None # holds VolumeImage instance self.deltas = defaultdict(list) self.locid2location = {} self.runid2run = {} if not self.tmpdir.exists(): self.tmpdir.mkdir() if not self.tmpdir.joinpath('apdata').exists(): self.tmpdir.joinpath('apdata').mkdir() self.cursor_position = None @on_trait_change('clear_locations') def clearLocations(self): self.locations[:] = [] self.measurements[:] = [] if self.mlab_locations is not None: self.mlab_locations.remove() self.mlab_locations = None @on_trait_change('view_normalized_data') def viewNormalizedDataClicked(self): self.reloadAP(self.selected_ap) @on_trait_change('reload_ap_data') def reloadAPClicked(self): self.reloadAP(self.selected_ap) @on_trait_change('toggle_ap_used') def toogleAPUsed(self): for ap in self.aps: ap.used = not ap.used @on_trait_change('run_device_adaption') def runDeviceAdaptation(self): apid_locid2measurement = self.measurementsAsArray() apid_locid2estimated = self.rawEstimatesForMeasurements(apid_locid2measurement) import lws.optimizer res, opt_avg_delta = lws.optimizer.optimizeDeviceAdaption({self.device_name: apid_locid2measurement}, apid_locid2estimated, 80) if self.device_name in self.davalues: log.info('old davalues: %s' % ','.join('%s: %.1f' % e for e in self.davalues[self.device_name][:])) log.info('new davalues: %s' % ','.join('%s: %.1f' % e for e in res[self.device_name])) self.davalues[self.device_name] = res[self.device_name] # update davalues on gui self.deviceNameChanged() self.clearCachedAPData() @on_trait_change('show_ap_data_at_cursor') def showAPDataAtPos(self): assert self.cursor_position is not None for ap in self.aps: if not ap.used: continue self.lazyLoadAP(ap) data_in_db = ap.data_in_db[tuple(self.cursor_position)] normalized_data_in_db = ap.normalized_data_in_db[tuple(self.cursor_position)] log.info('%s: %.2f, norm: %.2f' % (ap.id, data_in_db, normalized_data_in_db)) @on_trait_change('clear_cached_ap') def clearCachedAPData(self, apid=None): for ap in self.aps: if apid is not None: if not ap.id == apid: continue ap.reset() @on_trait_change('evaluate_all_aps') def evaluateAllAps(self): self.deltas.clear() for ap in self.aps: if not ap.used: continue try: self.lazyLoadAP(ap) except Exception: log.exception('cannot load ap %s' % ap) else: try: self.loadMeasurements(ap) except Exception: log.error('cannot load measurements for ap %s' % ap) @on_trait_change('clear_aps') def clearAPs(self): self.aps[:] = [] if self.mlab_aps is not None: self.mlab_aps.remove() self.mlab_aps = None @on_trait_change('load_aps') def loadAPs(self): self.clearAPs() cachefile = self.tmpdir.joinpath('ap_config.txt') try: assert HTTP_AVAILABLE cfgtree = opener.open(BASE_URL + '/getAPConfig').read() cachefile.write_text(cfgtree) except Exception: log.error('retrieving failed') cfgtree = cachefile.text() for e in StringToTree(cfgtree).getroot().getchildren(): a = e.attrib used = a['on']=='true' apid = a['id'] #~ used = apid in ('107', '108') self.aps.append(AccessPoint(id=apid, x=float(a['x']), y=float(a['y']), z=float(a['z']), powid=a['powerid'], power=float(a['power']), used=used)) self.powids = {ap.powid for ap in self.aps} #~ self.aps.append(AccessPoint(id='onewall', x=0, y=0, z=0, power=10, used=True)) xs = [e.x for e in self.aps] ys = [e.y for e in self.aps] zs = [e.z for e in self.aps] if len(xs) > 0: # add AP source as a 3d point self.mlab_aps = self.scene.mlab.points3d(xs, ys, zs, [1]*len(xs), colormap="binary", scale_factor=.5) @on_trait_change('retrieve_measurements') def retriveMeasurements(self, overlay=False, device_name=None, autoreload=True): if device_name == None: device_name = self.device_name if overlay: url = BASE_URL + '/getLocationsAndMeasurements/%s?overlay_tracked=true' % device_name else: url = BASE_URL + '/getLocationsAndMeasurements/%s' % device_name log.info('retriving %s' % url) s = urlopen(url).read() log.info('got %.1f mb' % (len(s) / 1024.0**2)) measurementfile = self.tmpdir.joinpath('measurements_%s_%s.xml' % (self.scene_name, device_name)) open(measurementfile, 'wb').write(s) if autoreload: # auto reload self.loadLocations() @on_trait_change('retrieve_measurements_overlay') def retriveMeasurementsOverlay(self): self.retriveMeasurements(overlay=True) @on_trait_change('load_locations') def loadLocations(self, device_name=None): if device_name == None: device_name = self.device_name self.measurementfile = self.tmpdir.joinpath('measurements_%s_%s.xml' % (self.scene_name, device_name)) if not path(self.measurementfile).exists(): return tree = FileToTree(self.measurementfile) locEls = tree.getroot().xpath('locations/location') self.clearLocations() for e in locEls: x, y, z = float(e.attrib['x']), float(e.attrib['y']), float(e.attrib['z']) loc = Location(locid=int(e.attrib['id']), x=x, y=y, z=z) m = Measurement() m.location = loc self.measurements.append(m) self.locations.append(loc) self.locid2location = dict([(loc.locid, loc) for loc in self.locations]) if self.selected_ap is not None: self.loadMeasurements(self.selected_ap) def measurementsAsArray(self): max_locid = max(self.locid2location.keys()) apid_locid2measurements = np.zeros(shape=(len(self.aps), max_locid)) + np.inf for i, ap in enumerate(self.aps): if not ap.used: continue tree = FileToTree(self.measurementfile) for e in tree.getroot().xpath('measurements/ap[@id=$apid]/location', apid=ap.id): locid = int(e.attrib['id']) if not locid in self.locid2location: log.error('unknown location %s' % locid) continue apid_locid2measurements[i, locid] = float(e.attrib['avgrssi']) np.save(self.tmpdir.joinpath('apdata', self.optrun_session, '%s_apid_locid2measurements.npy' % self.device_name), apid_locid2measurements) return apid_locid2measurements def rawEstimatesForMeasurements(self, apid_locid2measurements=None): if apid_locid2measurements is None: apid_locid2measurements = self.measurementsAsArray() apid_locid2estimates = np.zeros(shape=apid_locid2measurements.shape) + np.inf for i, ap in enumerate(self.aps): if not ap.used: continue for j in range(apid_locid2measurements.shape[1]): if not np.isfinite(apid_locid2measurements[i, j]): continue loc = self.locid2location[j] self.lazyLoadAP(ap) x, y, z = ap.vi.translate(loc.x, loc.y, loc.z) # fetch unnormalized data - therefore raw_estimates apid_locid2estimates[i, j] = ap.vi.data[x, y, z] np.save(self.tmpdir.joinpath('apdata', self.optrun_session, 'apid_locid2estimates.npy'), apid_locid2estimates) return apid_locid2estimates def loadMeasurements(self, ap): locid2measurement = dict([(m.locid, m) for m in self.measurements]) for m in self.measurements: m.available = False m.rssi = 0 m.delta = 0 if not self.measurementfile: return tree = FileToTree(self.measurementfile) for e in tree.getroot().xpath('measurements/ap[@id=$apid]/location', apid=ap.id): locid = int(e.attrib['id']) rssi = float(e.attrib['avgrssi']) if not locid in locid2measurement: log.warn('unknown locid: %s' % locid) continue #~ if locid > 65: #~ continue m = locid2measurement[locid] distance = ((ap.x - m.x) ** 2 + (ap.y - m.y)**2 + (ap.z - m.z)**2)**(0.5) m.rssi = rssi m.rssis[:] = [float(e) for e in e.text.split(',')] m.distance = distance m.available = True self.calcMeasurementDeltas(ap) def calcMeasurementDeltas(self, ap): if ap.vi is None: log.warn('no volume image available - skipping calcMeasurementDeltas') return deltas = self.deltas[ap.id] deltas[:] = [] try: for m in self.measurements: x, y, z = ap.vi.translate(m.x, m.y, m.z) m.rssi_sim = ap.data_in_db[x][y][z] m.rssi_norm = ap.normalized_data_in_db[x][y][z] if not m.available: continue if m.rssi_sim <= -130 or m.rssi_norm <= -100: continue m.delta = m.rssi_norm - m.rssi deltas.append(m.delta) except IndexError: log.warn('measurements out of bounds') if len(deltas) > 0: self.avg_ap_delta = sum(abs(e) for e in deltas) / float(len(deltas)) self.sum_ap_delta = sum(deltas) ap.avg_delta = self.avg_ap_delta else: self.avg_ap_delta = 0 self.sum_ap_delta = 0 ap.avg_delta = 0 all_deltas = reduce(lambda a, b: a + b, self.deltas.values()) if len(all_deltas) > 0: self.total_avg_ap_delta = sum(abs(e) for e in all_deltas) / len(all_deltas) lastrun = time.time() @on_trait_change('run_simulation') def runsim(self): # there is a dirty traits-ui(?)bug # leading to double reload if editing a cell + button press if time.time() < self.lastrun + 2: log.warn('prevented double reload') return self.lastrun = time.time() #~ log.warn('### Run Simulation for aps: %s ###' % ','.join(ap.id for ap in self.aps)) disabledObjects = {e.name for e in self.scene_objects if not e.used} objfile = path(self.objfile) self.sim_finished.clear() aps = [ap for ap in self.aps if ap.used] def onResult(runids, tree): _getids = lambda s: {e for e in s.split(',') if e.strip()} for state in 'finished', 'running', 'waiting': ids = _getids(tree.getroot().attrib[state]) for _state in 'finished', 'running', 'waiting': traitsval = getattr(self, 'sim_%s' % _state) if state != _state: traitsval.difference_update(ids) else: traitsval.update(ids) #~ _ids = getattr(self, 'sim_%s' % state) #~ setattr(self, 'sim_%s_display' % state, ', '.join(_ids)) finished = _getids(tree.getroot().attrib['finished']) for runid in finished: apid = runids[runid].name self.clearCachedAPData(apid) reload(localizer) tx, ty, tz = gui.bbox.x1, gui.bbox.y1, gui.bbox.z1 dx, dy, dz = gui.res_dx, gui.res_dy, gui.res_dz di = localizer.Dimensions(tx, ty, tz, dx, dy, dz) ap2power = {ap.id: ap.power for ap in self.aps} env = localizer.Environment(objfile, aps=localizer.getAPsFromGui(self, assertLoadable=False), vi_path=self.apdatafiles, di=di) env.buildSimulations(self.scene_name, sceneloader.materials, ap2power, self.bbox, self.resolution, self.density, self.numphotons, disabledObjects, BASE_URL, onResult) def apid2datfile(self, ap_id): return path(self.apdatafiles % ap_id) #~ outname = '%s_%s' % (self.scene_name, ap_id) #~ return self.tmpdir.joinpath('%s.dat' % outname) @on_trait_change('load_all') def _loadAll(self): if len(self.opt_runs) == 0: optrun = self.loadLastOptRun() if optrun is not None: self.selectOptRun(optrun) # done - loadAll is triggered by select() return self.loadAll() def loadLastOptRun(self): f = self.tmpdir.joinpath('curr_optrun.dat') if f.exists(): optrun = pickle.load(open(f, 'rb')) self.opt_runs.append(optrun) return optrun def loadAll(self, retrive=True): t = time.time() with LOADING(): #~ self.scene.mlab.clf() self.loadSceneConfig() self.loadAPs() if retrive: self.retriveMaterials() self.retriveSceneObject() #~ self.retriveMeasurements() else: #~ self.loadMaterials() self.loadSceneFiles() self.loadLocations() self.loadCached() self.scene.mlab.view(45, 45) log.info('reloaded in %.3f sec' % (time.time() - t)) def loadCached(self): ''' restore store values ''' cachefile = self.tmpdir.joinpath('_last_loaded_measurements.txt') if cachefile.exists(): log.info('restoring measurements from %s' % cachefile.abspath()) self.synthetic_measurements = cachefile.text() @on_trait_change('scene_name') def sceneNameChanged(self): self.materialfile = self.tmpdir.joinpath('materials_%s.xml' % self.scene_name) self.objfile = self.tmpdir.joinpath('retrived_%s.obj' % self.scene_name) self.apdatafiles = self.tmpdir.joinpath('apdata', self.optrun_session, self.scene_name + '_%s.dat') @on_trait_change('load_scene_config') def loadSceneConfig(self): cachefile = self.tmpdir.joinpath('scene_config.txt') try: assert HTTP_AVAILABLE url = BASE_URL + '/getSceneConfig' log.info('retriving %s' % url) s = urlopen(url).read() cachefile.write_text(s) except Exception: log.error('retrieving failed') s = cachefile.text() tree = StringToTree(s) a = tree.getroot().attrib self.scene_name = a['name'] self.device_name = a['device'] self.device_names[:] = a['alldevices'].split(',') x1, x2, y1, y2, z1, z2 = [float(e) for e in a['bbox'].split(',')] self.bbox.x1 = x1 self.bbox.x2 = x2 self.bbox.y1 = y1 self.bbox.y2 = y2 self.bbox.z1 = z1 self.bbox.z2 = z2 x, y, z = [int(e) for e in a['resolution'].split(',')] self.resolution.x = x self.resolution.y = y self.resolution.z = z self.numphotons = int(a['numphotons']) self.density = float(a['density']) updateRes() self.setupScalarField() @on_trait_change('scene.activated') def load(self): updateRes() # this init has to be handled better @on_trait_change('load_scene_objects') def loadSceneFiles(self): self.clearSceneFiles() sceneloader.loadMesh(self.objfile) self.loadMaterials() self.setupSceneObjects() #~ sceneloader.loadMeshIntoMlab() @on_trait_change('retrieve_scene_object') def retriveSceneObject(self): try: assert HTTP_AVAILABLE url = BASE_URL + '/getObjFile' log.info('retriving %s' % url) s = urlopen(url).read() open(self.objfile, 'wb').write(s) except Exception: log.error('retrieving failed') s = self.objfile.text() log.info('got %.1f mb' % (len(s) / 1024.0**2)) try: l1 = s[:500].split('\n')[0] name = l1.split("'")[1] except Exception: log.error('cannot retrive name from (blender exported) obj file ') name = 'unknown' # auto reload self.loadSceneFiles() @on_trait_change('retrieve_materials') def retriveMaterials(self): try: assert HTTP_AVAILABLE url = BASE_URL + '/getMaterialsFile' log.info('retriving %s' % url) s = urlopen(url).read() log.info('got %.1f mb' % (len(s) / 1024.0**2)) open(self.materialfile, 'wb').write(s) except Exception: log.error('retriving of materials failed') # auto reload self.loadMaterials() @on_trait_change('load_materials') def loadMaterials(self): sceneloader.loadMaterials(self.materialfile) @on_trait_change('clear_scene_objects') def clearSceneFiles(self): for so in self.scene_objects: if not hasattr(so.mlab_mesh, '__call__'): so.mlab_mesh.remove() self.scene_objects[:] = [] # clear list self.scene_object_groups[:] = [] #~ for mlab_mesh in sceneloader.object2mesh.values(): #~ mlab_mesh.remove() #~ sceneloader.object2mesh.clear() @on_trait_change('surface_number_of_contours') def changeSurfNumContours(self): self.surface_view.contour.number_of_contours = self.surface_number_of_contours @on_trait_change('ipw_vmax') def changeIPWMax(self): self.changeIPWConfig() @on_trait_change('ipw_vmin') def changeIPWMin(self): self.changeIPWConfig() def changeIPWConfig(self): if self.ipw_vmin < self.ipw_vmax and self.ipw_z is not None: self.ipw_z.module_manager.scalar_lut_manager.data_range = (self.ipw_vmin, self.ipw_vmax) def setupSceneObjects(self): self.scene_objects[:] = [] # clear list COLORS = [(0.7,0.7,0.9), (0.9,0.7,0.7), (0.7,0.9,0.7), (0.9,0.9,0.3), (0.2,0.9,0.9), (0.3,0.3,0.3)] matnames = sceneloader.mesh.materials.values() matname2color = dict([(matname, COLORS[i % len(COLORS)]) for i, matname in enumerate(matnames)]) x, y, z = sceneloader.mesh.vertices def lazyLoadMesh(objname, matname, x, y, z, triangles): def _inner(): log.info('adding %s triangles for mesh "%s" with material "%s"' % (len(triangles), objname, matname)) return self.scene.mlab.triangular_mesh(x, y, z, triangles, color=matname2color[matname], opacity=0.1, name=objname) return _inner for objname in sceneloader.mesh.objects: matname = sceneloader.mesh.materials.get(objname, 'default') if matname == '(null)': # no material defined in blender log.warn('ignoring object %s' % objname) continue triangles = sceneloader.mesh.objects[objname] if matname in sceneloader.materials: brdf = sceneloader.materials[matname] self.scene_objects.append(SceneObject(name=objname, visible=False, used=True, matname=matname, reflect=brdf.reflect, alpha=brdf.alpha, ior=brdf.ior, display_color=matname2color[matname], mlab_mesh=lazyLoadMesh(objname, matname, x, y, z, triangles))) self.scene_object_groups[:] = [ SceneObjectGroup(name='EG', filter=['EG']), SceneObjectGroup(name='OG 1', filter=['OG1']), SceneObjectGroup(name='OG 2', filter=['OG2']), SceneObjectGroup(name='Fascade', filter=['Fascade', ]), SceneObjectGroup(name='Floor', filter=['Floor']), SceneObjectGroup(name='Stairs', filter=['Stairs', 'Railing']), SceneObjectGroup(name='Doors', filter=['Doors']), SceneObjectGroup(name='Stuff', filter=['Hardware', 'Cupboard', 'Table']), ] # this shouldnt be needed but the first is always checked in the table for e in self.scene_object_groups: e.visible = False def setupLogging(self): log.setLevel(logging.DEBUG) formatter = logging.Formatter("%(asctime)s.%(msecs)03d %(name)s %(levelname)s %(message)s", "%H:%M:%S") h = LoggingHandler() h.setFormatter(formatter) log.addHandler(h) h = StreamHandler() h.setFormatter(formatter) log.addHandler(h) def _doubleclicked_ap_changed(self): ap = self.doubleclicked_ap[0] self.reloadAP(ap) def reloadAP(self, ap): if isinstance(ap, basestring): # its a apid ap = [a for a in self.aps if a.id == ap][0] log.debug('loading data for %s' % ap.id) self.lazyLoadAP(ap) self.loadAPDataIntoScalarField(ap) self.loadMeasurements(ap) def _selected_ap_changed(self): if self.mlab_aps is None: return # colorize AP 3D-Sphere if self.selected_ap is not None: # this is a slow way to modify the acces point colorization l = [1] * len(self.aps) l[self.aps.index(self.selected_ap)] = 1.2 self.mlab_aps.mlab_source.scalars = l if self.loaded_ap_id != self.selected_ap.id: self.reloadAP(self.selected_ap) def _selected_measurement_changed(self): if self.mlab_locations is None or len(self.mlab_locations.mlab_source.scalars) != len(self.locations): xs, ys, zs = zip(*[(loc.x, loc.y, loc.z) for loc in self.locations]) self.visualizeLocations(xs, ys, zs, [1.0]*len(xs), UN_SELECTED_MEASUREMENT) if self.selected_measurement is not None: l = len(self.mlab_locations.mlab_source.scalars) * [1.0] l[self.measurements.index(self.selected_measurement)] = 1.2 self.mlab_locations.mlab_source.scalars = l if self.vi is not None: _, _, z = self.vi.translate(0, 0, self.selected_measurement.z) self.ipw_z.ipw.plane_orientation = 2 # 2 == Z-Orientation self.ipw_z.ipw.slice_index = z - 1 else: self.mlab_locations.mlab_source.scalars = [UN_SELECTED_MEASUREMENT] * len(self.measurements) def setupScalarField(self): if self.scalar_field is not None: try: self.scalar_field.remove() except Exception: pass if self.ipw_z is not None: old_slice_index = self.ipw_z.ipw.slice_index try: self.ipw_z.remove() except Exception: pass else: old_slice_index = 0 data = np.zeros((self.resolution.x, self.resolution.y, self.resolution.z)) - 100 self.scalar_field = self.scene.mlab.pipeline.scalar_field(data) sx = self.res_dx sy = self.res_dy sz = self.res_dz self.scalar_field.spacing = [sx, sy, sz] self.scalar_field.origin = [self.bbox.x1, self.bbox.y1, self.bbox.z1] # shifting the full plane is also an InteractionEvent # we react only on _real_ position changes via cross-hair movements - therefor we track lastpos lastpos = [None, None, None] def move_view(obj, evt): data = self.scalar_field.mlab_source position = list(obj.GetCurrentCursorPosition()) self.cursor_position = position if position != lastpos: if hasattr(self, 'vi') and self.vi is not None: data_in_mw = self.vi.data[tuple(position)] * 1000 else: data_in_mw = 0 if hasattr(self, 'data_in_db'): data_in_db = self.data_in_db[tuple(position)] normalized_data_in_db = self.normalized_data_in_db[tuple(position)] else: data_in_db = 0 normalized_data_in_db = 0 xyz = self.translateToMeter(*position) self.plane_cursor_coords = ('x: %.2f, y: %.2f, z:%.2f:' % xyz + ' rssi: %.1f [%.1e mw] normalized: %.1f' % (data_in_db, data_in_mw, normalized_data_in_db)) self.plane_state_coords = 'x: %d, y: %d, z: %d' % self.translateToStateVoxel(*xyz) x, y, z = self.translateToStateVoxel(*xyz) self.state_x = x self.state_y = y self.state_z = z lastpos[:] = position # replace contents of list self.ipw_z = gui.scene.mlab.pipeline.image_plane_widget(self.scalar_field, plane_orientation='z_axes', slice_index=old_slice_index, vmax=0, vmin=-100) self.ipw_z.ipw.add_observer('InteractionEvent', move_view) self.surface_view = self.scene.mlab.pipeline.iso_surface(self.scalar_field, opacity=0.9) self.surface_view.contour.number_of_contours = self.surface_number_of_contours self.surface_view.visible = False def translateToStateVoxel(self, x, y, z): '''translate float real world coordinates into voxel coordinates''' cube_width = self.cube_width return (int(round((x - self.bbox.x1) / self.res_dx)) / cube_width, int(round((y - self.bbox.y1) / self.res_dy)) / cube_width, int(round((z - self.bbox.z1) / self.res_dz)) / cube_width) def translateToMeter(self, x, y, z): '''translate voxel coords to float real world coordinates''' return (self.bbox.x1 + x * self.res_dx, self.bbox.y1 + y * self.res_dy, self.bbox.z1 + z * self.res_dz) def loadVolumeImage(self, apid): datfile = self.apid2datfile(apid) log.debug('reading %s' % datfile.abspath()) vi = VolumeImage() vi.read(datfile) return vi def lazyLoadAP(self, ap): if ap.vi is None: t = time.time() log.debug('loading %s' % ap.id) vi = ap.vi = self.loadVolumeImage(ap.id) ap.data_in_db = vi.asDecibelData(CLAMP) ap.normalized_data_in_db = toNormalizedDecibelwithDeviceAdaption(vi.data, self.davalues.get(self.device_name, [])) log.info('loaded %s in %.3f sec' % (ap.id, time.time() - t)) def loadAPDataIntoScalarField(self, ap): self.loaded_ap_id = ap.id self.vi = vi = ap.vi self.surface_view.visible = False self.surface_number_of_contours = 5 # convert to decibel self.data_in_db = ap.data_in_db self.normalized_data_in_db = ap.normalized_data_in_db unclamped = 10 * np.log10(vi.data[np.where(vi.data > 0)]) self.ipw_vmin = max(-100, int(unclamped.min())) self.ipw_vmax = min(0, int(unclamped.max())) _, _, z = vi.translate(0, 0, ap.z) self.ipw_z.ipw.plane_orientation = 2 # 2 == Z-Orientation self.ipw_z.ipw.slice_index = z - 1 if self.view_normalized_data: self.scalar_field.mlab_source.scalars = self.normalized_data_in_db else: self.scalar_field.mlab_source.scalars = self.data_in_db self.changeIPWConfig() @on_trait_change('load_opt_runs') def loadOptruns(self): self.opt_runs[:] = [] t = time.time() s = urlopen(BASE_URL + '/getOptimizeSessions').read() for sessionEl in StringToTree(s).getroot().xpath('session'): session = sessionEl.attrib['name'] try: dt = datetime.datetime.strptime(sessionEl.attrib['dt'], '%Y-%m-%d %H:%M:%S') numphotons = int(sessionEl.attrib['numphotons']) density = float(sessionEl.attrib['density']) resolution = sessionEl.attrib['resolution'] bbox = sessionEl.attrib['bbox'] devices = sessionEl.attrib['station'].split(',') scene = sessionEl.attrib['scene'] minimumEl = sessionEl.xpath('minimum') if len(minimumEl) == 0: continue minimumEl = minimumEl[0] minavgdelta = float(minimumEl.attrib['avg-delta']) powers = {} materials = {} davalues = defaultdict(list) rssieq = 0.0 for name, value in minimumEl.attrib.items(): if name in self.powids: powers[name] = float(value) elif name.startswith('da-'): # device adaption params device_darssi = name[3:].split('_') if len(device_darssi) == 1: # backward compat davalues[sessionEl.attrib['station']].append((float(device_darssi[0]), float(value))) else: device, darssi = device_darssi davalues[device].append((float(darssi), float(value))) elif name == 'n-rssieq': rssieq = float(value) elif ',' in value: # detect material param by scanning for 0.444,0.345 reflect, alpha = value.split(',') materials[name] = Brdf(float(reflect), float(alpha)) for device, dav in davalues.items(): dav.sort() r = OptimizeRun(date=dt, session=session, minavgdelta=minavgdelta, numphotons=numphotons, density=density, powers=powers, materials=materials, resolution=resolution, bbox=bbox, davalues=davalues, rssieq=rssieq, devices=devices, scene=scene) self.opt_runs.append(r) except Exception: log.exception('error during loading optrun %s' % session) log.info('load optruns in %.2f sec' % (time.time() - t)) def _doubleclicked_optrun_changed(self): optrun = self.doubleclicked_optrun[0] self.selectOptRun(optrun) def selectOptRun(self, optrun): pickle.dump(optrun, open(self.tmpdir.joinpath('curr_optrun.dat'), 'wb')) self.optrun_session = optrun.session self.scene_name = optrun.scene self.apdatafiles = self.tmpdir.joinpath('apdata', self.optrun_session, self.scene_name + '_%s.dat') r = optrun.resolution.split(',') self.res_x = int(r[0]) self.res_y = int(r[1]) self.res_z = int(r[2]) bb = optrun.bbox.split(',') self.bb_x1 = float(bb[0]) self.bb_x2 = float(bb[1]) self.bb_y1 = float(bb[2]) self.bb_y2 = float(bb[3]) self.bb_z1 = float(bb[4]) self.bb_z2 = float(bb[5]) # store materials TreeToFile(materialsAsXml(optrun.materials), self.materialfile) self.loadAll(retrive=False) for ap in self.aps: if ap.powid in optrun.powers: ap.power = optrun.powers[ap.powid] else: print '%s not in %s' % (ap.powid, optrun.powers.keys()) ap.used = False self.numphotons = optrun.numphotons self.density = optrun.density self.davalues = optrun.davalues self.rssieq = optrun.rssieq self.device_name = optrun.devices[0] self.deviceNameChanged() def setupNormalizationPlot(self): self.plot.clf() xs = np.arange(-130, -20, 0.1) # from log space into float space _xs = [10**(x/10.0) for x in xs] ys = toNormalizedDecibelwithDeviceAdaption(np.array([[_xs]]).astype(np.float32), self.davalues.get(self.device_name, []))[0][0] ax1 = self.plot.add_subplot(111) ax1.set_title('normalization of %s' % self.device_name) ax1.set_xlim(min(xs), max(xs)) ax1.set_ylim(min(ys), max(ys)) ax1.plot(xs, ys) ax2 = ax1.twinx() ys = [(y-x) for x, y in zip(xs, ys)] ax2.set_ylim(-10, 10) ax2.set_xlim(min(xs), max(xs)) ax2.plot(xs, ys, color='green') def _toogle_object_groups_changed(self): for objgroup in self.scene_object_groups: objgroup.visible = not objgroup.visible @on_trait_change('do_localizeHMM') def doLocalizeHMM(self, keybinding_dummy=None, threaded=True): self._doLocalize('hmm', threaded=threaded) @on_trait_change('do_localizePF') def doLocalizePF(self, keybinding_dummy=None, threaded=True): self._doLocalize('pf', threaded=threaded) @on_trait_change('do_localizeLMSE') def doLocalizeLMSE(self, keybinding_dummy=None, threaded=True): self._doLocalize('lmse', threaded=threaded) def _doLocalize(self, algo, threaded): self.gui_thread_id = thread.get_ident() try: reload(localizer) except Exception: log.exception('error reload localizer') else: if ':' in self.localize_range: start, end = [int(e) if e.strip() else None for e in self.localize_range.split(':')] else: start, end = int(self.localize_range), None if threaded: thread.start_new_thread(localizer.localizeGui, (self, log, algo, start, end)) else: localizer.localizeGui(self, log, algo, start, end) def doViewHistory(self, keybinding_dummy=None): try: reload(localizer) except Exception: log.exception('error reload localizer') else: localizer.fullPruniningAnimation(self.localizer, 2) @on_trait_change('do_viewpftrans') def viewPFTrans(Self): reload(localizer) localizer.viewPFTransitionsAtPos(self, self.localizer) @on_trait_change('do_viewblocked') def viewBlockedCubes(self): reload(localizer) thread.start_new_thread(localizer.viewBlockedCubes, (self, log)) def viewHistorySingle(self): assert localizer is not None, 'viewHistory needs a localization run' self.localizer.viewHistory(self.pruning_idx, self.pruning_visible_count) @on_trait_change('do_viewhistory') def viewPruningStepNext(self, keybinding_dummy=None): self.pruning_idx += self.pruning_step_width self.viewHistorySingle() @on_trait_change('pruning_visible_count') def historyCountChanged(self): self.viewHistorySingle() @on_trait_change('do_viewhistory_prev') def viewPruningStepPrev(self, keybinding_dummy=None): self.pruning_idx -= self.pruning_step_width self.viewHistorySingle() @on_trait_change('do_viewgradients') def viewGradients(self, keybinding_dummy=None): reload(localizer) thread.start_new_thread(localizer.viewSignalGradients, (self, log)) def _loadPathSequence(self, ps): with LOADING(): self.localization_path[:] = [] if len(ps.locs) > 0: self.runid2run = {str(r.id): r for r in ps.runs} runids = self.runid2run.keys() self.measurement_runs[:] = runids if len(runids) > 0: self.measurement_runid = runids[0] if isinstance(ps.locs[0], int): for locid in ps.locs: loc = self.locid2location.get(locid) if loc is None: log.warn('locid %s not found' % locid) continue p = PathPosition(id=locid, x=loc.x, y=loc.y, z=loc.z) self.localization_path.append(p) ps.locs[:] = self.localization_path else: self.localization_path[:] = ps.locs @on_trait_change('selected_path_sequence') def selectedPathSequenceChanged(self): if self.selected_path_sequence is None or _LOADING: return self._loadPathSequence(self.selected_path_sequence) self._localization_path_changed() @on_trait_change('selected_path_pos') def selectedPathPosChanged(self): #~ print self.selected_path_pos pass @on_trait_change('do_delete_path_segment') def doDeletePathSegment(self): if self.selected_path_pos is not None: i = self.localization_path.index(self.selected_path_pos) self.localization_path.remove(self.selected_path_pos) if i < len(self.localization_path): self.selected_path_pos = self.localization_path[i] else: self.selected_path_pos = None self._localization_path_changed(store=True) def _localization_path_changed(self, refreshCubes=True, *args, **kwds): # update distances total_dist = dist = 0 for pos1, pos2 in zip(self.localization_path, self.localization_path[1:]): dist = ((pos2.x - pos1.x)**2 + (pos2.y - pos1.y)**2 + (pos2.z - pos1.z)**2)**0.5 pos2.distance = dist total_dist += dist pos2.total_distance = total_dist for i, pos in enumerate(self.localization_path): pos.id = i if refreshCubes: localizer.buildPathCubes(self) xs, ys, zs = zip(*[(loc.x, loc.y, loc.z) for loc in self.localization_path]) self.visualizeLocations(xs, ys, zs, [1.0]*len(xs), self.res_dx * self.cube_width * 0.5) if kwds.get('store'): self.custom_path.locs[:] = self.localization_path f = self.tmpdir.joinpath('localization_path.dat').open('w') pickle.dump(self.localization_path, f) @on_trait_change('do_load_paths') def doLoadPaths(self): with LOADING(): self.localization_paths[:] = [] CACHED = True if not CACHED: url = BASE_URL + '/getCollectedPaths?station=%s' % self.device_name log.debug('loading %s...' % url) tree = opener.open(url).read() self.tmpdir.joinpath('path_data_%s.txt' % self.device_name).write_text(tree) else: tree = self.tmpdir.joinpath('path_data_%s.txt' % self.device_name).text() for pel in sorted(StringToTree(tree).getroot().xpath('path'), key=lambda x: x.attrib['id']): a = pel.attrib runEls = pel.xpath('run') runs = [] for runEl in runEls: run_measurements = runEl.xpath('string(measurements/text())') if run_measurements == '': log.info('skipping empty measurements') continue run_locations = runEl.xpath('string(locations/text())') r = MeasurementRun(id=int(runEl.attrib['id']), measurements=run_measurements, locations=run_locations) runs.append(r) locs = [int(e) for e in pel.attrib['locations'].split(',')] p = PathSequence(id=a['id'], length=len(locs), collect_runs=len(runEls), locs=locs, runs=runs) self.localization_paths.append(p) f = self.tmpdir.joinpath('localization_path.dat') if f.exists(): lp = pickle.load(f.open()) else: lp = [] p = PathSequence(id='custom', length=len(lp), collect_runs=-1, locs=lp, runs=[]) self.localization_paths.append(p) self.custom_path = p @on_trait_change('do_draw_path') def doDrawPath(self): self._localization_path_changed() @on_trait_change('do_record_path') def doRecordPath(self): if self.ipw_z is None: return self.ipw_z.visible = True def new_path_entry(obj, evt): doubleclick = time.time() - self.record_path_last_interaction < 0.5 if doubleclick: position = list(obj.GetCurrentCursorPosition()) x, y, z = [round(p * s + o, 1) for p, s, o in zip(position, self.scalar_field.spacing, self.scalar_field.origin)] if len(self.localization_path) > 0: last_pos = self.localization_path[-1] if last_pos.x == x and last_pos.y == y and last_pos.z == z: return with LOADING(): pp = PathPosition(id=len(self.localization_path), x=x, y=y, z=z) if self.selected_path_pos is None: self.localization_path.append(pp) else: i = self.localization_path.index(self.selected_path_pos) self.localization_path.insert(i, pp) if len(self.localization_path) == 1: self.selected_path_pos = None self._localization_path_changed(store=True) self.record_path_last_interaction = time.time() oid = getattr(self, 'record_path_oberserver_id', None) if oid is None: self.record_path_last_interaction = 0 self.ipw_z.ipw.left_button_action = 0 self.record_path_oberserver_id = self.ipw_z.ipw.add_observer('StartInteractionEvent', new_path_entry) else: self.ipw_z.ipw.left_button_action = 1 # the default self.ipw_z.ipw.remove_observer(oid) delattr(self, 'record_path_oberserver_id') delattr(self, 'record_path_last_interaction') @on_trait_change('do_generate_synthetic_measurements') def doGenerateSyntheticMeasurementsFromCorners(self): reload(localizer) env = localizer.Environment(self.objfile, aps=localizer.getAPsFromGui(self)) corners = [(p.x, p.y, p.z) for p in self.localization_path] measurements = env.generateSyntheticMeasurementsFromCorners(corners=corners, speed=self.synthetic_measurements_speed, noise=self.synthetic_measurements_noise, granularity=self.synthetic_measurements_granularity) self.loadMeasurementSequence(measurements) @on_trait_change('do_generate_synthetic_measurements_cubes') def doGenerateSyntheticMeasurementsAtCubeCenters(self): reload(localizer) env = localizer.Environment(self.objfile, aps=localizer.getAPsFromGui(self)) cubes = localizer.getCubesFromPath(gui, env) half_cube = (self.res_dx * self.cube_width) / 2.0 positions = [np.array(self.translateToMeter(*(xyz * self.cube_width))) + half_cube for xyz in cubes] measurements = env.generateSyntheticMeasurementsAtPositions(positions, speed=self.synthetic_measurements_speed, noise=self.synthetic_measurements_noise, sample_environment=half_cube/2.0) self.loadMeasurementSequence(measurements) @on_trait_change('do_load_measurement_run') def loadMeasurementRun(self): runid = self.measurement_runid run = self.runid2run.get(runid) if run is None: log.error('no measurement_run found for runid %s' % runid) return reload(localizer) measurements = localizer.Measurements() measurements.loadFromString(run.measurements) measurements.interpolateFromLocationString(run.locations, self.locid2location) self.loadMeasurementSequence(measurements) def loadMeasurementSequence(self, measurements): self.synthetic_measurements = str(measurements) cachefile = self.tmpdir.joinpath('_last_loaded_measurements.txt') cachefile.write_text(self.synthetic_measurements) xs, ys, zs = zip(*[(m.pos.x, m.pos.y, m.pos.z) for m in measurements]) values = [1.0]*len(xs) self.visualizeLocations(xs, ys, zs, values, self.res_dx * self.cube_width * 0.5) def visualizeLocations(self, xs, ys, zs, values, scale_factor): if self.mlab_locations is not None: self.mlab_locations.remove() self.mlab_locations = self.scene.mlab.points3d(xs, ys, zs, values, mode='axes', colormap='Reds', scale_factor=scale_factor) @on_trait_change('show_scalar_bar') def showScalarBar(self, title=None): lut_mgr = self.scene.mlab.scalarbar(title=title) if not lut_mgr.visible: # resizing this bitch is ugly - see mayavi.tools.decorations.py lut_mgr.scalar_bar_representation.position2 = (0.8, 0.10) else: lut_mgr.visible = False @on_trait_change('toggle_ipw_z') def toggleIPWZ(self): self.ipw_z.visible = not self.ipw_z.visible @on_trait_change('toggle_surfaceview') def toggleSurfaceView(self): self.surface_view.visible = not self.surface_view.visible @on_trait_change('cube_width') def updateCubeWidth(self): updateRes() @on_trait_change('device_name') def deviceNameChanged(self): dav = self.davalues.get(self.device_name, []) self.device_davalues = ', '.join('%d:%.1f' % (float(e[0]), float(e[1])) for e in dav) self.setupNormalizationPlot() self.localization_paths[:] = [] self.loadLocations() @on_trait_change('do_current_ap_surface_plot') def doCurrentApSurfacePlot(self): import thesis; reload(thesis) thesis.currentApSurfacePlot(self) @on_trait_change('do_thesis_pruning_plot') def doThesisPruningPlot(self): import thesis reload(thesis) thesis.pruningPlot(self) @on_trait_change('do_thesis_path_info') def doThesisPathInfo(self): import thesis reload(thesis) thesis.pathInfo(self) @on_trait_change('do_thesis_localization_plot') def doThesisLocalizationPlot(self): import thesis reload(thesis) thesis.localizationPlot(self) @on_trait_change('do_thesis_pruning_scatter') def doThesisPruningScatter(self): import thesis reload(thesis) thesis.pruningScatter(self) @on_trait_change('do_3dmodel_latextable') def doThesis3DModelTable(self): import thesis reload(thesis) thesis.latex3dmodel(self, sceneloader.mesh) @on_trait_change('do_device2measurements_latextable') def doD2MTable(self): import thesis reload(thesis) thesis.latexDevice2Measurements(self) @on_trait_change('do_generate_synthetic_paths') def doSynthPaths(self): import thesis reload(thesis) thesis.generateSyntheticPaths(self) @on_trait_change('do_plot_apcoverage') def doPlotAPCoverage(self): import thesis reload(thesis) thesis.plotAPCoverage(self) gui = Gui() view = View( HGroup( VGroup( Item(name='scene', editor=SceneEditor(scene_class=MayaviScene), show_label=False, height=500, width=500 ), Tabbed( Item(name='loggingout', show_label = False, label = 'Log', editor = CodeEditor(show_line_numbers=False, foldable=False, selected_color='white'), height=300, ), Item(name='shell', label = 'Shell', show_label = False, editor = ShellEditor(), height=300, ), VGroup( Item('plot', editor=MPLFigureEditor(), show_label=False), label = 'Plot', ), ), layout = 'split', ), VGrid( Tabbed( HGroup( VGroup( HGroup( Item('load_scene_objects', show_label = False, label = 'Load Scene', editor = ButtonEditor(), ), Item('clear_scene_objects', show_label = False, label = 'Clear Scene', editor = ButtonEditor(), ), Item('retrieve_scene_object', show_label = False, label = 'Retrive Scene', editor = ButtonEditor(), ), Item('toogle_object_groups', show_label = False, label = 'Toogle Groups', editor = ButtonEditor(), ), ), Item('objfile', show_label = False, label = 'objfile', editor = FileEditor(filter = ['*.obj',]), ), VGrid( Item('scene_object_groups', show_label = False, label = 'Groups', editor = objectsgroups_table, width=100, ), Item('scene_objects', show_label = False, label='Scene', editor = objects_table, width=500, ), ), label = 'Scene & Materials', ), VGroup( HGroup( Item('load_materials', show_label = False, label = 'Load Materials', editor = ButtonEditor(), ), Item('retrieve_materials', show_label = False, label = 'Retrive Materials', editor = ButtonEditor(), ), ), Item('materialfile', show_label = False, label = 'materialfile', editor = FileEditor(filter = ['*.xml',]), ), Item('materials', show_label = False, editor = materials_table, ), ), layout = 'split', ), HGroup( VGroup( HGroup( Item('load_aps', show_label = False, label = 'Load APs', editor = ButtonEditor(), ), Item('clear_aps', show_label = False, label = 'Clear', editor = ButtonEditor(), ), Item('reload_ap_data', show_label = False, label = 'Reload SimData', editor = ButtonEditor(), ), Item('view_normalized_data', show_label=True, label='Normalized',), ), HGroup( Item('toggle_ap_used', show_label = False, label = 'Toggle', editor = ButtonEditor(), ), Item('evaluate_all_aps', show_label = False, label = 'Eval All', editor = ButtonEditor(), ), Item('run_device_adaption', show_label = False, label = 'Device Adaption', editor = ButtonEditor(), ), Item('clear_cached_ap', show_label = False, label = 'Clear AP Cache', editor = ButtonEditor(), ), ), Item('apdatafiles', show_label=False), Item('aps', show_label = False, editor = ap_table, ), label = 'APs & Measurements', ), VGroup( HGroup( Item('load_locations', show_label = False, label = 'Load Locations', editor = ButtonEditor(), ), Item('clear_locations', show_label = False, label = 'Clear Locations', editor = ButtonEditor(), ), Item('retrieve_measurements', show_label = False, label = 'Retrieve Measurements', editor = ButtonEditor(), ), Item('retrieve_measurements_overlay', show_label = False, label = 'Retrieve with overlay', editor = ButtonEditor(), ), ), Item('measurementfile', show_label = False, editor = FileEditor(filter = ['*.xml',]), ), Item('measurements', show_label = False, editor = measurements_table, ), ), layout = 'split', ), VGroup( Item('load_opt_runs', show_label = False, label = 'Refresh', editor = ButtonEditor(), ), Item('opt_runs', show_label = False, editor = opt_runs_table, ), label='Optimize Runs', ), VGroup( Item('load_scene_config', show_label = False, label = 'Load Scene', editor = ButtonEditor(), ), HGroup( Item('bb_x1', label='bbx1',), Item('bb_y1', label='bby1',), Item('bb_z1', label='bbz1',), ), HGroup( Item('bb_x2', label='bbx2',), Item('bb_y2', label='bby2',), Item('bb_z2', label='bbz2',), ), HGroup( Item('res_x', label='rx',), Item('res_y', label='ry',), Item('res_z', label='rz',), ), HGroup( Item('res_dx', label='rdx',), Item('res_dy', label='rdy',), Item('res_dz', label='rdz',), ), Item('numphotons'), Item('density'), Item('scene_name', label='Scene Name',), label = 'BBox & Resolution', ), VGroup( HGroup( Item('do_localizeHMM', show_label = False, label = 'Localize HMM', editor = ButtonEditor(), ), Item('do_localizePF', show_label = False, label = 'Localize PF', editor = ButtonEditor(), ), Item('do_localizeLMSE', show_label = False, label = 'Localize LMSE', editor = ButtonEditor(), ), Item('localize_range'), Item('localizer', style="readonly"), ), HGroup( Item('do_viewgradients', show_label = False, label = 'View Gradients', editor = ButtonEditor(), ), Item('do_viewblocked', show_label = False, label = 'View Blocked', editor = ButtonEditor(), ), Item('do_viewpftrans', show_label = False, label = 'View PFTrans', editor = ButtonEditor(), ), Item('cube_width', label='CubeWidth'), Item('cube_width_display', label='Resolution', style='readonly'), ), HGroup( Item('do_viewhistory', show_label = False, label = 'View History Next', editor = ButtonEditor(), ), Item('do_viewhistory_prev', show_label = False, label = 'Prev', editor = ButtonEditor(), ), Item('pruning_step_width', label='Step'), Item('pruning_idx', label='Index'), Item('pruning_visible_count', label='VisibleCount', ), ), HGroup( Item('prune_to'), Item('threads'), Item('freespace_scan'), ), HGroup( VGroup( HGroup( Item('do_load_paths', show_label = False, label = 'Load Paths', editor = ButtonEditor(), ), Item('do_draw_path', show_label = False, label = 'Draw Path', editor = ButtonEditor(), ), Item('do_record_path', label='Record Path'), Item('do_delete_path_segment', show_label = False, label = 'Delete Pos', editor = ButtonEditor(), ), ), HGroup( Item(name='localization_paths', show_label = False, editor = path_table, ), Item(name='localization_path', show_label = False, editor = path_pos_table, ), ), ), VGroup( HGroup( Item('do_generate_synthetic_measurements_cubes', show_label = False, label = 'Generate (cubes)', editor = ButtonEditor(), ), Item('synthetic_measurements_noise', label='Noise(sigma in dbm)'), Item('synthetic_measurements_speed', label='Speed(m/s)'), ), HGroup( Item('do_generate_synthetic_measurements', show_label = False, label = 'Generate (fluid)', editor = ButtonEditor(), ), Item('synthetic_measurements_granularity', label='Granularity(m)'), ), HGroup( Item('do_load_measurement_run', show_label = False, label = 'Load collected', editor = ButtonEditor(), ), Item('measurement_runid', show_label = True, label = 'Run', editor = EnumEditor(name='measurement_runs'), ), ), Item(name='synthetic_measurements', show_label = False, editor = CodeEditor(show_line_numbers=True, foldable=False, selected_color='white'), ), ), layout = 'split' ), label = 'Localization', ), VGroup( HGroup( Item('do_current_ap_surface_plot', show_label = False, label = 'Current AP Surface Plot', editor = ButtonEditor(), ), Item('do_thesis_pruning_plot', show_label = False, label = 'Pruning Plot', editor = ButtonEditor(), ), Item('do_thesis_pruning_scatter', show_label = False, label = 'Pruning Scatter', editor = ButtonEditor(), ), Item('do_thesis_localization_plot', show_label = False, label = 'Localization with Errors', editor = ButtonEditor(), ), ), HGroup( Item('do_3dmodel_latextable', show_label = False, label = '3D-Model Info Table', editor = ButtonEditor(), ), Item('do_plot_apcoverage', show_label = False, label = 'Plot AP Coverage', editor = ButtonEditor(), ), Item('do_device2measurements_latextable', show_label = False, label = 'Devce2Measurements Info Table', editor = ButtonEditor(), ), ), HGroup( Item('do_generate_synthetic_paths', show_label = False, label = 'Build Synthetic Path Variants', editor = ButtonEditor(), ), Item('do_thesis_path_info', show_label = False, label = 'Latex Path Table', editor = ButtonEditor(), ), ), label = 'Thesis', ), ), VGrid( VGroup( Item('load_all', show_label = False, label = 'Load from Server', editor = ButtonEditor(), ), ), VGroup( Item('plane_cursor_coords', label='Cursor', style='readonly'), Item('plane_state_coords', label='Cursor/States', style='readonly'), Item('avg_ap_delta', show_label = True, label = 'avg_delta', editor = TextEditor(), style='readonly', ), Item('sum_ap_delta', show_label = True, label = 'sum_delta', editor = TextEditor(), style='readonly', ), Item('total_avg_ap_delta', show_label = True, label = 'total avg_delta', editor = TextEditor(), style='readonly', ), ), HGroup( Item('show_ap_data_at_cursor', show_label = False, label = 'Show AP Data', editor = ButtonEditor(), ), ), HGroup( Item('show_scalar_bar', show_label = False, label = 'Scalar Bar', editor = ButtonEditor(), ), Item('toggle_ipw_z', show_label = False, label = 'Toggle IPW Z', editor = ButtonEditor(), ), Item('toggle_surfaceview', show_label = False, label = 'Toggle Surface View', editor = ButtonEditor(), ), Item('surface_number_of_contours', show_label = False, label = 'Surface Num Contours', ), ), VGroup( Item('ipw_vmin', show_label = True, label = 'DB Start', editor = RangeEditor(low=-100, high=0), ), Item('ipw_vmax', show_label = True, label = 'DB End', editor = RangeEditor(low=-100, high=0), ), ), HGroup( Item('scene_name', label='Scene', style="readonly"), Item('optrun_session', label='Optrun', style="readonly"), ), HGroup( Item('device_name', label='Device', editor = EnumEditor(name='device_names'), ), Item('device_davalues', label='Device Adaptation', style='readonly'), ), VGroup( Item('run_simulation', show_label = False, label = 'Run Raytracer', editor = ButtonEditor(), ), ), VGrid( Item('sim_waiting', editor=ListEditor(style='readonly'), show_label=True, label='Waiting'), Item('sim_running', editor=ListEditor(style='readonly'), show_label=True, label='Running'), Item('sim_finished', editor=ListEditor(style='readonly'), show_label=True, label='Finished'), columns=3, ), ), layout = 'split', ), layout = 'split', #auto_size = False, #~ springy = True, ), height = 500, width = 950, resizable = True, key_bindings = KeyBindings( KeyBinding( binding1 = 'F9', description = 'Run Localizer HMM', method_name = 'doLocalizeHMM' ), KeyBinding( binding1 = 'F10', description = 'View Pruning', method_name = 'doViewPruning'), KeyBinding( binding1 = 'F8', description = 'View Gradients', method_name = 'viewGradients'), KeyBinding( binding1 = 'F7', description = 'next History', method_name = 'viewPruningStepNext'), KeyBinding( binding1 = 'F6', description = 'prev History', method_name = 'viewPruningStepPrev'), ), ) gui.configure_traits(view=view)