c3d-parser 1.5.2__tar.gz → 1.5.3__tar.gz

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 (47) hide show
  1. {c3d_parser-1.5.2/src/c3d_parser.egg-info → c3d_parser-1.5.3}/PKG-INFO +2 -2
  2. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/requirements.txt +1 -1
  3. c3d_parser-1.5.3/src/c3d_parser/__init__.py +2 -0
  4. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/core/c3d_parser.py +20 -6
  5. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/core/osim_resources/ik_task_set.xml +6 -0
  6. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/view/main_window.py +15 -0
  7. {c3d_parser-1.5.2 → c3d_parser-1.5.3/src/c3d_parser.egg-info}/PKG-INFO +2 -2
  8. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser.egg-info/requires.txt +1 -1
  9. c3d_parser-1.5.2/src/c3d_parser/__init__.py +0 -2
  10. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/LICENSE +0 -0
  11. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/README.md +0 -0
  12. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/pyproject.toml +0 -0
  13. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/setup.cfg +0 -0
  14. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/application.py +0 -0
  15. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/core/c3d_patch.py +0 -0
  16. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/core/osim.py +0 -0
  17. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/core/osim_resources/external_loads_template.xml +0 -0
  18. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/core/utils.py +0 -0
  19. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/settings/general.py +0 -0
  20. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/settings/logging.py +0 -0
  21. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/settings/marker_maps/AUC.json +0 -0
  22. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/settings/marker_maps/FMC.json +0 -0
  23. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/settings/marker_maps/MH.json +0 -0
  24. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/settings/marker_maps/QCMAS.json +0 -0
  25. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/settings/marker_maps/RBWH.json +0 -0
  26. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/settings/marker_maps/RCH.json +0 -0
  27. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/settings/marker_maps/Sydney.json +0 -0
  28. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/splash_rc.py +0 -0
  29. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/splashscreen.py +0 -0
  30. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/view/dialogs/about_dialog.py +0 -0
  31. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/view/dialogs/delete_marker_set_dialog.py +0 -0
  32. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/view/dialogs/marker_set_dialog.py +0 -0
  33. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/view/dialogs/marker_set_import_dialog.py +0 -0
  34. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/view/dialogs/options_dialog.py +0 -0
  35. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/view/ui/resources_rc.py +0 -0
  36. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/view/ui/ui_delete_marker_set_dialog.py +0 -0
  37. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/view/ui/ui_main_window.py +0 -0
  38. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/view/ui/ui_marker_set_dialog.py +0 -0
  39. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/view/ui/ui_marker_set_import_dialog.py +0 -0
  40. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/view/ui/ui_options_dialog.py +0 -0
  41. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/view/utils.py +0 -0
  42. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser/view/widgets.py +0 -0
  43. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser.egg-info/SOURCES.txt +0 -0
  44. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser.egg-info/dependency_links.txt +0 -0
  45. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser.egg-info/entry_points.txt +0 -0
  46. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/src/c3d_parser.egg-info/top_level.txt +0 -0
  47. {c3d_parser-1.5.2 → c3d_parser-1.5.3}/tests/test_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: c3d-parser
3
- Version: 1.5.2
3
+ Version: 1.5.3
4
4
  Summary: C3D parser for gait data harmonisation.
5
5
  Author-email: Timothy Salemink <tim.nicolas@outlook.com>, Sally Jack <sallyjaack@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -12,7 +12,7 @@ Requires-Dist: numpy==1.26.4
12
12
  Requires-Dist: pandas
13
13
  Requires-Dist: c3d==0.5.2
14
14
  Requires-Dist: trc-data-reader>=0.4.1
15
- Requires-Dist: opensim-model-creator==0.8.1
15
+ Requires-Dist: opensim-model-creator==0.8.2
16
16
  Requires-Dist: PySide6
17
17
  Requires-Dist: matplotlib
18
18
  Requires-Dist: mplcursors
@@ -3,7 +3,7 @@ numpy==1.26.4
3
3
  pandas
4
4
  c3d==0.5.2
5
5
  trc-data-reader>=0.4.1
6
- opensim-model-creator==0.8.1
6
+ opensim-model-creator==0.8.2
7
7
  PySide6
8
8
  matplotlib
9
9
  mplcursors
@@ -0,0 +1,2 @@
1
+
2
+ __version__ = "1.5.3"
@@ -525,8 +525,10 @@ def trim_frames(frame_data):
525
525
  if not drop_frames.empty:
526
526
  frame_data.drop(drop_frames, inplace=True)
527
527
 
528
+ # TODO: If we convert this to a dictionary we can keep the markers that are missing and check if they are required.
528
529
  remaining_frames = [frame for frame in incomplete_frames.keys() if trim_start <= frame <= trim_end]
529
530
  if remaining_frames:
531
+ # TODO: We should raise a ParserError (skip this trial) if the missing markers are required...?
530
532
  logger.warn(f"Frames {remaining_frames} are incomplete.")
531
533
 
532
534
  return trim_start, trim_end
@@ -1090,6 +1092,8 @@ def scale_grf_data(analog_data):
1090
1092
  analog_data[columns] = analog_data[columns] / 1000
1091
1093
 
1092
1094
 
1095
+ # TODO: This incorrectly classifies Adelaide's static trials as dynamic.
1096
+ # Use `calculate_distance_covered` instead?
1093
1097
  def is_dynamic(file_path):
1094
1098
  with open(file_path, 'rb') as handle:
1095
1099
  try:
@@ -1265,6 +1269,11 @@ def normalise_kinetics(kinetic_data, events):
1265
1269
  normalised_data[foot][file_name] = {}
1266
1270
  data_segment = data.iloc[start:frame, 1:]
1267
1271
 
1272
+ # TODO: If the model +tve and -tve are wrong, then we can't just flip these.
1273
+ # Because the non-GRF parts of the moments would also be flipped.
1274
+ # Just visually check the results against some clinical kinetics.
1275
+ # ...
1276
+ # Looks pretty good so far.
1268
1277
  # Perform sign transformations.
1269
1278
  data_segment[f"hip_flexion_{side}_moment"] = -data_segment[f"hip_flexion_{side}_moment"]
1270
1279
  data_segment[f"hip_adduction_{side}_moment"] = -data_segment[f"hip_adduction_{side}_moment"]
@@ -1357,6 +1366,9 @@ def write_normalised_data(data, column_names, selected_trials, excluded_cycles,
1357
1366
  file.write('\n')
1358
1367
 
1359
1368
 
1369
+ # TODO: Rework this function to be less sequential.
1370
+ # It should be able to calculate metrics for walking and running gait.
1371
+ # Put this at the start of the sequential bit.
1360
1372
  def calculate_spatiotemporal_data(frame_data, events, static_data):
1361
1373
  stride_lengths = {"Left": {}, "Right": {}}
1362
1374
  step_lengths = {"Left": {}, "Right": {}}
@@ -1379,6 +1391,8 @@ def calculate_spatiotemporal_data(frame_data, events, static_data):
1379
1391
  for event_time, (event_type, event_plate) in stride_events.items():
1380
1392
  time_ordered_events[event_time][foot] = [event_type, stride_number]
1381
1393
 
1394
+ # TODO: We should be able to use this to calculate ALL measurements non-sequentially.
1395
+ # TODO: Double check that we don't have situations where the events are not ordered in increasing stride number.
1382
1396
  # Add terminal foot-strike to events for each cycle.
1383
1397
  full_cycle_events = copy.deepcopy(events)
1384
1398
  for foot, foot_events in full_cycle_events.items():
@@ -1617,13 +1631,13 @@ def add_medial_knee_markers(frame_data, left_knee_width, right_knee_width, marke
1617
1631
  This function takes a pandas.DataFrame of TRC data, extracts a single frame from the data
1618
1632
  and adds the medial knee markers if they are missing. It returns the frame as a pandas.Series.
1619
1633
 
1620
- The ``padding`` argument should include skin-padding as well as the thickness of the
1621
- baseplate used to attach the markers.
1634
+ The ``padding`` values are the thickness of the baseplate used to attach the markers. Knee
1635
+ widths are measured over the skin.
1622
1636
  """
1623
1637
  frame = frame_data.iloc[len(frame_data) // 2].copy()
1624
1638
 
1625
- medial_padding = 6
1626
- lateral_padding = 4
1639
+ medial_padding = 2
1640
+ lateral_padding = 2
1627
1641
 
1628
1642
  for side in ['L', 'R']:
1629
1643
  medial_label = f'{side}KNEM'
@@ -1637,7 +1651,7 @@ def add_medial_knee_markers(frame_data, left_knee_width, right_knee_width, marke
1637
1651
  magnitude = np.sqrt((np.array(axix_vector) ** 2.0).sum(-1))
1638
1652
  knee_axis = np.divide(axix_vector, magnitude)
1639
1653
 
1640
- # Adjust knee width to account for marker-radius, skin-padding.
1654
+ # Adjust knee width to account for marker-radius, baseplate.
1641
1655
  knee_width = left_knee_width if side == 'L' else right_knee_width
1642
1656
  knee_width = knee_width + marker_diameter + medial_padding + lateral_padding
1643
1657
  medial_marker = lateral_marker + knee_width * knee_axis
@@ -1654,7 +1668,7 @@ def create_osim_model(static_trc, dynamic_trc, static_marker_data, marker_diamet
1654
1668
  rotation_matrix = np.array([[1, 0, 0], [0, 0, 1], [0, -1, 0]])
1655
1669
  static_marker_data = {k: np.dot(rotation_matrix, v) for k, v in static_marker_data.items()}
1656
1670
  subject_info = get_subject_info(static_data)
1657
- marker_radius = marker_diameter / 2
1671
+ marker_radius = marker_diameter / 2 + 2 # Include the 2mm marker baseplate.
1658
1672
 
1659
1673
  model_path = create_model(static_trc, dynamic_trc, output_directory, static_marker_data, subject_info,
1660
1674
  marker_radius, left_foot_flat, right_foot_flat,
@@ -74,6 +74,12 @@
74
74
  <!--Weight given to the task when solving inverse kinematics problems, default is 0.-->
75
75
  <weight>1</weight>
76
76
  </IKMarkerTask>
77
+ <IKMarkerTask name="SACR">
78
+ <!--Whether or not this task will be used during inverse kinematics solve, default is true.-->
79
+ <apply>true</apply>
80
+ <!--Weight given to the task when solving inverse kinematics problems, default is 0.-->
81
+ <weight>2</weight>
82
+ </IKMarkerTask>
77
83
  <IKMarkerTask name="RHEE">
78
84
  <!--Whether or not this task will be used during inverse kinematics solve, default is true.-->
79
85
  <apply>true</apply>
@@ -57,6 +57,7 @@ class ProgressTracker(QObject):
57
57
  progress = Signal(str, str)
58
58
 
59
59
 
60
+ # TODO: CGM2 event detector on GitHub...?
60
61
  class MainWindow(QMainWindow):
61
62
 
62
63
  def __init__(self):
@@ -258,6 +259,12 @@ class MainWindow(QMainWindow):
258
259
  table.deleteLater()
259
260
  self._spatiotemporal_tables = []
260
261
 
262
+ # TODO: The legend is not correctly displayed if the ST tab is open while processing...
263
+ # Repositioning and updating the legend do nothing.
264
+
265
+ # TODO: The border is still having issues.
266
+ # Seems to be related to the area being scrollable.
267
+ # Only happens on some PCs/monitors...
261
268
  def _visualise_spatiotemporal_data(self):
262
269
 
263
270
  # Temporarily disable spatio-temporal visualisation for running gait.
@@ -903,6 +910,8 @@ class MainWindow(QMainWindow):
903
910
  if (file_name, f"{foot}_{cycle_number}") not in excluded_cycles:
904
911
  counts[foot] += 1
905
912
 
913
+ # TODO: This is being displayed before processing has finished.
914
+ # Which should not be happening.
906
915
  self._ui.labelCount.setText(f"Cycles: L {counts['Left']} / R {counts['Right']}")
907
916
 
908
917
  tab = self._ui.tabWidget.currentWidget()
@@ -930,6 +939,7 @@ class MainWindow(QMainWindow):
930
939
  self._update_s_t_colours()
931
940
  self._update_legend()
932
941
 
942
+ # TODO: For some reason the legend doesn't get created at all if we are visualising the ST tab while processing...
933
943
  def _update_legend(self):
934
944
  if self._boxes:
935
945
  for side, boxes in self._boxes.items():
@@ -1021,6 +1031,8 @@ class MainWindow(QMainWindow):
1021
1031
  settings.beginGroup('MainWindow')
1022
1032
  settings.setValue('size', self.size())
1023
1033
  settings.setValue('pos', self.pos())
1034
+ # TODO: The taskbar icon fails if the application opens in full-screen...
1035
+ # DON'T open in full screen...?
1024
1036
  settings.setValue('is_maximized', self.isMaximized())
1025
1037
  settings.setValue('lab', self._ui.comboBoxLab.currentText())
1026
1038
  settings.setValue('marker_diameter', self._ui.doubleSpinBoxMarkerDiameter.value())
@@ -1225,6 +1237,9 @@ class GaitCurves(defaultdict):
1225
1237
  line.set_color(colour)
1226
1238
  line.set_zorder(z_order)
1227
1239
 
1240
+ # TODO: Replace all these with `draw_idle`?
1241
+ # Just the ones that handle many curves...?
1242
+ # Probably all...?
1228
1243
  self._canvas.draw()
1229
1244
 
1230
1245
  def show_curve_menu(self, event):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: c3d-parser
3
- Version: 1.5.2
3
+ Version: 1.5.3
4
4
  Summary: C3D parser for gait data harmonisation.
5
5
  Author-email: Timothy Salemink <tim.nicolas@outlook.com>, Sally Jack <sallyjaack@gmail.com>
6
6
  License-Expression: Apache-2.0
@@ -12,7 +12,7 @@ Requires-Dist: numpy==1.26.4
12
12
  Requires-Dist: pandas
13
13
  Requires-Dist: c3d==0.5.2
14
14
  Requires-Dist: trc-data-reader>=0.4.1
15
- Requires-Dist: opensim-model-creator==0.8.1
15
+ Requires-Dist: opensim-model-creator==0.8.2
16
16
  Requires-Dist: PySide6
17
17
  Requires-Dist: matplotlib
18
18
  Requires-Dist: mplcursors
@@ -3,7 +3,7 @@ numpy==1.26.4
3
3
  pandas
4
4
  c3d==0.5.2
5
5
  trc-data-reader>=0.4.1
6
- opensim-model-creator==0.8.1
6
+ opensim-model-creator==0.8.2
7
7
  PySide6
8
8
  matplotlib
9
9
  mplcursors
@@ -1,2 +0,0 @@
1
-
2
- __version__ = "1.5.2"
File without changes
File without changes
File without changes
File without changes