volview.py 91 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468
  1. # -*- coding: utf-8 -*-
  2. #~ from traits.etsconfig.api import ETSConfig
  3. #~ ETSConfig.toolkit = 'qt4'
  4. from enthought.mayavi import mlab
  5. import datetime
  6. import logging
  7. import time
  8. import thread
  9. import threading
  10. from collections import namedtuple, defaultdict
  11. import math
  12. import cPickle as pickle
  13. from contextlib import contextmanager
  14. import numpy as np
  15. import scipy
  16. from matplotlib.figure import Figure
  17. from ansistrm import ColorizingStreamHandler as StreamHandler
  18. from enthought.traits.api import HasTraits, Instance, on_trait_change, HasStrictTraits, DelegatesTo
  19. from enthought.traits.api import Enum, Range, List, Bool, Str, Int, Float, Event, Dict, File, Any, Date, Instance, Property, Set, Tuple
  20. from enthought.traits.ui.api import (Handler, View, Item, Group, VGroup, HGroup, TextEditor, ButtonEditor, HSplit, HFlow, VFold, VGrid,
  21. EnumEditor, ListEditor, BooleanEditor, ShellEditor, FileEditor, Tabbed, CodeEditor, RangeEditor)
  22. from enthought.traits.ui.key_bindings import KeyBinding, KeyBindings
  23. from enthought.tvtk.pyface.scene_editor import SceneEditor
  24. from enthought.mayavi.core.ui.mayavi_scene import MayaviScene
  25. from enthought.mayavi.tools.mlab_scene_model import MlabSceneModel
  26. from enthought.traits.ui.api import View, Item, TableEditor, TabularEditor
  27. from enthought.traits.ui.extras.checkbox_column import CheckboxColumn
  28. from enthought.traits.ui.table_column import ObjectColumn
  29. from enthought.traits.ui.tabular_adapter import TabularAdapter
  30. from utils.traitsmpl import MPLFigureEditor
  31. from utils.path import path
  32. from utils import cython_annotate
  33. from utils.objparser import Mesh
  34. from utils.xml import FileToTree, subelement, TreeToFile, prettyPrint, TreeToString, StringToTree
  35. from utils.volumeimage import VolumeImage
  36. from utils.materials import loadMaterials, Brdf, materialsAsXml
  37. from utils.url import urlopen
  38. from utils.accelerated import toNormalizedDecibelwithDeviceAdaption
  39. import lws.localize as localizer
  40. log = logging.getLogger()
  41. gui = None
  42. UN_SELECTED_MEASUREMENT = 0.5
  43. CLAMP = -130
  44. HTTP_AVAILABLE = True
  45. from utils.url import getOpener
  46. mpart_opener = getOpener(enableMultipart=True)
  47. opener = getOpener()
  48. BASE_URL = 'http://nostromo.informatik.rwth-aachen.de:20080'
  49. #BASE_URL = 'http://loco.visual-library.de'
  50. #~ BASE_URL = 'http://localhost:42777'
  51. gui_lock = threading.Lock()
  52. class LoggingHandler(logging.Handler):
  53. def __init__(self):
  54. logging.Handler.__init__(self)
  55. self.level = logging.DEBUG
  56. formatter = logging.Formatter("%(asctime)s.%(msecs)03d "
  57. "%(name)s %(levelname)s %(message)s",
  58. "%H:%M:%S")
  59. self.setFormatter(formatter)
  60. def emit(self, record):
  61. msg = self.format(record)
  62. gui.loggingout = msg + '\n' + gui.loggingout
  63. class Material(HasStrictTraits):
  64. name = Str
  65. reflect = Float(0.5)
  66. alpha = Float(0.5)
  67. ior = Float(1.0)
  68. def _reflect_changed(self):
  69. if sceneloader.materials is not None and self.name in sceneloader.materials:
  70. sceneloader.materials[self.name].reflect = self.reflect
  71. def _alpha_changed(self):
  72. if sceneloader.materials is not None and self.name in sceneloader.materials:
  73. sceneloader.materials[self.name].alpha = self.alpha
  74. materials_table = TableEditor(
  75. sortable = False,
  76. configurable = False,
  77. columns = [ObjectColumn(name ='name'),
  78. ObjectColumn(name='reflect', format_func = lambda x: '%.3f' % x),
  79. ObjectColumn(name='alpha', format_func = lambda x: '%.3f' % x),
  80. ],
  81. )
  82. class SceneObjectColumn (ObjectColumn):
  83. # Override some default settings for the column:
  84. width = 0.08
  85. horizontal_alignment = 'center'
  86. editable = False
  87. def get_text_color(self, object):
  88. return [ 'light grey', 'black' ][1]
  89. objects_table = TableEditor(
  90. sortable = False,
  91. configurable = False,
  92. #~ auto_size = False,
  93. columns = [CheckboxColumn(name ='visible', label='View'),
  94. CheckboxColumn(name ='used', label='Used'),
  95. SceneObjectColumn(name='name'),
  96. SceneObjectColumn(name='matname'),
  97. ],
  98. )
  99. class SceneObject(HasStrictTraits):
  100. # Trait definitions:
  101. name = Str
  102. matname = Str
  103. visible = Bool(True)
  104. used = Bool(False)
  105. reflect = Float
  106. alpha = Float
  107. ior = Float
  108. display_color = Tuple # the mayavi mesh color
  109. mlab_mesh = Any(None) # the mayavi mesh
  110. def _visible_changed(self):
  111. if _LOADING:
  112. return
  113. if hasattr(self.mlab_mesh, '__call__'):
  114. if self.visible: # create mesh lazy
  115. self.mlab_mesh = self.mlab_mesh()
  116. else:
  117. self.mlab_mesh.visible = self.visible
  118. class MeasurementColumn(ObjectColumn):
  119. def get_text_color(self, m):
  120. if self.name == 'rssi_norm' and m.rssi_norm == m.rssi_sim:
  121. return 'light grey'
  122. else:
  123. return 'black' if m.available else 'light grey'
  124. objectsgroups_table = TableEditor(
  125. sortable = False,
  126. configurable = False,
  127. columns = [CheckboxColumn(name ='visible', label='View'),
  128. ObjectColumn(name='name'),
  129. ],
  130. )
  131. class SceneObjectGroup(HasStrictTraits):
  132. name = Str
  133. visible = Bool(False)
  134. filter = List
  135. def _visible_changed(self):
  136. if not _LOADING:
  137. for f in self.filter:
  138. for sceneobject in gui.scene_objects:
  139. if f in sceneobject.name:
  140. sceneobject.visible = self.visible
  141. class Location(HasTraits):
  142. locid = Int
  143. x = Float
  144. y = Float
  145. z = Float
  146. class Measurement(HasStrictTraits):
  147. location = Instance(Location)
  148. locid = DelegatesTo('location')
  149. x = DelegatesTo('location')
  150. y = DelegatesTo('location')
  151. z = DelegatesTo('location')
  152. rssi = Float
  153. rssi_sim = Float
  154. rssi_norm = Float
  155. rssis = List
  156. delta = Float # delta between measured and simulated rssi
  157. distance = Float # distance to ap
  158. available = Bool(False)
  159. class MeasurementTableAdapter(TabularAdapter):
  160. columns = [ ('id', 'locid'), ('x', 'x'), ('y', 'y'), ('z', 'z'),
  161. ('Dist', 'distance'), ('meas', 'rssi'), ('sim', 'rssi_sim'), ('norm', 'rssi_norm'), ('delta', 'delta') ]
  162. distance_format = Str('%.1f')
  163. rssi_format = Str('%.1f')
  164. rssi_sim_format = Str('%.1f')
  165. rssi_norm_format = Str('%.1f')
  166. delta_format = Str('%.1f')
  167. value_text = Property
  168. def _get_value_text ( self ):
  169. return self.item
  170. measurements_table = TabularEditor(
  171. auto_update = True,
  172. editable = False,
  173. selected = 'selected_measurement',
  174. adapter = MeasurementTableAdapter() )
  175. class AccessPoint(HasStrictTraits):
  176. id = Str
  177. x = Float
  178. y = Float
  179. z = Float
  180. power = Float
  181. used = Bool
  182. powid = Str
  183. avg_delta = Float
  184. # raytracer results - loaded lazy
  185. data_in_db = Any
  186. normalized_data_in_db = Any
  187. vi = Any
  188. def __str__(self):
  189. return '<AccessPoint>%s at (%.1f,%.1f,%.1f)' % (self.id, self.x, self.y, self.z)
  190. def reset(self):
  191. self.data_in_db = None
  192. self.normalized_data_in_db = None
  193. self.vi = None
  194. ap_table = TableEditor(
  195. columns = [ObjectColumn(name='id', editable=False),
  196. ObjectColumn(name='x'),
  197. ObjectColumn(name='y'),
  198. ObjectColumn(name='z'),
  199. ObjectColumn(name='powid'),
  200. ObjectColumn(name='power', format_func = lambda x: ('%.1f' if x > 0.1 else '%.1e') % x),
  201. CheckboxColumn(name ='used', label='Used'),
  202. ObjectColumn(name='avg_delta', format_func = lambda x: '%.1f' % x),
  203. ],
  204. dclick = 'doubleclicked_ap',
  205. selected = 'selected_ap'
  206. )
  207. class OptimizeRun(HasStrictTraits):
  208. date = Date
  209. minavgdelta = Float
  210. session = Str
  211. scene = Str
  212. density = Float
  213. numphotons = Int
  214. materials = Dict # key matname, value: Brdf
  215. powers = Dict # key powid, value power
  216. resolution = Str # store only string form "320,90,50"
  217. bbox = Str # store only string form
  218. rssieq = Float # normalization via normalizeLogarithmic
  219. davalues = Dict # normalization via normalizeDeviceAdaption
  220. devices = List # list of included devices in optrun
  221. opt_runs_table = TableEditor(
  222. columns = [ObjectColumn(name='date', editable=False, format_func = lambda x: x.strftime("%m-%d %H:%M:%S")),
  223. ObjectColumn(name='minavgdelta', editable=False),
  224. ObjectColumn(name='session', editable=False),
  225. ObjectColumn(name='density', editable=False),
  226. ObjectColumn(name='numphotons', editable=False),
  227. ObjectColumn(name='devices', editable=False, format_func = lambda x: ','.join(x)),
  228. ],
  229. dclick = 'doubleclicked_optrun',
  230. )
  231. def updateRes():
  232. if gui is not None:
  233. gui.res_dx = round((gui.bbox.x2 - gui.bbox.x1) / gui.resolution.x, 6)
  234. gui.res_dy = round((gui.bbox.y2 - gui.bbox.y1) / gui.resolution.y, 6)
  235. gui.res_dz = round((gui.bbox.z2 - gui.bbox.z1) / gui.resolution.z, 6)
  236. gui.cube_res_x = gui.res_x / gui.cube_width
  237. gui.cube_res_y = gui.res_y / gui.cube_width
  238. gui.cube_res_z = gui.res_z / gui.cube_width
  239. total = gui.cube_res_x * gui.cube_res_y * gui.cube_res_z
  240. gui.cube_width_display = '%s, %s, %s [%.2fk states]' % (gui.cube_res_x, gui.cube_res_y, gui.cube_res_z, total / 1000.0)
  241. class _BBox(HasStrictTraits):
  242. x1 = Float
  243. x2 = Float
  244. y1 = Float
  245. y2 = Float
  246. z1 = Float
  247. z2 = Float
  248. @on_trait_change('anytrait')
  249. def _update(self, x):
  250. updateRes()
  251. class Resolution(HasStrictTraits):
  252. x = Int
  253. y = Int
  254. z = Int
  255. @on_trait_change('anytrait')
  256. def _update(self, x):
  257. updateRes()
  258. class SceneLoader(object):
  259. ''' pretty much obsolete now'''
  260. def __init__(self):
  261. self.mesh = None
  262. self.materials = {}
  263. def loadMesh(self, objfile):
  264. objfile = path(objfile)
  265. self.mesh = Mesh()
  266. t = time.time()
  267. self.mesh.parseObjFile(objfile)
  268. log.debug('parsed %s vertices in %.3f seconds' % (len(self.mesh.vertices[0]), time.time() - t))
  269. def loadMaterials(self, materialfile):
  270. materialfile = path(materialfile)
  271. log.info('loading materials from %s' % materialfile.normpath())
  272. self.setMaterials(loadMaterials(materialfile))
  273. def setMaterials(self, materials):
  274. gui.materials[:] = []
  275. self.materials.clear()
  276. for matname, brdf in materials.items():
  277. # convert Brdf() to traits representation
  278. m = Material(name=matname, reflect=brdf.reflect, alpha=brdf.alpha)
  279. self.materials[matname] = m
  280. gui.materials.append(m)
  281. sceneloader = SceneLoader()
  282. path_pos_table = TableEditor(
  283. columns = [ObjectColumn(name='id', editable=False),
  284. ObjectColumn(name='x', format_func=lambda x: '%.1f' % x),
  285. ObjectColumn(name='y', format_func=lambda x: '%.1f' % x),
  286. ObjectColumn(name='z', format_func=lambda x: '%.1f' % x),
  287. ObjectColumn(name='distance', label='dist', format_func=lambda x: '%.1f' % x, editable=False),
  288. ObjectColumn(name='total_distance', label='total', format_func=lambda x: '%.1f' % x, editable=False),
  289. ],
  290. selected = 'selected_path_pos'
  291. )
  292. class PathPosition(HasStrictTraits):
  293. id = Int
  294. x = Float
  295. y = Float
  296. z = Float
  297. distance = Float
  298. total_distance = Float
  299. @on_trait_change('x,y,z')
  300. def _update(self, v):
  301. if _LOADING: return
  302. gui._localization_path_changed()
  303. path_table = TableEditor(
  304. columns = [ObjectColumn(name='id', label='id', editable=False),
  305. ObjectColumn(name='length', label='l', editable=False),
  306. ObjectColumn(name='collect_runs', label='runs', editable=False),
  307. ],
  308. selected = 'selected_path_sequence'
  309. )
  310. class MeasurementRun(HasStrictTraits):
  311. id = Int
  312. measurements = Str
  313. locations = Str
  314. class PathSequence(HasStrictTraits):
  315. id = Str
  316. length = Int
  317. collect_runs = Int
  318. locs = List # either [int locids] or [PathPosition]
  319. runs = List(MeasurementRun)
  320. _LOADING = False
  321. @contextmanager
  322. def LOADING():
  323. global _LOADING
  324. try:
  325. _LOADING = True
  326. yield None
  327. finally:
  328. _LOADING = False
  329. class Gui(HasTraits):
  330. # The scene model.
  331. scene = Instance(MlabSceneModel, ())
  332. # Trait definitions:
  333. scene_objects = List(SceneObject) # different blender objects as trait definition
  334. load_scene_objects = Event
  335. clear_scene_objects = Event
  336. retrieve_scene_object = Event
  337. scene_object_groups = List(SceneObjectGroup)
  338. toogle_object_groups = Event
  339. plane_cursor_coords = Str('<first focus plane>')
  340. plane_state_coords = Str
  341. state_x = Int(0)
  342. state_y = Int(0)
  343. state_z = Int(0)
  344. avg_ap_delta = Float
  345. total_avg_ap_delta = Float
  346. sum_ap_delta = Float
  347. measurements_mean = Float
  348. measurements_stddev = Float
  349. locations = List(Location)
  350. measurements = List(Measurement) # measured db/rssi values at different coords
  351. measurements_points = None # points3d instance
  352. clear_locations = Event
  353. load_locations = Event
  354. retrieve_measurements = Event
  355. retrieve_measurements_overlay = Event
  356. aps = List(AccessPoint) #different access points
  357. powids = Set
  358. load_aps = Event
  359. clear_aps = Event
  360. reload_ap_data = Event
  361. toggle_ap_used = Event
  362. evaluate_all_aps = Event
  363. run_device_adaption = Event
  364. clear_cached_ap = Event
  365. show_ap_data_at_cursor = Event
  366. load_all = Event
  367. load_scene_config = Event
  368. scene_name = Str('new_scene')
  369. device_name = Str('device')
  370. device_names = List(Str)
  371. device_davalues = Str()
  372. #~ objfile = File(r'D:\loco-dev\maps\onewall\One-Wall.obj')
  373. objfile = File()
  374. materials = List(Material)
  375. retrieve_materials = Event
  376. load_materials = Event
  377. materialfile = File
  378. #~ materialfile = File(r'D:\loco-dev\maps\onewall\materials.xml')
  379. measurementfile = File()
  380. tmpdir = path('_tmp').abspath()
  381. run_simulation = Event
  382. shell = Dict
  383. loggingout = Str
  384. ap_power = Float
  385. ap_x = Float
  386. ap_y = Float
  387. ap_z = Float
  388. apdatafiles = Str
  389. doubleclicked_ap = Any # tuple (AccessPoint, clicked Colum)
  390. selected_ap = Any # Instance of AccessPoint
  391. loaded_ap_id = None
  392. selected_measurement = Any
  393. opt_runs = List(OptimizeRun)
  394. optrun_session = Str('default')
  395. load_opt_runs = Event
  396. doubleclicked_optrun = Any # tuple (OptimizeRun, clicked Column)
  397. bbox = _BBox(x1=-1, x2=1, y1=-1, y2=1, z1=-1, z2=1)
  398. #~ bbox = _BBox(x1=-10.0, x2=10, y1=-10.0, y2=10.0, z1=-5, z2=4.0)
  399. bb_x1 = DelegatesTo('bbox', prefix='x1')
  400. bb_x2 = DelegatesTo('bbox', prefix='x2')
  401. bb_y1 = DelegatesTo('bbox', prefix='y1')
  402. bb_y2 = DelegatesTo('bbox', prefix='y2')
  403. bb_z1 = DelegatesTo('bbox', prefix='z1')
  404. bb_z2 = DelegatesTo('bbox', prefix='z2')
  405. resolution = Resolution(x=32, y=32, z=32)
  406. res_x = DelegatesTo('resolution', prefix='x')
  407. res_y = DelegatesTo('resolution', prefix='y')
  408. res_z = DelegatesTo('resolution', prefix='z')
  409. cube_resolution = Resolution(x=0, y=0, z=0)
  410. cube_res_x = DelegatesTo('cube_resolution', prefix='x')
  411. cube_res_y = DelegatesTo('cube_resolution', prefix='y')
  412. cube_res_z = DelegatesTo('cube_resolution', prefix='z')
  413. res_dx = Float
  414. res_dy = Float
  415. res_dz = Float
  416. # normalization param
  417. davalues = Dict
  418. rssieq = Float(0.0)
  419. plot = Instance(Figure, ())
  420. view_normalized_data = Bool(False)
  421. sim_waiting = Set
  422. sim_running = Set
  423. sim_finished = Set
  424. numphotons = Int(300000)
  425. density = Float(0.1)
  426. localizer = Any
  427. localization_paths = List(PathSequence)
  428. localization_path = List(PathPosition)
  429. custom_path = PathSequence
  430. do_localizeHMM = Event
  431. do_localizePF = Event
  432. do_localizeLMSE = Event
  433. localize_range = Str('0:') # slice notation
  434. do_viewblocked = Event
  435. do_viewpftrans = Event
  436. do_viewgradients = Event
  437. do_record_path = Bool
  438. do_delete_path_segment = Event
  439. do_draw_path = Event
  440. do_load_paths = Event
  441. selected_path_pos = Any
  442. selected_path_sequence = Any
  443. do_viewhistory = Event
  444. do_viewhistory_prev = Event
  445. pruning_idx = Int(0)
  446. pruning_step_width = Int(1)
  447. pruning_visible_count = Int(1000)
  448. do_generate_synthetic_measurements = Event
  449. do_generate_synthetic_measurements_cubes = Event
  450. synthetic_measurements = Str
  451. synthetic_measurements_noise = Float(5)
  452. synthetic_measurements_speed = Float(1.5)
  453. synthetic_measurements_granularity = Float(2.0)
  454. do_load_measurement_run = Event
  455. measurement_runid = Str
  456. measurement_runs = List(Str)
  457. cube_width = Int(3)
  458. cube_width_display = Str
  459. prune_to = Int(3000)
  460. threads = Int(4)
  461. freespace_scan = Int(-1)
  462. show_scalar_bar = Event
  463. toggle_ipw_z = Event
  464. toggle_surfaceview = Event
  465. ipw_vmin = Range(-100, 10)
  466. ipw_vmax = Range(-100, 10)
  467. surface_number_of_contours = Range(5, 150, 8)
  468. do_current_ap_surface_plot = Event
  469. do_thesis_pruning_plot = Event
  470. do_thesis_path_info = Event
  471. do_thesis_localization_plot = Event
  472. do_thesis_pruning_scatter = Event
  473. do_3dmodel_latextable = Event
  474. do_device2measurements_latextable = Event
  475. do_generate_synthetic_paths = Event
  476. do_plot_apcoverage = Event
  477. ######################
  478. def __init__(self, **traits):
  479. HasTraits.__init__(self, **traits)
  480. self.setupLogging()
  481. self.mlab_aps = None # holds mlab ap geometry
  482. self.scalar_field = None # holds mlab volume image data
  483. self.ipw_z = None
  484. self.surface_view = None
  485. self.mlab_locations = None # holds mlab locations geometry
  486. self.vi = None # holds VolumeImage instance
  487. self.deltas = defaultdict(list)
  488. self.locid2location = {}
  489. self.runid2run = {}
  490. if not self.tmpdir.exists():
  491. self.tmpdir.mkdir()
  492. if not self.tmpdir.joinpath('apdata').exists():
  493. self.tmpdir.joinpath('apdata').mkdir()
  494. self.cursor_position = None
  495. @on_trait_change('clear_locations')
  496. def clearLocations(self):
  497. self.locations[:] = []
  498. self.measurements[:] = []
  499. if self.mlab_locations is not None:
  500. self.mlab_locations.remove()
  501. self.mlab_locations = None
  502. @on_trait_change('view_normalized_data')
  503. def viewNormalizedDataClicked(self):
  504. self.reloadAP(self.selected_ap)
  505. @on_trait_change('reload_ap_data')
  506. def reloadAPClicked(self):
  507. self.reloadAP(self.selected_ap)
  508. @on_trait_change('toggle_ap_used')
  509. def toogleAPUsed(self):
  510. for ap in self.aps:
  511. ap.used = not ap.used
  512. @on_trait_change('run_device_adaption')
  513. def runDeviceAdaptation(self):
  514. apid_locid2measurement = self.measurementsAsArray()
  515. apid_locid2estimated = self.rawEstimatesForMeasurements(apid_locid2measurement)
  516. import lws.optimizer
  517. res, opt_avg_delta = lws.optimizer.optimizeDeviceAdaption({self.device_name: apid_locid2measurement}, apid_locid2estimated, 80)
  518. if self.device_name in self.davalues:
  519. log.info('old davalues: %s' % ','.join('%s: %.1f' % e for e in self.davalues[self.device_name][:]))
  520. log.info('new davalues: %s' % ','.join('%s: %.1f' % e for e in res[self.device_name]))
  521. self.davalues[self.device_name] = res[self.device_name]
  522. # update davalues on gui
  523. self.deviceNameChanged()
  524. self.clearCachedAPData()
  525. @on_trait_change('show_ap_data_at_cursor')
  526. def showAPDataAtPos(self):
  527. assert self.cursor_position is not None
  528. for ap in self.aps:
  529. if not ap.used:
  530. continue
  531. self.lazyLoadAP(ap)
  532. data_in_db = ap.data_in_db[tuple(self.cursor_position)]
  533. normalized_data_in_db = ap.normalized_data_in_db[tuple(self.cursor_position)]
  534. log.info('%s: %.2f, norm: %.2f' % (ap.id, data_in_db, normalized_data_in_db))
  535. @on_trait_change('clear_cached_ap')
  536. def clearCachedAPData(self, apid=None):
  537. for ap in self.aps:
  538. if apid is not None:
  539. if not ap.id == apid:
  540. continue
  541. ap.reset()
  542. @on_trait_change('evaluate_all_aps')
  543. def evaluateAllAps(self):
  544. self.deltas.clear()
  545. for ap in self.aps:
  546. if not ap.used:
  547. continue
  548. try:
  549. self.lazyLoadAP(ap)
  550. except Exception:
  551. log.exception('cannot load ap %s' % ap)
  552. else:
  553. try:
  554. self.loadMeasurements(ap)
  555. except Exception:
  556. log.error('cannot load measurements for ap %s' % ap)
  557. @on_trait_change('clear_aps')
  558. def clearAPs(self):
  559. self.aps[:] = []
  560. if self.mlab_aps is not None:
  561. self.mlab_aps.remove()
  562. self.mlab_aps = None
  563. @on_trait_change('load_aps')
  564. def loadAPs(self):
  565. self.clearAPs()
  566. cachefile = self.tmpdir.joinpath('ap_config.txt')
  567. try:
  568. assert HTTP_AVAILABLE
  569. cfgtree = opener.open(BASE_URL + '/getAPConfig').read()
  570. cachefile.write_text(cfgtree)
  571. except Exception:
  572. log.error('retrieving failed')
  573. cfgtree = cachefile.text()
  574. for e in StringToTree(cfgtree).getroot().getchildren():
  575. a = e.attrib
  576. used = a['on']=='true'
  577. apid = a['id']
  578. #~ used = apid in ('107', '108')
  579. self.aps.append(AccessPoint(id=apid,
  580. x=float(a['x']), y=float(a['y']), z=float(a['z']),
  581. powid=a['powerid'], power=float(a['power']),
  582. used=used))
  583. self.powids = {ap.powid for ap in self.aps}
  584. #~ self.aps.append(AccessPoint(id='onewall', x=0, y=0, z=0, power=10, used=True))
  585. xs = [e.x for e in self.aps]
  586. ys = [e.y for e in self.aps]
  587. zs = [e.z for e in self.aps]
  588. if len(xs) > 0:
  589. # add AP source as a 3d point
  590. self.mlab_aps = self.scene.mlab.points3d(xs, ys, zs, [1]*len(xs), colormap="binary", scale_factor=.5)
  591. @on_trait_change('retrieve_measurements')
  592. def retriveMeasurements(self, overlay=False, device_name=None, autoreload=True):
  593. if device_name == None:
  594. device_name = self.device_name
  595. if overlay:
  596. url = BASE_URL + '/getLocationsAndMeasurements/%s?overlay_tracked=true' % device_name
  597. else:
  598. url = BASE_URL + '/getLocationsAndMeasurements/%s' % device_name
  599. log.info('retriving %s' % url)
  600. s = urlopen(url).read()
  601. log.info('got %.1f mb' % (len(s) / 1024.0**2))
  602. measurementfile = self.tmpdir.joinpath('measurements_%s_%s.xml' % (self.scene_name, device_name))
  603. open(measurementfile, 'wb').write(s)
  604. if autoreload:
  605. # auto reload
  606. self.loadLocations()
  607. @on_trait_change('retrieve_measurements_overlay')
  608. def retriveMeasurementsOverlay(self):
  609. self.retriveMeasurements(overlay=True)
  610. @on_trait_change('load_locations')
  611. def loadLocations(self, device_name=None):
  612. if device_name == None:
  613. device_name = self.device_name
  614. self.measurementfile = self.tmpdir.joinpath('measurements_%s_%s.xml' % (self.scene_name, device_name))
  615. if not path(self.measurementfile).exists():
  616. return
  617. tree = FileToTree(self.measurementfile)
  618. locEls = tree.getroot().xpath('locations/location')
  619. self.clearLocations()
  620. for e in locEls:
  621. x, y, z = float(e.attrib['x']), float(e.attrib['y']), float(e.attrib['z'])
  622. loc = Location(locid=int(e.attrib['id']), x=x, y=y, z=z)
  623. m = Measurement()
  624. m.location = loc
  625. self.measurements.append(m)
  626. self.locations.append(loc)
  627. self.locid2location = dict([(loc.locid, loc) for loc in self.locations])
  628. if self.selected_ap is not None:
  629. self.loadMeasurements(self.selected_ap)
  630. def measurementsAsArray(self):
  631. max_locid = max(self.locid2location.keys())
  632. apid_locid2measurements = np.zeros(shape=(len(self.aps), max_locid)) + np.inf
  633. for i, ap in enumerate(self.aps):
  634. if not ap.used:
  635. continue
  636. tree = FileToTree(self.measurementfile)
  637. for e in tree.getroot().xpath('measurements/ap[@id=$apid]/location', apid=ap.id):
  638. locid = int(e.attrib['id'])
  639. if not locid in self.locid2location:
  640. log.error('unknown location %s' % locid)
  641. continue
  642. apid_locid2measurements[i, locid] = float(e.attrib['avgrssi'])
  643. np.save(self.tmpdir.joinpath('apdata', self.optrun_session, '%s_apid_locid2measurements.npy' % self.device_name), apid_locid2measurements)
  644. return apid_locid2measurements
  645. def rawEstimatesForMeasurements(self, apid_locid2measurements=None):
  646. if apid_locid2measurements is None:
  647. apid_locid2measurements = self.measurementsAsArray()
  648. apid_locid2estimates = np.zeros(shape=apid_locid2measurements.shape) + np.inf
  649. for i, ap in enumerate(self.aps):
  650. if not ap.used:
  651. continue
  652. for j in range(apid_locid2measurements.shape[1]):
  653. if not np.isfinite(apid_locid2measurements[i, j]):
  654. continue
  655. loc = self.locid2location[j]
  656. self.lazyLoadAP(ap)
  657. x, y, z = ap.vi.translate(loc.x, loc.y, loc.z)
  658. # fetch unnormalized data - therefore raw_estimates
  659. apid_locid2estimates[i, j] = ap.vi.data[x, y, z]
  660. np.save(self.tmpdir.joinpath('apdata', self.optrun_session, 'apid_locid2estimates.npy'), apid_locid2estimates)
  661. return apid_locid2estimates
  662. def loadMeasurements(self, ap):
  663. locid2measurement = dict([(m.locid, m) for m in self.measurements])
  664. for m in self.measurements:
  665. m.available = False
  666. m.rssi = 0
  667. m.delta = 0
  668. if not self.measurementfile:
  669. return
  670. tree = FileToTree(self.measurementfile)
  671. for e in tree.getroot().xpath('measurements/ap[@id=$apid]/location', apid=ap.id):
  672. locid = int(e.attrib['id'])
  673. rssi = float(e.attrib['avgrssi'])
  674. if not locid in locid2measurement:
  675. log.warn('unknown locid: %s' % locid)
  676. continue
  677. #~ if locid > 65:
  678. #~ continue
  679. m = locid2measurement[locid]
  680. distance = ((ap.x - m.x) ** 2 + (ap.y - m.y)**2 + (ap.z - m.z)**2)**(0.5)
  681. m.rssi = rssi
  682. m.rssis[:] = [float(e) for e in e.text.split(',')]
  683. m.distance = distance
  684. m.available = True
  685. self.calcMeasurementDeltas(ap)
  686. def calcMeasurementDeltas(self, ap):
  687. if ap.vi is None:
  688. log.warn('no volume image available - skipping calcMeasurementDeltas')
  689. return
  690. deltas = self.deltas[ap.id]
  691. deltas[:] = []
  692. try:
  693. for m in self.measurements:
  694. x, y, z = ap.vi.translate(m.x, m.y, m.z)
  695. m.rssi_sim = ap.data_in_db[x][y][z]
  696. m.rssi_norm = ap.normalized_data_in_db[x][y][z]
  697. if not m.available:
  698. continue
  699. if m.rssi_sim <= -130 or m.rssi_norm <= -100:
  700. continue
  701. m.delta = m.rssi_norm - m.rssi
  702. deltas.append(m.delta)
  703. except IndexError:
  704. log.warn('measurements out of bounds')
  705. if len(deltas) > 0:
  706. self.avg_ap_delta = sum(abs(e) for e in deltas) / float(len(deltas))
  707. self.sum_ap_delta = sum(deltas)
  708. ap.avg_delta = self.avg_ap_delta
  709. else:
  710. self.avg_ap_delta = 0
  711. self.sum_ap_delta = 0
  712. ap.avg_delta = 0
  713. all_deltas = reduce(lambda a, b: a + b, self.deltas.values())
  714. if len(all_deltas) > 0:
  715. self.total_avg_ap_delta = sum(abs(e) for e in all_deltas) / len(all_deltas)
  716. lastrun = time.time()
  717. @on_trait_change('run_simulation')
  718. def runsim(self):
  719. # there is a dirty traits-ui(?)bug
  720. # leading to double reload if editing a cell + button press
  721. if time.time() < self.lastrun + 2:
  722. log.warn('prevented double reload')
  723. return
  724. self.lastrun = time.time()
  725. #~ log.warn('### Run Simulation for aps: %s ###' % ','.join(ap.id for ap in self.aps))
  726. disabledObjects = {e.name for e in self.scene_objects if not e.used}
  727. objfile = path(self.objfile)
  728. self.sim_finished.clear()
  729. aps = [ap for ap in self.aps if ap.used]
  730. def onResult(runids, tree):
  731. _getids = lambda s: {e for e in s.split(',') if e.strip()}
  732. for state in 'finished', 'running', 'waiting':
  733. ids = _getids(tree.getroot().attrib[state])
  734. for _state in 'finished', 'running', 'waiting':
  735. traitsval = getattr(self, 'sim_%s' % _state)
  736. if state != _state:
  737. traitsval.difference_update(ids)
  738. else:
  739. traitsval.update(ids)
  740. #~ _ids = getattr(self, 'sim_%s' % state)
  741. #~ setattr(self, 'sim_%s_display' % state, ', '.join(_ids))
  742. finished = _getids(tree.getroot().attrib['finished'])
  743. for runid in finished:
  744. apid = runids[runid].name
  745. self.clearCachedAPData(apid)
  746. reload(localizer)
  747. tx, ty, tz = gui.bbox.x1, gui.bbox.y1, gui.bbox.z1
  748. dx, dy, dz = gui.res_dx, gui.res_dy, gui.res_dz
  749. di = localizer.Dimensions(tx, ty, tz, dx, dy, dz)
  750. ap2power = {ap.id: ap.power for ap in self.aps}
  751. env = localizer.Environment(objfile, aps=localizer.getAPsFromGui(self, assertLoadable=False), vi_path=self.apdatafiles, di=di)
  752. env.buildSimulations(self.scene_name, sceneloader.materials, ap2power, self.bbox, self.resolution,
  753. self.density, self.numphotons, disabledObjects, BASE_URL, onResult)
  754. def apid2datfile(self, ap_id):
  755. return path(self.apdatafiles % ap_id)
  756. #~ outname = '%s_%s' % (self.scene_name, ap_id)
  757. #~ return self.tmpdir.joinpath('%s.dat' % outname)
  758. @on_trait_change('load_all')
  759. def _loadAll(self):
  760. if len(self.opt_runs) == 0:
  761. optrun = self.loadLastOptRun()
  762. if optrun is not None:
  763. self.selectOptRun(optrun)
  764. # done - loadAll is triggered by select()
  765. return
  766. self.loadAll()
  767. def loadLastOptRun(self):
  768. f = self.tmpdir.joinpath('curr_optrun.dat')
  769. if f.exists():
  770. optrun = pickle.load(open(f, 'rb'))
  771. self.opt_runs.append(optrun)
  772. return optrun
  773. def loadAll(self, retrive=True):
  774. t = time.time()
  775. with LOADING():
  776. #~ self.scene.mlab.clf()
  777. self.loadSceneConfig()
  778. self.loadAPs()
  779. if retrive:
  780. self.retriveMaterials()
  781. self.retriveSceneObject()
  782. #~ self.retriveMeasurements()
  783. else:
  784. #~ self.loadMaterials()
  785. self.loadSceneFiles()
  786. self.loadLocations()
  787. self.loadCached()
  788. self.scene.mlab.view(45, 45)
  789. log.info('reloaded in %.3f sec' % (time.time() - t))
  790. def loadCached(self):
  791. ''' restore store values '''
  792. cachefile = self.tmpdir.joinpath('_last_loaded_measurements.txt')
  793. if cachefile.exists():
  794. log.info('restoring measurements from %s' % cachefile.abspath())
  795. self.synthetic_measurements = cachefile.text()
  796. @on_trait_change('scene_name')
  797. def sceneNameChanged(self):
  798. self.materialfile = self.tmpdir.joinpath('materials_%s.xml' % self.scene_name)
  799. self.objfile = self.tmpdir.joinpath('retrived_%s.obj' % self.scene_name)
  800. self.apdatafiles = self.tmpdir.joinpath('apdata', self.optrun_session, self.scene_name + '_%s.dat')
  801. @on_trait_change('load_scene_config')
  802. def loadSceneConfig(self):
  803. cachefile = self.tmpdir.joinpath('scene_config.txt')
  804. try:
  805. assert HTTP_AVAILABLE
  806. url = BASE_URL + '/getSceneConfig'
  807. log.info('retriving %s' % url)
  808. s = urlopen(url).read()
  809. cachefile.write_text(s)
  810. except Exception:
  811. log.error('retrieving failed')
  812. s = cachefile.text()
  813. tree = StringToTree(s)
  814. a = tree.getroot().attrib
  815. self.scene_name = a['name']
  816. self.device_name = a['device']
  817. self.device_names[:] = a['alldevices'].split(',')
  818. x1, x2, y1, y2, z1, z2 = [float(e) for e in a['bbox'].split(',')]
  819. self.bbox.x1 = x1
  820. self.bbox.x2 = x2
  821. self.bbox.y1 = y1
  822. self.bbox.y2 = y2
  823. self.bbox.z1 = z1
  824. self.bbox.z2 = z2
  825. x, y, z = [int(e) for e in a['resolution'].split(',')]
  826. self.resolution.x = x
  827. self.resolution.y = y
  828. self.resolution.z = z
  829. self.numphotons = int(a['numphotons'])
  830. self.density = float(a['density'])
  831. updateRes()
  832. self.setupScalarField()
  833. @on_trait_change('scene.activated')
  834. def load(self):
  835. updateRes() # this init has to be handled better
  836. @on_trait_change('load_scene_objects')
  837. def loadSceneFiles(self):
  838. self.clearSceneFiles()
  839. sceneloader.loadMesh(self.objfile)
  840. self.loadMaterials()
  841. self.setupSceneObjects()
  842. #~ sceneloader.loadMeshIntoMlab()
  843. @on_trait_change('retrieve_scene_object')
  844. def retriveSceneObject(self):
  845. try:
  846. assert HTTP_AVAILABLE
  847. url = BASE_URL + '/getObjFile'
  848. log.info('retriving %s' % url)
  849. s = urlopen(url).read()
  850. open(self.objfile, 'wb').write(s)
  851. except Exception:
  852. log.error('retrieving failed')
  853. s = self.objfile.text()
  854. log.info('got %.1f mb' % (len(s) / 1024.0**2))
  855. try:
  856. l1 = s[:500].split('\n')[0]
  857. name = l1.split("'")[1]
  858. except Exception:
  859. log.error('cannot retrive name from (blender exported) obj file ')
  860. name = 'unknown'
  861. # auto reload
  862. self.loadSceneFiles()
  863. @on_trait_change('retrieve_materials')
  864. def retriveMaterials(self):
  865. try:
  866. assert HTTP_AVAILABLE
  867. url = BASE_URL + '/getMaterialsFile'
  868. log.info('retriving %s' % url)
  869. s = urlopen(url).read()
  870. log.info('got %.1f mb' % (len(s) / 1024.0**2))
  871. open(self.materialfile, 'wb').write(s)
  872. except Exception:
  873. log.error('retriving of materials failed')
  874. # auto reload
  875. self.loadMaterials()
  876. @on_trait_change('load_materials')
  877. def loadMaterials(self):
  878. sceneloader.loadMaterials(self.materialfile)
  879. @on_trait_change('clear_scene_objects')
  880. def clearSceneFiles(self):
  881. for so in self.scene_objects:
  882. if not hasattr(so.mlab_mesh, '__call__'):
  883. so.mlab_mesh.remove()
  884. self.scene_objects[:] = [] # clear list
  885. self.scene_object_groups[:] = []
  886. #~ for mlab_mesh in sceneloader.object2mesh.values():
  887. #~ mlab_mesh.remove()
  888. #~ sceneloader.object2mesh.clear()
  889. @on_trait_change('surface_number_of_contours')
  890. def changeSurfNumContours(self):
  891. self.surface_view.contour.number_of_contours = self.surface_number_of_contours
  892. @on_trait_change('ipw_vmax')
  893. def changeIPWMax(self):
  894. self.changeIPWConfig()
  895. @on_trait_change('ipw_vmin')
  896. def changeIPWMin(self):
  897. self.changeIPWConfig()
  898. def changeIPWConfig(self):
  899. if self.ipw_vmin < self.ipw_vmax and self.ipw_z is not None:
  900. self.ipw_z.module_manager.scalar_lut_manager.data_range = (self.ipw_vmin, self.ipw_vmax)
  901. def setupSceneObjects(self):
  902. self.scene_objects[:] = [] # clear list
  903. 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)]
  904. matnames = sceneloader.mesh.materials.values()
  905. matname2color = dict([(matname, COLORS[i % len(COLORS)]) for i, matname in enumerate(matnames)])
  906. x, y, z = sceneloader.mesh.vertices
  907. def lazyLoadMesh(objname, matname, x, y, z, triangles):
  908. def _inner():
  909. log.info('adding %s triangles for mesh "%s" with material "%s"' % (len(triangles), objname, matname))
  910. return self.scene.mlab.triangular_mesh(x, y, z, triangles, color=matname2color[matname], opacity=0.1, name=objname)
  911. return _inner
  912. for objname in sceneloader.mesh.objects:
  913. matname = sceneloader.mesh.materials.get(objname, 'default')
  914. if matname == '(null)': # no material defined in blender
  915. log.warn('ignoring object %s' % objname)
  916. continue
  917. triangles = sceneloader.mesh.objects[objname]
  918. if matname in sceneloader.materials:
  919. brdf = sceneloader.materials[matname]
  920. self.scene_objects.append(SceneObject(name=objname, visible=False, used=True, matname=matname,
  921. reflect=brdf.reflect, alpha=brdf.alpha, ior=brdf.ior, display_color=matname2color[matname],
  922. mlab_mesh=lazyLoadMesh(objname, matname, x, y, z, triangles)))
  923. self.scene_object_groups[:] = [
  924. SceneObjectGroup(name='EG', filter=['EG']),
  925. SceneObjectGroup(name='OG 1', filter=['OG1']),
  926. SceneObjectGroup(name='OG 2', filter=['OG2']),
  927. SceneObjectGroup(name='Fascade', filter=['Fascade', ]),
  928. SceneObjectGroup(name='Floor', filter=['Floor']),
  929. SceneObjectGroup(name='Stairs', filter=['Stairs', 'Railing']),
  930. SceneObjectGroup(name='Doors', filter=['Doors']),
  931. SceneObjectGroup(name='Stuff', filter=['Hardware', 'Cupboard', 'Table']),
  932. ]
  933. # this shouldnt be needed but the first is always checked in the table
  934. for e in self.scene_object_groups:
  935. e.visible = False
  936. def setupLogging(self):
  937. log.setLevel(logging.DEBUG)
  938. formatter = logging.Formatter("%(asctime)s.%(msecs)03d %(name)s %(levelname)s %(message)s",
  939. "%H:%M:%S")
  940. h = LoggingHandler()
  941. h.setFormatter(formatter)
  942. log.addHandler(h)
  943. h = StreamHandler()
  944. h.setFormatter(formatter)
  945. log.addHandler(h)
  946. def _doubleclicked_ap_changed(self):
  947. ap = self.doubleclicked_ap[0]
  948. self.reloadAP(ap)
  949. def reloadAP(self, ap):
  950. if isinstance(ap, basestring):
  951. # its a apid
  952. ap = [a for a in self.aps if a.id == ap][0]
  953. log.debug('loading data for %s' % ap.id)
  954. self.lazyLoadAP(ap)
  955. self.loadAPDataIntoScalarField(ap)
  956. self.loadMeasurements(ap)
  957. def _selected_ap_changed(self):
  958. if self.mlab_aps is None:
  959. return
  960. # colorize AP 3D-Sphere
  961. if self.selected_ap is not None:
  962. # this is a slow way to modify the acces point colorization
  963. l = [1] * len(self.aps)
  964. l[self.aps.index(self.selected_ap)] = 1.2
  965. self.mlab_aps.mlab_source.scalars = l
  966. if self.loaded_ap_id != self.selected_ap.id:
  967. self.reloadAP(self.selected_ap)
  968. def _selected_measurement_changed(self):
  969. if self.mlab_locations is None or len(self.mlab_locations.mlab_source.scalars) != len(self.locations):
  970. xs, ys, zs = zip(*[(loc.x, loc.y, loc.z) for loc in self.locations])
  971. self.visualizeLocations(xs, ys, zs, [1.0]*len(xs), UN_SELECTED_MEASUREMENT)
  972. if self.selected_measurement is not None:
  973. l = len(self.mlab_locations.mlab_source.scalars) * [1.0]
  974. l[self.measurements.index(self.selected_measurement)] = 1.2
  975. self.mlab_locations.mlab_source.scalars = l
  976. if self.vi is not None:
  977. _, _, z = self.vi.translate(0, 0, self.selected_measurement.z)
  978. self.ipw_z.ipw.plane_orientation = 2 # 2 == Z-Orientation
  979. self.ipw_z.ipw.slice_index = z - 1
  980. else:
  981. self.mlab_locations.mlab_source.scalars = [UN_SELECTED_MEASUREMENT] * len(self.measurements)
  982. def setupScalarField(self):
  983. if self.scalar_field is not None:
  984. try:
  985. self.scalar_field.remove()
  986. except Exception:
  987. pass
  988. if self.ipw_z is not None:
  989. old_slice_index = self.ipw_z.ipw.slice_index
  990. try:
  991. self.ipw_z.remove()
  992. except Exception:
  993. pass
  994. else:
  995. old_slice_index = 0
  996. data = np.zeros((self.resolution.x, self.resolution.y, self.resolution.z)) - 100
  997. self.scalar_field = self.scene.mlab.pipeline.scalar_field(data)
  998. sx = self.res_dx
  999. sy = self.res_dy
  1000. sz = self.res_dz
  1001. self.scalar_field.spacing = [sx, sy, sz]
  1002. self.scalar_field.origin = [self.bbox.x1, self.bbox.y1, self.bbox.z1]
  1003. # shifting the full plane is also an InteractionEvent
  1004. # we react only on _real_ position changes via cross-hair movements - therefor we track lastpos
  1005. lastpos = [None, None, None]
  1006. def move_view(obj, evt):
  1007. data = self.scalar_field.mlab_source
  1008. position = list(obj.GetCurrentCursorPosition())
  1009. self.cursor_position = position
  1010. if position != lastpos:
  1011. if hasattr(self, 'vi') and self.vi is not None:
  1012. data_in_mw = self.vi.data[tuple(position)] * 1000
  1013. else:
  1014. data_in_mw = 0
  1015. if hasattr(self, 'data_in_db'):
  1016. data_in_db = self.data_in_db[tuple(position)]
  1017. normalized_data_in_db = self.normalized_data_in_db[tuple(position)]
  1018. else:
  1019. data_in_db = 0
  1020. normalized_data_in_db = 0
  1021. xyz = self.translateToMeter(*position)
  1022. self.plane_cursor_coords = ('x: %.2f, y: %.2f, z:%.2f:' % xyz +
  1023. ' rssi: %.1f [%.1e mw] normalized: %.1f' % (data_in_db, data_in_mw, normalized_data_in_db))
  1024. self.plane_state_coords = 'x: %d, y: %d, z: %d' % self.translateToStateVoxel(*xyz)
  1025. x, y, z = self.translateToStateVoxel(*xyz)
  1026. self.state_x = x
  1027. self.state_y = y
  1028. self.state_z = z
  1029. lastpos[:] = position # replace contents of list
  1030. self.ipw_z = gui.scene.mlab.pipeline.image_plane_widget(self.scalar_field,
  1031. plane_orientation='z_axes', slice_index=old_slice_index, vmax=0, vmin=-100)
  1032. self.ipw_z.ipw.add_observer('InteractionEvent', move_view)
  1033. self.surface_view = self.scene.mlab.pipeline.iso_surface(self.scalar_field, opacity=0.9)
  1034. self.surface_view.contour.number_of_contours = self.surface_number_of_contours
  1035. self.surface_view.visible = False
  1036. def translateToStateVoxel(self, x, y, z):
  1037. '''translate float real world coordinates into voxel coordinates'''
  1038. cube_width = self.cube_width
  1039. return (int(round((x - self.bbox.x1) / self.res_dx)) / cube_width,
  1040. int(round((y - self.bbox.y1) / self.res_dy)) / cube_width,
  1041. int(round((z - self.bbox.z1) / self.res_dz)) / cube_width)
  1042. def translateToMeter(self, x, y, z):
  1043. '''translate voxel coords to float real world coordinates'''
  1044. return (self.bbox.x1 + x * self.res_dx,
  1045. self.bbox.y1 + y * self.res_dy,
  1046. self.bbox.z1 + z * self.res_dz)
  1047. def loadVolumeImage(self, apid):
  1048. datfile = self.apid2datfile(apid)
  1049. log.debug('reading %s' % datfile.abspath())
  1050. vi = VolumeImage()
  1051. vi.read(datfile)
  1052. return vi
  1053. def lazyLoadAP(self, ap):
  1054. if ap.vi is None:
  1055. t = time.time()
  1056. log.debug('loading %s' % ap.id)
  1057. vi = ap.vi = self.loadVolumeImage(ap.id)
  1058. ap.data_in_db = vi.asDecibelData(CLAMP)
  1059. ap.normalized_data_in_db = toNormalizedDecibelwithDeviceAdaption(vi.data, self.davalues.get(self.device_name, []))
  1060. log.info('loaded %s in %.3f sec' % (ap.id, time.time() - t))
  1061. def loadAPDataIntoScalarField(self, ap):
  1062. self.loaded_ap_id = ap.id
  1063. self.vi = vi = ap.vi
  1064. self.surface_view.visible = False
  1065. self.surface_number_of_contours = 5
  1066. # convert to decibel
  1067. self.data_in_db = ap.data_in_db
  1068. self.normalized_data_in_db = ap.normalized_data_in_db
  1069. unclamped = 10 * np.log10(vi.data[np.where(vi.data > 0)])
  1070. self.ipw_vmin = max(-100, int(unclamped.min()))
  1071. self.ipw_vmax = min(0, int(unclamped.max()))
  1072. _, _, z = vi.translate(0, 0, ap.z)
  1073. self.ipw_z.ipw.plane_orientation = 2 # 2 == Z-Orientation
  1074. self.ipw_z.ipw.slice_index = z - 1
  1075. if self.view_normalized_data:
  1076. self.scalar_field.mlab_source.scalars = self.normalized_data_in_db
  1077. else:
  1078. self.scalar_field.mlab_source.scalars = self.data_in_db
  1079. self.changeIPWConfig()
  1080. @on_trait_change('load_opt_runs')
  1081. def loadOptruns(self):
  1082. self.opt_runs[:] = []
  1083. t = time.time()
  1084. s = urlopen(BASE_URL + '/getOptimizeSessions').read()
  1085. for sessionEl in StringToTree(s).getroot().xpath('session'):
  1086. session = sessionEl.attrib['name']
  1087. try:
  1088. dt = datetime.datetime.strptime(sessionEl.attrib['dt'], '%Y-%m-%d %H:%M:%S')
  1089. numphotons = int(sessionEl.attrib['numphotons'])
  1090. density = float(sessionEl.attrib['density'])
  1091. resolution = sessionEl.attrib['resolution']
  1092. bbox = sessionEl.attrib['bbox']
  1093. devices = sessionEl.attrib['station'].split(',')
  1094. scene = sessionEl.attrib['scene']
  1095. minimumEl = sessionEl.xpath('minimum')
  1096. if len(minimumEl) == 0:
  1097. continue
  1098. minimumEl = minimumEl[0]
  1099. minavgdelta = float(minimumEl.attrib['avg-delta'])
  1100. powers = {}
  1101. materials = {}
  1102. davalues = defaultdict(list)
  1103. rssieq = 0.0
  1104. for name, value in minimumEl.attrib.items():
  1105. if name in self.powids:
  1106. powers[name] = float(value)
  1107. elif name.startswith('da-'): # device adaption params
  1108. device_darssi = name[3:].split('_')
  1109. if len(device_darssi) == 1:
  1110. # backward compat
  1111. davalues[sessionEl.attrib['station']].append((float(device_darssi[0]), float(value)))
  1112. else:
  1113. device, darssi = device_darssi
  1114. davalues[device].append((float(darssi), float(value)))
  1115. elif name == 'n-rssieq':
  1116. rssieq = float(value)
  1117. elif ',' in value: # detect material param by scanning for 0.444,0.345
  1118. reflect, alpha = value.split(',')
  1119. materials[name] = Brdf(float(reflect), float(alpha))
  1120. for device, dav in davalues.items():
  1121. dav.sort()
  1122. r = OptimizeRun(date=dt, session=session, minavgdelta=minavgdelta,
  1123. numphotons=numphotons, density=density, powers=powers,
  1124. materials=materials, resolution=resolution, bbox=bbox,
  1125. davalues=davalues, rssieq=rssieq, devices=devices,
  1126. scene=scene)
  1127. self.opt_runs.append(r)
  1128. except Exception:
  1129. log.exception('error during loading optrun %s' % session)
  1130. log.info('load optruns in %.2f sec' % (time.time() - t))
  1131. def _doubleclicked_optrun_changed(self):
  1132. optrun = self.doubleclicked_optrun[0]
  1133. self.selectOptRun(optrun)
  1134. def selectOptRun(self, optrun):
  1135. pickle.dump(optrun, open(self.tmpdir.joinpath('curr_optrun.dat'), 'wb'))
  1136. self.optrun_session = optrun.session
  1137. self.scene_name = optrun.scene
  1138. self.apdatafiles = self.tmpdir.joinpath('apdata', self.optrun_session, self.scene_name + '_%s.dat')
  1139. r = optrun.resolution.split(',')
  1140. self.res_x = int(r[0])
  1141. self.res_y = int(r[1])
  1142. self.res_z = int(r[2])
  1143. bb = optrun.bbox.split(',')
  1144. self.bb_x1 = float(bb[0])
  1145. self.bb_x2 = float(bb[1])
  1146. self.bb_y1 = float(bb[2])
  1147. self.bb_y2 = float(bb[3])
  1148. self.bb_z1 = float(bb[4])
  1149. self.bb_z2 = float(bb[5])
  1150. # store materials
  1151. TreeToFile(materialsAsXml(optrun.materials), self.materialfile)
  1152. self.loadAll(retrive=False)
  1153. for ap in self.aps:
  1154. if ap.powid in optrun.powers:
  1155. ap.power = optrun.powers[ap.powid]
  1156. else:
  1157. print '%s not in %s' % (ap.powid, optrun.powers.keys())
  1158. ap.used = False
  1159. self.numphotons = optrun.numphotons
  1160. self.density = optrun.density
  1161. self.davalues = optrun.davalues
  1162. self.rssieq = optrun.rssieq
  1163. self.device_name = optrun.devices[0]
  1164. self.deviceNameChanged()
  1165. def setupNormalizationPlot(self):
  1166. self.plot.clf()
  1167. xs = np.arange(-130, -20, 0.1)
  1168. # from log space into float space
  1169. _xs = [10**(x/10.0) for x in xs]
  1170. ys = toNormalizedDecibelwithDeviceAdaption(np.array([[_xs]]).astype(np.float32), self.davalues.get(self.device_name, []))[0][0]
  1171. ax1 = self.plot.add_subplot(111)
  1172. ax1.set_title('normalization of %s' % self.device_name)
  1173. ax1.set_xlim(min(xs), max(xs))
  1174. ax1.set_ylim(min(ys), max(ys))
  1175. ax1.plot(xs, ys)
  1176. ax2 = ax1.twinx()
  1177. ys = [(y-x) for x, y in zip(xs, ys)]
  1178. ax2.set_ylim(-10, 10)
  1179. ax2.set_xlim(min(xs), max(xs))
  1180. ax2.plot(xs, ys, color='green')
  1181. def _toogle_object_groups_changed(self):
  1182. for objgroup in self.scene_object_groups:
  1183. objgroup.visible = not objgroup.visible
  1184. @on_trait_change('do_localizeHMM')
  1185. def doLocalizeHMM(self, keybinding_dummy=None, threaded=True):
  1186. self._doLocalize('hmm', threaded=threaded)
  1187. @on_trait_change('do_localizePF')
  1188. def doLocalizePF(self, keybinding_dummy=None, threaded=True):
  1189. self._doLocalize('pf', threaded=threaded)
  1190. @on_trait_change('do_localizeLMSE')
  1191. def doLocalizeLMSE(self, keybinding_dummy=None, threaded=True):
  1192. self._doLocalize('lmse', threaded=threaded)
  1193. def _doLocalize(self, algo, threaded):
  1194. self.gui_thread_id = thread.get_ident()
  1195. try:
  1196. reload(localizer)
  1197. except Exception:
  1198. log.exception('error reload localizer')
  1199. else:
  1200. if ':' in self.localize_range:
  1201. start, end = [int(e) if e.strip() else None for e in self.localize_range.split(':')]
  1202. else:
  1203. start, end = int(self.localize_range), None
  1204. if threaded:
  1205. thread.start_new_thread(localizer.localizeGui, (self, log, algo, start, end))
  1206. else:
  1207. localizer.localizeGui(self, log, algo, start, end)
  1208. def doViewHistory(self, keybinding_dummy=None):
  1209. try:
  1210. reload(localizer)
  1211. except Exception:
  1212. log.exception('error reload localizer')
  1213. else:
  1214. localizer.fullPruniningAnimation(self.localizer, 2)
  1215. @on_trait_change('do_viewpftrans')
  1216. def viewPFTrans(Self):
  1217. reload(localizer)
  1218. localizer.viewPFTransitionsAtPos(self, self.localizer)
  1219. @on_trait_change('do_viewblocked')
  1220. def viewBlockedCubes(self):
  1221. reload(localizer)
  1222. thread.start_new_thread(localizer.viewBlockedCubes, (self, log))
  1223. def viewHistorySingle(self):
  1224. assert localizer is not None, 'viewHistory needs a localization run'
  1225. self.localizer.viewHistory(self.pruning_idx, self.pruning_visible_count)
  1226. @on_trait_change('do_viewhistory')
  1227. def viewPruningStepNext(self, keybinding_dummy=None):
  1228. self.pruning_idx += self.pruning_step_width
  1229. self.viewHistorySingle()
  1230. @on_trait_change('pruning_visible_count')
  1231. def historyCountChanged(self):
  1232. self.viewHistorySingle()
  1233. @on_trait_change('do_viewhistory_prev')
  1234. def viewPruningStepPrev(self, keybinding_dummy=None):
  1235. self.pruning_idx -= self.pruning_step_width
  1236. self.viewHistorySingle()
  1237. @on_trait_change('do_viewgradients')
  1238. def viewGradients(self, keybinding_dummy=None):
  1239. reload(localizer)
  1240. thread.start_new_thread(localizer.viewSignalGradients, (self, log))
  1241. def _loadPathSequence(self, ps):
  1242. with LOADING():
  1243. self.localization_path[:] = []
  1244. if len(ps.locs) > 0:
  1245. self.runid2run = {str(r.id): r for r in ps.runs}
  1246. runids = self.runid2run.keys()
  1247. self.measurement_runs[:] = runids
  1248. if len(runids) > 0:
  1249. self.measurement_runid = runids[0]
  1250. if isinstance(ps.locs[0], int):
  1251. for locid in ps.locs:
  1252. loc = self.locid2location.get(locid)
  1253. if loc is None:
  1254. log.warn('locid %s not found' % locid)
  1255. continue
  1256. p = PathPosition(id=locid, x=loc.x, y=loc.y, z=loc.z)
  1257. self.localization_path.append(p)
  1258. ps.locs[:] = self.localization_path
  1259. else:
  1260. self.localization_path[:] = ps.locs
  1261. @on_trait_change('selected_path_sequence')
  1262. def selectedPathSequenceChanged(self):
  1263. if self.selected_path_sequence is None or _LOADING:
  1264. return
  1265. self._loadPathSequence(self.selected_path_sequence)
  1266. self._localization_path_changed()
  1267. @on_trait_change('selected_path_pos')
  1268. def selectedPathPosChanged(self):
  1269. #~ print self.selected_path_pos
  1270. pass
  1271. @on_trait_change('do_delete_path_segment')
  1272. def doDeletePathSegment(self):
  1273. if self.selected_path_pos is not None:
  1274. i = self.localization_path.index(self.selected_path_pos)
  1275. self.localization_path.remove(self.selected_path_pos)
  1276. if i < len(self.localization_path):
  1277. self.selected_path_pos = self.localization_path[i]
  1278. else:
  1279. self.selected_path_pos = None
  1280. self._localization_path_changed(store=True)
  1281. def _localization_path_changed(self, refreshCubes=True, *args, **kwds):
  1282. # update distances
  1283. total_dist = dist = 0
  1284. for pos1, pos2 in zip(self.localization_path, self.localization_path[1:]):
  1285. dist = ((pos2.x - pos1.x)**2 + (pos2.y - pos1.y)**2 + (pos2.z - pos1.z)**2)**0.5
  1286. pos2.distance = dist
  1287. total_dist += dist
  1288. pos2.total_distance = total_dist
  1289. for i, pos in enumerate(self.localization_path):
  1290. pos.id = i
  1291. if refreshCubes:
  1292. localizer.buildPathCubes(self)
  1293. xs, ys, zs = zip(*[(loc.x, loc.y, loc.z) for loc in self.localization_path])
  1294. self.visualizeLocations(xs, ys, zs, [1.0]*len(xs), self.res_dx * self.cube_width * 0.5)
  1295. if kwds.get('store'):
  1296. self.custom_path.locs[:] = self.localization_path
  1297. f = self.tmpdir.joinpath('localization_path.dat').open('w')
  1298. pickle.dump(self.localization_path, f)
  1299. @on_trait_change('do_load_paths')
  1300. def doLoadPaths(self):
  1301. with LOADING():
  1302. self.localization_paths[:] = []
  1303. CACHED = True
  1304. if not CACHED:
  1305. url = BASE_URL + '/getCollectedPaths?station=%s' % self.device_name
  1306. log.debug('loading %s...' % url)
  1307. tree = opener.open(url).read()
  1308. self.tmpdir.joinpath('path_data_%s.txt' % self.device_name).write_text(tree)
  1309. else:
  1310. tree = self.tmpdir.joinpath('path_data_%s.txt' % self.device_name).text()
  1311. for pel in sorted(StringToTree(tree).getroot().xpath('path'), key=lambda x: x.attrib['id']):
  1312. a = pel.attrib
  1313. runEls = pel.xpath('run')
  1314. runs = []
  1315. for runEl in runEls:
  1316. run_measurements = runEl.xpath('string(measurements/text())')
  1317. if run_measurements == '':
  1318. log.info('skipping empty measurements')
  1319. continue
  1320. run_locations = runEl.xpath('string(locations/text())')
  1321. r = MeasurementRun(id=int(runEl.attrib['id']), measurements=run_measurements, locations=run_locations)
  1322. runs.append(r)
  1323. locs = [int(e) for e in pel.attrib['locations'].split(',')]
  1324. p = PathSequence(id=a['id'], length=len(locs), collect_runs=len(runEls), locs=locs, runs=runs)
  1325. self.localization_paths.append(p)
  1326. f = self.tmpdir.joinpath('localization_path.dat')
  1327. if f.exists():
  1328. lp = pickle.load(f.open())
  1329. else:
  1330. lp = []
  1331. p = PathSequence(id='custom', length=len(lp), collect_runs=-1, locs=lp, runs=[])
  1332. self.localization_paths.append(p)
  1333. self.custom_path = p
  1334. @on_trait_change('do_draw_path')
  1335. def doDrawPath(self):
  1336. self._localization_path_changed()
  1337. @on_trait_change('do_record_path')
  1338. def doRecordPath(self):
  1339. if self.ipw_z is None:
  1340. return
  1341. self.ipw_z.visible = True
  1342. def new_path_entry(obj, evt):
  1343. doubleclick = time.time() - self.record_path_last_interaction < 0.5
  1344. if doubleclick:
  1345. position = list(obj.GetCurrentCursorPosition())
  1346. x, y, z = [round(p * s + o, 1) for p, s, o in zip(position, self.scalar_field.spacing, self.scalar_field.origin)]
  1347. if len(self.localization_path) > 0:
  1348. last_pos = self.localization_path[-1]
  1349. if last_pos.x == x and last_pos.y == y and last_pos.z == z:
  1350. return
  1351. with LOADING():
  1352. pp = PathPosition(id=len(self.localization_path), x=x, y=y, z=z)
  1353. if self.selected_path_pos is None:
  1354. self.localization_path.append(pp)
  1355. else:
  1356. i = self.localization_path.index(self.selected_path_pos)
  1357. self.localization_path.insert(i, pp)
  1358. if len(self.localization_path) == 1:
  1359. self.selected_path_pos = None
  1360. self._localization_path_changed(store=True)
  1361. self.record_path_last_interaction = time.time()
  1362. oid = getattr(self, 'record_path_oberserver_id', None)
  1363. if oid is None:
  1364. self.record_path_last_interaction = 0
  1365. self.ipw_z.ipw.left_button_action = 0
  1366. self.record_path_oberserver_id = self.ipw_z.ipw.add_observer('StartInteractionEvent', new_path_entry)
  1367. else:
  1368. self.ipw_z.ipw.left_button_action = 1 # the default
  1369. self.ipw_z.ipw.remove_observer(oid)
  1370. delattr(self, 'record_path_oberserver_id')
  1371. delattr(self, 'record_path_last_interaction')
  1372. @on_trait_change('do_generate_synthetic_measurements')
  1373. def doGenerateSyntheticMeasurementsFromCorners(self):
  1374. reload(localizer)
  1375. env = localizer.Environment(self.objfile, aps=localizer.getAPsFromGui(self))
  1376. corners = [(p.x, p.y, p.z) for p in self.localization_path]
  1377. measurements = env.generateSyntheticMeasurementsFromCorners(corners=corners,
  1378. speed=self.synthetic_measurements_speed,
  1379. noise=self.synthetic_measurements_noise,
  1380. granularity=self.synthetic_measurements_granularity)
  1381. self.loadMeasurementSequence(measurements)
  1382. @on_trait_change('do_generate_synthetic_measurements_cubes')
  1383. def doGenerateSyntheticMeasurementsAtCubeCenters(self):
  1384. reload(localizer)
  1385. env = localizer.Environment(self.objfile, aps=localizer.getAPsFromGui(self))
  1386. cubes = localizer.getCubesFromPath(gui, env)
  1387. half_cube = (self.res_dx * self.cube_width) / 2.0
  1388. positions = [np.array(self.translateToMeter(*(xyz * self.cube_width))) + half_cube for xyz in cubes]
  1389. measurements = env.generateSyntheticMeasurementsAtPositions(positions,
  1390. speed=self.synthetic_measurements_speed,
  1391. noise=self.synthetic_measurements_noise,
  1392. sample_environment=half_cube/2.0)
  1393. self.loadMeasurementSequence(measurements)
  1394. @on_trait_change('do_load_measurement_run')
  1395. def loadMeasurementRun(self):
  1396. runid = self.measurement_runid
  1397. run = self.runid2run.get(runid)
  1398. if run is None:
  1399. log.error('no measurement_run found for runid %s' % runid)
  1400. return
  1401. reload(localizer)
  1402. measurements = localizer.Measurements()
  1403. measurements.loadFromString(run.measurements)
  1404. measurements.interpolateFromLocationString(run.locations, self.locid2location)
  1405. self.loadMeasurementSequence(measurements)
  1406. def loadMeasurementSequence(self, measurements):
  1407. self.synthetic_measurements = str(measurements)
  1408. cachefile = self.tmpdir.joinpath('_last_loaded_measurements.txt')
  1409. cachefile.write_text(self.synthetic_measurements)
  1410. xs, ys, zs = zip(*[(m.pos.x, m.pos.y, m.pos.z) for m in measurements])
  1411. values = [1.0]*len(xs)
  1412. self.visualizeLocations(xs, ys, zs, values, self.res_dx * self.cube_width * 0.5)
  1413. def visualizeLocations(self, xs, ys, zs, values, scale_factor):
  1414. if self.mlab_locations is not None:
  1415. self.mlab_locations.remove()
  1416. self.mlab_locations = self.scene.mlab.points3d(xs, ys, zs, values, mode='axes', colormap='Reds', scale_factor=scale_factor)
  1417. @on_trait_change('show_scalar_bar')
  1418. def showScalarBar(self, title=None):
  1419. lut_mgr = self.scene.mlab.scalarbar(title=title)
  1420. if not lut_mgr.visible:
  1421. # resizing this bitch is ugly - see mayavi.tools.decorations.py
  1422. lut_mgr.scalar_bar_representation.position2 = (0.8, 0.10)
  1423. else:
  1424. lut_mgr.visible = False
  1425. @on_trait_change('toggle_ipw_z')
  1426. def toggleIPWZ(self):
  1427. self.ipw_z.visible = not self.ipw_z.visible
  1428. @on_trait_change('toggle_surfaceview')
  1429. def toggleSurfaceView(self):
  1430. self.surface_view.visible = not self.surface_view.visible
  1431. @on_trait_change('cube_width')
  1432. def updateCubeWidth(self):
  1433. updateRes()
  1434. @on_trait_change('device_name')
  1435. def deviceNameChanged(self):
  1436. dav = self.davalues.get(self.device_name, [])
  1437. self.device_davalues = ', '.join('%d:%.1f' % (float(e[0]), float(e[1])) for e in dav)
  1438. self.setupNormalizationPlot()
  1439. self.localization_paths[:] = []
  1440. self.loadLocations()
  1441. @on_trait_change('do_current_ap_surface_plot')
  1442. def doCurrentApSurfacePlot(self):
  1443. import thesis;
  1444. reload(thesis)
  1445. thesis.currentApSurfacePlot(self)
  1446. @on_trait_change('do_thesis_pruning_plot')
  1447. def doThesisPruningPlot(self):
  1448. import thesis
  1449. reload(thesis)
  1450. thesis.pruningPlot(self)
  1451. @on_trait_change('do_thesis_path_info')
  1452. def doThesisPathInfo(self):
  1453. import thesis
  1454. reload(thesis)
  1455. thesis.pathInfo(self)
  1456. @on_trait_change('do_thesis_localization_plot')
  1457. def doThesisLocalizationPlot(self):
  1458. import thesis
  1459. reload(thesis)
  1460. thesis.localizationPlot(self)
  1461. @on_trait_change('do_thesis_pruning_scatter')
  1462. def doThesisPruningScatter(self):
  1463. import thesis
  1464. reload(thesis)
  1465. thesis.pruningScatter(self)
  1466. @on_trait_change('do_3dmodel_latextable')
  1467. def doThesis3DModelTable(self):
  1468. import thesis
  1469. reload(thesis)
  1470. thesis.latex3dmodel(self, sceneloader.mesh)
  1471. @on_trait_change('do_device2measurements_latextable')
  1472. def doD2MTable(self):
  1473. import thesis
  1474. reload(thesis)
  1475. thesis.latexDevice2Measurements(self)
  1476. @on_trait_change('do_generate_synthetic_paths')
  1477. def doSynthPaths(self):
  1478. import thesis
  1479. reload(thesis)
  1480. thesis.generateSyntheticPaths(self)
  1481. @on_trait_change('do_plot_apcoverage')
  1482. def doPlotAPCoverage(self):
  1483. import thesis
  1484. reload(thesis)
  1485. thesis.plotAPCoverage(self)
  1486. gui = Gui()
  1487. view = View(
  1488. HGroup(
  1489. VGroup(
  1490. Item(name='scene',
  1491. editor=SceneEditor(scene_class=MayaviScene),
  1492. show_label=False,
  1493. height=500,
  1494. width=500
  1495. ),
  1496. Tabbed(
  1497. Item(name='loggingout',
  1498. show_label = False,
  1499. label = 'Log',
  1500. editor = CodeEditor(show_line_numbers=False, foldable=False, selected_color='white'),
  1501. height=300,
  1502. ),
  1503. Item(name='shell',
  1504. label = 'Shell',
  1505. show_label = False,
  1506. editor = ShellEditor(),
  1507. height=300,
  1508. ),
  1509. VGroup(
  1510. Item('plot', editor=MPLFigureEditor(), show_label=False),
  1511. label = 'Plot',
  1512. ),
  1513. ),
  1514. layout = 'split',
  1515. ),
  1516. VGrid(
  1517. Tabbed(
  1518. HGroup(
  1519. VGroup(
  1520. HGroup(
  1521. Item('load_scene_objects',
  1522. show_label = False,
  1523. label = 'Load Scene',
  1524. editor = ButtonEditor(),
  1525. ),
  1526. Item('clear_scene_objects',
  1527. show_label = False,
  1528. label = 'Clear Scene',
  1529. editor = ButtonEditor(),
  1530. ),
  1531. Item('retrieve_scene_object',
  1532. show_label = False,
  1533. label = 'Retrive Scene',
  1534. editor = ButtonEditor(),
  1535. ),
  1536. Item('toogle_object_groups',
  1537. show_label = False,
  1538. label = 'Toogle Groups',
  1539. editor = ButtonEditor(),
  1540. ),
  1541. ),
  1542. Item('objfile',
  1543. show_label = False,
  1544. label = 'objfile',
  1545. editor = FileEditor(filter = ['*.obj',]),
  1546. ),
  1547. VGrid(
  1548. Item('scene_object_groups',
  1549. show_label = False,
  1550. label = 'Groups',
  1551. editor = objectsgroups_table,
  1552. width=100,
  1553. ),
  1554. Item('scene_objects',
  1555. show_label = False,
  1556. label='Scene',
  1557. editor = objects_table,
  1558. width=500,
  1559. ),
  1560. ),
  1561. label = 'Scene & Materials',
  1562. ),
  1563. VGroup(
  1564. HGroup(
  1565. Item('load_materials',
  1566. show_label = False,
  1567. label = 'Load Materials',
  1568. editor = ButtonEditor(),
  1569. ),
  1570. Item('retrieve_materials',
  1571. show_label = False,
  1572. label = 'Retrive Materials',
  1573. editor = ButtonEditor(),
  1574. ),
  1575. ),
  1576. Item('materialfile',
  1577. show_label = False,
  1578. label = 'materialfile',
  1579. editor = FileEditor(filter = ['*.xml',]),
  1580. ),
  1581. Item('materials',
  1582. show_label = False,
  1583. editor = materials_table,
  1584. ),
  1585. ),
  1586. layout = 'split',
  1587. ),
  1588. HGroup(
  1589. VGroup(
  1590. HGroup(
  1591. Item('load_aps',
  1592. show_label = False,
  1593. label = 'Load APs',
  1594. editor = ButtonEditor(),
  1595. ),
  1596. Item('clear_aps',
  1597. show_label = False,
  1598. label = 'Clear',
  1599. editor = ButtonEditor(),
  1600. ),
  1601. Item('reload_ap_data',
  1602. show_label = False,
  1603. label = 'Reload SimData',
  1604. editor = ButtonEditor(),
  1605. ),
  1606. Item('view_normalized_data', show_label=True, label='Normalized',),
  1607. ),
  1608. HGroup(
  1609. Item('toggle_ap_used',
  1610. show_label = False,
  1611. label = 'Toggle',
  1612. editor = ButtonEditor(),
  1613. ),
  1614. Item('evaluate_all_aps',
  1615. show_label = False,
  1616. label = 'Eval All',
  1617. editor = ButtonEditor(),
  1618. ),
  1619. Item('run_device_adaption',
  1620. show_label = False,
  1621. label = 'Device Adaption',
  1622. editor = ButtonEditor(),
  1623. ),
  1624. Item('clear_cached_ap',
  1625. show_label = False,
  1626. label = 'Clear AP Cache',
  1627. editor = ButtonEditor(),
  1628. ),
  1629. ),
  1630. Item('apdatafiles', show_label=False),
  1631. Item('aps',
  1632. show_label = False,
  1633. editor = ap_table,
  1634. ),
  1635. label = 'APs & Measurements',
  1636. ),
  1637. VGroup(
  1638. HGroup(
  1639. Item('load_locations',
  1640. show_label = False,
  1641. label = 'Load Locations',
  1642. editor = ButtonEditor(),
  1643. ),
  1644. Item('clear_locations',
  1645. show_label = False,
  1646. label = 'Clear Locations',
  1647. editor = ButtonEditor(),
  1648. ),
  1649. Item('retrieve_measurements',
  1650. show_label = False,
  1651. label = 'Retrieve Measurements',
  1652. editor = ButtonEditor(),
  1653. ),
  1654. Item('retrieve_measurements_overlay',
  1655. show_label = False,
  1656. label = 'Retrieve with overlay',
  1657. editor = ButtonEditor(),
  1658. ),
  1659. ),
  1660. Item('measurementfile',
  1661. show_label = False,
  1662. editor = FileEditor(filter = ['*.xml',]),
  1663. ),
  1664. Item('measurements',
  1665. show_label = False,
  1666. editor = measurements_table,
  1667. ),
  1668. ),
  1669. layout = 'split',
  1670. ),
  1671. VGroup(
  1672. Item('load_opt_runs',
  1673. show_label = False,
  1674. label = 'Refresh',
  1675. editor = ButtonEditor(),
  1676. ),
  1677. Item('opt_runs',
  1678. show_label = False,
  1679. editor = opt_runs_table,
  1680. ),
  1681. label='Optimize Runs',
  1682. ),
  1683. VGroup(
  1684. Item('load_scene_config',
  1685. show_label = False,
  1686. label = 'Load Scene',
  1687. editor = ButtonEditor(),
  1688. ),
  1689. HGroup(
  1690. Item('bb_x1', label='bbx1',),
  1691. Item('bb_y1', label='bby1',),
  1692. Item('bb_z1', label='bbz1',),
  1693. ),
  1694. HGroup(
  1695. Item('bb_x2', label='bbx2',),
  1696. Item('bb_y2', label='bby2',),
  1697. Item('bb_z2', label='bbz2',),
  1698. ),
  1699. HGroup(
  1700. Item('res_x', label='rx',),
  1701. Item('res_y', label='ry',),
  1702. Item('res_z', label='rz',),
  1703. ),
  1704. HGroup(
  1705. Item('res_dx', label='rdx',),
  1706. Item('res_dy', label='rdy',),
  1707. Item('res_dz', label='rdz',),
  1708. ),
  1709. Item('numphotons'),
  1710. Item('density'),
  1711. Item('scene_name', label='Scene Name',),
  1712. label = 'BBox & Resolution',
  1713. ),
  1714. VGroup(
  1715. HGroup(
  1716. Item('do_localizeHMM',
  1717. show_label = False,
  1718. label = 'Localize HMM',
  1719. editor = ButtonEditor(),
  1720. ),
  1721. Item('do_localizePF',
  1722. show_label = False,
  1723. label = 'Localize PF',
  1724. editor = ButtonEditor(),
  1725. ),
  1726. Item('do_localizeLMSE',
  1727. show_label = False,
  1728. label = 'Localize LMSE',
  1729. editor = ButtonEditor(),
  1730. ),
  1731. Item('localize_range'),
  1732. Item('localizer', style="readonly"),
  1733. ),
  1734. HGroup(
  1735. Item('do_viewgradients',
  1736. show_label = False,
  1737. label = 'View Gradients',
  1738. editor = ButtonEditor(),
  1739. ),
  1740. Item('do_viewblocked',
  1741. show_label = False,
  1742. label = 'View Blocked',
  1743. editor = ButtonEditor(),
  1744. ),
  1745. Item('do_viewpftrans',
  1746. show_label = False,
  1747. label = 'View PFTrans',
  1748. editor = ButtonEditor(),
  1749. ),
  1750. Item('cube_width', label='CubeWidth'),
  1751. Item('cube_width_display', label='Resolution', style='readonly'),
  1752. ),
  1753. HGroup(
  1754. Item('do_viewhistory',
  1755. show_label = False,
  1756. label = 'View History Next',
  1757. editor = ButtonEditor(),
  1758. ),
  1759. Item('do_viewhistory_prev',
  1760. show_label = False,
  1761. label = 'Prev',
  1762. editor = ButtonEditor(),
  1763. ),
  1764. Item('pruning_step_width', label='Step'),
  1765. Item('pruning_idx', label='Index'),
  1766. Item('pruning_visible_count', label='VisibleCount', ),
  1767. ),
  1768. HGroup(
  1769. Item('prune_to'),
  1770. Item('threads'),
  1771. Item('freespace_scan'),
  1772. ),
  1773. HGroup(
  1774. VGroup(
  1775. HGroup(
  1776. Item('do_load_paths',
  1777. show_label = False,
  1778. label = 'Load Paths',
  1779. editor = ButtonEditor(),
  1780. ),
  1781. Item('do_draw_path',
  1782. show_label = False,
  1783. label = 'Draw Path',
  1784. editor = ButtonEditor(),
  1785. ),
  1786. Item('do_record_path', label='Record Path'),
  1787. Item('do_delete_path_segment',
  1788. show_label = False,
  1789. label = 'Delete Pos',
  1790. editor = ButtonEditor(),
  1791. ),
  1792. ),
  1793. HGroup(
  1794. Item(name='localization_paths',
  1795. show_label = False,
  1796. editor = path_table,
  1797. ),
  1798. Item(name='localization_path',
  1799. show_label = False,
  1800. editor = path_pos_table,
  1801. ),
  1802. ),
  1803. ),
  1804. VGroup(
  1805. HGroup(
  1806. Item('do_generate_synthetic_measurements_cubes',
  1807. show_label = False,
  1808. label = 'Generate (cubes)',
  1809. editor = ButtonEditor(),
  1810. ),
  1811. Item('synthetic_measurements_noise', label='Noise(sigma in dbm)'),
  1812. Item('synthetic_measurements_speed', label='Speed(m/s)'),
  1813. ),
  1814. HGroup(
  1815. Item('do_generate_synthetic_measurements',
  1816. show_label = False,
  1817. label = 'Generate (fluid)',
  1818. editor = ButtonEditor(),
  1819. ),
  1820. Item('synthetic_measurements_granularity', label='Granularity(m)'),
  1821. ),
  1822. HGroup(
  1823. Item('do_load_measurement_run',
  1824. show_label = False,
  1825. label = 'Load collected',
  1826. editor = ButtonEditor(),
  1827. ),
  1828. Item('measurement_runid',
  1829. show_label = True,
  1830. label = 'Run',
  1831. editor = EnumEditor(name='measurement_runs'),
  1832. ),
  1833. ),
  1834. Item(name='synthetic_measurements',
  1835. show_label = False,
  1836. editor = CodeEditor(show_line_numbers=True, foldable=False, selected_color='white'),
  1837. ),
  1838. ),
  1839. layout = 'split'
  1840. ),
  1841. label = 'Localization',
  1842. ),
  1843. VGroup(
  1844. HGroup(
  1845. Item('do_current_ap_surface_plot',
  1846. show_label = False,
  1847. label = 'Current AP Surface Plot',
  1848. editor = ButtonEditor(),
  1849. ),
  1850. Item('do_thesis_pruning_plot',
  1851. show_label = False,
  1852. label = 'Pruning Plot',
  1853. editor = ButtonEditor(),
  1854. ),
  1855. Item('do_thesis_pruning_scatter',
  1856. show_label = False,
  1857. label = 'Pruning Scatter',
  1858. editor = ButtonEditor(),
  1859. ),
  1860. Item('do_thesis_localization_plot',
  1861. show_label = False,
  1862. label = 'Localization with Errors',
  1863. editor = ButtonEditor(),
  1864. ),
  1865. ),
  1866. HGroup(
  1867. Item('do_3dmodel_latextable',
  1868. show_label = False,
  1869. label = '3D-Model Info Table',
  1870. editor = ButtonEditor(),
  1871. ),
  1872. Item('do_plot_apcoverage',
  1873. show_label = False,
  1874. label = 'Plot AP Coverage',
  1875. editor = ButtonEditor(),
  1876. ),
  1877. Item('do_device2measurements_latextable',
  1878. show_label = False,
  1879. label = 'Devce2Measurements Info Table',
  1880. editor = ButtonEditor(),
  1881. ),
  1882. ),
  1883. HGroup(
  1884. Item('do_generate_synthetic_paths',
  1885. show_label = False,
  1886. label = 'Build Synthetic Path Variants',
  1887. editor = ButtonEditor(),
  1888. ),
  1889. Item('do_thesis_path_info',
  1890. show_label = False,
  1891. label = 'Latex Path Table',
  1892. editor = ButtonEditor(),
  1893. ),
  1894. ),
  1895. label = 'Thesis',
  1896. ),
  1897. ),
  1898. VGrid(
  1899. VGroup(
  1900. Item('load_all',
  1901. show_label = False,
  1902. label = 'Load from Server',
  1903. editor = ButtonEditor(),
  1904. ),
  1905. ),
  1906. VGroup(
  1907. Item('plane_cursor_coords', label='Cursor', style='readonly'),
  1908. Item('plane_state_coords', label='Cursor/States', style='readonly'),
  1909. Item('avg_ap_delta',
  1910. show_label = True,
  1911. label = 'avg_delta',
  1912. editor = TextEditor(),
  1913. style='readonly',
  1914. ),
  1915. Item('sum_ap_delta',
  1916. show_label = True,
  1917. label = 'sum_delta',
  1918. editor = TextEditor(),
  1919. style='readonly',
  1920. ),
  1921. Item('total_avg_ap_delta',
  1922. show_label = True,
  1923. label = 'total avg_delta',
  1924. editor = TextEditor(),
  1925. style='readonly',
  1926. ),
  1927. ),
  1928. HGroup(
  1929. Item('show_ap_data_at_cursor',
  1930. show_label = False,
  1931. label = 'Show AP Data',
  1932. editor = ButtonEditor(),
  1933. ),
  1934. ),
  1935. HGroup(
  1936. Item('show_scalar_bar',
  1937. show_label = False,
  1938. label = 'Scalar Bar',
  1939. editor = ButtonEditor(),
  1940. ),
  1941. Item('toggle_ipw_z',
  1942. show_label = False,
  1943. label = 'Toggle IPW Z',
  1944. editor = ButtonEditor(),
  1945. ),
  1946. Item('toggle_surfaceview',
  1947. show_label = False,
  1948. label = 'Toggle Surface View',
  1949. editor = ButtonEditor(),
  1950. ),
  1951. Item('surface_number_of_contours',
  1952. show_label = False,
  1953. label = 'Surface Num Contours',
  1954. ),
  1955. ),
  1956. VGroup(
  1957. Item('ipw_vmin',
  1958. show_label = True,
  1959. label = 'DB Start',
  1960. editor = RangeEditor(low=-100, high=0),
  1961. ),
  1962. Item('ipw_vmax',
  1963. show_label = True,
  1964. label = 'DB End',
  1965. editor = RangeEditor(low=-100, high=0),
  1966. ),
  1967. ),
  1968. HGroup(
  1969. Item('scene_name', label='Scene', style="readonly"),
  1970. Item('optrun_session', label='Optrun', style="readonly"),
  1971. ),
  1972. HGroup(
  1973. Item('device_name', label='Device',
  1974. editor = EnumEditor(name='device_names'),
  1975. ),
  1976. Item('device_davalues', label='Device Adaptation', style='readonly'),
  1977. ),
  1978. VGroup(
  1979. Item('run_simulation',
  1980. show_label = False,
  1981. label = 'Run Raytracer',
  1982. editor = ButtonEditor(),
  1983. ),
  1984. ),
  1985. VGrid(
  1986. Item('sim_waiting', editor=ListEditor(style='readonly'), show_label=True, label='Waiting'),
  1987. Item('sim_running', editor=ListEditor(style='readonly'), show_label=True, label='Running'),
  1988. Item('sim_finished', editor=ListEditor(style='readonly'), show_label=True, label='Finished'),
  1989. columns=3,
  1990. ),
  1991. ),
  1992. layout = 'split',
  1993. ),
  1994. layout = 'split',
  1995. #auto_size = False,
  1996. #~ springy = True,
  1997. ),
  1998. height = 500,
  1999. width = 950,
  2000. resizable = True,
  2001. key_bindings = KeyBindings(
  2002. KeyBinding( binding1 = 'F9',
  2003. description = 'Run Localizer HMM',
  2004. method_name = 'doLocalizeHMM' ),
  2005. KeyBinding( binding1 = 'F10',
  2006. description = 'View Pruning',
  2007. method_name = 'doViewPruning'),
  2008. KeyBinding( binding1 = 'F8',
  2009. description = 'View Gradients',
  2010. method_name = 'viewGradients'),
  2011. KeyBinding( binding1 = 'F7',
  2012. description = 'next History',
  2013. method_name = 'viewPruningStepNext'),
  2014. KeyBinding( binding1 = 'F6',
  2015. description = 'prev History',
  2016. method_name = 'viewPruningStepPrev'),
  2017. ),
  2018. )
  2019. gui.configure_traits(view=view)