1414from hexrd import resources as hexrd_resources
1515from hexrd .instrument import HEDMInstrument
1616from hexrd .rotations import (
17- angleAxisOfRotMat , make_rmat_euler , angles_from_rmat_zxz
17+ angleAxisOfRotMat , make_rmat_euler , angles_from_rmat_zxz , rotMatOfExpMap
1818)
1919
2020import hexrdgui .resources .calibration
3939from hexrdgui .utils .dialog import add_help_url
4040
4141
42+ class AtlasConfig :
43+ def __init__ (self , atlas_coords , instr ):
44+ self .coords = atlas_coords
45+ self .instr = instr
46+
47+ def _get_orientation (self , crds , det ):
48+ """vertex in 4x3 matrix of the
49+ 4 vertices. we return the normal
50+ using a cross product
51+ """
52+ vertex = self ._get_vertices (crds )
53+ if det == 'CAMERA-05' :
54+ xhat = - vertex [1 , :] + vertex [0 , :]
55+ yhat = vertex [3 , :] - vertex [0 , :]
56+ else :
57+ xhat = vertex [3 , :] - vertex [0 , :]
58+ yhat = vertex [1 , :] - vertex [0 , :]
59+
60+ xhat = xhat / np .linalg .norm (xhat )
61+ yhat = yhat / np .linalg .norm (yhat )
62+
63+ zhat = np .cross (xhat , yhat )
64+ zhat = zhat / np .linalg .norm (zhat )
65+
66+ xhat = np .cross (yhat , zhat )
67+ xhat = xhat / np .linalg .norm (xhat )
68+
69+ rmat = np .vstack ((- xhat , yhat , - zhat )).T
70+
71+ RMAT_Z_180 = rotMatOfExpMap (np .pi * zhat )
72+ if det in ['CAMERA-02' , 'CAMERA-03' ]:
73+ return np .dot (RMAT_Z_180 , rmat )
74+ return rmat
75+
76+ def _get_center (self , vertex ):
77+ """return center of detector given
78+ the four vertex
79+ """
80+ return np .mean (vertex , axis = 0 )
81+
82+ def _get_vertices (self , crds ):
83+ # by default we will look up from TCC, so there is
84+ # flip in the x-component sign
85+ return crds [0 :4 , :]
86+
87+ def update_instrument (self , detector ):
88+ v = self ._get_vertices (self .coords [detector ])
89+ # tvec sample is the position of the sample in NIF
90+ # chamber coordinates. the position of each detector
91+ # is measured from this point, so we need to take this
92+ # off
93+ tvec_sample = np .array ([0 , 0 , 9.8 ])
94+ tvec = self ._get_center (v ) - tvec_sample
95+ rmat = self ._get_orientation (self .coords [detector ], detector )
96+ ang , ax = angleAxisOfRotMat (rmat )
97+ self .instr .detectors [detector ].tvec = tvec
98+ self .instr .detectors [detector ].tilt = ang * ax
99+
100+
42101class LLNLImportToolDialog (QObject ):
43102
44103 # Emitted when new config is loaded
@@ -77,6 +136,7 @@ def __init__(self, cmap=None, parent=None):
77136 self .loaded_images = []
78137 self .canvas = parent .image_tab_widget .active_canvas
79138 self .detector_images = {}
139+ self .atlas_coords = None
80140
81141 # Disable these by default.
82142 # If we disable these in Qt Designer, there are some weird bugs
@@ -100,6 +160,8 @@ def __init__(self, cmap=None, parent=None):
100160 self .ui .detector_raw_image ,
101161 self .ui .instr_settings_label ,
102162 self .ui .instr_settings ,
163+ self .ui .load_atlas ,
164+ self .ui .atlas_label ,
103165 visible = False )
104166
105167 self .update_config_settings ()
@@ -138,6 +200,7 @@ def setup_connections(self):
138200 self .ui .dark_load .clicked .connect (self .load_detector_images )
139201 self .ui .accept_detector .clicked .connect (
140202 self .manually_load_detector_images )
203+ self .ui .load_atlas .clicked .connect (self .load_atlas_coords )
141204
142205 def enable_widgets (self , * widgets , enabled ):
143206 for w in widgets :
@@ -264,6 +327,8 @@ def instrument_selected(self, idx):
264327 self .ui .detector_raw_image ,
265328 self .ui .instr_settings_label ,
266329 self .ui .instr_settings ,
330+ self .ui .load_atlas ,
331+ self .ui .atlas_label ,
267332 visible = is_fiddle )
268333
269334 has_ip = self .ui .instr_settings .currentIndex () == 0
@@ -353,6 +418,16 @@ def update_config_settings(self):
353418 if prev :
354419 combo .setCurrentText (prev )
355420
421+ def load_atlas_coords (self ):
422+ file , filter = QFileDialog .getOpenFileName (
423+ self .ui , 'Select coordinates file' , dir = HexrdConfig ().working_dir )
424+ if not file :
425+ return
426+ with open (file , 'r' ) as f :
427+ coords = yaml .safe_load (f )
428+ self .atlas_coords = {d : np .array (c ) for d , c in coords .items ()}
429+ self .ui .atlas_label .setText (Path (file ).name )
430+
356431 def load_instrument_config (self ):
357432 temp = tempfile .NamedTemporaryFile (delete = False , suffix = '.hexrd' )
358433 self .config_file = temp .name
@@ -814,6 +889,7 @@ def reset_panel(self):
814889 self .clear_boundry ()
815890 # Reset internal state
816891 self .completed = []
892+ self .atlas_coords = None
817893 self .defaults .clear ()
818894 self .config_file = None
819895 self .import_in_progress = False
@@ -832,6 +908,7 @@ def reset_panel(self):
832908 self .ui .config_file_label .setText ('No File Selected' )
833909 self .ui .config_file_label .setToolTip (
834910 'Defaults to currently loaded configuration' )
911+ self .ui .atlas_label .setText ('No File Selected' )
835912 # Reset widget states - disable/enable/show/hide as appropriate
836913 self .enable_widgets (
837914 self .ui .image_plate_raw_image ,
@@ -855,6 +932,8 @@ def reset_panel(self):
855932 self .ui .detector_raw_image ,
856933 self .ui .instr_settings_label ,
857934 self .ui .instr_settings ,
935+ self .ui .load_atlas ,
936+ self .ui .atlas_label ,
858937 visible = False )
859938 # We're all reset and ready to re-enable the main UI features
860939 HexrdConfig ().enable_image_mode_widget .emit (True )
@@ -872,6 +951,12 @@ def import_complete(self):
872951
873952 instr = HEDMInstrument (
874953 instrument_config = self .ip_and_det_defaults ['default_config' ])
954+
955+ if self .atlas_coords is not None :
956+ atlas_config = AtlasConfig (self .atlas_coords , instr )
957+ for detector in self .detectors :
958+ atlas_config .update_instrument (detector )
959+
875960 for det in self .completed :
876961 panel = instr .detectors [det ]
877962 # first need the zxz Euler angles from the panel rotation matrix.
0 commit comments