c3d-parser 1.3.0__tar.gz → 1.4.0__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.
- {c3d_parser-1.3.0/src/c3d_parser.egg-info → c3d_parser-1.4.0}/PKG-INFO +1 -1
- c3d_parser-1.4.0/src/c3d_parser/__init__.py +2 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/core/c3d_parser.py +50 -21
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/view/main_window.py +33 -29
- {c3d_parser-1.3.0 → c3d_parser-1.4.0/src/c3d_parser.egg-info}/PKG-INFO +1 -1
- c3d_parser-1.3.0/src/c3d_parser/__init__.py +0 -2
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/LICENSE +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/README.md +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/pyproject.toml +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/requirements.txt +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/setup.cfg +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/application.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/core/c3d_patch.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/core/osim.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/core/osim_resources/external_loads_template.xml +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/core/osim_resources/ik_task_set.xml +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/core/utils.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/settings/general.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/settings/logging.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/settings/marker_maps/AUC.json +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/settings/marker_maps/FMC.json +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/settings/marker_maps/MH.json +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/settings/marker_maps/QCMAS.json +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/settings/marker_maps/RBWH.json +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/settings/marker_maps/RCH.json +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/settings/marker_maps/Sydney.json +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/splash_rc.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/splashscreen.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/view/dialogs/about_dialog.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/view/dialogs/delete_marker_set_dialog.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/view/dialogs/marker_set_dialog.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/view/dialogs/marker_set_import_dialog.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/view/dialogs/options_dialog.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/view/ui/resources_rc.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/view/ui/ui_delete_marker_set_dialog.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/view/ui/ui_main_window.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/view/ui/ui_marker_set_dialog.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/view/ui/ui_marker_set_import_dialog.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/view/ui/ui_options_dialog.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/view/utils.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/view/widgets.py +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser.egg-info/SOURCES.txt +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser.egg-info/dependency_links.txt +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser.egg-info/entry_points.txt +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser.egg-info/requires.txt +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser.egg-info/top_level.txt +0 -0
- {c3d_parser-1.3.0 → c3d_parser-1.4.0}/tests/test_parser.py +0 -0
|
@@ -16,6 +16,7 @@ from decimal import Decimal, ROUND_CEILING, ROUND_FLOOR
|
|
|
16
16
|
|
|
17
17
|
from trc import TRCData
|
|
18
18
|
from opensim_model_creator.Create_Model import create_model
|
|
19
|
+
from ll_visualiser.utils import get_fit_metrics, load_landmarks, define_measurements
|
|
19
20
|
|
|
20
21
|
from c3d_parser.core.c3d_patch import c3d
|
|
21
22
|
from c3d_parser.core.utils import clear_directory
|
|
@@ -82,13 +83,13 @@ def parse_session(static_trial, dynamic_trials, input_directory, output_director
|
|
|
82
83
|
grf_file_paths[trial] = grf_file_path
|
|
83
84
|
deidentified_file_names[trial] = os.path.basename(trc_file_path).rsplit(".", 1)[0]
|
|
84
85
|
|
|
85
|
-
write_c3d_parser_history(input_directory, static_trial, deidentified_file_names)
|
|
86
|
-
|
|
87
86
|
logger.info("Fitting shape model.")
|
|
88
87
|
dynamic_trc_path = list(trc_file_paths.values())[0] if trc_file_paths else ""
|
|
89
88
|
osim_model = create_osim_model(static_trc_path, dynamic_trc_path, frame, marker_diameter, static_data,
|
|
90
89
|
output_directory, left_foot_flat, right_foot_flat, optimise_knee_axis, progress_tracker)
|
|
91
90
|
|
|
91
|
+
write_c3d_parser_history(input_directory, output_directory, static_trial, deidentified_file_names, static_data)
|
|
92
|
+
|
|
92
93
|
if not trc_file_paths:
|
|
93
94
|
raise CancelException("No dynamic trials found.")
|
|
94
95
|
|
|
@@ -236,7 +237,7 @@ def parse_dynamic_trial(c3d_file, lab, output_directory, trial_index, marker_dat
|
|
|
236
237
|
return analog_data, events, s_t_data, trc_file_path, grf_file_path
|
|
237
238
|
|
|
238
239
|
|
|
239
|
-
def write_c3d_parser_history(input_directory, static_trial, deidentified_file_names):
|
|
240
|
+
def write_c3d_parser_history(input_directory, output_directory, static_trial, deidentified_file_names, static_data):
|
|
240
241
|
log_path = os.path.join(input_directory, "c3d_parser_history.log")
|
|
241
242
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M")
|
|
242
243
|
|
|
@@ -251,11 +252,56 @@ def write_c3d_parser_history(input_directory, static_trial, deidentified_file_na
|
|
|
251
252
|
f.write("Deidentified file names:\n")
|
|
252
253
|
for original_name, updated_name in deidentified_file_names.items():
|
|
253
254
|
f.write(f"{original_name}: {updated_name}\n")
|
|
255
|
+
f.write("\n")
|
|
256
|
+
|
|
257
|
+
if static_data:
|
|
258
|
+
units = {
|
|
259
|
+
"Height": "mm",
|
|
260
|
+
"Weight": "kg",
|
|
261
|
+
"ASIS Width": "mm",
|
|
262
|
+
"Left Knee Width": "mm",
|
|
263
|
+
"Right Knee Width": "mm",
|
|
264
|
+
"Left Ankle Width": "mm",
|
|
265
|
+
"Right Ankle Width": "mm",
|
|
266
|
+
"Left Leg Length": "mm",
|
|
267
|
+
"Right Leg Length": "mm",
|
|
268
|
+
}
|
|
269
|
+
f.write("Subject Information:\n")
|
|
270
|
+
for key, value in static_data.items():
|
|
271
|
+
label = "Body Mass" if key == "Weight" else key
|
|
272
|
+
unit = f" {units[key]}" if key in units else ""
|
|
273
|
+
f.write(f"{label}: {value}{unit}\n")
|
|
274
|
+
|
|
275
|
+
metrics, measurements = define_metrics_and_measurements(output_directory)
|
|
276
|
+
if metrics:
|
|
277
|
+
f.write("\n")
|
|
278
|
+
f.write("ASM Fit Metrics:\n")
|
|
279
|
+
for key, value in metrics.items():
|
|
280
|
+
f.write(f"{key}: {value} mm\n")
|
|
281
|
+
if measurements:
|
|
282
|
+
f.write("\n")
|
|
283
|
+
f.write("Bone Surface Measurements:\n")
|
|
284
|
+
for key, value in measurements.items():
|
|
285
|
+
f.write(f"{key}: {value} mm\n")
|
|
254
286
|
|
|
255
287
|
except (OSError, IOError):
|
|
256
288
|
raise ParserError("Could not write c3d_parser_history.log")
|
|
257
289
|
|
|
258
290
|
|
|
291
|
+
def define_metrics_and_measurements(output_directory):
|
|
292
|
+
model_directory = os.path.join(output_directory, "Models", "Meshes")
|
|
293
|
+
left_predicted_landmark_file = os.path.join(model_directory, 'predicted_lms_left.txt')
|
|
294
|
+
right_predicted_landmark_file = os.path.join(model_directory, 'predicted_lms_right.txt')
|
|
295
|
+
|
|
296
|
+
left_predicted_landmarks = load_landmarks(left_predicted_landmark_file)
|
|
297
|
+
right_predicted_landmarks = load_landmarks(right_predicted_landmark_file)
|
|
298
|
+
|
|
299
|
+
metrics = get_fit_metrics(model_directory)
|
|
300
|
+
measurements = define_measurements(left_predicted_landmarks, right_predicted_landmarks)
|
|
301
|
+
|
|
302
|
+
return metrics, measurements
|
|
303
|
+
|
|
304
|
+
|
|
259
305
|
def write_event_data(events, file_name, output_directory):
|
|
260
306
|
event_directory = os.path.join(output_directory, "events")
|
|
261
307
|
if not os.path.exists(event_directory):
|
|
@@ -421,8 +467,6 @@ def harmonise_markers(frame_data, lab, required_markers):
|
|
|
421
467
|
if None in frame_data.columns:
|
|
422
468
|
frame_data.drop(columns=frame_data.columns[frame_data.columns.isna()], inplace=True)
|
|
423
469
|
|
|
424
|
-
# TODO: This error window does not indicate which trial has the issue.
|
|
425
|
-
# Update this.
|
|
426
470
|
# Ensure required markers are present.
|
|
427
471
|
available = set(frame_data.columns)
|
|
428
472
|
for item in required_markers:
|
|
@@ -478,10 +522,8 @@ def trim_frames(frame_data):
|
|
|
478
522
|
if not drop_frames.empty:
|
|
479
523
|
frame_data.drop(drop_frames, inplace=True)
|
|
480
524
|
|
|
481
|
-
# TODO: If we convert this to a dictionary we can keep the markers that are missing and check if they are required.
|
|
482
525
|
remaining_frames = [frame for frame in incomplete_frames.keys() if trim_start <= frame <= trim_end]
|
|
483
526
|
if remaining_frames:
|
|
484
|
-
# TODO: We should raise a ParserError (skip this trial) if the missing markers are required...?
|
|
485
527
|
logger.warn(f"Frames {remaining_frames} are incomplete.")
|
|
486
528
|
|
|
487
529
|
return trim_start, trim_end
|
|
@@ -1045,8 +1087,6 @@ def scale_grf_data(analog_data):
|
|
|
1045
1087
|
analog_data[columns] = analog_data[columns] / 1000
|
|
1046
1088
|
|
|
1047
1089
|
|
|
1048
|
-
# TODO: This incorrectly classifies Adelaide's static trials as dynamic.
|
|
1049
|
-
# Use `calculate_distance_covered`...?
|
|
1050
1090
|
def is_dynamic(file_path):
|
|
1051
1091
|
with open(file_path, 'rb') as handle:
|
|
1052
1092
|
try:
|
|
@@ -1222,11 +1262,6 @@ def normalise_kinetics(kinetic_data, events):
|
|
|
1222
1262
|
normalised_data[foot][file_name] = {}
|
|
1223
1263
|
data_segment = data.iloc[start:frame, 1:]
|
|
1224
1264
|
|
|
1225
|
-
# TODO: If the model +tve and -tve are wrong, then we can't just flip these.
|
|
1226
|
-
# Because the non-GRF parts of the moments would also be flipped.
|
|
1227
|
-
# Just visually check the results against some clinical kinetics.
|
|
1228
|
-
# ...
|
|
1229
|
-
# Looks pretty good so far.
|
|
1230
1265
|
# Perform sign transformations.
|
|
1231
1266
|
data_segment[f"hip_flexion_{side}_moment"] = -data_segment[f"hip_flexion_{side}_moment"]
|
|
1232
1267
|
data_segment[f"hip_adduction_{side}_moment"] = -data_segment[f"hip_adduction_{side}_moment"]
|
|
@@ -1250,13 +1285,12 @@ def normalise_kinetics(kinetic_data, events):
|
|
|
1250
1285
|
return normalised_data
|
|
1251
1286
|
|
|
1252
1287
|
|
|
1253
|
-
def write_normalised_grfs(grf_data, selected_trials, output_directory):
|
|
1288
|
+
def write_normalised_grfs(grf_data, selected_trials, excluded_cycles, output_directory):
|
|
1254
1289
|
normalised_directory = os.path.join(output_directory, 'normalised')
|
|
1255
1290
|
if not os.path.exists(normalised_directory):
|
|
1256
1291
|
os.makedirs(normalised_directory)
|
|
1257
1292
|
output_file = os.path.join(normalised_directory, f"combined_grf.csv")
|
|
1258
1293
|
columns = ['anterior_posterior', 'medial_lateral', 'vertical']
|
|
1259
|
-
excluded_cycles = set()
|
|
1260
1294
|
write_normalised_data(grf_data, columns, selected_trials, excluded_cycles, output_file)
|
|
1261
1295
|
|
|
1262
1296
|
|
|
@@ -1314,9 +1348,6 @@ def write_normalised_data(data, column_names, selected_trials, excluded_cycles,
|
|
|
1314
1348
|
file.write('\n')
|
|
1315
1349
|
|
|
1316
1350
|
|
|
1317
|
-
# TODO: Rework this function to be less sequential.
|
|
1318
|
-
# It should be able to calculate metrics for walking and running gait.
|
|
1319
|
-
# Put this at the start of the sequential bit.
|
|
1320
1351
|
def calculate_spatiotemporal_data(frame_data, events, static_data):
|
|
1321
1352
|
stride_lengths = {"Left": {}, "Right": {}}
|
|
1322
1353
|
step_lengths = {"Left": {}, "Right": {}}
|
|
@@ -1339,8 +1370,6 @@ def calculate_spatiotemporal_data(frame_data, events, static_data):
|
|
|
1339
1370
|
for event_time, (event_type, event_plate) in stride_events.items():
|
|
1340
1371
|
time_ordered_events[event_time][foot] = [event_type, stride_number]
|
|
1341
1372
|
|
|
1342
|
-
# TODO: We should be able to use this to calculate ALL measurements non-sequentially.
|
|
1343
|
-
# TODO: Double check that we don't have situations where the events are not ordered in increasing stride number.
|
|
1344
1373
|
# Add terminal foot-strike to events for each cycle.
|
|
1345
1374
|
full_cycle_events = copy.deepcopy(events)
|
|
1346
1375
|
for foot, foot_events in full_cycle_events.items():
|
|
@@ -57,7 +57,6 @@ class ProgressTracker(QObject):
|
|
|
57
57
|
progress = Signal(str, str)
|
|
58
58
|
|
|
59
59
|
|
|
60
|
-
# TODO: CGM2 event detector on GitHub...?
|
|
61
60
|
class MainWindow(QMainWindow):
|
|
62
61
|
|
|
63
62
|
def __init__(self):
|
|
@@ -72,7 +71,7 @@ class MainWindow(QMainWindow):
|
|
|
72
71
|
self._line_width = 1.0
|
|
73
72
|
self._input_data_directory = ''
|
|
74
73
|
self._output_data_directory = ''
|
|
75
|
-
self._optimise_knee_axis =
|
|
74
|
+
self._optimise_knee_axis = False
|
|
76
75
|
self._filter_trc = True
|
|
77
76
|
self._filter_grf = True
|
|
78
77
|
self._use_custom_ik_task_set = False
|
|
@@ -112,6 +111,13 @@ class MainWindow(QMainWindow):
|
|
|
112
111
|
self._kinetic_curves = GaitCurves(self._kinetic_canvas, colours)
|
|
113
112
|
self._boxes = None
|
|
114
113
|
|
|
114
|
+
self._kinematic_curves.signals.cycles_excluded.connect(self._kinetic_curves.exclude_cycles)
|
|
115
|
+
self._kinematic_curves.signals.cycles_excluded.connect(self._grf_curves.exclude_cycles)
|
|
116
|
+
self._kinematic_curves.signals.cycles_included.connect(self._kinetic_curves.include_cycles)
|
|
117
|
+
self._kinematic_curves.signals.cycles_included.connect(self._grf_curves.include_cycles)
|
|
118
|
+
self._kinetic_curves.signals.cycles_excluded.connect(self._grf_curves.exclude_cycles)
|
|
119
|
+
self._kinetic_curves.signals.cycles_included.connect(self._grf_curves.include_cycles)
|
|
120
|
+
|
|
115
121
|
def _setup_progress_bar(self):
|
|
116
122
|
self._progress_text = ""
|
|
117
123
|
self._progress_value = 0
|
|
@@ -248,12 +254,6 @@ class MainWindow(QMainWindow):
|
|
|
248
254
|
table.deleteLater()
|
|
249
255
|
self._spatiotemporal_tables = []
|
|
250
256
|
|
|
251
|
-
# TODO: The legend is not correctly displayed if the ST tab is open while processing...
|
|
252
|
-
# Repositioning and updating the legend do nothing.
|
|
253
|
-
|
|
254
|
-
# TODO: The border is still having issues.
|
|
255
|
-
# Seems to be related to the area being scrollable.
|
|
256
|
-
# Only happens on some PCs/monitors...
|
|
257
257
|
def _visualise_spatiotemporal_data(self):
|
|
258
258
|
|
|
259
259
|
# Temporarily disable spatio-temporal visualisation for running gait.
|
|
@@ -684,8 +684,9 @@ class MainWindow(QMainWindow):
|
|
|
684
684
|
selected_trials = {key: value for key, value in self._deidentified_file_names.items() if key in selected}
|
|
685
685
|
kinematic_exclusions = self._kinematic_curves.get_excluded_cycles()
|
|
686
686
|
kinetic_exclusions = self._kinetic_curves.get_excluded_cycles()
|
|
687
|
+
grf_exclusions = self._grf_curves.get_excluded_cycles()
|
|
687
688
|
self._update_s_t_data_from_tables()
|
|
688
|
-
write_normalised_grfs(self._grf_data, selected_trials, self._output_directory)
|
|
689
|
+
write_normalised_grfs(self._grf_data, selected_trials, grf_exclusions, self._output_directory)
|
|
689
690
|
write_normalised_kinematics(self._kinematic_data, selected_trials, kinematic_exclusions, self._output_directory)
|
|
690
691
|
write_normalised_kinetics(self._kinetic_data, selected_trials, kinetic_exclusions, self._output_directory)
|
|
691
692
|
write_spatiotemporal_data(self._s_t_data, selected_trials, self._output_directory)
|
|
@@ -887,7 +888,6 @@ class MainWindow(QMainWindow):
|
|
|
887
888
|
self._update_s_t_colours()
|
|
888
889
|
self._update_legend()
|
|
889
890
|
|
|
890
|
-
# TODO: For some reason the legend doesn't get created at all if we are visualising the ST tab while processing...
|
|
891
891
|
def _update_legend(self):
|
|
892
892
|
if self._boxes:
|
|
893
893
|
for side, boxes in self._boxes.items():
|
|
@@ -979,8 +979,6 @@ class MainWindow(QMainWindow):
|
|
|
979
979
|
settings.beginGroup('MainWindow')
|
|
980
980
|
settings.setValue('size', self.size())
|
|
981
981
|
settings.setValue('pos', self.pos())
|
|
982
|
-
# TODO: The taskbar icon fails if the application opens in full-screen...
|
|
983
|
-
# DON'T open in full screen...?
|
|
984
982
|
settings.setValue('is_maximized', self.isMaximized())
|
|
985
983
|
settings.setValue('lab', self._ui.comboBoxLab.currentText())
|
|
986
984
|
settings.setValue('marker_diameter', self._ui.doubleSpinBoxMarkerDiameter.value())
|
|
@@ -1098,6 +1096,11 @@ class MainWindow(QMainWindow):
|
|
|
1098
1096
|
curves.exclude_side(file_name, "Right")
|
|
1099
1097
|
|
|
1100
1098
|
|
|
1099
|
+
class CurveSignals(QObject):
|
|
1100
|
+
cycles_included = Signal(list)
|
|
1101
|
+
cycles_excluded = Signal(list)
|
|
1102
|
+
|
|
1103
|
+
|
|
1101
1104
|
class GaitCurves(defaultdict):
|
|
1102
1105
|
|
|
1103
1106
|
def __init__(self, canvas, colours):
|
|
@@ -1107,6 +1110,8 @@ class GaitCurves(defaultdict):
|
|
|
1107
1110
|
self._canvas.mpl_connect('pick_event', lambda event: self.toggle_cycle(event))
|
|
1108
1111
|
self._canvas.mpl_connect('button_press_event', lambda event: self.show_curve_menu(event))
|
|
1109
1112
|
|
|
1113
|
+
self.signals = CurveSignals()
|
|
1114
|
+
|
|
1110
1115
|
self._selected_curves = []
|
|
1111
1116
|
self._excluded_cycles = set()
|
|
1112
1117
|
|
|
@@ -1173,9 +1178,6 @@ class GaitCurves(defaultdict):
|
|
|
1173
1178
|
line.set_color(colour)
|
|
1174
1179
|
line.set_zorder(z_order)
|
|
1175
1180
|
|
|
1176
|
-
# TODO: Replace all these with `draw_idle`?
|
|
1177
|
-
# Just the ones that handle many curves...?
|
|
1178
|
-
# Probably all...?
|
|
1179
1181
|
self._canvas.draw()
|
|
1180
1182
|
|
|
1181
1183
|
def show_curve_menu(self, event):
|
|
@@ -1201,15 +1203,16 @@ class GaitCurves(defaultdict):
|
|
|
1201
1203
|
context_menu.exec_(self._canvas.mapToGlobal(point))
|
|
1202
1204
|
|
|
1203
1205
|
def include_curves(self):
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
colour = self._colour_left if "Left" in cycle else self._colour_right
|
|
1207
|
-
for line in self[file_name][cycle]:
|
|
1208
|
-
line.set_linestyle('solid')
|
|
1209
|
-
line.set_color(colour)
|
|
1210
|
-
line.set_zorder(2)
|
|
1206
|
+
identifiers = list(self._selected_curves)
|
|
1207
|
+
self.include_cycles(identifiers)
|
|
1211
1208
|
self._selected_curves = []
|
|
1212
1209
|
|
|
1210
|
+
self.signals.cycles_included.emit(identifiers)
|
|
1211
|
+
|
|
1212
|
+
def include_cycles(self, identifiers):
|
|
1213
|
+
for file_name, cycle in identifiers:
|
|
1214
|
+
colour = self._colour_left if "Left" in cycle else self._colour_right
|
|
1215
|
+
self._include_cycle(file_name, cycle, colour)
|
|
1213
1216
|
self._canvas.draw()
|
|
1214
1217
|
|
|
1215
1218
|
def include_all(self):
|
|
@@ -1261,15 +1264,16 @@ class GaitCurves(defaultdict):
|
|
|
1261
1264
|
self._canvas.draw_idle()
|
|
1262
1265
|
|
|
1263
1266
|
def exclude_curves(self):
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
colour = self._colour_left if "Left" in cycle else self._colour_right
|
|
1267
|
-
for line in self[file_name][cycle]:
|
|
1268
|
-
line.set_linestyle('dotted')
|
|
1269
|
-
line.set_color(colour)
|
|
1270
|
-
line.set_zorder(1)
|
|
1267
|
+
identifiers = list(self._selected_curves)
|
|
1268
|
+
self.exclude_cycles(identifiers)
|
|
1271
1269
|
self._selected_curves = []
|
|
1272
1270
|
|
|
1271
|
+
self.signals.cycles_excluded.emit(identifiers)
|
|
1272
|
+
|
|
1273
|
+
def exclude_cycles(self, identifiers):
|
|
1274
|
+
for file_name, cycle in identifiers:
|
|
1275
|
+
colour = self._colour_left if "Left" in cycle else self._colour_right
|
|
1276
|
+
self._exclude_cycle(file_name, cycle, colour)
|
|
1273
1277
|
self._canvas.draw()
|
|
1274
1278
|
|
|
1275
1279
|
def exclude_all(self):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/core/osim_resources/external_loads_template.xml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/view/dialogs/delete_marker_set_dialog.py
RENAMED
|
File without changes
|
|
File without changes
|
{c3d_parser-1.3.0 → c3d_parser-1.4.0}/src/c3d_parser/view/dialogs/marker_set_import_dialog.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|