cgse-coordinates 0.17.3__py3-none-any.whl → 0.18.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.
@@ -34,7 +34,6 @@ Functionality:
34
34
  import logging
35
35
  from typing import Dict
36
36
  from typing import List
37
- from typing import Union
38
37
 
39
38
  import matplotlib.pyplot as plt
40
39
  import numpy as np
@@ -44,7 +43,6 @@ from mpl_toolkits.mplot3d import Axes3D
44
43
  import egse.coordinates.transform3d_addon as t3add
45
44
  from egse.coordinates import dict_to_ref_model
46
45
  from egse.coordinates import ref_model_to_dict
47
- from egse.coordinates.referenceFrame import ReferenceFrame
48
46
  from egse.setup import NavigableDict
49
47
 
50
48
  LOGGER = logging.getLogger(__name__)
@@ -73,22 +71,26 @@ class ReferenceFrameModel:
73
71
 
74
72
  def __init__(
75
73
  self,
76
- model: Union[Dict, List[ReferenceFrame]] = None,
77
- rot_config: str = _ROT_CONFIG_DEFAULT,
74
+ model: Dict | List = None,
75
+ rotation_config: str = _ROT_CONFIG_DEFAULT,
78
76
  use_degrees: bool = _DEGREES_DEFAULT,
79
77
  use_active_movements: bool = _ACTIVE_DEFAULT,
80
78
  ):
81
- """
82
- When the model_dict is empty or None, a new model is created with a master reference frame.
79
+ """Initialisation of a reference frame model.
83
80
 
84
81
  Args:
85
- model: a list or a dictionary of reference frames that make up the model
86
- use_degrees: use degrees throughout this model unless explicitly specified in the
87
- function call.
82
+ model (Dict | List[ReferenceFrame]): List or a dictionary of reference frames that make up the model.
83
+ rotation_config (str): Order in which the rotation about the three axes are chained.
84
+ use_degrees (bool): Indicates whether the rotation angles are specified in degrees, rather than radians.
85
+ use_active_movements (bool): Indicates if the rotation is active (object rotates IN a fixed coordinate
86
+ system) or passive (coordinate system rotates AROUND a fixed object). Even if
87
+ two angles are zero, the match between angle orders and rot_config is still
88
+ critical.
88
89
  """
90
+
89
91
  self._use_degrees = use_degrees
90
92
  self._use_active_movements = use_active_movements
91
- self._rot_config = rot_config
93
+ self._rot_config = rotation_config
92
94
 
93
95
  # Keep a dictionary with all reference frames that are part of the model. The keys shall
94
96
  # be the name of the reference frame. When the model passed is empty, create only a
@@ -99,155 +101,185 @@ class ReferenceFrameModel:
99
101
  else:
100
102
  self._model = NavigableDict({})
101
103
 
102
- def __str__(self):
104
+ def __str__(self) -> str:
105
+ """Returns a printable string representation of the reference frame.
106
+
107
+ Returns:
108
+ Printable string representation of the reference frame.
109
+ """
110
+
103
111
  return self._model.pretty_str()
104
112
 
105
- def __len__(self):
113
+ def __len__(self) -> int:
114
+ """Returns the number of reference frames in the model."""
115
+
106
116
  return len(self._model)
107
117
 
108
- def __contains__(self, item):
118
+ def __contains__(self, item) -> bool:
119
+ """Checks whether the given item is present in the model.
120
+
121
+ Args:
122
+ item: Item for which to check whether it's present in the model.
123
+
124
+ Returns:
125
+ True if the given item is present in the model; False otherwise.
126
+ """
127
+
109
128
  return item in self._model
110
129
 
111
130
  def __iter__(self):
131
+ """Returns an iterator over the reference frames in the model."""
132
+
112
133
  return iter(self._model.values())
113
134
 
114
- def summary(self):
115
- result = f"Nb of frames: {len(self)}\n"
135
+ def summary(self) -> str:
136
+ """Returns a summary of the model.
137
+
138
+ Returns:
139
+ String summary of the model.
140
+ """
141
+
142
+ result = f"Number of frames: {len(self)}\n"
143
+
144
+ for reference_frame in self:
145
+ result += f"{reference_frame.name:>10}[{reference_frame.reference_frame.name}] --- {[link.name for link in reference_frame.linked_to]}\n"
116
146
 
117
- for ref in self:
118
- result += f"{ref.name:>10}[{ref.ref.name}] --- {[link.name for link in ref.linkedTo]}\n"
119
147
  return result
120
148
 
121
149
  @staticmethod
122
150
  def deserialize(model_dict: dict) -> NavigableDict:
123
- """
124
- Deserialize means you take a serialized representation of a reference frames model and
125
- turn it into a dictionary containing all the reference frames with their links and
126
- references.
151
+ """De-serialisation of the model.
152
+
153
+ De-serialisation means you take a serialised representation of a reference frames model and turn it into a
154
+ dictionary containing all the reference frames with their links and references.
127
155
 
128
156
  Args:
129
- model_dict: a dictionary of serialized reference frames
157
+ model_dict (dict): Dictionary of serialised reference frames.
130
158
 
131
159
  Returns:
132
- A dictionary of ReferenceFrames that make up a model.
160
+ Dictionary of reference frames that make up a model.
133
161
 
134
162
  """
135
163
  return dict_to_ref_model(model_dict)
136
164
 
137
165
  def serialize(self) -> NavigableDict:
138
- """
139
- Serialize the model by serializing each of the reference frames into an object that can
140
- easily be saved to a YAML or a JSON file. Return a dictionary with the serialized frames.
166
+ """Serialisation of the model.
167
+
168
+
169
+ Serialisation of the model by serialising each of the reference frames into an object that can easily be saved
170
+ to a YAML or a JSON file.
141
171
 
142
172
  Returns:
143
- A dictionary with all the reference framed serialized.
173
+ Dictionary with all the serialised reference framed.
144
174
  """
145
175
 
146
176
  return ref_model_to_dict(self._model)
147
177
 
148
- def add_master_frame(self):
178
+ def add_master_frame(self) -> None:
179
+ """Adds the master reference frame to the model."""
180
+
149
181
  # TODO: First check if there is not already a Master frame in the model
150
182
 
151
- self._model["Master"] = ReferenceFrame.createMaster()
183
+ from egse.coordinates.reference_frame import ReferenceFrame
184
+
185
+ self._model["Master"] = ReferenceFrame.create_master()
152
186
 
153
187
  def add_frame(
154
188
  self,
155
189
  name: str,
156
190
  *,
157
- translation: List[float] = None,
158
- rotation: List[float] = None,
159
- transformation=None,
160
- ref: str,
161
- ):
162
- """
163
- Add a reference frame to the model.
164
-
165
- .. note::
166
- Only the `name` parameter can be positional, all the other arguments (translation,
167
- rotation, transformation, and ref) must be given as keyword arguments.
191
+ translation: np.ndarray = None,
192
+ rotation: np.ndarray = None,
193
+ transformation: np.ndarray = None,
194
+ reference: str,
195
+ ) -> None:
196
+ """Adds a reference frame to the model.
168
197
 
169
198
  Args:
170
- name: the name for the reference frame. This name is it's identifier within the model.
171
- translation: the translation vector
172
- rotation: the rotation vector
173
- transformation: the transformation vector, if `transformation` is given,
174
- both `translation` and `rotation` are ignored.
175
- ref: the reference frame that is a reference for 'name', i.e. 'name' is defined with
176
- respect to 'ref'.
199
+ name (str): Name of the reference frame to add to the model. Only this parameter can be positional. This
200
+ will serve as the identifier for the reference frame in the model.
201
+ translation (np.ndarray): Translation vector. Ignored when `transformation` is given.
202
+ rotation (np.ndarray: Rotation vector. Ignored when `transformation` is given.
203
+ transformation (np.ndarray): Transformation matrix.
204
+ reference (str): Name of the reference frame that is a reference for the new reference frame, i.e. the new
205
+ reference frame is defined w.r.t. this one.
177
206
  """
178
207
 
208
+ from egse.coordinates.reference_frame import ReferenceFrame
209
+
179
210
  if name in self._model:
180
211
  raise KeyError("A reference frame with the name '{name} already exists in the model.")
181
212
 
182
- ref = self._model[ref]
213
+ reference = self._model[reference]
183
214
 
184
- if transformation is not None:
215
+ if transformation:
185
216
  self._model[name] = ReferenceFrame(
186
217
  transformation,
187
- ref=ref,
218
+ reference_frame=reference,
188
219
  name=name,
189
- rot_config=self._rot_config,
220
+ rotation_config=self._rot_config,
190
221
  )
191
222
  else:
192
- self._model[name] = ReferenceFrame.fromTranslationRotation(
223
+ self._model[name] = ReferenceFrame.from_translation_rotation(
193
224
  translation,
194
225
  rotation,
195
226
  name=name,
196
- ref=ref,
197
- rot_config=self._rot_config,
227
+ reference_frame=reference,
228
+ rotation_config=self._rot_config,
198
229
  degrees=self._use_degrees,
199
230
  active=self._use_active_movements,
200
231
  )
201
232
 
202
233
  def remove_frame(self, name: str):
203
- """
204
- Deletes the reference frame from the model. If the reference frame doesn't exist in the
205
- model, a warning message is logged.
234
+ """Deletes the given reference frame from the model.
235
+
236
+ If the reference frame doesn't exist in the model, a warning message is logged.
206
237
 
207
238
  Args:
208
- name: the name of the reference frame to remove
239
+ name (str): Name of the reference frame to remove.
209
240
  """
210
241
 
211
242
  if name in self._model:
243
+ from egse.coordinates.reference_frame import ReferenceFrame
244
+
212
245
  frame: ReferenceFrame = self._model[name]
213
246
 
214
- # We need to get the links out in a list because the frame.removeLink() method deletes
215
- # frames from the linkedTo dictionary and that is not allowed in a for loop.
247
+ # We need to get the links out in a list because the frame.remove_link() method deletes
248
+ # frames from the linked_to dictionary and that is not allowed in a for loop.
216
249
 
217
- links = [linked_frame for linked_frame in frame.linkedTo]
250
+ links = [linked_frame for linked_frame in frame.linked_to]
218
251
  for link in links:
219
- frame.removeLink(link)
252
+ frame.remove_link(link)
220
253
 
221
254
  del self._model[name]
222
255
  else:
223
256
  LOGGER.warning(f"You tried to remove a non-existing reference frame '{name}' from the model.")
224
257
 
225
- def get_frame(self, name: str) -> ReferenceFrame:
226
- """
227
- Returns a frame with the given name.
258
+ def get_frame(self, name: str):
259
+ """Returns the reference frame with the given name.
228
260
 
229
- .. note::
230
- Use this function with care since this breaks encapsulation and may lead to an
231
- inconsistent model when the frame is changed outside of the scope of the reference
232
- model.
261
+ Use this function with care since this breaks encapsulation and may lead to an inconsistent model when the frame
262
+ is changed outside the scope of the reference model.
233
263
 
234
- Args:
235
- name: the name of the requested reference frame
264
+ Args:
265
+ name (str): Name of the requested reference frame.
236
266
 
237
- Returns:
238
- The reference frame with the given name.
267
+ Returns:
268
+ Reference frame with the given name.
239
269
  """
270
+
240
271
  return self._model[name]
241
272
 
242
273
  def add_link(self, source: str, target: str):
243
- """
244
- Add a link between two reference frames. All links are bi-directional.
274
+ """Adds a link between the two given reference frames of the model.
245
275
 
246
- Args:
247
- source: the source reference frame
248
- target: the target reference frame
276
+ All links are bi-directional.
249
277
 
278
+ Args:
279
+ source (args): Name of the source reference frame.
280
+ target (args): Name of the target reference frame.
250
281
  """
282
+
251
283
  if source not in self._model:
252
284
  raise KeyError(f"There is no reference frame with the name '{source} in the model.")
253
285
  if target not in self._model:
@@ -256,18 +288,18 @@ class ReferenceFrameModel:
256
288
  source = self._model[source]
257
289
  target = self._model[target]
258
290
 
259
- source.addLink(target)
291
+ source.add_link(target)
260
292
 
261
293
  def remove_link(self, source: str, target: str):
262
- """
263
- Remove a link between two reference frames. All links are bi-directional and this method
264
- removes both links.
294
+ """Removes a link between two reference frames.
265
295
 
266
- Args:
267
- source: the source reference frame
268
- target: the target reference frame
296
+ All links are bi-directional and this method removes both links.
269
297
 
298
+ Args:
299
+ source (args): Name of the source reference frame.
300
+ target (args): Name of the target reference frame.
270
301
  """
302
+
271
303
  if source not in self._model:
272
304
  raise KeyError(f"There is no reference frame with the name '{source} in the model.")
273
305
  if target not in self._model:
@@ -276,39 +308,54 @@ class ReferenceFrameModel:
276
308
  source = self._model[source]
277
309
  target = self._model[target]
278
310
 
279
- source.removeLink(target)
311
+ source.remove_link(target)
280
312
 
281
- def move_absolute_self(self, frame: str, translation, rotation, degrees=_DEGREES_DEFAULT):
282
- """
283
- Apply an absolute movement to the given ReferenceFrame such that it occupies a given
284
- absolute position wrt "frame_ref" after the movement.
313
+ def move_absolute_self(
314
+ self, name: str, translation: np.ndarray, rotation: np.ndarray, degrees: bool = _DEGREES_DEFAULT
315
+ ) -> None:
316
+ """Applies an absolute movement to the given reference frame.
317
+
318
+ Applies an absolute movement to the given reference frame such that it occupies a given absolute position w.r.t.
319
+ "frame_ref" after the movement.
285
320
 
286
- NO Hexapod equivalent.
321
+ There is no hexapod equivalent.
287
322
 
288
323
  Args:
289
- frame (str): the name of the reference frame to move
324
+ name (str): Name of the reference frame to move.
325
+ translation (np.ndarray): Translation vector.
326
+ rotation (np.ndarray): Rotation vector.
327
+ degrees (bool): Indicates whether the rotation angles are specified in degrees, rather than radians.
328
+
329
+ Args:
330
+ name (str): the name of the reference frame to move
290
331
  """
291
332
 
292
- frame = self._model[frame]
293
- frame.setTranslationRotation(
333
+ name = self._model[name]
334
+ name.set_translation_rotation(
294
335
  translation,
295
336
  rotation,
296
- rot_config=self._rot_config,
337
+ rotation_config=self._rot_config,
297
338
  active=self._use_active_movements,
298
339
  degrees=degrees,
299
- preserveLinks=True,
340
+ preserve_links=True,
300
341
  )
301
342
 
302
- def move_absolute_in_other(self, frame: str, other: str, translation, rotation, degrees=_DEGREES_DEFAULT):
303
- """
304
- Apply an absolute movement to the ReferenceFrame "frame", such that it occupies
305
- a given absolute position with respect to "other" after the movement.
343
+ def move_absolute_in_other(
344
+ self, frame: str, other: str, translation: np.ndarray, rotation: np.ndarray, degrees: bool = _DEGREES_DEFAULT
345
+ ):
346
+ """Applies an absolute movement to the given reference frame in another reference frame.
347
+
348
+ Apply an absolute movement to the ReferenceFrame "frame", such that it occupies a given absolute position
349
+ w.r.t. "other" after the movement.
306
350
 
307
- EQUIVALENT PunaSimulator.move_absolute, setting hexobj wrt hexusr.
351
+ Hexapod equivalent: PunaSimulator.move_absolute, setting `hexobj` w.r.t. `hexusr`.
308
352
 
309
353
  Args:
310
- frame (str): the name (id) of the reference frame to move
311
- other (str): the name (id) of the reference frame
354
+ frame (str): Name of the reference frame to move.
355
+ other (str): Name of the other reference frame.
356
+ translation (np.ndarray): Translation vector.
357
+ rotation (np.ndarray): Rotation vector.
358
+ degrees (bool): Indicates whether the rotation angles are specified in degrees, rather than radians.
312
359
  """
313
360
 
314
361
  # TODO:
@@ -318,58 +365,71 @@ class ReferenceFrameModel:
318
365
  frame = self._model[frame]
319
366
  other = self._model[other]
320
367
 
321
- transformation = other.getActiveTransformationTo(frame)
368
+ transformation = other.get_active_transformation_to(frame)
322
369
 
323
- moving_in_other = ReferenceFrame(transformation, rot_config=self._rot_config, ref=other, name="moving_in_other")
370
+ from egse.coordinates.reference_frame import ReferenceFrame
324
371
 
325
- moving_in_other.addLink(frame)
372
+ moving_in_other = ReferenceFrame(
373
+ transformation, rotation_config=self._rot_config, reference_frame=other, name="moving_in_other"
374
+ )
375
+
376
+ moving_in_other.add_link(frame)
326
377
 
327
- moving_in_other.setTranslationRotation(
378
+ moving_in_other.set_translation_rotation(
328
379
  translation,
329
380
  rotation,
330
- rot_config=self._rot_config,
381
+ rotation_config=self._rot_config,
331
382
  active=self._use_active_movements,
332
383
  degrees=degrees,
333
- preserveLinks=True,
384
+ preserve_links=True,
334
385
  )
335
386
 
336
- moving_in_other.removeLink(frame)
387
+ moving_in_other.remove_link(frame)
337
388
 
338
389
  del moving_in_other
339
390
 
340
- def move_relative_self(self, frame: str, translation, rotation, degrees=_DEGREES_DEFAULT):
341
- """
342
- Apply a relative movement to the given ReferenceFrame assuming the movement is expressed
343
- in that same frame.
391
+ def move_relative_self(
392
+ self, frame: str, translation: np.ndarray, rotation: np.ndarray, degrees: bool = _DEGREES_DEFAULT
393
+ ):
394
+ """Applies a relative movement to the given reference frame.
395
+
396
+ It is assumed that the movement is expressed in that same reference frame.
344
397
 
345
- EQUIVALENT PunaSimulator.move_relative_object
398
+ Hexapod equivalent: PunaSimulator.move_relative_object
346
399
 
347
400
  Args:
348
- frame (str): the name of the reference frame to move
401
+ frame (str): Name of the reference frame to move.
402
+ translation (np.ndarray): Translation vector.
403
+ rotation (np.ndarray): Rotation vector.
404
+ degrees (bool): Indicates whether the rotation angles are specified in degrees, rather than radians.
349
405
  """
350
406
 
351
407
  frame = self._model[frame]
352
- frame.applyTranslationRotation(
408
+ frame.apply_translation_rotation(
353
409
  translation,
354
410
  rotation,
355
- rot_config=self._rot_config,
411
+ rotation_config=self._rot_config,
356
412
  active=self._use_active_movements,
357
413
  degrees=degrees,
358
- preserveLinks=True,
414
+ preserve_links=True,
359
415
  )
360
416
 
361
- def move_relative_other(self, frame: str, other: str, translation, rotation, degrees=_DEGREES_DEFAULT):
362
- """
363
- Apply a relative movement to the ReferenceFrame "frame". The movement is expressed wrt
364
- the axes of another frame, "other".
417
+ def move_relative_other(
418
+ self, frame: str, other: str, translation: np.ndarray, rotation: np.ndarray, degrees: bool = _DEGREES_DEFAULT
419
+ ):
420
+ """Applies a relative movement to the given reference frame.
365
421
 
366
- The center of rotation is the origin of the reference frame 'other'.
422
+ The movement is expressed w.r.t. the axes of another frame. The centre of rotation is the origin of the
423
+ that other reference frame.
367
424
 
368
- NO Hexapod equivalent.
425
+ There is no hexapod equivalent.
369
426
 
370
427
  Args:
371
- frame (str): the name (id) of the reference frame to move
372
- other (str): the name (id) of the reference frame
428
+ frame (str): Name of the reference frame to move.
429
+ other (str): Name of the reference frame in which the movements have been defined.
430
+ translation (np.ndarray): Translation vector.
431
+ rotation (np.ndarray): Rotation vector.
432
+ degrees (bool): Indicates whether the rotation angles are specified in degrees, rather than radians.
373
433
  """
374
434
 
375
435
  # TODO:
@@ -379,35 +439,45 @@ class ReferenceFrameModel:
379
439
  frame = self._model[frame]
380
440
  other = self._model[other]
381
441
 
382
- transformation = frame.getActiveTransformationTo(other)
442
+ transformation = frame.get_active_transformation_to(other)
443
+
444
+ from egse.coordinates.reference_frame import ReferenceFrame
383
445
 
384
- moving_in_other = ReferenceFrame(transformation, rot_config=self._rot_config, ref=other, name="moving_in_other")
446
+ moving_in_other = ReferenceFrame(
447
+ transformation, rotation_config=self._rot_config, reference_frame=other, name="moving_in_other"
448
+ )
385
449
 
386
- moving_in_other.addLink(frame)
450
+ moving_in_other.add_link(frame)
387
451
 
388
- moving_in_other.applyTranslationRotation(
452
+ moving_in_other.apply_translation_rotation(
389
453
  translation,
390
454
  rotation,
391
- rot_config=self._rot_config,
455
+ rotation_config=self._rot_config,
392
456
  active=self._use_active_movements,
393
457
  degrees=degrees,
394
- preserveLinks=True,
458
+ preserve_links=True,
395
459
  )
396
460
 
397
- moving_in_other.removeLink(frame)
461
+ moving_in_other.remove_link(frame)
398
462
 
399
463
  del moving_in_other # not need as local scope
400
464
 
401
- def move_relative_other_local(self, frame: str, other: str, translation, rotation, degrees=_DEGREES_DEFAULT):
402
- """
403
- Apply a relative movement to the ReferenceFrame "frame".
404
-
405
- The movement is expressed wrt the axes of an external frame "other"
465
+ def move_relative_other_local(
466
+ self, frame: str, other: str, translation: np.ndarray, rotation: np.ndarray, degrees: bool = _DEGREES_DEFAULT
467
+ ):
468
+ """Applies a relative movement to the given reference frame.
406
469
 
407
- The center of rotation is the origin of the reference frame 'frame'.
470
+ The movement is expressed w.r.t. the axes of another reference frame. The centre of rotation is the origin of
471
+ that other reference frame.
408
472
 
409
- EQUIVALENT PunaSimulator.move_relative_user
473
+ Hexapod equivalent: PunaSimulator.move_relative_user
410
474
 
475
+ Args:
476
+ frame (str): Name of the reference frame to move.
477
+ other (str): Name of the reference frame in which the movements have been defined.
478
+ translation (np.ndarray): Translation vector.
479
+ rotation (np.ndarray): Rotation vector.
480
+ degrees (bool): Indicates whether the rotation angles are specified in degrees, rather than radians.
411
481
  """
412
482
 
413
483
  # TODO:
@@ -418,10 +488,9 @@ class ReferenceFrameModel:
418
488
  other = self._model[other]
419
489
 
420
490
  # Represent the requested movement
491
+ # De-rotation of MOVING -> REF (align frame_moving axes on those of frame_ref)
421
492
 
422
- # Derotation of MOVING --> REF (align frame_moving axes on those of frame_ref)
423
-
424
- derotation = frame.getActiveTransformationTo(other)
493
+ derotation = frame.get_active_transformation_to(other)
425
494
  derotation[:3, 3] = [0, 0, 0]
426
495
 
427
496
  # Reverse rotation (record inverse rotation, to restore the frame in the end)
@@ -436,24 +505,28 @@ class ReferenceFrameModel:
436
505
  # Requested rotation matrix (already expressed wrt frame_ref)
437
506
 
438
507
  zeros = [0, 0, 0]
439
- rotation_ = t3add.translationRotationToTransformation(zeros, rotation, rot_config=self._rot_config)
508
+ rotation_ = t3add.translation_rotation_to_transformation(
509
+ zeros, rotation, rotation_config=self._rot_config, degrees=degrees
510
+ )
440
511
 
441
512
  # All translations and rotations are applied to frame_moving
442
- # ==> a. need for "derotation" before applying the translation
443
- # b. the center or rotation is always the origin of frame_moving
444
- # 1. rotate frame_moving to align it with frame_ref (i.e. render their axes parallel)
445
- # 2. apply the translation in this frame
446
- # 3. restore the original orientation of the moving frame
447
- # 4. apply the requested rotation
513
+ # -> a. Need for "de-rotation" before applying the translation
514
+ # b. The centre of rotation is always the origin of frame_moving
515
+ # 1. Rotate frame_moving to align it with frame_ref (i.e. render their axes parallel)
516
+ # 2. Apply the translation in this frame
517
+ # 3. Restore the original orientation of the moving frame
518
+ # 4. Apply the requested rotation
448
519
 
449
520
  transformation = derotation @ translation_ @ rerotation @ rotation_
450
521
 
451
522
  # Apply the requested movement
452
523
 
453
- frame.applyTransformation(transformation, preserveLinks=True)
524
+ frame.apply_transformation(transformation, preserve_links=True)
454
525
 
455
526
 
456
- def plot_ref_model(model: ReferenceFrameModel):
527
+ def plot_ref_model(model: ReferenceFrameModel) -> None:
528
+ """Plots the xz-plane of the given reference frame model."""
529
+
457
530
  # figsize is in inch, 6 inch = 15.24 cm, 5 inch = 12.7 cm
458
531
 
459
532
  fig = plt.figure(figsize=(6, 5), dpi=100)
@@ -474,7 +547,9 @@ def plot_ref_model(model: ReferenceFrameModel):
474
547
  plt.show()
475
548
 
476
549
 
477
- def plot_ref_model_3d(model: ReferenceFrameModel):
550
+ def plot_ref_model_3d(model: ReferenceFrameModel) -> None:
551
+ """Plots the given reference frame model in 3D."""
552
+
478
553
  fig = plt.figure(figsize=(8, 8), dpi=100)
479
554
  ax = Axes3D(fig)
480
555
  # ax.set_box_aspect([1, 1, 1])
@@ -521,17 +596,16 @@ def plot_ref_model_3d(model: ReferenceFrameModel):
521
596
  plt.show()
522
597
 
523
598
 
524
- # The aspect ration of the plots is not equal by default.
525
- # This solution was given in SO: https://stackoverflow.com/a/63625222/4609203
599
+ def set_axes_equal(ax: plt.Axes) -> None:
600
+ """Sets 3D plot axes to equal scale.
526
601
 
602
+ Make axes of 3D plot have equal scale so that spheres appear as spheres and cubes as cubes. Required since
603
+ `ax.axis('equal')` and `ax.set_aspect('equal')` don't work on 3D.
527
604
 
528
- def set_axes_equal(ax: plt.Axes):
529
- """Set 3D plot axes to equal scale.
530
-
531
- Make axes of 3D plot have equal scale so that spheres appear as
532
- spheres and cubes as cubes. Required since `ax.axis('equal')`
533
- and `ax.set_aspect('equal')` don't work on 3D.
605
+ The aspect rati0 of the plots is not equal by default. This solution was given in Stack Overflow:
606
+ https://stackoverflow.com/a/63625222/4609203
534
607
  """
608
+
535
609
  limits = np.array([ax.get_xlim3d(), ax.get_ylim3d(), ax.get_zlim3d()])
536
610
  origin = np.mean(limits, axis=1)
537
611
  radius = 0.5 * np.max(np.abs(limits[:, 1] - limits[:, 0]))
@@ -541,23 +615,33 @@ def set_axes_equal(ax: plt.Axes):
541
615
  ax.set_zlim3d([z - radius, z + radius])
542
616
 
543
617
 
544
- def draw_frame_3d(ax: Axes3D, frame: ReferenceFrame, DEFAULT_AXIS_LENGTH=100, **kwargs):
618
+ def draw_frame_3d(ax: Axes3D, frame, **kwargs) -> None:
619
+ """Draws the given frame in 3D.
620
+
621
+ Args:
622
+ ax (Axes3D): Axis to draw the frame in.
623
+ frame (ReferenceFrame): Reference frame to draw.
624
+ **kwargs: Keyword arguments to pass to the quiver function.
625
+ """
626
+
545
627
  master = frame.find_master()
546
628
 
547
- f0 = frame.getOrigin()
548
- fx = frame.getAxis("x", name="fx")
549
- fy = frame.getAxis("y", name="fy")
550
- fz = frame.getAxis("z", name="fz")
551
- f0m = f0.expressIn(master)[:3]
552
- fxm = fx.expressIn(master)[:3]
553
- fym = fy.expressIn(master)[:3]
554
- fzm = fz.expressIn(master)[:3]
555
-
556
- # Origin of the X,Y and Z vectors (x = the 'x' coordinates of the origin of all 3 vectors)
557
- # Every vector independently (--> plot in diff. colors)
629
+ f0 = frame.get_origin()
630
+ fx = frame.get_axis("x", name="fx")
631
+ fy = frame.get_axis("y", name="fy")
632
+ fz = frame.get_axis("z", name="fz")
633
+ f0m = f0.express_in(master)[:3]
634
+ fxm = fx.express_in(master)[:3]
635
+ fym = fy.express_in(master)[:3]
636
+ fzm = fz.express_in(master)[:3]
637
+
638
+ # Origin of the x, y. and z vectors (x = the 'x' coordinates of the origin of all 3 vectors)
639
+ # Every vector independently (-> plot in different colours)
640
+
558
641
  x, y, z = np.array([f0m[0]]), np.array([f0m[1]]), np.array([f0m[2]])
559
642
 
560
- # Orientation of the X,Y and Z vectors
643
+ # Orientation of the x, y, and z vectors
644
+
561
645
  vecxx, vecyx, veczx = (
562
646
  np.array([fxm[0] - f0m[0]]),
563
647
  np.array([fym[0] - f0m[0]]),
@@ -585,7 +669,16 @@ def draw_frame_3d(ax: Axes3D, frame: ReferenceFrame, DEFAULT_AXIS_LENGTH=100, **
585
669
  ax.text(f0m[0] + offset, f0m[1] + offset, f0m[2] + offset, frame.name)
586
670
 
587
671
 
588
- def draw_frame(ax, frame: ReferenceFrame, plane="xz", DEFAULT_AXIS_LENGTH=100):
672
+ def draw_frame(ax: plt.Axes, reference_frame, plane="xz", default_axis_length: int = 100) -> None:
673
+ """Draws the given plane from the given reference frame in the given axis.
674
+
675
+ Args:
676
+ ax (plt.Axes): Axis to draw the plane in.
677
+ reference_frame (ReferenceFrame): Reference frame to draw.
678
+ plane (str, optional): Kind of plane to draw. Must be in ["xy", "yz", "zx"].
679
+ default_axis_length (int): Axis length.
680
+ """
681
+
589
682
  fig = ax.get_figure()
590
683
 
591
684
  # FC : Figure coordinates (pixels)
@@ -604,8 +697,8 @@ def draw_frame(ax, frame: ReferenceFrame, plane="xz", DEFAULT_AXIS_LENGTH=100):
604
697
 
605
698
  # Draw the origin
606
699
 
607
- origin = frame.getOrigin()
608
- origin_in_master = origin.expressIn(frame.find_master())
700
+ origin = reference_frame.get_origin()
701
+ origin_in_master = origin.express_in(reference_frame.find_master())
609
702
 
610
703
  ax.scatter([origin_in_master[x_idx]], [origin_in_master[y_idx]], color="k")
611
704
 
@@ -614,13 +707,13 @@ def draw_frame(ax, frame: ReferenceFrame, plane="xz", DEFAULT_AXIS_LENGTH=100):
614
707
  origin_dc = np.array([[origin_in_master[x_idx], origin_in_master[y_idx]]])
615
708
 
616
709
  point = dc2fc(origin_dc[0])
617
- point[0] += DEFAULT_AXIS_LENGTH
710
+ point[0] += default_axis_length
618
711
  target_dc = np.append(origin_dc, [fc2dc(point)], axis=0)
619
712
 
620
713
  ax.plot(target_dc[:, 0], target_dc[:, 1], color="k")
621
714
 
622
715
  point = dc2fc(origin_dc[0])
623
- point[1] += DEFAULT_AXIS_LENGTH
716
+ point[1] += default_axis_length
624
717
  target_dc = np.append(origin_dc, [fc2dc(point)], axis=0)
625
718
 
626
719
  ax.plot(target_dc[:, 0], target_dc[:, 1], color="k")
@@ -630,17 +723,23 @@ def draw_frame(ax, frame: ReferenceFrame, plane="xz", DEFAULT_AXIS_LENGTH=100):
630
723
  dx, dy = 10 / fig.dpi, 10 / fig.dpi
631
724
  offset = ScaledTranslation(dx, dy, fig.dpi_scale_trans)
632
725
  point = dc2ndc(origin_dc[0])
633
- plt.text(point[0], point[1], frame.name, transform=ax.transAxes + offset)
726
+ plt.text(point[0], point[1], reference_frame.name, transform=ax.transAxes + offset)
727
+
634
728
 
729
+ def define_the_initial_setup() -> ReferenceFrameModel:
730
+ """Defines the initial setup of the reference frame model.
731
+
732
+ Returns:
733
+ Reference frame model with the initial setup.
734
+ """
635
735
 
636
- def define_the_initial_setup():
637
736
  model = ReferenceFrameModel()
638
737
 
639
738
  model.add_master_frame()
640
- model.add_frame("A", translation=[2, 2, 2], rotation=[0, 0, 0], ref="Master")
641
- model.add_frame("B", translation=[-2, 2, 2], rotation=[0, 0, 0], ref="Master")
642
- model.add_frame("C", translation=[2, 2, 5], rotation=[0, 0, 0], ref="A")
643
- model.add_frame("D", translation=[2, 2, 2], rotation=[0, 0, 0], ref="B")
739
+ model.add_frame("A", translation=[2, 2, 2], rotation=[0, 0, 0], reference="Master")
740
+ model.add_frame("B", translation=[-2, 2, 2], rotation=[0, 0, 0], reference="Master")
741
+ model.add_frame("C", translation=[2, 2, 5], rotation=[0, 0, 0], reference="A")
742
+ model.add_frame("D", translation=[2, 2, 2], rotation=[0, 0, 0], reference="B")
644
743
 
645
744
  model.add_link("A", "B")
646
745
  model.add_link("B", "C")
@@ -651,28 +750,37 @@ def define_the_initial_setup():
651
750
  return model
652
751
 
653
752
 
654
- def get_vectors(rf1, rf2, model):
655
- """
656
- get_vectors(rf1,rf2, model)
657
- :param rf1: string : name of ref. frame "from"
658
- :param rf2: string : name of ref. frame "to"
659
- :param model: CSLReferenceFrameModel containing rf1 and rf2
660
- :return: translation and rotation vectors from rf1 to rf2
661
- """
662
- return model.get_frame(rf1).getActiveTranslationRotationVectorsTo(model.get_frame(rf2))
753
+ def get_vectors(reference_frame_1, reference_frame_2, model: ReferenceFrameModel) -> tuple[np.ndarray, np.ndarray]:
754
+ """Returns the translation and rotation vectors for the active transformation for the 1st reference frame to the 2nd.
663
755
 
756
+ Args:
757
+ reference_frame_1 (str): Name of the reference frame to get the active transformation from.
758
+ reference_frame_2 (str): Name of the reference frame to get the active transformation to.
759
+ model (ReferenceFrameModel): Model containing the reference frames with the given names.
664
760
 
665
- def print_vectors(rf1, rf2, model):
761
+ Returns:
762
+ Translation and rotation vectors from the active transformation from the 1st reference frame to the 2nd.
666
763
  """
667
- :param rf1: string : name of ref. frame "from"
668
- :param rf2: string : name of ref. frame "to"
669
- :param model: CSLReferenceFrameModel containing rf1 and rf2
670
- :return: N.A.
671
- Prints the translation and rotation vectors from rf1 to rf2
764
+
765
+ return model.get_frame(reference_frame_1).get_active_translation_rotation_vectors_to(
766
+ model.get_frame(reference_frame_2)
767
+ )
768
+
769
+
770
+ def print_vectors(reference_frame_1: str, reference_frame_2: str, model: ReferenceFrameModel) -> None:
771
+ """Prints the translation and rotation vectors for the active transformation for the 1st reference frame to the 2nd.
772
+
773
+ Args:
774
+ reference_frame_1 (str): Name of the reference frame to get the active transformation from.
775
+ reference_frame_2 (str): Name of the reference frame to get the active transformation to.
776
+ model (ReferenceFrameModel): Model containing the reference frames with the given names.
672
777
  """
673
- trans, rot = model.get_frame(rf1).getActiveTranslationRotationVectorsTo(model.get_frame(rf2))
778
+
779
+ trans, rot = model.get_frame(reference_frame_1).get_active_translation_rotation_vectors_to(
780
+ model.get_frame(reference_frame_2)
781
+ )
674
782
  print(
675
- f"{rf1:8s} -> {rf2:8s} : Trans [{trans[0]:11.4e}, {trans[1]:11.4e}, {trans[2]:11.4e}] Rot [{rot[0]:11.4e}, {rot[1]:11.4e}, {rot[2]:11.4e}]"
783
+ f"{reference_frame_1:8s} -> {reference_frame_2:8s} : Trans [{trans[0]:11.4e}, {trans[1]:11.4e}, {trans[2]:11.4e}] Rot [{rot[0]:11.4e}, {rot[1]:11.4e}, {rot[2]:11.4e}]"
676
784
  )
677
785
  return
678
786