nbs-bl 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. nbs_bl/__init__.py +15 -0
  2. nbs_bl/beamline.py +450 -0
  3. nbs_bl/configuration.py +838 -0
  4. nbs_bl/detectors.py +89 -0
  5. nbs_bl/devices/__init__.py +12 -0
  6. nbs_bl/devices/detectors.py +154 -0
  7. nbs_bl/devices/motors.py +242 -0
  8. nbs_bl/devices/sampleholders.py +360 -0
  9. nbs_bl/devices/shutters.py +120 -0
  10. nbs_bl/devices/slits.py +51 -0
  11. nbs_bl/gGrEqns.py +171 -0
  12. nbs_bl/geometry/__init__.py +0 -0
  13. nbs_bl/geometry/affine.py +197 -0
  14. nbs_bl/geometry/bars.py +189 -0
  15. nbs_bl/geometry/frames.py +534 -0
  16. nbs_bl/geometry/linalg.py +138 -0
  17. nbs_bl/geometry/polygons.py +56 -0
  18. nbs_bl/help.py +126 -0
  19. nbs_bl/hw.py +270 -0
  20. nbs_bl/load.py +113 -0
  21. nbs_bl/motors.py +19 -0
  22. nbs_bl/planStatus.py +5 -0
  23. nbs_bl/plans/__init__.py +8 -0
  24. nbs_bl/plans/batches.py +174 -0
  25. nbs_bl/plans/conditions.py +77 -0
  26. nbs_bl/plans/flyscan_base.py +180 -0
  27. nbs_bl/plans/groups.py +55 -0
  28. nbs_bl/plans/maximizers.py +423 -0
  29. nbs_bl/plans/metaplans.py +179 -0
  30. nbs_bl/plans/plan_stubs.py +246 -0
  31. nbs_bl/plans/preprocessors.py +160 -0
  32. nbs_bl/plans/scan_base.py +58 -0
  33. nbs_bl/plans/scan_decorators.py +524 -0
  34. nbs_bl/plans/scans.py +145 -0
  35. nbs_bl/plans/suspenders.py +87 -0
  36. nbs_bl/plans/time_estimation.py +168 -0
  37. nbs_bl/plans/xas.py +123 -0
  38. nbs_bl/printing.py +221 -0
  39. nbs_bl/qt/models/beamline.py +11 -0
  40. nbs_bl/qt/models/energy.py +53 -0
  41. nbs_bl/qt/widgets/energy.py +225 -0
  42. nbs_bl/queueserver.py +249 -0
  43. nbs_bl/redisDevice.py +96 -0
  44. nbs_bl/run_engine.py +63 -0
  45. nbs_bl/samples.py +130 -0
  46. nbs_bl/settings.py +68 -0
  47. nbs_bl/shutters.py +39 -0
  48. nbs_bl/sim/__init__.py +2 -0
  49. nbs_bl/sim/config/polphase.nc +0 -0
  50. nbs_bl/sim/energy.py +403 -0
  51. nbs_bl/sim/manipulator.py +14 -0
  52. nbs_bl/sim/utils.py +36 -0
  53. nbs_bl/startup.py +27 -0
  54. nbs_bl/status.py +114 -0
  55. nbs_bl/tests/__init__.py +0 -0
  56. nbs_bl/tests/modify_regions.py +160 -0
  57. nbs_bl/tests/test_frames.py +99 -0
  58. nbs_bl/tests/test_panels.py +69 -0
  59. nbs_bl/utils.py +235 -0
  60. nbs_bl-0.2.0.dist-info/METADATA +71 -0
  61. nbs_bl-0.2.0.dist-info/RECORD +64 -0
  62. nbs_bl-0.2.0.dist-info/WHEEL +4 -0
  63. nbs_bl-0.2.0.dist-info/entry_points.txt +2 -0
  64. nbs_bl-0.2.0.dist-info/licenses/LICENSE +13 -0
@@ -0,0 +1,534 @@
1
+ import numpy as np
2
+ from .linalg import (vec, constructBasis, changeBasisMatrix, rad_to_deg,
3
+ deg_to_rad, rotz, rotzMat)
4
+ from .polygons import isInPoly, getMinDist
5
+
6
+
7
+ class NullFrame:
8
+ def frame_to_beam(self, *args, **kwargs):
9
+ return args
10
+
11
+ def beam_to_frame(self, *args, **kwargs):
12
+ return args
13
+
14
+ def distance_to_beam(self, *args):
15
+ v = np.array(args)
16
+ return np.sqrt(np.dot(v, v))
17
+
18
+
19
+ class Axis:
20
+ def __init__(self, x0, scale=1, parent=None):
21
+ self.reset(x0, scale, parent=parent)
22
+
23
+ def reset(self, x0, scale, parent=None):
24
+ self.x0 = x0
25
+ self.scale = scale
26
+ self.parent = parent
27
+
28
+ def update_basis(self, x):
29
+ self.x0 = x
30
+
31
+ def frame_to_parent(self, x):
32
+ return x*self.scale + self.x0
33
+
34
+ def parent_to_frame(self, x):
35
+ return x*self.scale - self.x0
36
+
37
+ def add_parent_frame(self, parent):
38
+ """
39
+ Adds a new parent at the top of the parent
40
+ hierarchy, replacing the old global frame.
41
+ Maybe dangerous in practice...
42
+ """
43
+ if self.parent is None:
44
+ self.parent = parent
45
+ else:
46
+ self.parent.add_parent_frame(parent)
47
+
48
+ def frame_to_global(self, x_frame):
49
+ x_parent = self.frame_to_parent(x_frame)
50
+ if self.parent is not None:
51
+ return self.parent.frame_to_global(x_parent)
52
+ else:
53
+ return x_parent
54
+
55
+ def global_to_frame(self, x_global):
56
+ if self.parent is None:
57
+ return self.parent_to_frame(x_global)
58
+ else:
59
+ x_parent = self.parent.global_to_frame(x_global)
60
+ return self.parent_to_frame(x_parent)
61
+
62
+ def frame_to_beam(self, x_frame):
63
+ return self.frame_to_global(x_frame)
64
+
65
+ def beam_to_frame(self, x_global):
66
+ return self.global_to_frame(x_global)
67
+
68
+ def distance_to_beam(self, x_beam_global):
69
+ """
70
+ Distance from beam to origin
71
+
72
+ Parameters
73
+ -----------
74
+ x_beam_global : float
75
+ beam position in global coordinate system
76
+ """
77
+ x = self.global_to_frame(x_beam_global)
78
+ return x
79
+
80
+
81
+ class Interval(Axis):
82
+ def __init__(self, x0, length, *args, parent=None):
83
+ self.length = length
84
+ super().__init__(x0, *args, parent=parent)
85
+
86
+ def frame_to_global(self, x, origin="edge"):
87
+ if origin == "center":
88
+ x += self.length/2.0
89
+ return super().frame_to_global(x)
90
+
91
+ def global_to_frame(self, x, origin="edge"):
92
+ x = super().global_to_frame(x)
93
+ if origin == "center":
94
+ x -= self.length/2.0
95
+ return x
96
+
97
+ def frame_to_beam(self, x_frame, **kwargs):
98
+ return self.frame_to_global(x_frame, **kwargs)
99
+
100
+ def beam_to_frame(self, x_global, **kwargs):
101
+ return self.global_to_frame(x_global, **kwargs)
102
+
103
+ def distance_to_beam(self, x_beam_global):
104
+ x = self.global_to_frame(x_beam_global)
105
+ d1 = np.abs(x)
106
+ d2 = np.abs(x - self.length)
107
+ if (d1 < self.length) and (d2 < self.length):
108
+ return -1*min(d1, d2)
109
+ else:
110
+ return min(d1, d2)
111
+
112
+ def make_sample_frame(self, position, t=0):
113
+ x1, x2 = position
114
+ frame = Interval(x1, x2 - x1, parent=self)
115
+ return frame
116
+
117
+
118
+ class Frame:
119
+ """
120
+ 20220117: This entire thing is too complicated. Having a "manip" argument
121
+ was a really bad idea. I should have used a moveable manipulator frame
122
+ instead. Indeed, this is what I have essentially done, but the complexity
123
+ remains. There are also too many X_to_frame and frame_to_X functions.
124
+ There should have only been "parent_to_frame" and "global_to_frame". No
125
+ time to fix this now. Interval/Axis are done better
126
+ """
127
+ def __init__(self, p1, p2, p3, parent=None, rot_meas_axis=2):
128
+ """
129
+ Parameters
130
+ ------------
131
+ p1 : vector
132
+ origin of the frame in the parent system
133
+ p2 : vector
134
+ defines the frame's y basis vector
135
+ p3 : vector
136
+ defines the plane of the x basis vector
137
+ parent : Frame, optional
138
+ rot_meas_axis : int
139
+ Which axis will be used to measure rotation relative to the
140
+ global coordinate system X-Y plane
141
+ """
142
+ self.rot_meas_axis = rot_meas_axis
143
+ self.reset(p1, p2, p3, parent=parent)
144
+
145
+ def reset(self, p1, p2, p3, parent=None):
146
+ self.parent = parent
147
+ self.update_basis(p1, p2, p3)
148
+ self.update_rotation()
149
+
150
+ def update_basis(self, p1, p2, p3):
151
+ self.vectors = [p1, p2, p3]
152
+ self.p0 = p1
153
+ self._basis = constructBasis(p1, p2, p3)
154
+ # r_offset
155
+ self.A = changeBasisMatrix(*self._basis)
156
+ self.Ainv = self.A.T
157
+
158
+ def update_rotation(self):
159
+ self.r0 = rad_to_deg(self._roffset())
160
+
161
+ def add_parent_frame(self, parent):
162
+ """
163
+ Adds a new parent at the top of the parent
164
+ hierarchy, replacing the old global frame.
165
+ """
166
+ if self.parent is None:
167
+ self.parent = parent
168
+ else:
169
+ self.parent.add_parent_frame(parent)
170
+ self.update_rotation()
171
+
172
+ def reset_z(self, z, parent=None):
173
+ self.p0[2] = z
174
+
175
+ def _roffset(self):
176
+ """
177
+ R offset relative to the GLOBAL frame (not the parent frame!)
178
+
179
+ Important note! It is a BAKED IN ASSUMPTION that
180
+ these frames are being used for beamline samples, and
181
+ that there is only one rotation axis.
182
+ "Rotation" means the angle that the rotation axis makes
183
+ with respect to the beam in the global x-y plane. This
184
+ makes sense because we only have a 4-axis manipulator.
185
+ If we had, god forbid, a 6-axis manipulator, none of this
186
+ 1-axis rotation stuff would make sense, and you would just
187
+ have to specify an exact vector, rather than an angle.
188
+ """
189
+
190
+ # we bootstrap the rotation by finding the z-vector in the global
191
+ # frame, even if
192
+ # we have a parent.
193
+ axis = vec(0, 0, 0)
194
+ axis[self.rot_meas_axis] = 1
195
+ n3 = (self.frame_to_global(axis, rotation='global') -
196
+ self.frame_to_global(vec(0, 0, 0), rotation='global'))
197
+ x = n3[0]
198
+ y = n3[1]
199
+
200
+ if x > 0 and y >= 0:
201
+ return np.arctan(np.abs(y/x))
202
+ elif x <= 0 and y > 0:
203
+ return np.arctan(np.abs(x/y)) + np.pi/2.0
204
+ elif x < 0 and y <= 0:
205
+ return np.arctan(np.abs(y/x)) + np.pi
206
+ else:
207
+ return np.arctan(np.abs(x/y)) + np.pi*3/2.0
208
+
209
+
210
+ def _to_global(self, v):
211
+ return np.dot(self.A, v) + self.p0
212
+
213
+ def _to_frame(self, v):
214
+ return np.dot(self.Ainv, v - self.p0)
215
+
216
+ def _manip_to_global(self, v_manip, manip, r):
217
+ theta = deg_to_rad(r)
218
+ v_global = rotz(-theta, v_manip) + manip
219
+ return v_global
220
+
221
+ def _global_to_manip(self, v_global, manip, r):
222
+ theta = deg_to_rad(r)
223
+ v_manip = rotz(theta, v_global - manip)
224
+ return v_manip
225
+
226
+ def frame_to_global(self, v_frame, manip=vec(0, 0, 0), r=0,
227
+ rotation="frame"):
228
+ """
229
+ Find the global coordinates of a point in the frame, given the
230
+ rotation of the frame, and the manipulator position
231
+
232
+ Parameters
233
+ ------------
234
+ v_frame : vector
235
+ Coordinates of a point in the frame system
236
+ manip : vector
237
+ Manipulator coordinates
238
+ r : float, degrees
239
+ rotation of the frame
240
+ (0 = grazing incidence, 90 = normal)
241
+ """
242
+ if rotation == 'frame':
243
+ rg = r + self.r0
244
+ else:
245
+ rg = r
246
+ v_global = self._to_global(v_frame)
247
+ if self.parent is not None:
248
+ return self.parent.frame_to_global(v_global, manip, r=rg,
249
+ rotation='global')
250
+ else:
251
+ v_global = self._manip_to_global(v_global, manip, rg)
252
+ return v_global
253
+
254
+ def global_to_frame(self, v_global, manip=vec(0, 0, 0), r=0):
255
+ """
256
+ Find the frame coordinates of a point in the global system,
257
+ given the manipulator position and rotation
258
+
259
+ Parameters
260
+ -----------
261
+ v_global : vector
262
+ global vector
263
+ manip : vector
264
+ current position of manipulator
265
+ r : float, degrees
266
+ rotation of the manipulator
267
+ """
268
+ if self.parent is not None:
269
+ v_manip = self.parent.global_to_frame(v_global, manip, r)
270
+ else:
271
+ v_manip = self._global_to_manip(v_global, manip, r)
272
+ v_frame = self._to_frame(v_manip)
273
+ return v_frame
274
+
275
+ def frame_to_beam(self, fx, fy, fz, fr=0, **kwargs):
276
+ """
277
+ Given a frame coordinate, and rotation, find the manipulator position
278
+ and rotation that places the frame coordinate in the beam path.
279
+ The beam position is assumed to be the origin of the global coordinate
280
+ system.
281
+
282
+ Returns
283
+ --------
284
+ coordinates : tuple
285
+ The x, y, z, r coordinates of the manipulator that put the
286
+ frame coordinate into the beam path
287
+ """
288
+
289
+ v_frame = vec(fx, fy, fz)
290
+ v_global = -1*self.frame_to_global(v_frame, r=fr)
291
+ gr = fr + self.r0
292
+ gx, gy, gz = (v_global[0], v_global[1], v_global[2])
293
+ return gx, gy, gz, gr
294
+
295
+ def beam_to_frame(self, gx, gy, gz, gr=0, **kwargs):
296
+ """
297
+ Given a manipulator coordinate and rotation, find the beam intersection
298
+ position and incidence angle in the frame coordinates. The beam
299
+ position is assumed to be the origin of the global coordinate system.
300
+
301
+ Parameters
302
+ ------------
303
+ gx : float
304
+ manipulator x coordinate
305
+ gy : float
306
+ manipulator y coordinate
307
+ gz : float
308
+ manipulator z coordinate
309
+ gr : float, degrees
310
+ manipulator r coordinate
311
+
312
+ Returns
313
+ --------
314
+ coordinates : tuple
315
+ The x, y, z, r coordinates of the beam in the frame system
316
+ """
317
+ manip = vec(gx, gy, gz)
318
+ v_frame = self.origin_to_frame(manip, gr)
319
+ fx, fy, fz = (v_frame[0], v_frame[1], v_frame[2])
320
+ fr = gr - self.r0
321
+ return fx, fy, fz, fr
322
+
323
+ def origin_to_frame(self, manip=vec(0, 0, 0), r=0):
324
+ return self.global_to_frame(vec(0, 0, 0), manip, r)
325
+
326
+ def project_beam_to_frame_xy(self, manip=vec(0, 0, 0), r=0):
327
+ op = self.origin_to_frame(manip, r)
328
+ theta = deg_to_rad(r)
329
+ Rz_inv = rotzMat(-theta)
330
+ vp = np.dot(self.Ainv, np.dot(Rz_inv, vec(0, 1, 0)))
331
+ a = op[-1]/vp[-1]
332
+ proj = op - a*vp
333
+ return proj
334
+
335
+ def distance_to_beam(self, gx, gy, gz, gr=0):
336
+ """
337
+ Given the manipulator coordinate (and rotation, for consistency),
338
+ find the distance from the beam to the coordinate origin, ignoring
339
+ the beam y-axis
340
+
341
+ Parameters
342
+ ------------
343
+ gx : float
344
+ manipulator x coordinate
345
+ gy : float
346
+ manipulator y coordinate
347
+ gz : float
348
+ manipulator z coordinate
349
+ gr : float, degrees
350
+ manipulator r coordinate
351
+
352
+ Returns
353
+ --------
354
+ distance : float
355
+ Distance from the global y-axis (the beam) to the coordinate origin
356
+ """
357
+ op = self.frame_to_global(vec(0, 0, 0), manip=vec(gx, gy, gz), r=gr)
358
+ distance = np.sqrt(op[0]**2 + op[2]**2)
359
+ return distance
360
+
361
+
362
+ class Panel(Frame):
363
+ """
364
+ A frame that has boundaries, making it a rectangle
365
+
366
+ Parameters
367
+ ------------
368
+ p1 : vector
369
+ origin of the frame in the parent system
370
+ p2 : vector
371
+ defines the frame's y basis vector
372
+ p3 : vector
373
+ defines the plane of the x basis vector
374
+ parent : Frame, optional
375
+
376
+ """
377
+ def __init__(self, *args, width=19.5, height=130, parent=None):
378
+ super().__init__(*args, parent=parent)
379
+ self.width = width
380
+ self.height = height
381
+ self.edges = [vec(0, 0, 0), vec(width, 0, 0), vec(width, height, 0),
382
+ vec(0, height, 0)]
383
+
384
+ def frame_to_beam(self, fx, fy, fz, fr=0, origin="edge"):
385
+ if origin == "center":
386
+ fx += self.width/2.0
387
+ fy += self.height/2.0
388
+ return super().frame_to_beam(fx, fy, fz, fr)
389
+
390
+ def beam_to_frame(self, gx, gy, gz, gr=0, origin="edge"):
391
+ fx, fy, fz, fr = super().beam_to_frame(gx, gy, gz, gr)
392
+ if origin == "center":
393
+ fx -= self.width/2.0
394
+ fy -= self.height/2.0
395
+ return fx, fy, fz, fr
396
+
397
+ def real_edges(self, manip, r_manip):
398
+ """
399
+ Finds the vertices of the panel in global coordinate system,
400
+ given the manipulator position
401
+
402
+ Parameters
403
+ -----------
404
+ manip : vector
405
+ Manipulator x,y,z position vector
406
+ r_manip : float
407
+ Manipulator rotation in degrees
408
+
409
+ Returns
410
+ --------
411
+ Vertex positions in the global frame
412
+ """
413
+ re = []
414
+ for edge in self.edges:
415
+ real_coord = self.frame_to_global(edge, manip, r_manip,
416
+ rotation='global')
417
+ re.append(real_coord)
418
+ return re
419
+
420
+ def project_real_edges(self, manip, r_manip):
421
+ """
422
+
423
+ Parameters
424
+ ------------
425
+ manip : vector
426
+ Manipulator x,y,z position vector
427
+ r_manip : float
428
+ Manipulator rotation in degrees
429
+
430
+ Returns
431
+ --------
432
+ Vertex coordinates projected into the x-z axis
433
+ """
434
+
435
+ re = self.real_edges(manip, r_manip)
436
+ ret = []
437
+ for edge in re:
438
+ ret.append(np.array([edge[0], edge[2]]))
439
+ return ret
440
+
441
+ def distance_to_beam(self, x, y, z, r):
442
+ """
443
+ Returns the distance from the beam to the closest edge of
444
+ the Panel, given a manipulator position of x, y, z, r
445
+
446
+ Parameters
447
+ -------------
448
+ x : float
449
+ manipulator x coordinate
450
+ y : float
451
+ manipulator y coordinate
452
+ z : float
453
+ manipulator z coordinate
454
+ r : float
455
+ manipulator r coordinate (in degrees)
456
+
457
+ Returns
458
+ ----------
459
+ distance : float
460
+ The sign of distance is negative if the beam is inside the Panel,
461
+ and positive if the beam is outside the Panel
462
+ """
463
+
464
+ manip = vec(x, y, z)
465
+ real_edges = self.project_real_edges(manip, r)
466
+ inPoly = isInPoly(vec(0, 0), *real_edges)
467
+ distance = getMinDist(vec(0, 0), *real_edges)
468
+ if inPoly:
469
+ return -1*distance
470
+ else:
471
+ return distance
472
+
473
+ def make_sample_frame(self, position, t=0):
474
+ if len(position) == 4:
475
+ x1, y1, x2, y2 = position
476
+ p1 = vec(x1, y1, t)
477
+ p2 = vec(x1, y2, t)
478
+ p3 = vec(x2, y1, t)
479
+ width = x2 - x1
480
+ height = y2 - y1
481
+
482
+ frame = Panel(p1, p2, p3, height=height, width=width,
483
+ parent=self)
484
+ return frame
485
+
486
+
487
+ def make_geometry(*args, **kwargs):
488
+ if len(args) == 3:
489
+ if "height" in kwargs and "width" in kwargs:
490
+ return Panel(*args, **kwargs)
491
+ else:
492
+ return Frame(*args, **kwargs)
493
+
494
+
495
+ def make_regular_polygon(width, height, nsides, points=None, parent=None, invert=True):
496
+ geometry = []
497
+ interior_angle = deg_to_rad(360.0 / nsides)
498
+ if invert:
499
+ az = -1
500
+ else:
501
+ az = 1
502
+
503
+ if points is None:
504
+ y = -1 * az * width / 2.0
505
+ x = width / (2.0 * np.tan(interior_angle / 2.0))
506
+ if invert:
507
+ z = height
508
+ else:
509
+ z = 0
510
+ p1 = vec(x, y, z)
511
+ p2 = p1 + vec(0, 0, az)
512
+ p3 = p1 + vec(0, az, 0)
513
+ else:
514
+ p1, p2, p3 = points
515
+
516
+ def _newSideFromSide(side):
517
+ prev_edges = side.real_edges(vec(0, 0, 0), 0)
518
+ new_vector = vec(np.cos(np.pi - interior_angle), 0, -np.sin(np.pi - interior_angle))
519
+ p1 = prev_edges[1]
520
+ p2 = prev_edges[2]
521
+ p3 = side.frame_to_global(new_vector + side.edges[1], r=0, rotation="global")
522
+ return Panel(p1, p2, p3, width=width, height=height, parent=parent)
523
+
524
+ current_side = Panel(p1, p2, p3, width=width, height=height, parent=parent)
525
+ geometry.append(current_side)
526
+ new_sides = []
527
+ for n in range(1, nsides):
528
+ new_side = _newSideFromSide(current_side)
529
+ new_sides.append(new_side)
530
+ current_side = new_side
531
+ # It is unfortunately easier to generate sides in reverse order
532
+ # due to the coordinate system, so we must reverse them.
533
+ geometry += new_sides[::-1]
534
+ return geometry
@@ -0,0 +1,138 @@
1
+ import numpy as np
2
+
3
+ """
4
+ Module that implements basic linear algebra as it relates to vectors and
5
+ basis transformation/construction
6
+ """
7
+
8
+
9
+ def vec(*args):
10
+ """
11
+ Construct a vector from components
12
+ """
13
+ return np.array(args, dtype="float64")
14
+
15
+
16
+ def normVector(v):
17
+ """
18
+ Return the unit vector of v
19
+ """
20
+ n = np.sqrt(np.dot(v, v))
21
+ return v/n
22
+
23
+
24
+ def vec_len(v):
25
+ """
26
+ Find the magnitude of vector v
27
+ """
28
+ return np.sqrt(np.dot(v, v))
29
+
30
+
31
+ def vec_angle(v1, v2):
32
+ """
33
+ Find the angle between v1 and v2
34
+ """
35
+ return np.arccos(np.dot(v1, v2)/(vec_len(v1)*vec_len(v2)))
36
+
37
+
38
+ def findOrthonormal(v1, v2):
39
+ """
40
+ Find the length 1 vector normal to v1 and v2
41
+ """
42
+ v3 = np.cross(v1, v2)
43
+ return normVector(v3)
44
+
45
+
46
+ def constructBasis(p1, p2, p3):
47
+ """
48
+ Construct a basis from three points
49
+
50
+ Parameters
51
+ ------------
52
+ p1 : vector
53
+ The origin of the vector space
54
+ p2 : vector
55
+ defines the y basis vector
56
+ p3 : vector
57
+ defines the plane of the x basis vector
58
+
59
+ Returns
60
+ ----------
61
+ Returns three vectors, n1, n2, and n3, that form a basis.
62
+ n2 : vector
63
+ the "y" vector, is defined by p2 - p1
64
+ n3 : vector
65
+ the "z" vector, is defined as being orthornormal to n2 and p3-p1,
66
+ n1 : vector
67
+ the "x" vector, is then uniquely defined as orthonormal to n2 and n3
68
+ """
69
+ v1 = p3 - p1
70
+ v2 = p2 - p1
71
+ n2 = normVector(v2)
72
+ n3 = findOrthonormal(v1, n2)
73
+ n1 = findOrthonormal(n2, n3)
74
+ return n1, n2, n3
75
+
76
+
77
+ def changeBasisMatrix(n1, n2, n3):
78
+ return np.vstack([n1, n2, n3]).T
79
+
80
+
81
+ def constructBorders(p1, p2, p3, sidelength=1):
82
+ n1, n2, n3 = constructBasis(p1, p2, p3)
83
+ origin = p1
84
+ origin2 = n1*sidelength + origin
85
+ borders = {'n1': n1, 'n2': n2,
86
+ 'o1': origin, 'o2': origin2}
87
+ return borders
88
+
89
+
90
+ def rotzMat(theta):
91
+ """
92
+ Parameters
93
+ -----------
94
+ theta : float, radians
95
+ """
96
+ return np.array([[np.cos(theta), -np.sin(theta), 0],
97
+ [np.sin(theta), np.cos(theta), 0],
98
+ [0, 0, 1]])
99
+
100
+
101
+ def rotyMat(theta):
102
+ return np.array([[np.cos(theta), 0, np.sin(theta)],
103
+ [0, 1, 0],
104
+ [-np.sin(theta), 0, np.cos(theta)]
105
+ ])
106
+
107
+
108
+ def rotxMat(theta):
109
+ return np.array([[1, 0, 0],
110
+ [0, np.cos(theta), -np.sin(theta)],
111
+ [0, np.sin(theta), np.cos(theta)]
112
+ ])
113
+
114
+
115
+ def rotz(theta, v):
116
+ """
117
+ Rotate a vector by theta around the z axis
118
+ """
119
+ rz = rotzMat(theta)
120
+ return np.dot(rz, v)
121
+
122
+
123
+ def roty(theta, v):
124
+ ry = rotyMat(theta)
125
+ return np.dot(ry, v)
126
+
127
+
128
+ def rotx(theta, v):
129
+ rx = rotxMat(theta)
130
+ return np.dot(rx, v)
131
+
132
+
133
+ def deg_to_rad(d):
134
+ return d*np.pi/180.0
135
+
136
+
137
+ def rad_to_deg(d):
138
+ return d*180.0/np.pi