diff --git a/Applications/Analyze/test/arm26.osim b/Applications/Analyze/test/arm26.osim index be21429846..178c667fe4 100644 --- a/Applications/Analyze/test/arm26.osim +++ b/Applications/Analyze/test/arm26.osim @@ -1,1320 +1,1484 @@ - + - - - - - - - ground - - 1 1 1 - - - - 1 - - 1 1 1 - - - ground_ribs.vtp - - - - ground - - 1 1 1 - - - - 1 - - 1 1 1 - - - ground_spine.vtp - - - - ground - - 1 1 1 - - - - 1 - - 1 1 1 - - - ground_skull.vtp - - - - ground - - 1 1 1 - - - - 1 - - 1 1 1 - - - ground_jaw.vtp - - - - ground - - 1 1 1 - - - - 1 - - 1 1 1 - - - ground_r_clavicle.vtp - - - - ground - - 1 1 1 - - - - 1 - - 1 1 1 - - - ground_r_scapula.vtp - - - - - - - - true - - 1.3753194500000001 -0.29461157999999998 2.4359560400000002 - - -0.043905 -0.0038999999999999998 0.14779999999999999 - - x - - 0.0030000000000000001 - - 0.029999999999999999 - - - - - - - 0 -9.8065999999999995 0 - The OpenSim Development Team (Reinbolt, J; Seth, A; Habib, A; Hamner, S) - This is an example model distributed with OpenSim - meters - N - + + 0 -9.8066 0 + + + 0 + 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + + + + ground_ribs.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + ground_spine.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + ground_skull.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + ground_jaw.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + ground_r_clavicle.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + ground_r_scapula.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + + + 1 1 1 + + -0 0 -0 0 0 0 + + false + + 4 + + + + + 1.37532 -0.294612 2.43596 + -0.043905 -0.0039 0.1478 + true + x + + + + + + + + 1 1 1 + + 1.37532 -0.294612 2.43596 -0.043905 -0.0039 0.1478 + + false + + 4 + + 0.003 + 0.03 + + + + + - - - - - r_humerus - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_humerus.vtp - - - + 1.864572 + 0 -0.180496 0 + 0.01481 + 0.004551 + 0.013193 + 0 + 0 + 0 + + + + + ground + + -0.017545 -0.007 0.17 + + 0 0 0 + + 0 0 0 + + 0 0 0 + + + + + + rotational + + 0 + + 0 + + -1.57079633 3.14159265 + + false + + false + + + + false + + + + + + false + + + + + + r_shoulder_elev + + -0.05889802 0.0023 0.99826136 + + + + 1 0 + + + + + + + + 0 1 0 + + + + 0 + + + + + + + + 0.99826136 -0 0.05889802 + + + + 0 + + + + + + + + + 1 0 0 + + + + 0 + + + + + + + + 0 1 0 + + + + 0 + + + + + + + + 0 0 1 + + + + 0 + + + + + + + + + + + + + arm_r_humerus.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + + + 1 1 1 + + -0 0 -0 0 0 0 + + false + + 4 + - + 3.00162 -0.853466 2.57419 + -0.0078 -0.0041 -0.0014 true - - 3.0016172499999998 -0.85346599999999995 2.5741861099999999 - - -0.0077999999999999996 -0.0041000000000000003 -0.0014 - z + + + + + + + + 1 1 1 + + 3.00162 -0.853466 2.57419 -0.0078 -0.0041 -0.0014 + + false + + 4 + 0.035 0.02 0.02 - + -2.00434 -1.00164 0.975465 + 0.0033 0.0073 0.0003 true - - -2.0043361100000001 -1.0016444600000001 0.97546451999999995 - - 0.0033 0.0073000000000000001 0.00029999999999999997 - -y + + + + + + + + 1 1 1 + + -2.00434 -1.00164 0.975465 0.0033 0.0073 0.0003 + + false + + 4 + 0.025 0.02 0.02 - + -0.14015 -0.00628319 0.154985 + 0.0028 -0.2919 -0.0069 true - - -0.14014994 -0.0062831900000000001 0.15498524 - - 0.0028 -0.29189999999999999 -0.0068999999999999999 - all - + + + + + + + + 1 1 1 + + -0.14015 -0.00628319 0.154985 0.0028 -0.2919 -0.0069 + + false + + 4 + 0.016 - - 0.050000000000000003 + 0.05 - - 1.8645719999999999 - - 0 -0.18049599999999999 0 - - 0.01481 0.0045510000000000004 0.013193 0 0 0 - - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_ulna.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_radius.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_lunate.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_scaphoid.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_pisiform.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_triquetrum.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_capitate.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_trapezium.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_trapezoid.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_hamate.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_1mc.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_2mc.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_3mc.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_4mc.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_5mc.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_thumbprox.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_thumbdist.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_2proxph.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_2midph.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_2distph.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_3proxph.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_3midph.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_3distph.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_4proxph.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_4midph.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_4distph.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_5proxph.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_5midph.vtp - - - - r_ulna_radius_hand - - 1 1 1 - - - - 1 - - 1 1 1 - - - arm_r_5distph.vtp - - - + 1.534315 + 0 -0.181479 0 + 0.019281 + 0.001571 + 0.020062 + 0 + 0 + 0 + + + + + r_humerus + + 0.0061 -0.2904 -0.0123 + + 0 0 0 + + 0 0 0 + + 0 0 0 + + + + + + rotational + + 0 + + 0 + + 0 2.26892803 + + false + + false + + + + false + + + + + + false + + + + + + r_elbow_flex + + 0.04940001 0.03660001 0.99810825 + + + + 1 0 + + + + + + + + 0 1 0 + + + + 0 + + + + + + + + 0.99810825 0 -0.04940001 + + + + 0 + + + + + + + + + 1 0 0 + + + + 0 + + + + + + + + 0 1 0 + + + + 0 + + + + + + + + 0 0 1 + + + + 0 + + + + + + + + + + + + + arm_r_ulna.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_radius.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_lunate.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_scaphoid.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_pisiform.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_triquetrum.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_capitate.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_trapezium.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_trapezoid.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_hamate.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_1mc.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_2mc.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_3mc.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_4mc.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_5mc.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_thumbprox.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_thumbdist.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_2proxph.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_2midph.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_2distph.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_3proxph.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_3midph.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_3distph.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_4proxph.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_4midph.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_4distph.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_5proxph.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_5midph.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + arm_r_5distph.vtp + + 1 1 1 + + + + -0 0 -0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + + + 1 1 1 + + -0 0 -0 0 0 0 + + false + + 4 + - - 1.5343150000000001 - - 0 -0.181479 0 - - 0.019281 0.0015709999999999999 0.020062 0 0 0 - - - - - - ground_offset - - r_humerus - - - - - 0 - - 0 - - -1.5707963300000001 3.1415926500000002 - - false - - false - - - - - - false - - - - - ground - - -0.017545000000000002 -0.0070000000000000001 0.17000000000000001 - - 0 0 0 - - - - - - - - r_shoulder_elev - - -0.058898020000000002 0.0023 0.99826135999999999 - - - 1 0 - - - - - - - 0 1 0 - - - 0 - - - - - - - 0.99826135999999999 -0 0.058898020000000002 - - - 0 - - - - - - - - 1 0 0 - - - 0 - - - - - - - 0 1 0 - - - 0 - - - - - - - 0 0 1 - - - 0 - - - - - - - r_humerus_offset - - r_ulna_radius_hand - - - - - 0 - - 0 - - 0 2.2689280300000001 - - false - - false - - - - - - false - - - - - r_humerus - - 0.0061000000000000004 -0.29039999999999999 -0.0123 - - 0 0 0 - - - - - - - - r_elbow_flex - - 0.049400010000000001 0.036600010000000002 0.99810825000000003 - - - 1 0 - - - - - - - 0 1 0 - - - 0 - - - - - - - 0.99810825000000003 0 -0.049400010000000001 - - - 0 - - - - - - - - 1 0 0 - - - 0 - - - - - - - 0 1 0 - - - 0 - - - - - - - 0 0 1 - - - 0 - - - - - - - + - - true + + false + + 0.00001 + + 1 - - ground - - -0.053650000000000003 -0.013729999999999999 0.14723 + -0.05365 -0.01373 0.14723 + ground - - r_humerus - - -0.027140000000000001 -0.11441 -0.0066400000000000001 + -0.02714 -0.11441 -0.00664 + r_humerus - - r_humerus - - -0.03184 -0.22636999999999999 -0.01217 + -0.03184 -0.22637 -0.01217 + r_humerus - - r_humerus - - -0.017430000000000001 -0.26756999999999997 -0.01208 + -0.01743 -0.26757 -0.01208 + r_humerus - - r_ulna_radius_hand - - -0.021899999999999999 0.010460000000000001 -0.00077999999999999999 + -0.0219 0.01046 -0.00078 + r_ulna_radius_hand - + - TRI - hybrid - - -1 -1 + -1 -1 - TRIlonghh - hybrid - - -1 -1 + -1 -1 - TRIlongglen - hybrid - - -1 -1 + -1 -1 + + + + + + + + + 1 1 1 + + -0 0 -0 0 0 0 + + false + + 4 + 1 - 798.51999999999998 + 798.52 - 0.13400000000000001 + 0.134 - 0.14299999999999999 + 0.143 0.20943951 10 + + 0.01 + + 0.04 - 0.033000000000000002 + 0.033 - 0.59999999999999998 + 0.6 0.5 4 - 0.29999999999999999 + 0.3 1.8 - - 0.01 - - 0.040000000000000001 0.0 - - 0.0 - - true + + false + + 0.00001 + + 1 - - r_humerus - - -0.0059899999999999997 -0.12645999999999999 0.00428 + -0.00599 -0.12646 0.00428 + r_humerus - - r_humerus - - -0.023439999999999999 -0.14527999999999999 0.0092800000000000001 + -0.02344 -0.14528 0.00928 + r_humerus - - r_humerus - - -0.03184 -0.22636999999999999 -0.01217 + -0.03184 -0.22637 -0.01217 + r_humerus - - r_humerus - - -0.017430000000000001 -0.26756999999999997 -0.01208 + -0.01743 -0.26757 -0.01208 + r_humerus - - r_ulna_radius_hand - - -0.021899999999999999 0.010460000000000001 -0.00077999999999999999 + -0.0219 0.01046 -0.00078 + r_ulna_radius_hand - + - TRI - hybrid - - -1 -1 + -1 -1 + + + + + + + + + 1 1 1 + + -0 0 -0 0 0 0 + + false + + 4 + 1 - 624.29999999999995 + 624.3 0.1138 - 0.098000000000000004 + 0.098 0.15707963 10 + + 0.01 + + 0.04 - 0.033000000000000002 + 0.033 - 0.59999999999999998 + 0.6 0.5 4 - 0.29999999999999999 + 0.3 1.8 - - 0.01 - - 0.040000000000000001 0.0 - - 0.0 - - true + + false + + 0.00001 + + 1 - - r_humerus - - -0.0083800000000000003 -0.13694999999999999 -0.0090600000000000003 + -0.00838 -0.13695 -0.00906 + r_humerus - - r_humerus - - -0.026009999999999998 -0.15139 -0.010800000000000001 + -0.02601 -0.15139 -0.0108 + r_humerus - - r_humerus - - -0.03184 -0.22636999999999999 -0.01217 + -0.03184 -0.22637 -0.01217 + r_humerus - - r_humerus - - -0.017430000000000001 -0.26756999999999997 -0.01208 + -0.01743 -0.26757 -0.01208 + r_humerus - - r_ulna_radius_hand - - -0.021899999999999999 0.010460000000000001 -0.00077999999999999999 + -0.0219 0.01046 -0.00078 + r_ulna_radius_hand - + - TRI - hybrid - - -1 -1 + -1 -1 + + + + + + + + + 1 1 1 + + -0 0 -0 0 0 0 + + false + + 4 + 1 - 624.29999999999995 + 624.3 0.1138 - 0.090800000000000006 + 0.0908 0.15707963 10 + + 0.01 + + 0.04 - 0.033000000000000002 + 0.033 - 0.59999999999999998 + 0.6 0.5 4 - 0.29999999999999999 + 0.3 1.8 - - 0.01 - - 0.040000000000000001 0.0 - - 0.0 - - true + + false + + 0.00001 + + 1 - - ground - - -0.039234999999999999 0.00347 0.14795 + -0.039235 0.00347 0.14795 + ground - - ground - - -0.028944999999999999 0.01391 0.15639 + -0.028945 0.01391 0.15639 + ground - - r_humerus - - 0.021309999999999999 0.017930000000000001 0.010279999999999999 + 0.02131 0.01793 0.01028 + r_humerus - - r_humerus - - 0.023779999999999999 -0.00511 0.01201 + 0.02378 -0.00511 0.01201 + r_humerus - - r_humerus - - 0.01345 -0.02827 0.0013600000000000001 + 0.01345 -0.02827 0.00136 + r_humerus - - r_humerus - - 0.01068 -0.077359999999999998 -0.00165 + 0.01068 -0.07736 -0.00165 + r_humerus - - r_humerus - - 0.01703 -0.12125 0.00024000000000000001 + 0.01703 -0.12125 0.00024 + r_humerus - - r_humerus - - 0.022800000000000001 -0.1754 -0.0063 + 0.0228 -0.1754 -0.0063 + r_humerus - - r_ulna_radius_hand - - 0.0075100000000000002 -0.048390000000000002 0.02179 + 0.00751 -0.04839 0.02179 + r_ulna_radius_hand - + - BIClonghh - hybrid - - 2 3 + 2 3 + + + + + + + + + 1 1 1 + + -0 0 -0 0 0 0 + + false + + 4 + 1 - 624.29999999999995 + 624.3 0.1157 - 0.27229999999999999 + 0.2723 0 10 + + 0.01 + + 0.04 - 0.033000000000000002 + 0.033 - 0.59999999999999998 + 0.6 0.5 4 - 0.29999999999999999 + 0.3 1.8 - - 0.01 - - 0.040000000000000001 0.0 - - 0.0 - - true + + false + + 0.00001 + + 1 - - ground - - 0.0046750000000000003 -0.01231 0.13475000000000001 + 0.004675 -0.01231 0.13475 + ground - - ground - - -0.0070749999999999997 -0.040039999999999999 0.14507 + -0.007075 -0.04004 0.14507 + ground - - r_humerus - - 0.011169999999999999 -0.075759999999999994 -0.011010000000000001 + 0.01117 -0.07576 -0.01101 + r_humerus - - r_humerus - - 0.01703 -0.12125 -0.010789999999999999 + 0.01703 -0.12125 -0.01079 + r_humerus - - r_humerus - - 0.022800000000000001 -0.1754 -0.0063 + 0.0228 -0.1754 -0.0063 + r_humerus - - r_ulna_radius_hand - - 0.0075100000000000002 -0.048390000000000002 0.02179 + 0.00751 -0.04839 0.02179 + r_ulna_radius_hand - + + + + + + + + + + 1 1 1 + + -0 0 -0 0 0 0 + + false + + 4 + 1 @@ -1328,97 +1492,106 @@ 0 10 + + 0.01 + + 0.04 - 0.033000000000000002 + 0.033 - 0.59999999999999998 + 0.6 0.5 4 - 0.29999999999999999 + 0.3 1.8 - - 0.01 - - 0.040000000000000001 0.0 - - 0.0 - - true + + false + + 0.00001 + + 1 - - r_humerus - - 0.0067999999999999996 -0.1739 -0.0035999999999999999 + 0.0068 -0.1739 -0.0036 + r_humerus - - r_ulna_radius_hand - - -0.0032000000000000002 -0.023900000000000001 0.00089999999999999998 + -0.0032 -0.0239 0.0009 + r_ulna_radius_hand - + - TRI - hybrid - - -1 -1 + -1 -1 + + + + + + + + + 1 1 1 + + -0 0 -0 0 0 0 + + false + + 4 + 1 - 987.25999999999999 + 987.26 - 0.085800000000000001 + 0.0858 - 0.053499999999999999 + 0.0535 0 10 + + 0.01 + + 0.04 - 0.033000000000000002 + 0.033 - 0.59999999999999998 + 0.6 0.5 4 - 0.29999999999999999 + 0.3 1.8 - - 0.01 - - 0.040000000000000001 0.0 - - 0.0 @@ -1427,33 +1600,33 @@ - - ground - - -0.01256 0.040000000000000001 0.17000000000000001 - + + ground + + -0.01256 0.04 0.17 + false - - r_humerus - - 0.0050000000000000001 -0.29039999999999999 0.029999999999999999 - + + r_humerus + + 0.005 -0.2904 0.03 + false - - r_ulna_radius_hand - - -0.0011000000000000001 -0.23558999999999999 0.094299999999999995 - + + r_ulna_radius_hand + + -0.0011 -0.23559 0.0943 + false - + diff --git a/Applications/Analyze/test/subject01_adjusted_spring.osim b/Applications/Analyze/test/subject01_adjusted_spring.osim index ee594df996..1a35c30de9 100644 --- a/Applications/Analyze/test/subject01_adjusted_spring.osim +++ b/Applications/Analyze/test/subject01_adjusted_spring.osim @@ -1,1403 +1,1500 @@ - + - - - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - - - - - - - - - 0 -9.8066499999999994 0 - Delp S.L., Loan J.P., Hoy M.G., Zajac F.E., Topp E.L., Rosen J.M., Thelen D.G., Anderson F.C., Seth A. Notes: 3D, 23 DOF gait model created by D.G. Thelen, Univ. of Wisconsin-Madison, and Ajay Seth, Frank C. Anderson, and Scott L. Delp, Stanford University. Lower extremity joint defintions based on Delp et al. (1990). Low back joint and anthropometry based on Anderson and Pandy (1999, 2001). Planar knee model of Yamaguchi and Zajac (1989). Seth replaced tibia translation constraints with a CustomJoint for the knee and removed the patella to eliminate all kinematic constraints; insertions of the quadrucepts are handled with moving points in the tibia frame as defined by Delp 1990. Number of muscles was reduced by Anderson to improve simulation speed for demonstrations and is not intended to be used in research. License: Creative Commons (CCBY 3.0). You are free to distribute, remix, tweak, and build upon this work, even commercially, as long as you credit us for the original creation. http://creativecommons.org/licenses/by/3.0/ More Information: http://simtk-confluence.stanford.edu:8080/display/OpenSim/Gait+2392+and+2354+Models - Delp, S.L., Loan, J.P., Hoy, M.G., Zajac, F.E., Topp E.L., Rosen, J.M.: An interactive graphics-based model of the lower extremity to study orthopaedic surgical procedures, IEEE Transactions on Biomedical Engineering, vol. 37, pp. 757-767, 1990. Yamaguchi G.T., Zajac F.E.: A planar model of the knee joint to characterize the knee extensor mechanism." J . Biomech. vol. 22. pp. 1-10. 1989. Anderson F.C., Pandy M.G.: A dynamic optimization solution for vertical jumping in three dimensions. Computer Methods in Biomechanics and Biomedical Engineering 2:201-231, 1999. Anderson F.C., Pandy M.G.: Dynamic optimization of human walking. Journal of Biomechanical Engineering 123:381-390, 2001. - meters - N - + + 0 -9.80665 0 + - - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - - - - .. - - - - 1.02458 1.02458 1.02458 - - - - 1 - - 1 1 1 - - - sacrum.vtp - - - - .. - - - - 1.02458 1.02458 1.02458 - - - - 1 - - 1 1 1 - - - pelvis.vtp - - - - .. - - - - 1.02458 1.02458 1.02458 - - - - 1 - - 1 1 1 - - - l_pelvis.vtp - - - + + 0 + 0 0 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + - + + 11.3751712907406 - - 0.020684600000000001 0 0 - - 0.10423399999999999 0.088314699999999996 0.058707500000000003 0 0 0 + 0.0206846 0 0 + 0.10423369488353 + 0.0883147356454813 + 0.058707499355607 + 0 + 0 + 0 + + + + + ground + + 0 0 0 + + 0 0 0 + + 0 0 0 + + 0 0 0 + + + + + + rotational + + 0 + + 0 + + -1.57079633 1.57079633 + + false + + false + + + + false + + + + translational + + 0 + + 0 + + -5 5 + + false + + false + + + + false + + + + translational + + 0 + + 0 + + -1 2 + + false + + false + + + + false + + + + + + false + + + + + + pelvis_tilt + + 0 0 1 + + + + 1 0 + + + + + + + + 1 0 0 + + + + 0 + + + + + + + + 0 1 0 + + + + 0 + + + + + + + pelvis_tx + + 1 0 0 + + + + 1 0 + + + + + + pelvis_ty + + 0 1 0 + + + + 1 0 + + + + + + + + 0 0 1 + + + + + + 0.02 + + + 1 + + + + + + + + + + + + + sacrum.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + pelvis.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + l_pelvis.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + + + 1.02458 1.02458 1.02458 + + 0 0 0 0 0 0 + + false + + 4 + + + + + - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - - - - .. - - - - 1.14724 1.14724 1.14724 - - - - 1 - - 1 1 1 - - - femur.vtp - - - + 8.98403823076288 + 0 -0.195031 0 + 0.170220714339411 + 0.0446209639530494 + 0.179500857839617 + 0 + 0 + 0 + + + + + pelvis + + -0.072437806 -0.067724738 0.08555243 + + 0 0 0 + + 0 0 0 + + 0 0 0 + + + + + + rotational + + 0 + + 0 + + -2.0943951 2.0943951 + + false + + false + + + + false + + + + + + false + + + + + + + + + femur.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + + + 1.14724 1.14724 1.14724 + + 0 0 0 0 0 0 + + false + + 4 + - - 8.9840382307628808 - - 0 -0.19503100000000001 0 - - 0.17022100000000001 0.044621000000000001 0.17950099999999999 0 0 0 - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - - - - .. - - - - 0.98852300000000004 0.98852300000000004 0.98852300000000004 - - - - 1 - - 1 1 1 - - - tibia.vtp - - - - .. - - - - 0.98852300000000004 0.98852300000000004 0.98852300000000004 - - - - 1 - - 1 1 1 - - - fibula.vtp - - - + 3.58100089669871 + 0 -0.184557 0 + 0.0475693660337908 + 0.00481356680103835 + 0.048230051673149 + 0 + 0 + 0 + + + + + femur_r + + 0 0 0 + + 0 0 0 + + 0 0 0 + + 0 0 0 + + + + + + rotational + + 0 + + 0 + + -2.0943951 0.17453293 + + false + + false + + + + false + + + + + + false + + + + + + knee_angle_r + + 0 0 1 + + + + 1 0 + + + + + + + + 0 1 0 + + + + 0 + + + + + + + + 1 0 0 + + + + 0 + + + + + + + knee_angle_r + + 1 0 0 + + + + + + -2.0944 -1.74533 -1.39626 -1.0472 -0.698132 -0.349066 -0.174533 0.197344 0.337395 0.490178 1.52146 2.0944 + -0.0032 0.00179 0.00411 0.0041 0.00212 -0.001 -0.0031 -0.005227 -0.005435 -0.005574 -0.005435 -0.00525 + + + 1.14724 + + + + + + knee_angle_r + + 0 1 0 + + + + + + -2.0944 -1.22173 -0.523599 -0.349066 -0.174533 0.159149 2.0944 + -0.4226 -0.4082 -0.399 -0.3976 -0.3966 -0.395264 -0.396 + + + 1.14724 + + + + + + + + 0 0 1 + + + + + + 0 + + + 1.14724 + + + + + + + + + + + + + tibia.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + fibula.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + + + 0.988523 0.988523 0.988523 + + 0 0 0 0 0 0 + + false + + 4 + - - 3.5810008966987099 - - 0 -0.184557 0 - - 0.047569399999999998 0.0048135699999999997 0.048230099999999998 0 0 0 - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - - - - .. - - - - 1.11398 1.11398 1.11398 - - - - 1 - - 1 1 1 - - - talus.vtp - - - + 0.0965880214888392 + 0 0 0 + 0.00119861044391961 + 0.00119861044391961 + 0.00119861044391961 + 0 + 0 + 0 + + + + + tibia_r + + 0 -0.42506489 0 + + 0 0 0 + + 0 0 0 + + 0 0 0 + + + + + + rotational + + 0 + + 0 + + -1.57079633 1.57079633 + + false + + false + + + + false + + + + + + false + + + + + + + + + talus.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + + + 1.11398 1.11398 1.11398 + + 0 0 0 0 0 0 + + false + + 4 + - - 0.096588021488839201 - - 0 0 0 - - 0.0011986099999999999 0.0011986099999999999 0.0011986099999999999 0 0 0 - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - - - - .. - - - - 1.02708 1.02708 1.02708 - - - - 1 - - 1 1 1 - - - foot.vtp - - - + 1.20735026861049 + 0.102708 0.0308124 0 + 0.00142646082990259 + 0.00397371231187149 + 0.004177492430429 + 0 + 0 + 0 + + + + + talus_r + + -0.0543288046 -0.046731461 0.0088227216 + + 0 0 0 + + 0 0 0 + + 0 0 0 + + + + + + + false + + + + + + + + + foot.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + + + 1.02708 1.02708 1.02708 + + 0 0 0 0 0 0 + + false + + 4 + - - 1.20735026861049 - - 0.10270799999999999 0.0308124 0 - - 0.0014264600000000001 0.0039737100000000001 0.0041774899999999998 0 0 0 - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - - - - .. - - - - 1.02708 1.02708 1.02708 - - - - 1 - - 1 1 1 - - - bofoot.vtp - - - + 0.209209654544826 + 0.035537 0.00616248 -0.0179739 + 0.000101890059278756 + 0.000203780118557512 + 0.000101890059278756 + 0 + 0 + 0 + + + + + calcn_r + + 0.183641904 -0.00205416 0.0011092464 + + 0 0 0 + + 0 0 0 + + 0 0 0 + + + + + + + false + + + + + + + + + bofoot.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + + + 1.02708 1.02708 1.02708 + + 0 0 0 0 0 0 + + false + + 4 + - - 0.20920965454482601 - - 0.035536999999999999 0.0061624799999999997 -0.017973900000000001 - - 0.00010189 0.00020378 0.00010189 0 0 0 - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - - - - .. - - - - 1.14724 1.14724 1.14724 - - - - 1 - - 1 1 1 - - - l_femur.vtp - - - + 8.98403823076288 + 0 -0.195031 0 + 0.170220714339411 + 0.0446209639530494 + 0.179500857839617 + 0 + 0 + 0 + + + + + pelvis + + -0.072437806 -0.067724738 -0.08555243 + + 0 0 0 + + 0 0 0 + + 0 0 0 + + + + + + rotational + + 0 + + 0 + + -2.0943951 2.0943951 + + false + + false + + + + false + + + + + + false + + + + + + + + + l_femur.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + + + 1.14724 1.14724 1.14724 + + 0 0 0 0 0 0 + + false + + 4 + - - 8.9840382307628808 - - 0 -0.19503100000000001 0 - - 0.17022100000000001 0.044621000000000001 0.17950099999999999 0 0 0 - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - - - - .. - - - - 0.98852300000000004 0.98852300000000004 0.98852300000000004 - - - - 1 - - 1 1 1 - - - l_tibia.vtp - - - - .. - - - - 0.98852300000000004 0.98852300000000004 0.98852300000000004 - - - - 1 - - 1 1 1 - - - l_fibula.vtp - - - + 3.58100089669871 + 0 -0.184557 0 + 0.0475693660337908 + 0.00481356680103835 + 0.048230051673149 + 0 + 0 + 0 + + + + + femur_l + + 0 0 0 + + 0 0 0 + + 0 0 0 + + 0 0 0 + + + + + + rotational + + 0 + + 0 + + -2.0943951 0.17453293 + + false + + false + + + + false + + + + + + false + + + + + + knee_angle_l + + 0 0 1 + + + + 1 0 + + + + + + + + 0 1 0 + + + + 0 + + + + + + + + 1 0 0 + + + + 0 + + + + + + + knee_angle_l + + 1 0 0 + + + + + + -2.0944 -1.74533 -1.39626 -1.0472 -0.698132 -0.349066 -0.174533 0.197344 0.337395 0.490178 1.52146 2.0944 + -0.0032 0.00179 0.00411 0.0041 0.00212 -0.001 -0.0031 -0.005227 -0.005435 -0.005574 -0.005435 -0.00525 + + + 1.14724 + + + + + + knee_angle_l + + 0 1 0 + + + + + + -2.0944 -1.22173 -0.523599 -0.349066 -0.174533 0.159149 2.0944 + -0.4226 -0.4082 -0.399 -0.3976 -0.3966 -0.395264 -0.396 + + + 1.14724 + + + + + + + + 0 0 1 + + + + + + 0 + + + 1.14724 + + + + + + + + + + + + + l_tibia.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + l_fibula.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + + + 0.988523 0.988523 0.988523 + + 0 0 0 0 0 0 + + false + + 4 + - - 3.5810008966987099 - - 0 -0.184557 0 - - 0.047569399999999998 0.0048135699999999997 0.048230099999999998 0 0 0 - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - - - - .. - - - - 1.11398 1.11398 1.11398 - - - - 1 - - 1 1 1 - - - l_talus.vtp - - - + 0.0965880214888392 + 0 0 0 + 0.00119861044391961 + 0.00119861044391961 + 0.00119861044391961 + 0 + 0 + 0 + + + + + tibia_l + + 0 -0.42506489 0 + + 0 0 0 + + 0 0 0 + + 0 0 0 + + + + + + rotational + + 0 + + 0 + + -1.04719755 1.04719755 + + false + + false + + + + false + + + + + + false + + + + + + + + + l_talus.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + + + 1.11398 1.11398 1.11398 + + 0 0 0 0 0 0 + + false + + 4 + - - 0.096588021488839201 - - 0 0 0 - - 0.0011986099999999999 0.0011986099999999999 0.0011986099999999999 0 0 0 - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - - - - .. - - - - 1.02708 1.02708 1.02708 - - - - 1 - - 1 1 1 - - - l_foot.vtp - - - + 1.20735026861049 + 0.102708 0.0308124 0 + 0.00142646082990259 + 0.00397371231187149 + 0.004177492430429 + 0 + 0 + 0 + + + + + talus_l + + -0.0543288046 -0.046731461 -0.0088227216 + + 0 0 0 + + 0 0 0 + + 0 0 0 + + + + + + + false + + + + + + + + + l_foot.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + + + 1.02708 1.02708 1.02708 + + 0 0 0 0 0 0 + + false + + 4 + - - 1.20735026861049 - - 0.10270799999999999 0.0308124 0 - - 0.0014264600000000001 0.0039737100000000001 0.0041774899999999998 0 0 0 - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - - - - .. - - - - 1.02708 1.02708 1.02708 - - - - 1 - - 1 1 1 - - - l_bofoot.vtp - - - + 0.209209654544826 + 0.035537 0.00616248 0.0179739 + 0.000101890059278756 + 0.000203780118557512 + 0.000101890059278756 + 0 + 0 + 0 + + + + + calcn_l + + 0.183641904 -0.00205416 -0.0011092464 + + 0 0 0 + + 0 0 0 + + 0 0 0 + + + + + + + false + + + + + + + + + l_bofoot.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + + + 1.02708 1.02708 1.02708 + + 0 0 0 0 0 0 + + false + + 4 + - - 0.20920965454482601 - - 0.035536999999999999 0.0061624799999999997 0.017973900000000001 - - 0.00010189 0.00020378 0.00010189 0 0 0 - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - - - - .. - - - - 1.07972 1.07972 1.07972 - - - - 1 - - 1 1 1 - - - hat_spine.vtp - - - - .. - - - - 1.07972 1.07972 1.07972 - - - - 1 - - 1 1 1 - - - hat_jaw.vtp - - - - .. - - - - 1.07972 1.07972 1.07972 - - - - 1 - - 1 1 1 - - - hat_skull.vtp - - - - .. - - - - 1.07972 1.07972 1.07972 - - - - 1 - - 1 1 1 - - - hat_ribs.vtp - - - + 33.0684545650479 + -0.0323916 0.34551 0 + 1.66031441687787 + 0.850707047779741 + 1.61178301547574 + 0 + 0 + 0 + + + + + pelvis + + -0.103175206 0.08350327 0 + + 0 0 0 + + 0 0 0 + + 0 0 0 + + + + + + rotational + + 0 + + 0 + + -1.57079633 1.57079633 + + false + + false + + + + false + + + + + + false + + + + + + + + + hat_spine.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + hat_jaw.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + hat_skull.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + hat_ribs.vtp + + 1 1 1 + + + + 0 0 0 0 0 0 + + 1 1 1 + + 4 + + 1 + + + + + + 1.07972 1.07972 1.07972 + + 0 0 0 0 0 0 + + false + + 4 + - - 33.068454565047901 - - -0.0323916 0.34550999999999998 0 - - 1.66031 0.85070699999999999 1.61178 0 0 0 - - - - - - ../ground - - ../pelvis - - - - - 0 - - 0 - - -1.5707963300000001 1.5707963300000001 - - false - - false - - - - false - - - - 0 - - 0 - - -5 5 - - false - - false - - - - false - - - - 0 - - 0 - - -1 2 - - false - - false - - - - false - - - - - - - - pelvis_tilt - - 0 0 1 - - - 1 0 - - - - - - - 1 0 0 - - - 0 - - - - - - - 0 1 0 - - - 0 - - - - - - pelvis_tx - - 1 0 0 - - - 1 0 - - - - - pelvis_ty - - 0 1 0 - - - 1 0 - - - - - - - 0 0 1 - - - - - 0.02 - - - 1 - - - - - - - pelvis_offset - - ../femur_r - - - - - 0 - - 0 - - -2.0943950999999998 2.0943950999999998 - - false - - false - - - - false - - - - - - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - ../../pelvis - - -0.072437799999999997 -0.067724699999999999 0.085552400000000001 - - 0 0 0 - - - - - - ../femur_r - - ../tibia_r - - - - - 0 - - 0 - - -2.0943950999999998 0.17453293 - - false - - false - - - - false - - - - - - - - knee_angle_r - - 0 0 1 - - - 1 0 - - - - - - - 0 1 0 - - - 0 - - - - - - - 1 0 0 - - - 0 - - - - - - knee_angle_r - - 1 0 0 - - - - - -2.0944 -1.74533 -1.39626 -1.0472 -0.698132 -0.349066 -0.174533 0.197344 0.337395 0.490178 1.52146 2.0944 - -0.0032 0.00179 0.00411 0.0041 0.00212 -0.001 -0.0031 -0.005227 -0.005435 -0.005574 -0.005435 -0.00525 - - - 1.14724 - - - - - knee_angle_r - - 0 1 0 - - - - - -2.0944 -1.22173 -0.523599 -0.349066 -0.174533 0.159149 2.0944 - -0.4226 -0.4082 -0.399 -0.3976 -0.3966 -0.395264 -0.396 - - - 1.14724 - - - - - - - 0 0 1 - - - - - 0 - - - 1.14724 - - - - - - - tibia_r_offset - - ../talus_r - - - - - 0 - - 0 - - -1.5707963300000001 1.5707963300000001 - - false - - false - - - - false - - - - - - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - ../../tibia_r - - 0 -0.42506500000000003 0 - - 0 0 0 - - - - - - talus_r_offset - - ../calcn_r - - - - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - ../../talus_r - - -0.054328799999999997 -0.046731500000000002 0.0088227199999999992 - - 0 0 0 - - - - - - calcn_r_offset - - ../toes_r - - - - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - ../../calcn_r - - 0.183642 -0.0020541600000000002 0.00110925 - - 0 0 0 - - - - - - pelvis_offset - - ../femur_l - - - - - 0 - - 0 - - -2.0943950999999998 2.0943950999999998 - - false - - false - - - - false - - - - - - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - ../../pelvis - - -0.072437799999999997 -0.067724699999999999 -0.085552400000000001 - - 0 0 0 - - - - - - ../femur_l - - ../tibia_l - - - - - 0 - - 0 - - -2.0943950999999998 0.17453293 - - false - - false - - - - false - - - - - - - - knee_angle_l - - 0 0 1 - - - 1 0 - - - - - - - 0 1 0 - - - 0 - - - - - - - 1 0 0 - - - 0 - - - - - - knee_angle_l - - 1 0 0 - - - - - -2.0944 -1.74533 -1.39626 -1.0472 -0.698132 -0.349066 -0.174533 0.197344 0.337395 0.490178 1.52146 2.0944 - -0.0032 0.00179 0.00411 0.0041 0.00212 -0.001 -0.0031 -0.005227 -0.005435 -0.005574 -0.005435 -0.00525 - - - 1.14724 - - - - - knee_angle_l - - 0 1 0 - - - - - -2.0944 -1.22173 -0.523599 -0.349066 -0.174533 0.159149 2.0944 - -0.4226 -0.4082 -0.399 -0.3976 -0.3966 -0.395264 -0.396 - - - 1.14724 - - - - - - - 0 0 1 - - - - - 0 - - - 1.14724 - - - - - - - tibia_l_offset - - ../talus_l - - - - - 0 - - 0 - - -1.0471975499999999 1.0471975499999999 - - false - - false - - - - false - - - - - - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - ../../tibia_l - - 0 -0.42506500000000003 0 - - 0 0 0 - - - - - - talus_l_offset - - ../calcn_l - - - - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - ../../talus_l - - -0.054328799999999997 -0.046731500000000002 -0.0088227199999999992 - - 0 0 0 - - - - - - calcn_l_offset - - ../toes_l - - - - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - ../../calcn_l - - 0.183642 -0.0020541600000000002 -0.00110925 - - 0 0 0 - - - - - - pelvis_offset - - ../torso - - - - - 0 - - 0 - - -1.5707963300000001 1.5707963300000001 - - false - - false - - - - false - - - - - - - - - .. - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - ../../pelvis - - -0.103175 0.083503300000000003 0 - - 0 0 0 - - - - - - - - - - - - + - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../pelvis - - -0.129056 -0.105091 0.071146799999999996 + -0.129056 -0.105091 0.0711468 + pelvis - - ../../../tibia_r - - -0.0297545 -0.035586800000000002 0.029092199999999999 + -0.0297545 -0.0355868 0.0290922 + tibia_r - - ../../../tibia_r - - -0.0231314 -0.055653800000000003 0.0339063 + -0.0231314 -0.0556538 0.0339063 + tibia_r - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 2700 - 0.12363105583881601 + 0.123631055838816 - 0.36975893764636703 + 0.369758937646367 0 @@ -1405,9 +1502,9 @@ 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -1424,9 +1521,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -1438,65 +1535,72 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../femur_r - - 0.0057362000000000003 -0.24218200000000001 0.026845399999999998 + 0.0057362 -0.242182 0.0268454 + femur_r - - ../../../tibia_r - - -0.0297545 -0.035586800000000002 0.029092199999999999 + -0.0297545 -0.0355868 0.0290922 + tibia_r - - ../../../tibia_r - - -0.0231314 -0.055653800000000003 0.0339063 + -0.0231314 -0.0556538 0.0339063 + tibia_r - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 804 - 0.19144488517712899 + 0.191444885177129 - 0.098488987172048806 + 0.0984889871720488 - 0.40142572999999998 + 0.40142573 10 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -1513,9 +1617,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -1527,52 +1631,57 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../pelvis - - -0.134937 0.0089138499999999992 0.047335599999999999 + -0.134937 0.00891385 0.0473356 + pelvis - - ../../../pelvis - - -0.13770399999999999 -0.062396899999999998 0.083298399999999995 + -0.137704 -0.0623969 0.0832984 + pelvis - - ../../../femur_r - - -0.051625799999999999 -0.066998799999999997 0.028910399999999999 + -0.0516258 -0.0669988 0.0289104 + femur_r - - ../../../femur_r - - -0.0178969 -0.11656 0.048069399999999998 + -0.0178969 -0.11656 0.0480694 + femur_r - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 @@ -1581,7 +1690,7 @@ 0.1708506011799 - 0.079817393667856201 + 0.0798173936678562 0 @@ -1589,9 +1698,9 @@ 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -1608,9 +1717,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -1622,62 +1731,63 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../pelvis - - -0.066290299999999996 0.090880199999999994 0.029610399999999999 + -0.0662903 0.0908802 0.0296104 + pelvis - - ../../../pelvis - - -0.024385 -0.058401099999999997 0.077765600000000004 + -0.024385 -0.0584011 0.0777656 + pelvis - - ../../../pelvis - - -0.0295079 -0.082478700000000002 0.083605700000000005 - - ../../../hip_r/hip_flexion_r - - -1.5708 0.78539800000000004 + -0.0295079 -0.0824787 0.0836057 + pelvis + -1.5708 0.785398 + hip_flexion_r - - ../../../femur_r - - 0.0018355800000000001 -0.058165099999999997 0.0043595099999999996 + 0.00183558 -0.0581651 0.00435951 + femur_r - - ../../../femur_r - - -0.0215681 -0.068490200000000001 0.011931300000000001 + -0.0215681 -0.0684902 0.0119313 + femur_r - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 @@ -1688,15 +1798,15 @@ 0.168276029976587 - 0.13962633999999999 + 0.13962634 10 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -1713,9 +1823,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -1727,41 +1837,30 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../pelvis - - -0.030225100000000001 -0.031864400000000001 0.099179299999999998 + -0.0302251 -0.0318644 0.0991793 + pelvis - - ../../../femur_r - - 0.038317799999999999 -0.46233800000000003 0.0021797600000000002 - - ../../../knee_r/knee_angle_r - - -2.6179899999999998 -1.45997 + 0.0383178 -0.462338 0.00217976 + femur_r + -2.61799 -1.45997 + knee_angle_r - - ../../../tibia_r - - ../../../knee_r/knee_angle_r - - ../../../knee_r/knee_angle_r - - ../../../knee_r/knee_angle_r - + 0.0610488 0.0207432 0.00138393 + tibia_r @@ -1770,10 +1869,10 @@ 0.0155805 0.0179938 0.0275081 0.0296564 0.0307615 0.0365695 0.0422074 0.0450902 0.048391 0.0534299 0.0617576 0.0617669 0.0617762 0.0633083 0.066994 0.0733035 0.0573481 - 0.98852300000000004 + 0.988523 - + knee_angle_r @@ -1782,10 +1881,10 @@ 0.0234116 0.0237613 0.0251141 0.0252795 0.0253146 0.0249184 0.0242373 0.0238447 0.0234197 0.0227644 0.020984 0.0209814 0.0209788 0.0205225 0.0191754 0.0159554 -0.0673774 - 0.98852300000000004 + 0.988523 - + knee_angle_r @@ -1794,23 +1893,35 @@ 0.0014 0.0014 - 0.98852300000000004 + 0.988523 + knee_angle_r - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 @@ -1819,17 +1930,17 @@ 0.130462375970093 - 0.35476611009411202 + 0.354766110094112 - 0.087266460000000004 + 0.08726646 10 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -1846,9 +1957,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -1860,47 +1971,34 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../femur_r - - 0.033270000000000001 -0.22072900000000001 0.035564400000000003 + 0.03327 -0.220729 0.0355644 + femur_r - - ../../../femur_r - - 0.038432500000000001 -0.23908499999999999 0.032696299999999998 + 0.0384325 -0.239085 0.0326963 + femur_r - - ../../../femur_r - - 0.039350299999999998 -0.46233800000000003 0.0063098199999999998 - - ../../../knee_r/knee_angle_r - - -2.6179899999999998 -1.4199999999999999 + 0.0393503 -0.462338 0.00630982 + femur_r + -2.61799 -1.42 + knee_angle_r - - ../../../tibia_r - - ../../../knee_r/knee_angle_r - - ../../../knee_r/knee_angle_r - - ../../../knee_r/knee_angle_r - + 0.0548266 0.025002 0.00177934 + tibia_r @@ -1909,10 +2007,10 @@ 0.0082733 0.0106866 0.0202042 0.022353 0.0234583 0.0292715 0.0349465 0.037871 0.0412569 0.0465287 0.0554632 0.0554735 0.0554837 0.0571717 0.061272 0.0684368 0.0648818 - 0.98852300000000004 + 0.988523 - + knee_angle_r @@ -1921,10 +2019,10 @@ 0.025599 0.0259487 0.0273124 0.0274796 0.0275151 0.0271363 0.0265737 0.0263073 0.0261187 0.0260129 0.0252923 0.0252911 0.0252898 0.0250526 0.0242191 0.0218288 -0.0685706 - 0.98852300000000004 + 0.988523 - + knee_angle_r @@ -1933,23 +2031,35 @@ 0.0018 0.0018 - 0.98852300000000004 + 0.988523 + knee_angle_r - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 @@ -1958,17 +2068,17 @@ 0.124678696688354 - 0.13516568986774899 + 0.135165689867749 - 0.052359879999999998 + 0.05235988 10 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -1985,9 +2095,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -1999,69 +2109,74 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../femur_r - - -0.0217976 -0.45075100000000001 -0.026960100000000001 + -0.0217976 -0.450751 -0.0269601 + femur_r - - ../../../femur_r - - -0.034417200000000002 -0.46142 -0.029598800000000001 - - ../../../knee_r/knee_angle_r - - -0.78539800000000004 0.17453299999999999 + -0.0344172 -0.46142 -0.0295988 + femur_r + -0.785398 0.174533 + knee_angle_r - - ../../../calcn_r - - 0 0.0318395 -0.0054435200000000003 + 0 0.0318395 -0.00544352 + calcn_r - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 2500 - 0.090128750494776796 + 0.0901287504947768 - 0.36051500197910702 + 0.360515001979107 - 0.29670596999999999 + 0.29670597 10 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -2078,9 +2193,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -2092,40 +2207,49 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../tibia_r - - -0.0023724599999999998 -0.15154100000000001 0.0070185100000000004 + -0.00237246 -0.151541 0.00701851 + tibia_r - - ../../../calcn_r - - 0 0.0318395 -0.0054435200000000003 + 0 0.0318395 -0.00544352 + calcn_r - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 @@ -2134,7 +2258,7 @@ 0.050288844245806 - 0.25144422122902998 + 0.25144422122903 0.43633231 @@ -2142,9 +2266,9 @@ 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -2161,9 +2285,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -2175,65 +2299,72 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../tibia_r - - 0.017694600000000001 -0.16053600000000001 0.011368 + 0.0176946 -0.160536 0.011368 + tibia_r - - ../../../tibia_r - - 0.0325224 -0.390565 -0.017496899999999999 + 0.0325224 -0.390565 -0.0174969 + tibia_r - - ../../../calcn_r - - 0.119758 0.018282 -0.031325899999999997 + 0.119758 0.018282 -0.0313259 + calcn_r - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 3000 - 0.097912574684154305 + 0.0979125746841543 - 0.22280106280169801 + 0.222801062801698 - 0.087266460000000004 + 0.08726646 10 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -2250,9 +2381,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -2264,55 +2395,62 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../pelvis - - -0.129056 -0.105091 -0.071146799999999996 + -0.129056 -0.105091 -0.0711468 + pelvis - - ../../../tibia_l - - -0.0297545 -0.035586800000000002 -0.029092199999999999 + -0.0297545 -0.0355868 -0.0290922 + tibia_l - - ../../../tibia_l - - -0.0231314 -0.055653800000000003 -0.0339063 + -0.0231314 -0.0556538 -0.0339063 + tibia_l - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 2700 - 0.12363105583881601 + 0.123631055838816 - 0.36975893764636703 + 0.369758937646367 0 @@ -2320,9 +2458,9 @@ 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -2339,9 +2477,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -2353,65 +2491,72 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../femur_l - - 0.0057362000000000003 -0.24218200000000001 -0.026845399999999998 + 0.0057362 -0.242182 -0.0268454 + femur_l - - ../../../tibia_l - - -0.0297545 -0.035586800000000002 -0.029092199999999999 + -0.0297545 -0.0355868 -0.0290922 + tibia_l - - ../../../tibia_l - - -0.0231314 -0.055653800000000003 -0.0339063 + -0.0231314 -0.0556538 -0.0339063 + tibia_l - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 804 - 0.19144488517712899 + 0.191444885177129 - 0.098488987172048806 + 0.0984889871720488 - 0.40142572999999998 + 0.40142573 10 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -2428,9 +2573,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -2442,52 +2587,57 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../pelvis - - -0.134937 0.0089138499999999992 -0.047335599999999999 + -0.134937 0.00891385 -0.0473356 + pelvis - - ../../../pelvis - - -0.13770399999999999 -0.062396899999999998 -0.083298399999999995 + -0.137704 -0.0623969 -0.0832984 + pelvis - - ../../../femur_l - - -0.051625799999999999 -0.066998799999999997 -0.028910399999999999 + -0.0516258 -0.0669988 -0.0289104 + femur_l - - ../../../femur_l - - -0.0178969 -0.11656 -0.048069399999999998 + -0.0178969 -0.11656 -0.0480694 + femur_l - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 @@ -2496,7 +2646,7 @@ 0.1708506011799 - 0.079817393667856201 + 0.0798173936678562 0 @@ -2504,9 +2654,9 @@ 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -2523,9 +2673,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -2537,62 +2687,63 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../pelvis - - -0.066290299999999996 0.090880199999999994 -0.029610399999999999 + -0.0662903 0.0908802 -0.0296104 + pelvis - - ../../../pelvis - - -0.024385 -0.058401099999999997 -0.077765600000000004 + -0.024385 -0.0584011 -0.0777656 + pelvis - - ../../../pelvis - - -0.0295079 -0.082478700000000002 -0.083605700000000005 - - ../../../hip_l/hip_flexion_l - - -1.5708 0.78539800000000004 + -0.0295079 -0.0824787 -0.0836057 + pelvis + -1.5708 0.785398 + hip_flexion_l - - ../../../femur_l - - 0.0018355800000000001 -0.058165099999999997 -0.0043595099999999996 + 0.00183558 -0.0581651 -0.00435951 + femur_l - - ../../../femur_l - - -0.0215681 -0.068490200000000001 -0.011931300000000001 + -0.0215681 -0.0684902 -0.0119313 + femur_l - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 @@ -2603,15 +2754,15 @@ 0.168276029976587 - 0.13962633999999999 + 0.13962634 10 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -2628,9 +2779,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -2642,41 +2793,30 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../pelvis - - -0.030225100000000001 -0.031864400000000001 -0.099179299999999998 + -0.0302251 -0.0318644 -0.0991793 + pelvis - - ../../../femur_l - - 0.038317799999999999 -0.46233800000000003 -0.0021797600000000002 - - ../../../knee_l/knee_angle_l - - -2.6179899999999998 -1.45997 + 0.0383178 -0.462338 -0.00217976 + femur_l + -2.61799 -1.45997 + knee_angle_l - - ../../../tibia_l - - ../../../knee_l/knee_angle_l - - ../../../knee_l/knee_angle_l - - ../../../knee_l/knee_angle_l - + 0.0610488 0.0207432 -0.00138393 + tibia_l @@ -2685,10 +2825,10 @@ 0.0155805 0.0179938 0.0275081 0.0296564 0.0307615 0.0365695 0.0422074 0.0450902 0.048391 0.0534299 0.0617576 0.0617669 0.0617762 0.0633083 0.066994 0.0733035 0.0573481 - 0.98852300000000004 + 0.988523 - + knee_angle_l @@ -2697,10 +2837,10 @@ 0.0234116 0.0237613 0.0251141 0.0252795 0.0253146 0.0249184 0.0242373 0.0238447 0.0234197 0.0227644 0.020984 0.0209814 0.0209788 0.0205225 0.0191754 0.0159554 -0.0673774 - 0.98852300000000004 + 0.988523 - + knee_angle_l @@ -2709,23 +2849,35 @@ -0.0014 -0.0014 - 0.98852300000000004 + 0.988523 + knee_angle_l - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 @@ -2734,17 +2886,17 @@ 0.130462375970093 - 0.35476611009411202 + 0.354766110094112 - 0.087266460000000004 + 0.08726646 10 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -2761,9 +2913,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -2775,47 +2927,34 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../femur_l - - 0.033270000000000001 -0.22072900000000001 -0.035564400000000003 + 0.03327 -0.220729 -0.0355644 + femur_l - - ../../../femur_l - - 0.038432500000000001 -0.23908499999999999 -0.032696299999999998 + 0.0384325 -0.239085 -0.0326963 + femur_l - - ../../../femur_l - - 0.039350299999999998 -0.46233800000000003 -0.0063098199999999998 - - ../../../knee_l/knee_angle_l - - -2.6179899999999998 -1.4199999999999999 + 0.0393503 -0.462338 -0.00630982 + femur_l + -2.61799 -1.42 + knee_angle_l - - ../../../tibia_l - - ../../../knee_l/knee_angle_l - - ../../../knee_l/knee_angle_l - - ../../../knee_l/knee_angle_l - + 0.0548266 0.025002 -0.00177934 + tibia_l @@ -2824,10 +2963,10 @@ 0.0082733 0.0106866 0.0202042 0.022353 0.0234583 0.0292715 0.0349465 0.037871 0.0412569 0.0465287 0.0554632 0.0554735 0.0554837 0.0571717 0.061272 0.0684368 0.0648818 - 0.98852300000000004 + 0.988523 - + knee_angle_l @@ -2836,10 +2975,10 @@ 0.025599 0.0259487 0.0273124 0.0274796 0.0275151 0.0271363 0.0265737 0.0263073 0.0261187 0.0260129 0.0252923 0.0252911 0.0252898 0.0250526 0.0242191 0.0218288 -0.0685706 - 0.98852300000000004 + 0.988523 - + knee_angle_l @@ -2848,23 +2987,35 @@ -0.0018 -0.0018 - 0.98852300000000004 + 0.988523 + knee_angle_l - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 @@ -2873,17 +3024,17 @@ 0.124678696688354 - 0.13516568986774899 + 0.135165689867749 - 0.052359879999999998 + 0.05235988 10 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -2900,9 +3051,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -2914,69 +3065,74 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../femur_l - - -0.0217976 -0.45075100000000001 0.026960100000000001 + -0.0217976 -0.450751 0.0269601 + femur_l - - ../../../femur_l - - -0.034417200000000002 -0.46142 0.029598800000000001 - - ../../../knee_l/knee_angle_l - - -0.78539800000000004 0.17453299999999999 + -0.0344172 -0.46142 0.0295988 + femur_l + -0.785398 0.174533 + knee_angle_l - - ../../../calcn_l - - 0 0.0318395 0.0054435200000000003 + 0 0.0318395 0.00544352 + calcn_l - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 2500 - 0.090128750494776796 + 0.0901287504947768 - 0.36051500197910702 + 0.360515001979107 - 0.29670596999999999 + 0.29670597 10 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -2993,9 +3149,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -3007,40 +3163,49 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../tibia_l - - -0.0023724599999999998 -0.15154100000000001 -0.0070185100000000004 + -0.00237246 -0.151541 -0.00701851 + tibia_l - - ../../../calcn_l - - 0 0.0318395 0.0054435200000000003 + 0 0.0318395 0.00544352 + calcn_l - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 @@ -3049,7 +3214,7 @@ 0.050288844245806 - 0.25144422122902998 + 0.25144422122903 0.43633231 @@ -3057,9 +3222,9 @@ 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -3076,9 +3241,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -3090,65 +3255,72 @@ - - true + + false - 0 - + 0.0001 + + 1 + - - ../../../tibia_l - - 0.017694600000000001 -0.16053600000000001 -0.011368 + 0.0176946 -0.160536 -0.011368 + tibia_l - - ../../../tibia_l - - 0.0325224 -0.390565 0.017496899999999999 + 0.0325224 -0.390565 0.0174969 + tibia_l - - ../../../calcn_l - - 0.119758 0.018282 0.031325899999999997 + 0.119758 0.018282 0.0313259 + calcn_l - + - - - - 0.80000000000000004 0.10000000000000001 0.10000000000000001 - + + + + + + + + + 1 1 1 + + 0 0 0 0 0 0 + + false + + 4 + 1 3000 - 0.097912574684154305 + 0.0979125746841543 - 0.22280106280169801 + 0.222801062801698 - 0.087266460000000004 + 0.08726646 10 0.01 - 0.040000000000000001 + 0.04 - 0 + 0.0 @@ -3165,9 +3337,9 @@ 0 - 0.14999999999999999 + 0.15 - 1.3999999999999999 + 1.4 @@ -3195,8 +3367,8 @@ 2 - - true + + false -Inf @@ -3204,7 +3376,7 @@ pelvis - -0.034000000000000002 0 0 + -0.034 0 0 false @@ -3215,8 +3387,8 @@ 1 - - true + + false -Inf @@ -3224,7 +3396,7 @@ pelvis - -0.034000000000000002 0 0 + -0.034 0 0 false @@ -3235,8 +3407,8 @@ 1 - - true + + false -Inf @@ -3253,8 +3425,8 @@ 1 - - true + + false -Inf @@ -3265,8 +3437,8 @@ 1 - - true + + false -Inf @@ -3277,8 +3449,8 @@ 1 - - true + + false -Inf @@ -3289,8 +3461,8 @@ 1 - - true + + false -Inf @@ -3301,8 +3473,8 @@ 1 - - true + + false -Inf @@ -3313,8 +3485,8 @@ 1 - - true + + false -Inf @@ -3325,8 +3497,8 @@ 1 - - true + + false -Inf @@ -3343,327 +3515,332 @@ - - ../torso - - 0.103606 0.31243900000000002 1.0431799999999999e-06 - + + torso + + 0.103606 0.312439 1.04318e-006 + false - - ../torso - - -0.024871799999999999 0.42644500000000002 0.16858500000000001 - + + torso + + -0.0248718 0.426445 0.168585 + false - - ../torso - - -0.022008900000000001 0.44078899999999999 -0.17197100000000001 - + + torso + + -0.0220089 0.440789 -0.171971 + false - - ../torso - - 0.059513299999999998 0.69959800000000005 0.010501699999999999 - + + torso + + 0.0595133 0.699598 0.0105017 + false - - ../pelvis - - 0.0228989 0.035862400000000003 0.13011600000000001 - + + pelvis + + 0.0228989 0.0358624 0.130116 + false - - ../pelvis - - 0.0291329 0.027659099999999999 -0.13189400000000001 - + + pelvis + + 0.0291329 0.0276591 -0.131894 + false - - ../pelvis - - -0.17209099999999999 0.040002900000000001 0.0061984300000000004 - + + pelvis + + -0.172091 0.0400029 0.00619843 + false - - ../femur_r - - 0.050711600000000003 -0.220081 0.088385500000000006 - + + femur_r + + 0.0507116 -0.220081 0.0883855 + false - - ../femur_r - - 0.107902 -0.28174700000000003 -0.0069011400000000001 - + + femur_r + + 0.107902 -0.281747 -0.00690114 + false - - ../femur_r - - 0.039510900000000002 -0.34091500000000002 0.078954300000000005 - + + femur_r + + 0.0395109 -0.340915 0.0789543 + false - - ../femur_r - - -0.00058641499999999996 -0.426232 0.0605411 - + + femur_r + + -0.000586415 -0.426232 0.0605411 + false - - ../femur_r - - -0.0024303100000000002 -0.44290800000000002 -0.060748200000000002 - + + femur_r + + -0.00243031 -0.442908 -0.0607482 + false - - ../tibia_r - - -0.023313899999999999 -0.0603613 0.070733000000000004 - + + tibia_r + + -0.0233139 -0.0603613 0.070733 + false - - ../tibia_r - - 0.051675199999999998 -0.095429799999999995 0.016304599999999999 - + + tibia_r + + 0.0516752 -0.0954298 0.0163046 + false - - ../tibia_r - - -0.0073816400000000001 -0.14552599999999999 0.080002900000000002 - + + tibia_r + + -0.00738164 -0.145526 0.0800029 + false - - ../tibia_r - - -0.0049054299999999997 -0.43084299999999998 0.054920700000000003 - + + tibia_r + + -0.00490543 -0.430843 0.0549207 + false - - ../tibia_r - - 0.0028625899999999999 -0.416327 -0.034325000000000001 - + + tibia_r + + 0.00286259 -0.416327 -0.034325 + false - - ../calcn_r - - -0.020481900000000001 0.017288399999999999 -0.0050373500000000003 - + + calcn_r + + -0.0204819 0.0172884 -0.00503735 + false - - ../calcn_r - - 0.122708 0.030965800000000002 -0.0403332 - + + calcn_r + + 0.122708 0.0309658 -0.0403332 + false - - ../calcn_r - - 0.117766 0.011129 0.066972599999999993 - + + calcn_r + + 0.117766 0.011129 0.0669726 + false - - ../calcn_r - - 0.20769299999999999 -0.011410699999999999 0.076066900000000007 - + + calcn_r + + 0.207693 -0.0114107 0.0760669 + false - - ../calcn_r - - 0.209814 0.0016980700000000001 -0.032368399999999999 - + + calcn_r + + 0.209814 0.00169807 -0.0323684 + false - - ../calcn_r - - 0.27073399999999997 0.0031500500000000002 -0.00061229700000000004 - + + calcn_r + + 0.270734 0.00315005 -0.000612297 + false - - ../femur_l - - 0.0358442 -0.20749000000000001 -0.093257300000000001 - + + femur_l + + 0.0358442 -0.20749 -0.0932573 + false - - ../femur_l - - 0.114084 -0.24917700000000001 -0.0175704 - + + femur_l + + 0.114084 -0.249177 -0.0175704 + false - - ../femur_l - - 0.025891000000000001 -0.31621300000000002 -0.077853199999999997 - + + femur_l + + 0.025891 -0.316213 -0.0778532 + false - - ../femur_l - - -0.00075351300000000003 -0.44614199999999998 -0.062295999999999997 - + + femur_l + + -0.000753513 -0.446142 -0.062296 + false - - ../femur_l - - 0.00047251200000000002 -0.44543199999999999 0.053950600000000001 - + + femur_l + + 0.000472512 -0.445432 0.0539506 + false - - ../tibia_l - - 0.0039858799999999998 -0.071610999999999994 -0.077708600000000003 - + + tibia_l + + 0.00398588 -0.071611 -0.0777086 + false - - ../tibia_l - - 0.048142699999999997 -0.12153600000000001 -0.022303699999999999 - + + tibia_l + + 0.0481427 -0.121536 -0.0223037 + false - - ../tibia_l - - -0.013243599999999999 -0.11473899999999999 -0.088507199999999994 - + + tibia_l + + -0.0132436 -0.114739 -0.0885072 + false - - ../tibia_l - - 0.0038343100000000001 -0.42845100000000003 -0.054433799999999997 - + + tibia_l + + 0.00383431 -0.428451 -0.0544338 + false - - ../tibia_l - - 0.0078901000000000006 -0.40516099999999999 0.036925300000000001 - + + tibia_l + + 0.0078901 -0.405161 0.0369253 + false - - ../calcn_l - - -0.022619199999999999 0.026864300000000001 0.0078618799999999999 - + + calcn_l + + -0.0226192 0.0268643 0.00786188 + false - - ../calcn_l - - 0.14970600000000001 0.030704499999999999 0.034260600000000002 - + + calcn_l + + 0.149706 0.0307045 0.0342606 + false - - ../calcn_l - - 0.13132099999999999 0.030572599999999998 -0.064363000000000004 - + + calcn_l + + 0.131321 0.0305726 -0.064363 + false - - ../calcn_l - - 0.194745 0.00778416 -0.074838600000000005 - + + calcn_l + + 0.194745 0.00778416 -0.0748386 + false - - ../calcn_l - - 0.211787 0.0078861899999999995 0.027316500000000001 - + + calcn_l + + 0.211787 0.00788619 0.0273165 + false - - ../calcn_l - - 0.26097799999999999 0.0090690700000000003 0.0020131799999999998 - + + calcn_l + + 0.260978 0.00906907 0.00201318 + false - + + + + + + - + diff --git a/Bindings/Java/Matlab/examples/wiringInputsAndOutputsWithTableReporter.m b/Bindings/Java/Matlab/examples/wiringInputsAndOutputsWithTableReporter.m index 7cde76e060..c865701328 100644 --- a/Bindings/Java/Matlab/examples/wiringInputsAndOutputsWithTableReporter.m +++ b/Bindings/Java/Matlab/examples/wiringInputsAndOutputsWithTableReporter.m @@ -51,6 +51,7 @@ reporter = TableReporterVec3(); reporter.setName('reporter'); reporter.set_report_time_interval(0.1); + % Report the position of the origin of the body. reporter.addToReport(body.getOutput('position')); % For comparison, we will also get the center of mass position from the @@ -64,6 +65,9 @@ model.addComponent(reporter); +% We must finalize connections to save the input-output connections in the +% model file. +model.finalizeConnections(); model.print(modelFilename); @@ -78,7 +82,7 @@ % We can access the names of the outputs that the reporter is connected to. disp('Outputs connected to the reporter:'); for i = 0:(reporter.getInput('inputs').getNumConnectees() - 1) - disp(reporter.getInput('inputs').getConnecteeName(i)); + disp(reporter.getInput('inputs').getConnecteePath(i)); end % Simulate the model. diff --git a/Bindings/Java/Matlab/tests/testConnectorsInputsOutputs.m b/Bindings/Java/Matlab/tests/testConnectorsInputsOutputs.m index bf1136388b..8061e53604 100644 --- a/Bindings/Java/Matlab/tests/testConnectorsInputsOutputs.m +++ b/Bindings/Java/Matlab/tests/testConnectorsInputsOutputs.m @@ -33,7 +33,7 @@ % Sockets -% ========== +% ======= % Access (and iterate through) a component's AbstractSockets, using names. names = joint.getSocketNames(); @@ -56,7 +56,8 @@ % Connect a socket. Try the different methods to ensure they all work. offset.connectSocket_parent(ground); offset.updSocket('parent').connect(ground); -assert(strcmp(offset.getSocket('parent').getConnecteeName(), '../ground')); +model.finalizeConnections() +assert(strcmp(offset.getSocket('parent').getConnecteePath(), '/ground')); @@ -81,7 +82,7 @@ % -------- % Access AbstractChannels. assert(strcmp(coord.getOutput('speed').getChannel('').getPathName(), ... - '/leg/jointset/pin/pin_coord_0|speed')); + '/jointset/pin/pin_coord_0|speed')); % Access the value of a concrete Channel. % TODO Concrete channels are not wrapped yet. @@ -99,7 +100,7 @@ rep.addToReport(source.getOutput('column').getChannel('c1')); rep.updInput('inputs').connect(source.getOutput('column').getChannel('c2'), ... 'second_col'); - +model.finalizeConnections() % Inputs % ====== @@ -107,8 +108,8 @@ % Access (and iterate through) the AbstractInputs, using names. names = rep.getInputNames(); expectedAliases = {'', 'target', '', 'second_col'}; -expectedLabels = {'/leg/jointset/pin/pin_coord_0|value', 'target', ... - '/leg/source|column:c1', 'second_col'}; +expectedLabels = {'/jointset/pin/pin_coord_0|value', 'target', ... + '/source|column:c1', 'second_col'}; for i = 0:(names.size() - 1) % Actually, there is only one Input, named 'inputs'. % We connected it to 4 channels. diff --git a/Bindings/Java/OpenSimJNI/OpenSimContext.cpp b/Bindings/Java/OpenSimJNI/OpenSimContext.cpp index bb93eee53c..36b5d7e04b 100644 --- a/Bindings/Java/OpenSimJNI/OpenSimContext.cpp +++ b/Bindings/Java/OpenSimJNI/OpenSimContext.cpp @@ -434,7 +434,7 @@ void OpenSimContext::restoreStateFromCachedModel() this->realizePosition(); } -void OpenSimContext::setSocketConnecteeName(AbstractSocket& socket, +void OpenSimContext::setSocketConnecteePath(AbstractSocket& socket, const std::string& componentPathName) { // Since some socket changes can form an invalid system // we will make the change in a more conservative manner, by: @@ -448,7 +448,7 @@ void OpenSimContext::setSocketConnecteeName(AbstractSocket& socket, const Component& comp = socket.getOwner(); Component& componentInClone = clonedModel->updComponent(comp.getAbsolutePath()); auto& clonesocket = componentInClone.updSocket(socket.getName()); - clonesocket.setConnecteeName(componentPathName); + clonesocket.setConnecteePath(componentPathName); // The following line either succeeds or throws, if the latter happens then // neither model or socket are changed and the message will be caught by GUI try { @@ -462,7 +462,8 @@ void OpenSimContext::setSocketConnecteeName(AbstractSocket& socket, throw OpenSim::Exception(message); } // if we made it to this line then the change is safe, redo in actual model/comp/socket - socket.setConnecteeName(componentPathName); + socket.disconnect(); + socket.setConnecteePath(componentPathName); restoreStateFromCachedModel(); } } // namespace diff --git a/Bindings/Java/OpenSimJNI/OpenSimContext.h b/Bindings/Java/OpenSimJNI/OpenSimContext.h index d1247e5f42..a3fcc094ee 100644 --- a/Bindings/Java/OpenSimJNI/OpenSimContext.h +++ b/Bindings/Java/OpenSimJNI/OpenSimContext.h @@ -221,7 +221,8 @@ OpenSim_DECLARE_CONCRETE_OBJECT(OpenSimContext, Object); void cacheModelAndState(); void restoreStateFromCachedModel() SWIG_DECLARE_EXCEPTION; - void setSocketConnecteeName(AbstractSocket& socket, const std::string& newValue ) SWIG_DECLARE_EXCEPTION; + void setSocketConnecteePath(AbstractSocket& socket, + const std::string& newValue) SWIG_DECLARE_EXCEPTION; //============================================================================= // DATA //============================================================================= diff --git a/Bindings/Java/OpenSimJNI/Test/testContext.cpp b/Bindings/Java/OpenSimJNI/Test/testContext.cpp index 52dd90cd65..3284a9d695 100644 --- a/Bindings/Java/OpenSimJNI/Test/testContext.cpp +++ b/Bindings/Java/OpenSimJNI/Test/testContext.cpp @@ -231,7 +231,7 @@ int main() try { // create an invalid model where joint connects two frames on ground, // the test will verify the connectee has not been changed - context->setSocketConnecteeName(socket, "ground"); + context->setSocketConnecteePath(socket, "ground"); } catch (const std::exception& e) { // Expect meaningful error message explaining why initsystem failed @@ -243,7 +243,7 @@ int main() try { // Try to create an invalid model again, this call should leave the // model untouched since change invalidates psocket - context->setSocketConnecteeName(psocket, "r_ulna_radius_hand"); + context->setSocketConnecteePath(psocket, "r_ulna_radius_hand"); } catch (const std::exception& e) { diff --git a/Bindings/Java/tests/TestEditMarkers.java b/Bindings/Java/tests/TestEditMarkers.java index 8d292c1ca5..8cf7d09119 100644 --- a/Bindings/Java/tests/TestEditMarkers.java +++ b/Bindings/Java/tests/TestEditMarkers.java @@ -18,7 +18,7 @@ public static void main(String[] args) { Marker newMarker = new Marker(); newMarker.setName(newMarkerName); newMarker.set_location(offset); - newMarker.setParentFrameName(body.getName()); + newMarker.setParentFrame(body); context.cacheModelAndState(); model.addMarker(newMarker); try { diff --git a/Bindings/Java/tests/TestReporter.java b/Bindings/Java/tests/TestReporter.java index 16935aa3f5..2b24cbddb7 100644 --- a/Bindings/Java/tests/TestReporter.java +++ b/Bindings/Java/tests/TestReporter.java @@ -45,9 +45,9 @@ public static void test_TableReporter_1() throws java.io.IOException { assert table.getColumnLabels().size() == 2; assert table.getColumnLabel(0). - equals("/model/table_source|column:col1"); + equals("/table_source|column:col1"); assert table.getColumnLabel(1). - equals("/model/table_source|column:col2"); + equals("/table_source|column:col2"); assert table.getNumRows() == 3; assert table.getNumColumns() == 2; assert table.getRowAtIndex(0).get(0) == 1; @@ -66,17 +66,17 @@ public static void test_TableReporter_1() throws java.io.IOException { assert table.getNumColumns() == 0; assert table.getColumnLabels().size() == 2; assert table.getColumnLabel(0). - equals("/model/table_source|column:col1"); + equals("/table_source|column:col1"); assert table.getColumnLabel(1). - equals("/model/table_source|column:col2"); + equals("/table_source|column:col2"); // Make sure the table reference is still valid. assert table.getNumRows() == 0; assert table.getNumColumns() == 0; assert table.getColumnLabels().size() == 2; assert table.getColumnLabel(0). - equals("/model/table_source|column:col1"); + equals("/table_source|column:col1"); assert table.getColumnLabel(1). - equals("/model/table_source|column:col2"); + equals("/table_source|column:col2"); state = model.initSystem(); state.setTime(0.1); @@ -88,9 +88,9 @@ public static void test_TableReporter_1() throws java.io.IOException { assert table.getColumnLabels().size() == 2; assert table.getColumnLabel(0). - equals("/model/table_source|column:col1"); + equals("/table_source|column:col1"); assert table.getColumnLabel(1). - equals("/model/table_source|column:col2"); + equals("/table_source|column:col2"); assert table.getNumRows() == 3; assert table.getNumColumns() == 2; assert table.getRowAtIndex(0).get(0) == 1; diff --git a/Bindings/Python/examples/wiring_inputs_and_outputs_with_TableReporter.py b/Bindings/Python/examples/wiring_inputs_and_outputs_with_TableReporter.py index dc8bd980ee..12f8fcaeb2 100644 --- a/Bindings/Python/examples/wiring_inputs_and_outputs_with_TableReporter.py +++ b/Bindings/Python/examples/wiring_inputs_and_outputs_with_TableReporter.py @@ -59,10 +59,12 @@ def print_model(): # one-body system. The (optional) second argument is an alias for the name # of the output; it is used as the column label in the table. reporter.addToReport(model.getOutput('com_position'), 'com_pos') + + model.addComponent(reporter) + model.finalizeConnections() + # Display what input-output connections look like in XML (in .osim files). print("Reporter input-output connections in XML:\n" + reporter.dump()) - - model.addComponent(reporter) model.printToXML(model_filename) @@ -79,7 +81,7 @@ def print_model(): # We can access the names of the outputs that the reporter is connected to. print('Outputs connected to the reporter:') for i in range(reporter.getInput('inputs').getNumConnectees()): - print(reporter.getInput('inputs').getConnecteeName(i)) + print(reporter.getInput('inputs').getConnecteePath(i)) # Simulate the model. manager = osim.Manager(deserialized_model) @@ -104,5 +106,3 @@ def print_model(): - - diff --git a/Bindings/Python/tests/test_sockets_inputs_outputs.py b/Bindings/Python/tests/test_sockets_inputs_outputs.py index fdfccff35d..feccd8d450 100644 --- a/Bindings/Python/tests/test_sockets_inputs_outputs.py +++ b/Bindings/Python/tests/test_sockets_inputs_outputs.py @@ -134,7 +134,7 @@ def test_output_values(self): # AbstractChannel. coord = model.getCoordinateSet().get(0) self.assertEquals(coord.getOutput('speed').getChannel('').getPathName(), - '/arm26/jointset/r_shoulder/r_shoulder_elev|speed') + '/jointset/r_shoulder/r_shoulder_elev|speed') # Access the value of a concrete Channel. # TODO Concrete channels are not wrapped yet. @@ -211,8 +211,8 @@ def test_connecting_and_iterate_inputs(self): s = m.initSystem() # Access and iterate through AbstractInputs, using names. - expectedLabels = ['/model/jointset/pin/pin_coord_0|value', 'spd', - '/model/source|column:col1', 'second_col'] + expectedLabels = ['/jointset/pin/pin_coord_0|value', 'spd', + '/source|column:col1', 'second_col'] i = 0 for name in rep.getInputNames(): # Actually, there is only one input, which we connected to 4 @@ -255,7 +255,12 @@ def print_model(): reporter = osim.TableReporterVec3() reporter.setName('reporter') reporter.set_report_time_interval(0.1) + reporter.addToReport(model.getOutput('com_position')) + + model.addComponent(reporter) + model.finalizeConnections() + reporter.getInput('inputs').setAlias(0, 'com_pos') # Display what input-output connections look like in XML @@ -263,8 +268,6 @@ def print_model(): print("Reporter input-output connections in XML:\n" + \ reporter.dump()) - model.addComponent(reporter) - model.printToXML(model_filename) # Create and print the model file. diff --git a/OpenSim/Actuators/BodyActuator.cpp b/OpenSim/Actuators/BodyActuator.cpp index 6d1a1f3b70..54c820979e 100644 --- a/OpenSim/Actuators/BodyActuator.cpp +++ b/OpenSim/Actuators/BodyActuator.cpp @@ -76,12 +76,12 @@ void BodyActuator::constructProperties() void BodyActuator::setBodyName(const std::string& name) { - updSocket("body").setConnecteeName(name); + updSocket("body").setConnecteePath(name); } const std::string& BodyActuator::getBodyName() const { - return getSocket("body").getConnecteeName(); + return getSocket("body").getConnecteePath(); } //============================================================================= diff --git a/OpenSim/Actuators/Test/testActuators.cpp b/OpenSim/Actuators/Test/testActuators.cpp index c90784d389..dd5d2da6cb 100644 --- a/OpenSim/Actuators/Test/testActuators.cpp +++ b/OpenSim/Actuators/Test/testActuators.cpp @@ -209,6 +209,7 @@ void testTorqueActuator() //model->addProbe(powerProbe); + model->finalizeConnections(); model->print("TestTorqueActuatorModel.osim"); model->setUseVisualizer(false); @@ -355,6 +356,7 @@ void testClutchedPathSpring() controller->prescribeControlForActuator("clutch_spring", controlfunc); model->addController(controller); + model->finalizeConnections(); model->print("ClutchedPathSpringModel.osim"); //Test deserialization diff --git a/OpenSim/Common/Component.cpp b/OpenSim/Common/Component.cpp index b9bcb3d654..962ee57f6a 100644 --- a/OpenSim/Common/Component.cpp +++ b/OpenSim/Common/Component.cpp @@ -127,8 +127,7 @@ Component::Component(SimTK::Xml::Element& element) : Object(element) constructProperty_components(); } -void Component::addComponent(Component* subcomponent) -{ +bool Component::isComponentInOwnershipTree(const Component* subcomponent) const { //get to the root Component const Component* root = this; while (root->hasOwner()) { @@ -139,21 +138,41 @@ void Component::addComponent(Component* subcomponent) if ((root->getNumImmediateSubcomponents() > 0)) { auto components = root->getComponentList(); for (auto& c : components) { - if (subcomponent == &c) { - OPENSIM_THROW(ComponentAlreadyPartOfOwnershipTree, - subcomponent->getName(), getName()); - } + if (subcomponent == &c) return true; } } + return false; +} + +void Component::addComponent(Component* subcomponent) +{ + OPENSIM_THROW_IF(isComponentInOwnershipTree(subcomponent), + ComponentAlreadyPartOfOwnershipTree, + subcomponent->getName(), getName()); updProperty_components().adoptAndAppendValue(subcomponent); finalizeFromProperties(); + prependComponentPathToConnecteePath(*subcomponent); + // allow the derived Component to perform secondary operations // in response to the inclusion of the subcomponent extendAddComponent(subcomponent); } +void Component::prependComponentPathToConnecteePath( + Component& subcomponent) { + const std::string compPath = subcomponent.getAbsolutePathString(); + for (auto& comp : subcomponent.updComponentList()) { + for (auto& it : comp._socketsTable) { + it.second->prependComponentPathToConnecteePath(compPath); + } + for (auto& it : comp._inputsTable) { + it.second->prependComponentPathToConnecteePath(compPath); + } + } +} + void Component::finalizeFromProperties() { reset(); @@ -191,12 +210,12 @@ void Component::finalizeFromProperties() for (auto& it : _socketsTable) { it.second->setOwner(*this); // Let the Socket handle any errors in the connectee_name property. - it.second->checkConnecteeNameProperty(); + it.second->checkConnecteePathProperty(); } for (auto& it : _inputsTable) { it.second->setOwner(*this); // Let the Socket handle any errors in the connectee_name property. - it.second->checkConnecteeNameProperty(); + it.second->checkConnecteePathProperty(); } for (auto& it : _outputsTable) { it.second->setOwner(*this); @@ -283,9 +302,8 @@ void Component::finalizeConnections(Component& root) for (auto& it : _socketsTable) { auto& socket = it.second; - socket->disconnect(); try { - socket->findAndConnect(root); + socket->finalizeConnection(root); } catch (const std::exception& x) { OPENSIM_THROW_FRMOBJ(Exception, "Failed to connect Socket '" + @@ -297,23 +315,8 @@ void Component::finalizeConnections(Component& root) for (auto& it : _inputsTable) { auto& input = it.second; - - if (!input->isListSocket() && input->getConnecteeName(0).empty()) { - // TODO When we support verbose/debug logging we should include - // message about unspecified Outputs but generally this OK - // if the Input's value is not required. - /** - std::cout << getConcreteClassName() << "'" << getName() << "'"; - std::cout << "::connect() Input<" << input.getConnecteeTypeName(); - std::cout << ">`" << input.getName(); - std::cout << "' Output has not been specified." << std::endl; - */ - continue; - } - - input->disconnect(); try { - input->findAndConnect(root); + input->finalizeConnection(root); } catch (const std::exception& x) { OPENSIM_THROW_FRMOBJ(Exception, "Failed to connect Input '" + @@ -325,10 +328,10 @@ void Component::finalizeConnections(Component& root) // Allow derived Components to handle/check their connections and also // override the order in which its subcomponents are ordered when // adding subcomponents to the System - extendConnect(root); + extendFinalizeConnections(root); // Allow subcomponents to form their connections - componentsConnect(root); + componentsFinalizeConnections(root); // Forming connections changes the Socket which is a property // Remark as upToDate. @@ -336,7 +339,7 @@ void Component::finalizeConnections(Component& root) } // invoke connect on all (sub)components of this component -void Component::componentsConnect(Component& root) +void Component::componentsFinalizeConnections(Component& root) { // enable the subcomponents the opportunity to connect themselves for (unsigned int i = 0; i<_memberSubcomponents.size(); ++i) { @@ -686,6 +689,14 @@ bool Component::hasOwner() const return !_owner.empty(); } +const Component& Component::getRoot() const { + const Component* root = this; + while (root->hasOwner()) { + root = &root->getOwner(); + } + return *root; +} + void Component::setOwner(const Component& owner) { if (&owner == this) { @@ -702,13 +713,15 @@ void Component::setOwner(const Component& owner) std::string Component::getAbsolutePathString() const { + if (!hasOwner()) return "/"; std::string absPathName("/" + getName()); const Component* up = this; while (up && up->hasOwner()) { up = &up->getOwner(); - absPathName.insert(0, "/" + up->getName()); + if (up->hasOwner()) + absPathName.insert(0, "/" + up->getName()); } return absPathName; @@ -717,6 +730,8 @@ std::string Component::getAbsolutePathString() const ComponentPath Component::getAbsolutePath() const { + if (!hasOwner()) return ComponentPath({}, true); + std::vector pathVec; pathVec.push_back(getName()); @@ -724,18 +739,24 @@ ComponentPath Component::getAbsolutePath() const while (up && up->hasOwner()) { up = &up->getOwner(); - pathVec.insert(pathVec.begin(), up->getName()); + if (up->hasOwner()) + pathVec.insert(pathVec.begin(), up->getName()); } return ComponentPath(pathVec, true); } -std::string Component::getRelativePathName(const Component& wrt) const +std::string Component::getRelativePathString(const Component& wrt) const +{ + return getRelativePath(wrt).toString(); +} + +ComponentPath Component::getRelativePath(const Component& wrt) const { ComponentPath thisP = getAbsolutePath(); ComponentPath wrtP = wrt.getAbsolutePath(); - return thisP.formRelativePath(wrtP).toString(); + return thisP.formRelativePath(wrtP); } const Component::StateVariable* Component:: @@ -1045,6 +1066,11 @@ void Component::setNextSubcomponentInSystem(const Component& sub) const void Component::updateFromXMLNode(SimTK::Xml::Element& node, int versionNumber) { + // During deserialization, some components' clone() may + // finalizeFromProperties(). Upating from XML can then cause stale pointers. + // We must make sure to clear any pointers to properties that may exist + // in this component. + reset(); if (versionNumber < XMLDocument::getLatestVersion()) { if (versionNumber < 30500) { // In 3.3 and earlier, spaces in names were tolerated. Spaces are @@ -1522,8 +1548,9 @@ void Component::AddedStateVariable:: void Component::printSocketInfo() const { - std::cout << "Sockets for component " << getName() << " of type [" - << getConcreteClassName() << "] along with connectee names:"; + std::cout << "Sockets for component " << getName() + << " of type [" << getConcreteClassName() + << "] along with connectee paths:"; if (getNumSockets() == 0) std::cout << " none"; std::cout << std::endl; @@ -1550,7 +1577,7 @@ void Component::printSocketInfo() const { std::cout << "no connectees" << std::endl; } else { for (unsigned i = 0; i < socket->getNumConnectees(); ++i) { - std::cout << socket->getConnecteeName(i) << " "; + std::cout << socket->getConnecteePath(i) << " "; } std::cout << std::endl; } @@ -1560,7 +1587,7 @@ void Component::printSocketInfo() const { void Component::printInputInfo() const { std::cout << "Inputs for component " << getName() << " of type [" - << getConcreteClassName() << "] along with connectee names:"; + << getConcreteClassName() << "] along with connectee paths:"; if (getNumInputs() == 0) std::cout << " none"; std::cout << std::endl; @@ -1584,11 +1611,11 @@ void Component::printInputInfo() const { input->getName().length(), ' ') << input->getName() << " : "; if (input->getNumConnectees() == 0 || - (input->getNumConnectees() == 1 && input->getConnecteeName().empty())) { + (input->getNumConnectees() == 1 && input->getConnecteePath().empty())) { std::cout << "no connectees" << std::endl; } else { for (unsigned i = 0; i < input->getNumConnectees(); ++i) { - std::cout << input->getConnecteeName(i) << " "; + std::cout << input->getConnecteePath(i) << " "; // TODO as is, requires the input connections to be satisfied. // std::cout << " (alias: " << input.getAlias(i) << ") "; } @@ -1729,7 +1756,45 @@ void Component::reset() _simTKcomponentIndex.invalidate(); clearStateAllocations(); + _propertySubcomponents.clear(); + _adoptedSubcomponents.clear(); resetSubcomponentOrder(); } +void Component::warnBeforePrint() const { + if (!isObjectUpToDateWithProperties()) return; + std::string message; + auto checkIfConnecteePathIsSet = + [](const Component& comp, std::string& message) { + for (const auto& it : comp._socketsTable) { + const auto& socket = it.second; + if (socket->isConnected() && + ((socket->isListSocket() && + socket->getNumConnectees() == 0) || + (!socket->isListSocket() && + socket->getConnecteePath().empty()))) { + // TODO: Improve this condition by making sure the connectee + // name is correct. + message += " Socket '" + socket->getName() + "' in " + + comp.getConcreteClassName() + " at " + + comp.getAbsolutePathString() + "\n"; + } + } + }; + if (getNumImmediateSubcomponents() == 0) { + checkIfConnecteePathIsSet(*this, message); + } else { + for (const auto& comp : getComponentList()) { + checkIfConnecteePathIsSet(comp, message); + } + } + if (!message.empty()) { + std::cout << "Warning in " << getConcreteClassName() + << "::print(): The following connections are not finalized " + "and will not appear in the resulting XML file. " + "Call finalizeConnections() before print().\n" + << message << std::endl; + } +} + } // end of namespace OpenSim diff --git a/OpenSim/Common/Component.h b/OpenSim/Common/Component.h index 8cbf70782d..2b9844603f 100644 --- a/OpenSim/Common/Component.h +++ b/OpenSim/Common/Component.h @@ -557,6 +557,10 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object); * Component has not added itself to the System. */ bool hasSystem() const { return !_system.empty(); } + /** Does the provided component already exist anywhere in the ownership + * tree (not just subcomponents of this component)? */ + bool isComponentInOwnershipTree(const Component* component) const; + /** * Add a Component (as a subcomponent) of this component. * This component takes ownership of the subcomponent and it will be @@ -684,9 +688,13 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object); * need the path as a string. */ ComponentPath getAbsolutePath() const; - /** Get the relative pathname of this Component with respect to another + /** Get the relative path of this Component with respect to another + * Component, as a string. */ + std::string getRelativePathString(const Component& wrt) const; + + /** Get the relative path of this Component with respect to another * Component. */ - std::string getRelativePathName(const Component& wrt) const; + ComponentPath getRelativePath(const Component& wrt) const; /** Query if there is a component (of any type) at the specified * path name. For example, @@ -949,13 +957,13 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object); if (it != _socketsTable.end()) { // The following allows one to use a Socket immediately after // copying the component; - // e.g., myComponent.clone().getSocket("a").getConnecteeName(). + // e.g., myComponent.clone().getSocket("a").getConnecteePath(). // Since we use the default copy constructor for Component, // the copied AbstractSocket cannot know its new owner // immediately after copying. if (!it->second->hasOwner()) { // The `this` pointer must be non-const because the Socket - // will want to be able to modify the connectee name property. + // will want to be able to modify the connectee path property. const_cast(it->second.get())->setOwner( const_cast(*this)); } @@ -1070,7 +1078,7 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object); if (it != _inputsTable.end()) { // The following allows one to use an Input immediately after // copying the component; - // e.g., myComponent.clone().getInput("a").getConnecteeName(). + // e.g., myComponent.clone().getInput("a").getConnecteePath(). // Since we use the default copy constructor for Component, // the copied AbstractSocket (base class of AbstractInput) // cannot know its new owner immediately after copying. @@ -1577,11 +1585,11 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object); void printSubcomponentInfo() const; /** List all the Sockets of this component and whether or not they are - connected. Also list the connectee names for sockets that are connected. */ + connected. Also list the connectee paths for sockets that are connected. */ void printSocketInfo() const; /** List all the inputs of this component and whether or not they are - connected. Also list the (desired) connectee names for the inputs. */ + connected. Also list the (desired) connectee paths for the inputs. */ void printInputInfo() const; template @@ -1793,12 +1801,12 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object); If you override this method, be sure to invoke the base class method first, using code like this: @code - void MyComponent::extendConnect(Component& root) { - Super::extendConnect(root); // invoke parent class method + void MyComponent::extendFinalizeConnections(Component& root) { + Super::extendFinalizeConnections(root); // invoke parent class method // ... your code goes here } @endcode */ - virtual void extendConnect(Component& root) {}; + virtual void extendFinalizeConnections(Component& root) {}; /** Build the tree of Components from this component through its descendants. This method is invoked whenever a ComponentList is requested. Note that @@ -2198,9 +2206,9 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object); #pragma clang diagnostic ignored "-Wunsupported-friend" #endif template - friend void Socket::findAndConnect(const Component& root); + friend void Socket::finalizeConnection(const Component& root); template - friend void Input::findAndConnect(const Component& root); + friend void Input::finalizeConnection(const Component& root); #if defined(__clang__) #pragma clang diagnostic pop #endif @@ -2321,12 +2329,7 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object); size_t iPathEltStart = 0u; const Component* current = this; if (path.isAbsolute()) { - while (current->hasOwner()) current = ¤t->getOwner(); - if (path.getNumPathLevels() == 0 || - current->getName() != path.getSubcomponentNameAtLevel(0)) - return nullptr; - // Skip over the root name. - iPathEltStart = 1u; + current = ¤t->getRoot(); } else { while (iPathEltStart < path.getNumPathLevels() && path.getSubcomponentNameAtLevel(iPathEltStart) == "..") { @@ -2390,6 +2393,10 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object); * (2) has not been added to another component */ bool hasOwner() const; + /** Obtain the root %Component, which is this component if it is orphaned. + */ + const Component& getRoot() const; + protected: /** %Set this %Component's reference to its owning %Component */ void setOwner(const Component& owner); @@ -2418,7 +2425,7 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object); * type and enables the Component to automatically traverse its dependencies * and provide a meaningful message if the provided Component is * incompatible or non-existent. This function also creates a Property in - * this component to store the connectee name for this socket; the + * this component to store the connectee path for this socket; the * propertyComment argument is the comment to use for that Property. */ template PropertyIndex constructSocket(const std::string& name, @@ -2550,7 +2557,7 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object); * dependsOnStage is above the Input's requiredAtStage, an Exception is * thrown because the output cannot satisfy the Input's requirement. * This function also creates a Property in this component to store the - * connectee names for this input; the + * connectee paths for this input; the * propertyComment argument is the comment to use for that Property. */ template PropertyIndex constructInput(const std::string& name, bool isList, @@ -2581,6 +2588,11 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object); } /// @} + /// For internal use. Update absolute connectee paths in all sockets and + /// inputs in the subcomponent by prepending the absolute path of the + /// subcomponent. To be used when adding subcomponent to another component. + static void prependComponentPathToConnecteePath(Component& subcomponent); + private: //Mark components that are properties of this Component as subcomponents of @@ -2597,7 +2609,7 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object); void componentsFinalizeFromProperties() const; /// Invoke connect() on the (sub)components of this Component. - void componentsConnect(Component& root); + void componentsFinalizeConnections(Component& root); /// Base Component must create underlying resources in computational System. void baseAddToSystem(SimTK::MultibodySystem& system) const; @@ -2655,6 +2667,8 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object); // Reset by clearing underlying system indices. void reset(); + void warnBeforePrint() const override; + protected: //Derived Components must create concrete StateVariables to expose their state //variables. When exposing state variables allocated by the underlying Simbody @@ -2727,24 +2741,24 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Component, Object); /// Helper method to enable Component makers to specify the order of their /// subcomponents to be added to the System during addToSystem(). It is /// highly unlikely that you will need to reorder the subcomponents of your - /// custom component. This ability is primarily intended for Model (and + /// custom component. This ability is primarily intended for Model (and /// other top-level) components that have the responsibility of creating a - /// valid SimTK::MultibodySystem. MultibodySystem (Simbody) elements such - /// as MobilizedBodies must be added sequentially to form a Multibody tree. + /// valid SimTK::MultibodySystem. MultibodySystem (Simbody) elements such as + /// MobilizedBodies must be added sequentially to form a Multibody tree. /// SimTK::Constraints and SimTK::Forces must be applied to MobilizedBodies /// that are already present in the MultibodySystem. The Model component /// handles this order for you and should handle user-defined Components /// without any issues. You should rarely need to use this method yourself. - /// If needed, use this method in extendConnect() of your Component (or - /// within your extendConnectToModel() for ModelComponents) to set the - /// order of your subcomponents. For example, Model orders subcomponents - /// according to the Multibody tree and adds bodies and joints in order - /// starting from Ground and growing outward. - /// If the subcomponent already appears in the ordered list setting it - /// later in the list has no effect. The list remains unique. - /// NOTE: If you do need to set the order of your subcomponents, you must - /// do so for all your immediate subcomponents, otherwise those - /// components not in the ordered list will not be added to the System. + /// If needed, use this method in extendFinalizeConnections() of your + /// Component (or within your extendConnectToModel() for ModelComponents) to + /// set the order of your subcomponents. For example, Model orders + /// subcomponents according to the Multibody tree and adds bodies and joints + /// in order starting from Ground and growing outward. If the subcomponent + /// already appears in the ordered list setting it later in the list has no + /// effect. The list remains unique. NOTE: If you do need to set the order + /// of your subcomponents, you must do so for all your immediate + /// subcomponents, otherwise those components not in the ordered list will + /// not be added to the System. void setNextSubcomponentInSystem(const Component& sub) const; /// resetSubcomponentOrder clears this Component's list of ordered @@ -2999,38 +3013,69 @@ void ComponentListIterator::advanceToNextValidComponent() { } return; } + + +class ConnecteeNotSpecified : public Exception { +public: + ConnecteeNotSpecified(const std::string& file, + size_t line, + const std::string& func, + const AbstractSocket& socket, + const Component& owner) : + Exception(file, line, func) { + std::string msg = "Connectee for Socket '" + socket.getName() + + "' of type " + socket.getConnecteeTypeName() + " in " + + owner.getConcreteClassName() + " at " + + owner.getAbsolutePathString() + " is unspecified. " + "If this model was built programmatically, perhaps " + "finalizeConnections() was not called before " + "printing."; + addMessage(msg); + } +}; + template -void Socket::findAndConnect(const Component& root) { - - ComponentPath path(getConnecteeName()); - const C* comp = nullptr; +void Socket::finalizeConnection(const Component& root) { + + // If the reference to the connectee is set, use that. Otherwise, use the + // connectee path property. + if (isConnected()) { + const auto& comp = *connectee; + const auto& rootOfConnectee = comp.getRoot(); + const auto& myRoot = getOwner().getRoot(); + OPENSIM_THROW_IF(&myRoot != &rootOfConnectee, Exception, + "Socket<" + getConnecteeTypeName() + "> '" + getName() + + "' in " + getOwner().getConcreteClassName() + " at " + + getOwner().getAbsolutePathString() + " cannot connect to " + + comp.getConcreteClassName() + " at " + + comp.getAbsolutePathString() + ": components do not have the same " + "root component. Did you intend to add '" + + rootOfConnectee.getName() + "' to '" + myRoot.getName() + "'?"); + + ComponentPath connecteePath = connectee->getRelativePath(getOwner()); + // If the relative path starts with ".." then use an absolute path + // instead. + if (connecteePath.getNumPathLevels() > 1 && + connecteePath.getSubcomponentNameAtLevel(0) == "..") + connecteePath = connectee->getAbsolutePath(); + updConnecteePathProp().setValue(0, connecteePath.toString()); + + } else { + const auto connecteePath = getConnecteePath(); + OPENSIM_THROW_IF(connecteePath.empty(), ConnecteeNotSpecified, + *this, getOwner()); - try { + ComponentPath path(connecteePath); + const C* comp = nullptr; if (path.isAbsolute()) { - comp = &root.template getComponent(path); - } - else { - comp = &getOwner().template getComponent(path); + comp = &root.template getComponent(path); + } else { + comp = &getOwner().template getComponent(path); } + connectInternal(*comp); } - catch (const ComponentNotFoundOnSpecifiedPath& ex) { - if (Object::getDebugLevel() > 0) { - // TODO once we fix how connections are established when building - // models programmatically, we should show this warning even for - // debug level 0. - std::cout << ex.getMessage() << std::endl; - } - comp = root.template findComponent(path); - } - if (comp) - connect(*comp); - else - OPENSIM_THROW(ComponentNotFoundOnSpecifiedPath, - path.toString(), - C::getClassName(), - getName() ); } template @@ -3045,142 +3090,114 @@ void Input::connect(const AbstractOutput& output, << "' of type " << output.getTypeName() << "."; OPENSIM_THROW(Exception, msg.str()); } - - if (!isListSocket() && outT->isListOutput()) { + + if (!isListSocket() && outT->getChannels().size() > 1) { OPENSIM_THROW(Exception, "Non-list input '" + getName() + - "' cannot connect to list output '" + output.getPathName() + "."); + "' cannot connect to output '" + output.getPathName() + + " with more than 1 channel"); } // For a non-list socket, there will only be one channel. for (const auto& chan : outT->getChannels()) { - - // Record the number of pre-existing satisfied connections... - const size_t numPreexistingSatisfiedConnections(_connectees.size()); - // ...which happens to be the index of this new connectee. - const size_t idxThisConnectee = numPreexistingSatisfiedConnections; - _connectees.push_back( - SimTK::ReferencePtr(&chan.second) ); - - // Update the connectee name as - // /<:Channel><(annotation)> - ComponentPath path(output.getOwner().getRelativePathName(getOwner())); - - auto pathStr = - composeConnecteeName(path.toString(), - chan.second.getOutput().getName(), - chan.second.getOutput().isListOutput() ? - chan.second.getChannelName() : - "", - alias); - - // set the connectee name so that the connection can be - // serialized - const unsigned numDesiredConnections = getNumConnectees(); - if (idxThisConnectee < numDesiredConnections) - setConnecteeName(pathStr, unsigned(idxThisConnectee)); - else - appendConnecteeName(pathStr); - - // Use the provided alias for all channels. - _aliases.push_back(alias); + registerChannel(chan.second, alias); } } template void Input::connect(const AbstractChannel& channel, const std::string& alias) { - const auto* chanT = dynamic_cast(&channel); - if (!chanT) { - std::stringstream msg; - msg << "Type mismatch between Input and Output: Input '" << getName() - << "' of type " << getConnecteeTypeName() - << " cannot connect to Output (channel) '" << channel.getPathName() - << "' of type " << channel.getTypeName() << "."; - OPENSIM_THROW(Exception, msg.str()); - } - - if (!isListSocket()) { - // Remove the existing connectee (if it exists). - disconnect(); - } - - // Record the number of pre-existing satisfied connections... - const size_t numPreexistingSatisfiedConnections(_connectees.size()); - // ...which happens to be the index of this new connectee. - const size_t idxThisConnectee{ numPreexistingSatisfiedConnections }; - _connectees.push_back(SimTK::ReferencePtr(chanT)); - - // Update the connectee name as - // /<:Channel><(annotation)> - ComponentPath - path(chanT->getOutput().getOwner().getRelativePathName(getOwner())); - - auto pathStr = composeConnecteeName(path.toString(), - chanT->getOutput().getName(), - chanT->getOutput().isListOutput() ? - chanT->getChannelName() : - "", - alias); - - // Set the connectee name so the connection can be serialized. - const unsigned numDesiredConnections = getNumConnectees(); - - if (idxThisConnectee < numDesiredConnections) - // satisifed <= desired - setConnecteeName(pathStr, unsigned(idxThisConnectee)); - else - appendConnecteeName(pathStr); - - // Store the provided alias. - _aliases.push_back(alias); + registerChannel(channel, alias); } template -void Input::findAndConnect(const Component& root) { - std::string compPathStr, outputName, channelName, alias; - for (unsigned ix = 0; ix < getNumConnectees(); ++ix) { - parseConnecteeName(getConnecteeName(ix), - compPathStr, outputName, channelName, alias); - ComponentPath compPath(compPathStr); - const AbstractOutput* output = nullptr; - - if (compPath.isAbsolute()) { //absolute path string - if (compPathStr.empty()) { - output = &root.getOutput(outputName); - } - else { - output = &root.getComponent(compPathStr).getOutput(outputName); - } +void Input::finalizeConnection(const Component& root) { + + _connectees.clear(); + _aliases.clear(); + if (!_registeredChannels.empty()) { + clearConnecteePath(); + OPENSIM_THROW_IF(!isListSocket() && getChannels().size() > 1, + Exception, + "Cannot connect single-value input to multiple channels."); + for (const auto& reg : _registeredChannels) { + const Output& output = std::get<0>(reg).getRef(); + std::string channelName = std::get<1>(reg); + const AbstractChannel& channel = output.getChannel(channelName); + const std::string& alias = std::get<2>(reg); + connectInternal(channel, std::get<2>(reg)); } - else { // relative path string - const Component* comp = nullptr; - if (compPathStr.empty()) { - comp = &getOwner(); - } - else { - try { + int i = -1; + for (const auto& chan : getChannels()) { + + const auto& rootOfConnectee = + chan->getOutput().getOwner().getRoot(); + const auto& myRoot = getOwner().getRoot(); + OPENSIM_THROW_IF(&myRoot != &rootOfConnectee, Exception, + "Input<" + getConnecteeTypeName() + "> '" + getName() + + "' in " + getOwner().getConcreteClassName() + " at " + + getOwner().getAbsolutePathString() + " cannot connect to " + + "Channel " + chan->getPathName() + ": components do not have " + "the same root component. Did you intend to add '" + + rootOfConnectee.getName() + "' to '" + myRoot.getName() + "'?"); + + ++i; + // Update the connectee path as + // /<:Channel><(annotation)> + const auto& outputOwner = chan->getOutput().getOwner(); + ComponentPath path = outputOwner.getRelativePath(getOwner()); + // If the relative path starts with ".." then use an absolute path + // instead. + if (path.getNumPathLevels() > 1 && + path.getSubcomponentNameAtLevel(0) == "..") + path = outputOwner.getAbsolutePath(); + + auto pathStr = composeConnecteePath(path.toString(), + chan->getOutput().getName(), + chan->getOutput().isListOutput() + ? + chan->getChannelName() : + "", + _aliases[i]); + + if (isListSocket()) + updConnecteePathProp().appendValue(pathStr); + else + updConnecteePathProp().setValue(pathStr); + } + } else { + if (!isListSocket() && getConnecteePath().empty()) return; + std::string compPathStr, outputName, channelName, alias; + for (unsigned ix = 0; ix < getNumConnectees(); ++ix) { + parseConnecteePath(getConnecteePath(ix), + compPathStr, outputName, channelName, alias); + ComponentPath compPath(compPathStr); + const AbstractOutput* output = nullptr; + + if (compPath.isAbsolute()) { //absolute path string + if (compPathStr.empty()) { + output = &root.getOutput(outputName); + } else { + output = &root.getComponent(compPathStr).getOutput( + outputName); + } + } else { // relative path string + const Component* comp = nullptr; + if (compPathStr.empty()) { + comp = &getOwner(); + } else { comp = &getOwner().getComponent(compPathStr); - } catch (const ComponentNotFoundOnSpecifiedPath& ex) { - // If we cannot find the component at the specified path, - // look for the component anywhere in the model. - if (Object::getDebugLevel() > 0) { - // TODO once we fix how connections are established - // when building models programmatically, we should - // show this warning even for debug level 0. - std::cout << ex.getMessage() << std::endl; - } - comp = root.findComponent(compPath); } + // comp should never be null at this point. + OPENSIM_THROW_IF(!comp, Exception, "Internal error: " + "could not find component '" + + compPathStr + "."); + output = &comp->getOutput(outputName); } - // comp should never be null at this point. - OPENSIM_THROW_IF(!comp, Exception, "Internal error: " - "could not find component '" + compPathStr + "."); - output = &comp->getOutput(outputName); + const auto& channel = output->getChannel(channelName); + connectInternal(channel, alias); } - const auto& channel = output->getChannel(channelName); - connect(channel, alias); } } diff --git a/OpenSim/Common/ComponentOutput.cpp b/OpenSim/Common/ComponentOutput.cpp index 52d9f594e8..64d703a08b 100644 --- a/OpenSim/Common/ComponentOutput.cpp +++ b/OpenSim/Common/ComponentOutput.cpp @@ -25,6 +25,7 @@ #include "Component.h" using namespace OpenSim; + std::string AbstractOutput::getPathName() const { return getOwner().getAbsolutePathString() + "/" + getName(); } diff --git a/OpenSim/Common/ComponentOutput.h b/OpenSim/Common/ComponentOutput.h index 22ab8f4c48..de759f4a84 100644 --- a/OpenSim/Common/ComponentOutput.h +++ b/OpenSim/Common/ComponentOutput.h @@ -43,6 +43,7 @@ namespace OpenSim { class Component; +class AbstractInput; /** One of the values of an Output. */ class AbstractChannel { @@ -246,9 +247,12 @@ class Output : public AbstractOutput { throw Exception("Channel name cannot be empty."); _channels[channelName] = Channel(this, channelName); } - + + /** For a single-value output, name must be empty or must be the output's + * name. */ const AbstractChannel& getChannel(const std::string& name) const override { try { + if (!isListOutput() && name == getName()) return _channels.at(""); return _channels.at(name); } catch (const std::out_of_range&) { OPENSIM_THROW(Exception, "Output '" + getName() + "' does not have " diff --git a/OpenSim/Common/ComponentSocket.cpp b/OpenSim/Common/ComponentSocket.cpp index 0fb492e0f4..2415af7bc5 100644 --- a/OpenSim/Common/ComponentSocket.cpp +++ b/OpenSim/Common/ComponentSocket.cpp @@ -27,12 +27,62 @@ using namespace OpenSim; const Property& -AbstractSocket::getConnecteeNameProp() const { - return _owner->getProperty(_connecteeNameIndex); +AbstractSocket::getConnecteePathProp() const { + return _owner->getProperty(_connecteePathIndex); } Property& -AbstractSocket::updConnecteeNameProp() { - return const_cast(_owner.get())->updProperty( - _connecteeNameIndex); +AbstractSocket::updConnecteePathProp() { + auto* owner = const_cast(_owner.get()); + // We do not want to flip the isObjectUpToDateWithProperties flag. + const auto& prop = owner->getProperty(_connecteePathIndex); + return const_cast&>(prop); +} + +void AbstractSocket::prependComponentPathToConnecteePath( + const std::string& pathToPrepend) { + for (unsigned iConn = 0u; iConn < getNumConnectees(); ++iConn) { + ComponentPath path(getConnecteePath(iConn)); + if (path.isAbsolute()) { + ComponentPath newPath(pathToPrepend); + for (int iPath = 0; iPath < path.getNumPathLevels(); + ++iPath) { + newPath.pushBack( + path.getSubcomponentNameAtLevel(iPath)); + } + setConnecteePath(newPath.toString(), iConn); + } + } +} + +void AbstractInput::prependComponentPathToConnecteePath( + const std::string& pathToPrepend) { + for (unsigned iConn = 0u; iConn < getNumConnectees(); ++iConn) { + std::string connecteePath = getConnecteePath(iConn); + std::string componentPath; + std::string outputName; + std::string channelName; + std::string alias; + AbstractInput::parseConnecteePath(connecteePath, + componentPath, + outputName, + channelName, + alias); + ComponentPath path(componentPath); + if (path.isAbsolute()) { + ComponentPath newPath(pathToPrepend); + for (int iPath = 0; iPath < path.getNumPathLevels(); + ++iPath) { + newPath.pushBack( + path.getSubcomponentNameAtLevel(iPath)); + } + std::string newConnecteePath = + AbstractInput::composeConnecteePath( + newPath.toString(), + outputName, channelName, alias); + + setConnecteePath(newConnecteePath, iConn); + } + } + } diff --git a/OpenSim/Common/ComponentSocket.h b/OpenSim/Common/ComponentSocket.h index 44aea66467..9aa08fe451 100644 --- a/OpenSim/Common/ComponentSocket.h +++ b/OpenSim/Common/ComponentSocket.h @@ -23,20 +23,6 @@ * limitations under the License. * * -------------------------------------------------------------------------- */ -/** @file - * This file defines the Socket class, which formalizes the dependency of - * of a Component on another Object/Component in order to operate, BUT it does - * not own it. While Components can be composites (of multiple components) - * they often depend on unrelated objects/components that are defined and - * owned elsewhere. - * - * For example a Joint connects two bodies together, but the Joint does - * not own either body. Instead, the Joint has Sockets to a parent and - * a child body that already exists. The maintenance of the dependency and - * the run-time verification of the existence of the bodies is the duty - * of the Socket. - */ - // INCLUDES #include "osimCommonDLL.h" @@ -68,12 +54,15 @@ class InputNotConnected : public Exception { //============================================================================= // OPENSIM COMPONENT SOCKET //============================================================================= + /** * A Socket formalizes the dependency between a Component and another object - * (typically another Component) without owning that object. The object that - * satisfies the requirements of the Socket we term the "connectee". When a - * Socket is satisfied by a connectee we have a successful "connection" or - * is said to be connected. + * (typically another Component) without owning that object. While Components + * can be composites (of multiple components) they often depend on unrelated + * objects/components that are defined and owned elsewhere. The object that + * satisfies the requirements of the Socket we term the "connectee". When a + * Socket is satisfied by a connectee we have a successful "connection" or is + * said to be connected. * * The purpose of a Socket is to specify: 1) the connectee type that the * Component is dependent on, 2) by when (what stage) the socket must be @@ -93,6 +82,24 @@ class InputNotConnected : public Exception { * topology or add new states could potentially be connected at later stages * like Model or Instance. * + * Programmatically, the connectee can be specified as an object reference + * or via a connectee path: + * + * @code{.cpp} + * // Specifying the connectee using an object reference. + * socket.connect(myConnectee); + * // Specifying the connectee via a path. + * socket.setConnecteePath("/path/to/connectee"); + * @endcode + * + * Use finalizeConnection() to synchronize the object reference and connectee + * name. It is preferable to use connect() instead of setConnecteePath(). + * If *both* are set, then the object reference overrides the connectee path. + * + * The connectee path appears in XML files and is how a connection is maintained + * across serialization (writing to an XML file) and deserialization (reading + * from an XML file). + * * @author Ajay Seth */ class OSIMCOMMON_API AbstractSocket { @@ -114,9 +121,11 @@ class OSIMCOMMON_API AbstractSocket { /** Can this Socket have more than one connectee? */ bool isListSocket() const { return _isList; } /** The number of slots to fill in order to satisfy this socket. - * This is 1 for a non-list socket. */ + * This is 1 for a non-list socket. This is the number of elements in the + * connectee path property; to sync this with the number of connectee + * objects, call finalizeConnection(). */ unsigned getNumConnectees() const { - return static_cast(getConnecteeNameProp().size()); + return static_cast(getConnecteePathProp().size()); } //-------------------------------------------------------------------------- @@ -141,56 +150,75 @@ class OSIMCOMMON_API AbstractSocket { otherwise, the provided connectee replaces the single connectee. */ virtual void connect(const Object& connectee) = 0; - /** Connect this %Socket according to its connectee name property + /** Connect this %Socket according to its connectee path property given a root %Component to search its subcomponents for the connect_to Component. */ - virtual void findAndConnect(const Component& root) { - throw Exception("findAndConnect() not implemented; not supported " + virtual void finalizeConnection(const Component& root) { + throw Exception("finalizeConnection() not implemented; not supported " "for this type of socket", __FILE__, __LINE__); } - /** Disconnect this %Socket from its connectee. */ + /** Clear references to connectees. The connectee path property is not + * affected. Calling finalizeConnection() will use the connectee path + * property to satisfy the socket. */ virtual void disconnect() = 0; - /** %Set connectee name. This function can only be used if this socket is - not a list socket. */ - void setConnecteeName(const std::string& name) { + /** %Set connectee path. This function can only be used if this socket is + * not a list socket. If a connectee reference is set (with connect()) the + * connectee path is ignored; call disconnect() if you want the socket to be + * connected using the connectee path. + * + * It is preferable to use connect() instead of this function. */ + void setConnecteePath(const std::string& name) { OPENSIM_THROW_IF(_isList, Exception, "An index must be provided for a list Socket."); - setConnecteeName(name, 0); + setConnecteePath(name, 0); } - /** %Set connectee name of a connectee among a list of connectees. This - function is used if this socket is a list socket. */ - void setConnecteeName(const std::string& name, unsigned ix) { + /** %Set connectee path of a connectee among a list of connectees. This + * function is used if this socket is a list socket. If a connectee + * reference is set (with connect()) the connectee path is ignored; call + * disconnect() if you want the socket to be connected using the connectee + * name. + * + * It is preferable to use connect() instead of this function. */ + void setConnecteePath(const std::string& name, unsigned ix) { using SimTK::isIndexInRange; SimTK_INDEXCHECK_ALWAYS(ix, getNumConnectees(), - "AbstractSocket::setConnecteeName()"); - updConnecteeNameProp().setValue(ix, name); + "AbstractSocket::setConnecteePath()"); + updConnecteePathProp().setValue(ix, name); } - /** Get connectee name. This function can only be used if this socket is + /** Get connectee path. This function can only be used if this socket is not a list socket. */ - const std::string& getConnecteeName() const { + const std::string& getConnecteePath() const { OPENSIM_THROW_IF(_isList, Exception, "An index must be provided for a list Socket."); - return getConnecteeName(0); + return getConnecteePath(0); } - /** Get connectee name of a connectee among a list of connectees. */ - const std::string& getConnecteeName(unsigned ix) const { + /** Get connectee path of a connectee among a list of connectees. */ + const std::string& getConnecteePath(unsigned ix) const { using SimTK::isIndexInRange; SimTK_INDEXCHECK_ALWAYS(ix, getNumConnectees(), - "AbstractSocket::getConnecteeName()"); - return getConnecteeNameProp().getValue(ix); + "AbstractSocket::getConnecteePath()"); + return getConnecteePathProp().getValue(ix); } - void appendConnecteeName(const std::string& name) { + void appendConnecteePath(const std::string& name) { OPENSIM_THROW_IF((getNumConnectees() > 0 && !_isList), Exception, - "Multiple connectee names can only be appended to a list Socket."); - updConnecteeNameProp().appendValue(name); + "Multiple connectee paths can only be appended to a list Socket."); + updConnecteePathProp().appendValue(name); + } + + /** Clear all connectee paths in the connectee path property. */ + void clearConnecteePath() { + if (isListSocket()) + updConnecteePathProp().clear(); + else + updConnecteePathProp().setValue(0, ""); } /** Get owner component of this socket */ @@ -204,25 +232,25 @@ class OSIMCOMMON_API AbstractSocket { connected. @param name name of the socket, usually describes its dependency. - @param connecteeNameIndex Index of the property in the containing Component - that holds this Socket's connectee name(s). + @param connecteePathIndex Index of the property in the containing Component + that holds this Socket's connectee path(s). @param connectAtStage Stage at which Socket should be connected. @param owner Component to which this Socket belongs. */ AbstractSocket(const std::string& name, - const PropertyIndex& connecteeNameIndex, + const PropertyIndex& connecteePathIndex, const SimTK::Stage& connectAtStage, Component& owner) : _name(name), _connectAtStage(connectAtStage), - _connecteeNameIndex(connecteeNameIndex), + _connecteePathIndex(connecteePathIndex), _owner(&owner), - _isList(getConnecteeNameProp().isListProperty()) {} + _isList(getConnecteePathProp().isListProperty()) {} /** %Set an internal pointer to the Component that contains this Socket. This should only be called by Component. This exists so that after the containing Component is copied, the 'owner' is the new Component. This Socket needs to be able to modify - the associated connectee name property in the Component. Thus, we require + the associated connectee path property in the Component. Thus, we require a writable reference. */ // We could avoid the need for this function by writing a custom copy // constructor for Component. @@ -230,17 +258,17 @@ class OSIMCOMMON_API AbstractSocket { /** This will be false immediately after copy construction or assignment.*/ bool hasOwner() const { return !_owner.empty(); } - /** Check if entries of the connectee name property's value is valid (if + /** Check if entries of the connectee path property's value is valid (if it contains spaces, etc.); if so, print out a warning. */ - void checkConnecteeNameProperty() { - // TODO Move this check elsewhere once the connectee name + void checkConnecteePathProperty() { + // TODO Move this check elsewhere once the connectee path // property is a ComponentPath (or a ChannelPath?). for (unsigned iname = 0u; iname < getNumConnectees(); ++iname) { - const auto& connecteeName = getConnecteeName(iname); - ComponentPath cp(connecteeName); + const auto& connecteePath = getConnecteePath(iname); + ComponentPath cp(connecteePath); if (!cp.isLegalPathElement(cp.getComponentName()) ) { std::string msg = "In Socket '" + getName() + - "', connectee name '" + connecteeName + + "', connectee path '" + connecteePath + "' contains illegal characters such as spaces."; if (!_isList) { msg += " Did you try to specify multiple connectee " @@ -248,41 +276,47 @@ class OSIMCOMMON_API AbstractSocket { } OPENSIM_THROW(Exception, msg); } - - // Use the cleaned-up connectee name created by ComponentPath. - setConnecteeName(cp.toString(), iname); // TODO update the above for Inputs when ChannelPath exists. - // TODO There might be a bug with empty connectee name being + // TODO There might be a bug with empty connectee path being // interpreted as "this component." } } -private: +protected: - /// Const access to the connectee name property from the Component in which + /// Const access to the connectee path property from the Component in which /// this Socket resides. The name of that property is something like /// 'socket_'. This is a special type of property /// that users cannot easily access (e.g., there is no macro-generated /// `get_socket_()` function). - const Property& getConnecteeNameProp() const; - /// Writable access to the connectee name property from the Component in + const Property& getConnecteePathProp() const; + /// Writable access to the connectee path property from the Component in /// which this Socket resides. Calling this will mark the Component as /// not "up to date with properties" /// (Object::isObjectUpToDateWithProperties()). - Property& updConnecteeNameProp(); - + Property& updConnecteePathProp(); + + +private: + + /// Prepend the provided name to all (if any) absolute connectee paths + /// stored in this socket. This is to be used when adding one component + /// to another. + virtual void prependComponentPathToConnecteePath( + const std::string& pathToPrepend); + std::string _name; SimTK::Stage _connectAtStage = SimTK::Stage::Empty; - PropertyIndex _connecteeNameIndex; - // Even though updConnecteeNameProp() requires non-const access to this + PropertyIndex _connecteePathIndex; + // Even though updConnecteePathProp() requires non-const access to this // pointer, we make this a const pointer to reduce the chance of mis-use. // If this were a non-const pointer, then const functions in this class // would be able to edit _owner (see declaration of ReferencePtr). SimTK::ReferencePtr _owner; // _isList must be after _owner, as _owner is used to set its value. bool _isList; - + /* So that Component can invoke setOwner(), etc. */ friend Component; @@ -316,9 +350,10 @@ class Socket : public AbstractSocket { Return a const reference to the object connected to this Socket */ const T& getConnectee() const { if (!isConnected()) { - std::string msg = getOwner().getConcreteClassName() + "::Socket '" - + getName() + "' is not connected to '" + getConnecteeName() - + "' of type " + T::getClassName(); + std::string msg = "Socket " + getName() + " of type " + + T::getClassName() + " in " + + getOwner().getAbsolutePathString() + " of type " + + getOwner().getConcreteClassName() + " is not connected."; OPENSIM_THROW(Exception, msg); } return connectee.getRef(); @@ -335,34 +370,12 @@ class Socket : public AbstractSocket { << object.getConcreteClassName() << "."; OPENSIM_THROW(Exception, msg.str()); } - - connectee = *objT; - - std::string objPathName = objT->getAbsolutePathString(); - std::string ownerPathName = getOwner().getAbsolutePathString(); - - // Check if the connectee is an orphan (yet to be adopted component) - if (!objT->hasOwner()) { - // The API permits connecting to orphans when passing in the - // dependency directly. - // Workaround: Identify it as a "floating" - // Component and we will find its absolute path next time we try to - // connect - setConnecteeName(objT->getName()); - } - // This can happen when top level components like a Joint and Body - // have the same name like a pelvis Body and pelvis Joint that - // connects to a Body of the same name. - else if(objPathName == ownerPathName) - setConnecteeName(objPathName); - else { // otherwise store the relative path name to the object - std::string relPathName = objT->getRelativePathName(getOwner()); - setConnecteeName(relPathName); - } + + connectInternal(*objT); } - /** Connect this Socket given its connectee name property */ - void findAndConnect(const Component& root) override; + /** Connect this Socket given its connectee path property */ + void finalizeConnection(const Component& root) override; void disconnect() override { connectee.reset(nullptr); @@ -387,21 +400,26 @@ class Socket : public AbstractSocket { specified name and stage at which it should be connected. Only Component can ever construct this class. @param name name of the socket used to describe its dependency. - @param connecteeNameIndex Index of the property in the containing Component - that holds this Socket's connectee name(s). + @param connecteePathIndex Index of the property in the containing Component + that holds this Socket's connectee path(s). @param connectAtStage Stage at which Socket should be connected. @param owner The component that contains this input. */ Socket(const std::string& name, - const PropertyIndex& connecteeNameIndex, + const PropertyIndex& connecteePathIndex, const SimTK::Stage& connectAtStage, Component& owner) : - AbstractSocket(name, connecteeNameIndex, connectAtStage, owner), + AbstractSocket(name, connecteePathIndex, connectAtStage, owner), connectee(nullptr) {} /** So that Component can construct a Socket. */ friend Component; private: + + void connectInternal(const T& objT) { + connectee = &objT; + } + mutable SimTK::ReferencePtr connectee; }; // END class Socket @@ -411,7 +429,7 @@ An AbstractInput enables maintenance of a list of unconnected Inputs. An Input can either be a single-value Input or a list Input. A list Input can connect to multiple (Output) Channels. -#### XML Syntax of a connectee name +#### XML Syntax of a connectee path For every %Input that a component has, the XML representation of the component contains an element named `input_`. For example, a component @@ -425,7 +443,7 @@ that has an Input named `desired_angle` might look like the following in XML: @endcode You use this field to specify the outputs/channels that should be connected to -this input (that is, the connectees). The syntax for the connectee name +this input (that is, the connectees). The syntax for the connectee path property is as follows: @code |[:][()] @@ -448,10 +466,10 @@ Here are some examples: - `../averager|output(knee_joint_center)`: The component `../averager` (presumably a component that averages its inputs) has an output named `output`, and we are aliasing this output as `knee_joint_center`. - - `/leg_model/soleus|activation`: This connectee name uses the absolute path + - `/leg_model/soleus|activation`: This connectee path uses the absolute path to component `soleus`, which has an output named `activation`. -List inputs can contain multiple entries in its connectee name, with the +List inputs can contain multiple entries in its connectee path, with the entries separated by a space. For example: @code @@ -467,7 +485,7 @@ class OSIMCOMMON_API AbstractInput : public AbstractSocket { // Change the return type of clone(). This is similar to what the Object // macros do (see OpenSim_OBJECT_ABSTRACT_DEFS). AbstractInput* clone() const override = 0; - + // Socket interface void connect(const Object& object) override { std::stringstream msg; @@ -477,6 +495,9 @@ class OSIMCOMMON_API AbstractInput : public AbstractSocket { throw Exception(msg.str(), __FILE__, __LINE__); } + /** TODO */ +// virtual bool isConnecteeSpecified() const = 0; + /** Connect this Input to a single-valued (single-channel) Output or, if this is a list %Input and the %Output is a list %Output, connect to all the channels of the %Output. You can optionally provide an alias that will be @@ -491,40 +512,46 @@ class OSIMCOMMON_API AbstractInput : public AbstractSocket { %Input to refer to the %Channel. */ virtual void connect(const AbstractChannel& channel, const std::string& alias = "") = 0; - + /** Get the alias for a Channel. An alias is a description for a %Channel that is specific to how the Input will use the %Channel. For example, the Component that owns this %Input might expect the aliases to be the names of markers in the model. This method can be used only for non-list %Inputs; for - list %Inputs, use the overload that takes an index. */ + list %Inputs, use the overload that takes an index. + You must finalize connections (Component::finalizeConnections()) first. */ virtual const std::string& getAlias() const = 0; /** Get the alias for the Channel indicated by the provided index. An alias is a description for a %Channel that is specific to how the Input will use the %Channel. For example, the Component that owns this %Input might expect - the aliases to be the names of markers in the model. */ + the aliases to be the names of markers in the model. + You must finalize connections (Component::finalizeConnections()) first. */ virtual const std::string& getAlias(unsigned index) const = 0; /** %Set the alias for a Channel. If this is a list Input, the aliases of all %Channels will be set to the provided string. If you wish to set the alias - of only one %Channel, use the two-argument overload. */ + of only one %Channel, use the two-argument overload. + You must finalize connections (Component::finalizeConnections()) first. */ virtual void setAlias(const std::string& alias) = 0; - /** %Set the alias for the Channel indicated by the provided index. */ + /** %Set the alias for the Channel indicated by the provided index. + You must finalize connections (Component::finalizeConnections()) first. */ virtual void setAlias(unsigned index, const std::string& alias) = 0; /** Get the label for this Channel. If an alias has been set, the label is the alias; otherwise, the label is the full path of the Output that has been connected to this Input. This method can be used only for non-list %Inputs; - for list %Inputs, use the single-argument overload. */ + for list %Inputs, use the single-argument overload. + You must finalize connections (Component::finalizeConnections()) first. */ virtual std::string getLabel() const = 0; /** Get the label for the Channel indicated by the provided index. If an alias has been set, the label is the alias; otherwise, the label is the full - path of the %Channel that has been connected to this Input. */ + path of the %Channel that has been connected to this Input. + You must finalize connections (Component::finalizeConnections()) first. */ virtual std::string getLabel(unsigned index) const = 0; - /** Break up a connectee name into its output path, channel name + /** Break up a connectee path into its output path, channel name (empty for single-value outputs), and alias. This function writes to the passed-in outputPath, channelName, and alias. @@ -551,30 +578,30 @@ class OSIMCOMMON_API AbstractInput : public AbstractSocket { alias is "baz" @endverbatim */ - static bool parseConnecteeName(const std::string& connecteeName, + static bool parseConnecteePath(const std::string& connecteePath, std::string& componentPath, std::string& outputName, std::string& channelName, std::string& alias) { - auto bar = connecteeName.rfind("|"); - auto colon = connecteeName.rfind(":"); - auto leftParen = connecteeName.rfind("("); - auto rightParen = connecteeName.rfind(")"); + auto bar = connecteePath.rfind("|"); + auto colon = connecteePath.rfind(":"); + auto leftParen = connecteePath.rfind("("); + auto rightParen = connecteePath.rfind(")"); - componentPath = connecteeName.substr(0, bar); - outputName = connecteeName.substr(bar + 1, + componentPath = connecteePath.substr(0, bar); + outputName = connecteePath.substr(bar + 1, std::min(colon, leftParen) - (bar + 1)); // Channel name. if (colon != std::string::npos) { - channelName = connecteeName.substr(colon + 1, leftParen - (colon + 1)); + channelName = connecteePath.substr(colon + 1, leftParen - (colon + 1)); } else { channelName = ""; } // Alias. if (leftParen != std::string::npos && rightParen != std::string::npos) { - alias = connecteeName.substr(leftParen + 1, + alias = connecteePath.substr(leftParen + 1, rightParen - (leftParen + 1)); } else { alias = ""; @@ -583,8 +610,8 @@ class OSIMCOMMON_API AbstractInput : public AbstractSocket { return true; } - /** Compose the connectee name from its constituents. This is the opposite - operation of parseConnecteeName(). + /** Compose the connectee path from its constituents. This is the opposite + operation of parseConnecteePath(). Example: @verbatim if inputs are @@ -595,7 +622,7 @@ class OSIMCOMMON_API AbstractInput : public AbstractSocket { then result --> /foo/bar|output:channel(baz) @endverbatim */ - static std::string composeConnecteeName(const std::string& componentPath, + static std::string composeConnecteePath(const std::string& componentPath, const std::string& outputName, const std::string& channelName, const std::string& alias) { @@ -616,16 +643,23 @@ class OSIMCOMMON_API AbstractInput : public AbstractSocket { AbstractOutput specified by name and stage at which it should be connected. Only Component should ever construct this class. @param name name of the dependent (Abstract)Output. - @param connecteeNameIndex Index of the property in the containing Component - that holds this Input's connectee name(s). + @param connecteePathIndex Index of the property in the containing Component + that holds this Input's connectee path(s). @param connectAtStage Stage at which Input should be connected. @param owner The component that contains this input. */ AbstractInput(const std::string& name, - const PropertyIndex& connecteeNameIndex, + const PropertyIndex& connecteePathIndex, const SimTK::Stage& connectAtStage, Component& owner) : - AbstractSocket(name, connecteeNameIndex, connectAtStage, owner) {} - + AbstractSocket(name, connecteePathIndex, connectAtStage, owner) {} + +private: + void prependComponentPathToConnecteePath( + const std::string& pathToPrepend) override; + + /* So that Component can invoke prependComponentPathToConnecteePath(). */ + friend Component; + //============================================================================= }; // END class AbstractInput @@ -651,10 +685,11 @@ class Input : public AbstractInput { const std::string& alias = "") override; /** Connect this Input given a root Component to search for - the Output according to the connectee name of this Input */ - void findAndConnect(const Component& root) override; + the Output according to the connectee path of this Input */ + void finalizeConnection(const Component& root) override; void disconnect() override { + _registeredChannels.clear(); _connectees.clear(); _aliases.clear(); } @@ -705,12 +740,12 @@ class Input : public AbstractInput { using SimTK::isIndexInRange; SimTK_INDEXCHECK_ALWAYS(index, getNumConnectees(), "Input::getChannel()"); - + SimTK_ASSERT(index < _connectees.size(), "Internal error: " + "getNumConnectees() and _connectees.size() are not consistent."); return _connectees[index].getRef(); } const std::string& getAlias() const override { - OPENSIM_THROW_IF(!isConnected(), InputNotConnected, getName()); OPENSIM_THROW_IF(isListSocket(), Exception, "Input::getAlias(): this is a list Input; an index " @@ -724,13 +759,12 @@ class Input : public AbstractInput { using SimTK::isIndexInRange; SimTK_INDEXCHECK_ALWAYS(index, getNumConnectees(), "Input::getAlias()"); - + SimTK_ASSERT(index < _aliases.size(), "Internal error: " + "getNumConnectees() and _aliases.size() are not consistent."); return _aliases[index]; } void setAlias(const std::string& alias) override { - OPENSIM_THROW_IF(!isConnected(), InputNotConnected, getName()); - for (unsigned i=0; i::setAlias()"); - const auto& connecteeName = getConnecteeName(index); + const auto& connecteePath = getConnecteePath(index); std::string componentPath{}; std::string outputName{}; std::string channelName{}; std::string currAlias{}; - parseConnecteeName(connecteeName, + parseConnecteePath(connecteePath, componentPath, outputName, channelName, currAlias); - setConnecteeName(composeConnecteeName(componentPath, - outputName, - channelName, - alias), - index); + updConnecteePathProp().setValue(index, + composeConnecteePath(componentPath, + outputName, + channelName, + alias)); _aliases[index] = alias; } @@ -828,18 +862,68 @@ class Input : public AbstractInput { name and stage at which it should be connected. Only Component should ever construct an Input. @param name name of the Output dependency. - @param connecteeNameIndex Index of the property in the containing Component - that holds this Input's connectee name(s). + @param connecteePathIndex Index of the property in the containing Component + that holds this Input's connectee path(s). @param connectAtStage Stage at which Input should be connected. @param owner The component that contains this input. */ - Input(const std::string& name, const PropertyIndex& connecteeNameIndex, + Input(const std::string& name, const PropertyIndex& connecteePathIndex, const SimTK::Stage& connectAtStage, Component& owner) : - AbstractInput(name, connecteeNameIndex, connectAtStage, owner) {} + AbstractInput(name, connecteePathIndex, connectAtStage, owner) {} /** So that Component can construct an Input. */ friend Component; private: + /** Register a channel to connect to. Since channels are created on the fly, + * we do not want to hold onto references to channels. Instead, we hold + * onto references of outputs. */ + void registerChannel(const AbstractChannel& channel, + const std::string& alias, bool validate = true) + { + const Channel* chanT = nullptr; + if (validate) { + chanT = dynamic_cast(&channel); + if (!chanT) { + std::stringstream msg; + msg << "Type mismatch between Input and Output: Input '" + << getName() << "' of type " << getConnecteeTypeName() + << " cannot connect to Output (channel) '" + << channel.getPathName() + << "' of type " << channel.getTypeName() << "."; + OPENSIM_THROW(Exception, msg.str()); + } + } else { + chanT = static_cast(&channel); + } + _registeredChannels.emplace_back( + SimTK::ReferencePtr>(&chanT->getOutput()), + chanT->getChannelName(), alias); + } + void connectInternal(const AbstractChannel& channel, + const std::string& alias) { + const auto* chanT = dynamic_cast(&channel); + if (!chanT) { + std::stringstream msg; + msg << "Type mismatch between Input and Output: Input '" + << getName() << "' of type " << getConnecteeTypeName() + << " cannot connect to Output (channel) '" + << channel.getPathName() + << "' of type " << channel.getTypeName() << "."; + OPENSIM_THROW(Exception, msg.str()); + } + + if (!isListSocket()) { + _connectees.clear(); + _aliases.clear(); + } + _connectees.emplace_back(chanT); + _aliases.push_back(alias); + } + // These are channels the user has requested that we connect to. + using RegisteredChannel = + std::tuple>, + std::string, std::string>; + SimTK::ResetOnCopy> _registeredChannels; SimTK::ResetOnCopy _connectees; // Aliases are serialized, since tools may depend on them for // interpreting the connected channels. @@ -883,7 +967,7 @@ class Input : public AbstractInput { /** @name Sockets */ \ /** @{ */ \ /** comment */ \ - /** In an XML file, you can set this Socket's connectee name */ \ + /** In an XML file, you can set this Socket's connectee path */ \ /** via the \ element. */ \ /** This socket was generated with the */ \ /** #OpenSim_DECLARE_SOCKET macro; */ \ @@ -901,6 +985,9 @@ class Input : public AbstractInput { /** @name Socket-related functions */ \ /** @{ */ \ /** Connect the '##cname##' Socket to an object of type T##. */ \ + /** Call finalizeConnections() afterwards to update the socket's */ \ + /** connectee path property. The reference to the connectee set here */ \ + /** takes precedence over the connectee path property. */ \ void connectSocket_##cname(const Object& object) { \ this->updSocket(#cname).connect(object); \ } \ @@ -959,7 +1046,7 @@ class Input : public AbstractInput { /** @name Sockets */ \ /** @{ */ \ /** comment */ \ - /** In an XML file, you can set this socket's connectee name */ \ + /** In an XML file, you can set this socket's connectee path */ \ /** via the \ element. */ \ /** See AbstractSocket for more information. */ \ /** @see connectsocket_##cname##() */ \ @@ -978,6 +1065,9 @@ class Input : public AbstractInput { /** @name Socket-related functions */ \ /** @{ */ \ /** Connect the '##cname##' Socket to an object of type T##. */ \ + /** Call finalizeConnections() afterwards to update the socket's */ \ + /** connectee path property. The reference to the connectee set here */ \ + /** takes precedence over the connectee path property. */ \ void connectSocket_##cname(const Object& object) { \ this->updSocket(#cname).connect(object); \ } \ @@ -1044,9 +1134,9 @@ PropertyIndex Class::constructSocket_##cname() { \ /** @{ */ \ /** comment */ \ /** This input is needed at stage istage##. */ \ - /** In an XML file, you can set this Input's connectee name */ \ + /** In an XML file, you can set this Input's connectee path */ \ /** via the \ element. */ \ - /** The syntax for a connectee name is */ \ + /** The syntax for a connectee path is */ \ /** `|[:][()]`. */ \ /** This input was generated with the */ \ /** #OpenSim_DECLARE_INPUT macro; */ \ @@ -1069,6 +1159,9 @@ PropertyIndex Class::constructSocket_##cname() { \ /** list output. */ \ /** You can optionally provide an alias that will be used by this */ \ /** component to refer to the output. */ \ + /** Call finalizeConnections() afterwards to update the input's */ \ + /** connectee path property. The reference to the output set here */ \ + /** takes precedence over the connectee path property. */ \ void connectInput_##iname(const AbstractOutput& output, \ const std::string& alias = "") { \ updInput(#iname).connect(output, alias); \ @@ -1076,6 +1169,9 @@ PropertyIndex Class::constructSocket_##cname() { \ /** Connect this Input to an output channel of type T##. */ \ /** You can optionally provide an alias that will be used by this */ \ /** component to refer to the channel. */ \ + /** Call finalizeConnections() afterwards to update the input's */ \ + /** connectee path property. The reference to the channel set here */ \ + /** takes precedence over the connectee path property. */ \ void connectInput_##iname(const AbstractChannel& channel, \ const std::string& alias = "") { \ updInput(#iname).connect(channel, alias); \ @@ -1084,7 +1180,7 @@ PropertyIndex Class::constructSocket_##cname() { \ // TODO create new macros to handle custom copy constructors: with // constructInput_() methods, etc. NOTE: constructProperty_() must be called -// first within these macros, b/c the connectee name property must exist before +// first within these macros, b/c the connectee path property must exist before // the Input etc is constructed. @@ -1105,9 +1201,9 @@ PropertyIndex Class::constructSocket_##cname() { \ /** comment */ \ /** This input can connect to multiple outputs, all of which are */ \ /** needed at stage istage##. */ \ - /** In an XML file, you can set this Input's connectee name */ \ + /** In an XML file, you can set this Input's connectee path */ \ /** via the \ element. */ \ - /** The syntax for a connectee name is */ \ + /** The syntax for a connectee path is */ \ /** `|[:][()]`. */ \ /** This input was generated with the */ \ /** #OpenSim_DECLARE_LIST_INPUT macro; */ \ @@ -1132,6 +1228,9 @@ PropertyIndex Class::constructSocket_##cname() { \ /** You can optionally provide an alias that will be used by this */ \ /** component to refer to the output; the alias will be used for all */ \ /** channels of the output. */ \ + /** Call finalizeConnections() afterwards to update the input's */ \ + /** connectee path property. The reference to the output set here */ \ + /** takes precedence over the connectee path property. */ \ void connectInput_##iname(const AbstractOutput& output, \ const std::string& alias = "") { \ updInput(#iname).connect(output, alias); \ @@ -1139,6 +1238,9 @@ PropertyIndex Class::constructSocket_##cname() { \ /** Connect this Input to an output channel of type T##. */ \ /** You can optionally provide an alias that will be used by this */ \ /** component to refer to the channel. */ \ + /** Call finalizeConnections() afterwards to update the input's */ \ + /** connectee path property. The reference to the channel set here */ \ + /** takes precedence over the connectee path property. */ \ void connectInput_##iname(const AbstractChannel& channel, \ const std::string& alias = "") { \ updInput(#iname).connect(channel, alias); \ diff --git a/OpenSim/Common/Object.cpp b/OpenSim/Common/Object.cpp index e9432794da..02cae399ff 100644 --- a/OpenSim/Common/Object.cpp +++ b/OpenSim/Common/Object.cpp @@ -236,23 +236,55 @@ void Object::setNull() // operator. bool Object::operator==(const Object& other) const { - if (getConcreteClassName() != other.getConcreteClassName()) return false; - if (getName() != other.getName()) return false; - if (getDescription() != other.getDescription()) return false; - if (getAuthors() != other.getAuthors()) return false; - if (getReferences() != other.getReferences()) return false; + auto printDiff = [](const std::string& name, + const std::string& thisValue, + const std::string& otherValue) { + if (Object::getDebugLevel() > 0) { + std::cout << "In Object::operator==(), differing " << name << ":\n" + << "left: " << thisValue + << "\nright: " << otherValue << std::endl; + } + + }; + if (getConcreteClassName() != other.getConcreteClassName()) { + printDiff("ConcreteClassName", getConcreteClassName(), + other.getConcreteClassName()); + return false; + } + if (getName() != other.getName()) { + printDiff("name", getName(), other.getName()); + return false; + } + if (getDescription() != other.getDescription()) { + printDiff("description", getDescription(), other.getDescription()); + return false; + } + if (getAuthors() != other.getAuthors()) { + printDiff("authors", getAuthors(), other.getAuthors()); + return false; + } + if (getReferences() != other.getReferences()) { + printDiff("references", getReferences(), other.getReferences()); + return false; + } // Must have the same number of properties, in the same order. const int numProps = getNumProperties(); - if (other.getNumProperties() != numProps) + if (other.getNumProperties() != numProps) { + printDiff("number of properties", std::to_string(numProps), + std::to_string(other.getNumProperties())); return false; + } for (int px = 0; px < numProps; ++px) { const AbstractProperty& myProp = getPropertyByIndex(px); const AbstractProperty& otherProp = other.getPropertyByIndex(px); - if (!myProp.equals(otherProp)) + if (!myProp.equals(otherProp)) { + printDiff("property '" + myProp.getName() + "'", + myProp.toString(), otherProp.toString()); return false; + } } return true; @@ -1335,6 +1367,9 @@ setAllPropertiesUseDefault(bool aUseDefault) bool Object:: print(const string &aFileName) const { + try { + warnBeforePrint(); + } catch (...) {} // Temporarily change current directory so that inlined files are written to correct relative directory std::string savedCwd = IO::getCwd(); IO::chDir(IO::getParentDirectory(aFileName)); diff --git a/OpenSim/Common/Object.h b/OpenSim/Common/Object.h index a916e02e55..874427b73f 100644 --- a/OpenSim/Common/Object.h +++ b/OpenSim/Common/Object.h @@ -250,7 +250,9 @@ class OSIMCOMMON_API Object properties and corresponding properties are equal, and if the objects are the same concrete type and the concrete class says they are equal. Concrete object classes must override this if they have any fields to - compare, but be sure to invoke the base class operator too. **/ + compare, but be sure to invoke the base class operator too. + To print information about the exact differences, + set the debug level (setDebugLevel()) to a number greater than 0. **/ virtual bool operator==(const Object &aObject) const; /** Provide an ordering for objects so they can be put in sorted containers. **/ @@ -806,6 +808,13 @@ class OSIMCOMMON_API Object void updateDefaultObjectsFromXMLNode(); void updateDefaultObjectsXMLNode(SimTK::Xml::Element& aParent); + /** This is invoked at the start of print(). Derived classes can use this + * as an opportunity to issue warnings to users. + * Any exception thrown in this function is ignored, as exceptions would + * prevent the user from printing the object, which could be useful for + * debugging. */ + virtual void warnBeforePrint() const {} + //============================================================================== // DATA //============================================================================== diff --git a/OpenSim/Common/Path.cpp b/OpenSim/Common/Path.cpp index a63939fbb2..e3a891846c 100644 --- a/OpenSim/Common/Path.cpp +++ b/OpenSim/Common/Path.cpp @@ -175,8 +175,13 @@ std::vector Path::formRelativePathVec(const Path& otherPath) const for (size_t i = 0; i < numDotDot; ++i) { pathVec.push_back(".."); } - for (; ind < thisPathLength; ++ind) { - pathVec.push_back(_path[ind]); + if (thisPathLength == 0) { + // This path points to the root, which we treat as having an empty name. + pathVec.push_back(""); + } else { + for (; ind < thisPathLength; ++ind) { + pathVec.push_back(_path[ind]); + } } return pathVec; diff --git a/OpenSim/Common/Reporter.h b/OpenSim/Common/Reporter.h index e94f2d587a..e7ccfe2423 100644 --- a/OpenSim/Common/Reporter.h +++ b/OpenSim/Common/Reporter.h @@ -225,8 +225,8 @@ OpenSim_DECLARE_CONCRETE_OBJECT_T(TableReporter_, InputT, Reporter); } } - void extendConnect(Component& root) override { - Super::extendConnect(root); + void extendFinalizeConnections(Component& root) override { + Super::extendFinalizeConnections(root); const auto& input = this->template getInput("inputs"); diff --git a/OpenSim/Common/Test/testComponentInterface.cpp b/OpenSim/Common/Test/testComponentInterface.cpp index 802571f497..31fae5aa41 100644 --- a/OpenSim/Common/Test/testComponentInterface.cpp +++ b/OpenSim/Common/Test/testComponentInterface.cpp @@ -201,8 +201,8 @@ class Foo : public Component { protected: /** Component Interface */ - void extendConnect(Component& root) override { - Super::extendConnect(root); + void extendFinalizeConnections(Component& root) override { + Super::extendFinalizeConnections(root); // do any internal wiring world = dynamic_cast(&root); } @@ -284,18 +284,22 @@ class Bar : public Component { double getCopytestingMemVar(const SimTK::State& s) const { return copytestingViaMemberVariable; } + class ParentAndFooAreSame : OpenSim::Exception { + public: + using OpenSim::Exception::Exception; + }; protected: /** Component Interface */ - void extendConnect(Component& root) override{ - Super::extendConnect(root); + void extendFinalizeConnections(Component& root) override{ + Super::extendFinalizeConnections(root); // do any internal wiring world = dynamic_cast(&root); // perform custom checking if (&updSocket("parentFoo").getConnectee() == &updSocket("childFoo").getConnectee()){ - string msg = "ERROR - Bar::extendConnect()\n"; + string msg = "ERROR - Bar::extendFinalizeConnections()\n"; msg += " parentFoo and childFoo cannot be the same component."; - throw OpenSim::Exception(msg); + throw ParentAndFooAreSame(msg); } } @@ -480,12 +484,13 @@ void testMisc() { //Configure the socket to look for its dependency by this name //Will get resolved and connected automatically at Component connect - bar.updSocket("parentFoo").setConnecteeName(foo.getAbsolutePathString()); + bar.updSocket("parentFoo").setConnecteePath( + foo.getAbsolutePathString()); bar.connectSocket_childFoo(foo); - + // add a subcomponent // connect internals - ASSERT_THROW( OpenSim::Exception, + ASSERT_THROW( Bar::ParentAndFooAreSame, theWorld.connect() ); @@ -531,6 +536,9 @@ void testMisc() { bar.connectSocket_childFoo(foo2); string socketName = bar.updSocket("childFoo").getName(); + // do any other input/output connections + foo.connectInput_input1(bar.getOutput("PotentialEnergy")); + // Bar should connect now theWorld.connect(); theWorld.buildUpSystem(system); @@ -538,9 +546,6 @@ void testMisc() { const Foo& foo2found = theWorld.getComponent("Foo2"); ASSERT(foo2 == foo2found); - // do any other input/output connections - foo.connectInput_input1(bar.getOutput("PotentialEnergy")); - // check how this model serializes string modelFile("testComponentInterfaceModel.osim"); theWorld.print(modelFile); @@ -609,7 +614,7 @@ void testMisc() { MultibodySystem system2; TheWorld *world2 = new TheWorld(modelFile, true); - + world2->updComponent("Bar").getSocket("childFoo"); // We haven't called connect yet, so this connection isn't made yet. SimTK_TEST_MUST_THROW_EXC( @@ -673,14 +678,14 @@ void testMisc() { //Configure the socket to look for its dependency by this name //Will get resolved and connected automatically at Component connect - bar2.updSocket("parentFoo") - .setConnecteeName(compFoo.getRelativePathName(bar2)); + bar2.updSocket("parentFoo").setConnecteePath( + compFoo.getRelativePathString(bar2)); - bar2.connectSocket_childFoo(foo); + bar2.connectSocket_childFoo(compFoo.get_Foo1()); compFoo.upd_Foo1().updInput("input1") .connect(bar2.getOutput("PotentialEnergy")); - world3.finalizeFromProperties(); + world3.connect(); world3.print("Compound_" + modelFile); cout << "Adding world3 to theWorld" << endl; @@ -701,14 +706,15 @@ void testMisc() { reporter->set_report_time_interval(0.1); reporter->connectInput_inputs(foo.getOutput("Qs")); theWorld.add(reporter); + + // Connect our state variables. + foo.connectInput_fiberLength(bar.getOutput("fiberLength")); + foo.connectInput_activation(bar.getOutput("activation")); MultibodySystem system3; cout << "Building theWorld's system:" << endl; theWorld.buildUpSystem(system3); - // Connect our state variables. - foo.connectInput_fiberLength(bar.getOutput("fiberLength")); - foo.connectInput_activation(bar.getOutput("activation")); // Since hiddenStateVar is a hidden state variable, it has no // corresponding output. ASSERT_THROW( OpenSim::Exception, @@ -818,7 +824,7 @@ void testExceptionsFinalizeFromPropertiesAfterCopy() { } { TheWorld copy = theWorld; - SimTK_TEST_MUST_THROW(copy.getComponentList()); + SimTK_TEST_MUST_THROW_EXC(copy.getComponentList(), ComponentIsAnOrphan); } } @@ -841,9 +847,9 @@ void testListInputs() { bar.setName("Bar"); theWorld.add(&bar); - bar.updSocket("parentFoo").setConnecteeName("Foo"); - bar.updSocket("childFoo").setConnecteeName("Foo2"); - + bar.connectSocket_parentFoo(foo); + bar.connectSocket_childFoo(foo2); + auto* reporter = new ConsoleReporter(); reporter->setName("rep0"); theWorld.add(reporter); @@ -899,9 +905,9 @@ void testListSockets() { theWorld.add(&bar); // Non-list sockets. - bar.updSocket("parentFoo").setConnecteeName("foo"); - bar.updSocket("childFoo").setConnecteeName("foo2"); - + bar.connectSocket_parentFoo(foo); + bar.connectSocket_childFoo(foo2); + // Ensure that calling connect() on bar's "parentFoo" doesn't increase // its number of connectees. bar.connectSocket_parentFoo(foo); @@ -956,27 +962,27 @@ void testComponentPathNames() top.printOutputInfo(); std::string absPathC = C->getAbsolutePathString(); - ASSERT(absPathC == "/Top/A/B/C"); + ASSERT(absPathC == "/A/B/C"); std::string absPathE = E->getAbsolutePathString(); - ASSERT(absPathE == "/Top/A/D/E"); + ASSERT(absPathE == "/A/D/E"); // Specific tests to relative path name facilities - std::string EWrtB = E->getRelativePathName(*B); + std::string EWrtB = E->getRelativePathString(*B); ASSERT(EWrtB == "../D/E"); // "/A/B/" as common - std::string BWrtE = B->getRelativePathName(*E); - ASSERT(BWrtE == "../../B"); // "/Top/A/" as common + std::string BWrtE = B->getRelativePathString(*E); + ASSERT(BWrtE == "../../B"); // "/A/" as common // null case component wrt itself - std::string fooWrtFoo = D->getRelativePathName(*D); + std::string fooWrtFoo = D->getRelativePathString(*D); ASSERT(fooWrtFoo == ""); - std::string CWrtOtherTop = C->getRelativePathName(otherTop); - ASSERT(CWrtOtherTop == "../Top/A/B/C"); + std::string CWrtOtherTop = C->getRelativePathString(otherTop); + ASSERT(CWrtOtherTop == "A/B/C"); - std::string OtherTopWrtC = otherTop.getRelativePathName(*C); - ASSERT(OtherTopWrtC == "../../../../OtherTop"); + std::string OtherTopWrtC = otherTop.getRelativePathString(*C); + ASSERT(OtherTopWrtC == "../../../"); // Must specify a unique path to E ASSERT_THROW(OpenSim::ComponentNotFoundOnSpecifiedPath, @@ -985,10 +991,10 @@ void testComponentPathNames() auto& cref = top.getComponent(absPathC); auto& eref = top.getComponent(absPathE); - auto cFromE = cref.getRelativePathName(eref); + auto cFromE = cref.getRelativePathString(eref); ASSERT(cFromE == "../../B/C"); - auto eFromC = eref.getRelativePathName(cref); + auto eFromC = eref.getRelativePathString(cref); ASSERT(eFromC == "../../D/E"); // verify that we can also navigate relative paths properly @@ -1018,11 +1024,11 @@ void testComponentPathNames() std::string aBar2AbsPath = A->getComponent("Bar2").getAbsolutePathString(); auto bar2FromBarFoo = - bar2->getRelativePathName(F->getComponent("Foo1")); + bar2->getRelativePathString(F->getComponent("Foo1")); // Verify deep copy of subcomponents - const Foo& foo1inA = top.getComponent("/Top/A/Foo1"); - const Foo& foo1inF = top.getComponent("/Top/F/Foo1"); + const Foo& foo1inA = top.getComponent("/A/Foo1"); + const Foo& foo1inF = top.getComponent("/F/Foo1"); ASSERT(&foo1inA != &foo1inF); // double check that we have the original Foo foo1 in A @@ -1041,7 +1047,7 @@ void testComponentPathNames() fbar2.connectSocket_parentFoo(*foo1); fbar2.updSocket("childFoo") - .setConnecteeName("../Foo1"); + .setConnecteePath("../Foo1"); top.printSubcomponentInfo(); top.printOutputInfo(); @@ -1110,9 +1116,10 @@ void testTraversePathToComponent() { SimTK_TEST(&a1->getComponent("../b1") == b1); SimTK_TEST(&a1->getComponent("../a1/b2") == b2); // Absolute paths. - SimTK_TEST(&top.getComponent("/top/a1") == a1); - SimTK_TEST(&b1->getComponent("/top/a1/b2") == b2); - SimTK_TEST(&b2->getComponent("/top/a1/a2") == a2); + SimTK_TEST(&top.getComponent("/a1") == a1); + SimTK_TEST(&b1->getComponent("/a1/b2") == b2); + SimTK_TEST(&b2->getComponent("/a1/a2") == a2); + SimTK_TEST(&top.getComponent("/") == &top); // No component. @@ -1123,7 +1130,6 @@ void testTraversePathToComponent() { // Wrong type. SimTK_TEST_MUST_THROW(top.getComponent("a1/a2")); // Going too high up. - SimTK_TEST_MUST_THROW(top.getComponent("/")); SimTK_TEST_MUST_THROW(top.getComponent("..")); SimTK_TEST_MUST_THROW(top.getComponent("../")); SimTK_TEST_MUST_THROW(top.getComponent("../..")); @@ -1280,11 +1286,12 @@ void testInputOutputConnections() } } -void testInputConnecteeNames() { +void testInputConnecteePaths() { { std::string componentPath, outputName, channelName, alias; - AbstractInput::parseConnecteeName("/foo/bar|output", - componentPath, outputName, channelName, alias); + AbstractInput::parseConnecteePath("/foo/bar|output", + componentPath, outputName, + channelName, alias); SimTK_TEST(componentPath == "/foo/bar"); SimTK_TEST(outputName == "output"); SimTK_TEST(channelName == ""); @@ -1292,8 +1299,9 @@ void testInputConnecteeNames() { } { std::string componentPath, outputName, channelName, alias; - AbstractInput::parseConnecteeName("/foo/bar|output:channel", - componentPath, outputName, channelName, alias); + AbstractInput::parseConnecteePath("/foo/bar|output:channel", + componentPath, outputName, + channelName, alias); SimTK_TEST(componentPath == "/foo/bar"); SimTK_TEST(outputName == "output"); SimTK_TEST(channelName == "channel"); @@ -1301,8 +1309,9 @@ void testInputConnecteeNames() { } { std::string componentPath, outputName, channelName, alias; - AbstractInput::parseConnecteeName("/foo/bar|output(baz)", - componentPath, outputName, channelName, alias); + AbstractInput::parseConnecteePath("/foo/bar|output(baz)", + componentPath, outputName, + channelName, alias); SimTK_TEST(componentPath == "/foo/bar"); SimTK_TEST(outputName == "output"); SimTK_TEST(channelName == ""); @@ -1310,8 +1319,9 @@ void testInputConnecteeNames() { } { std::string componentPath, outputName, channelName, alias; - AbstractInput::parseConnecteeName("/foo/bar|output:channel(baz)", - componentPath, outputName, channelName, alias); + AbstractInput::parseConnecteePath("/foo/bar|output:channel(baz)", + componentPath, outputName, + channelName, alias); SimTK_TEST(componentPath == "/foo/bar"); SimTK_TEST(outputName == "output"); SimTK_TEST(channelName == "channel"); @@ -1408,7 +1418,7 @@ void testExceptionsForConnecteeTypeMismatch() { B* b = new B(); b->setName("b"); C* c = new C(); c->setName("c"); model.add(b); model.add(c); - c->updSocket("socket1").setConnecteeName("../b"); + c->updSocket("socket1").setConnecteePath("../b"); SimTK_TEST_MUST_THROW_EXC(model.connect(), OpenSim::Exception); } { // single-value output -> single-value input. @@ -1416,7 +1426,7 @@ void testExceptionsForConnecteeTypeMismatch() { A* a = new A(); a->setName("a"); B* b = new B(); b->setName("b"); model.add(a); model.add(b); - b->updInput("in1").setConnecteeName("../a/out1"); + b->updInput("in1").setConnecteePath("../a/out1"); SimTK_TEST_MUST_THROW_EXC(model.connect(), OpenSim::Exception); } { // single-value output -> list input. @@ -1424,7 +1434,7 @@ void testExceptionsForConnecteeTypeMismatch() { A* a = new A(); a->setName("a"); B* b = new B(); b->setName("b"); model.add(a); model.add(b); - b->updInput("inL").appendConnecteeName("../a/out1"); + b->updInput("inL").appendConnecteePath("../a/out1"); SimTK_TEST_MUST_THROW_EXC(model.connect(), OpenSim::Exception); } { // list output -> single-value input. @@ -1432,7 +1442,7 @@ void testExceptionsForConnecteeTypeMismatch() { A* a = new A(); a->setName("a"); B* b = new B(); b->setName("b"); model.add(a); model.add(b); - b->updInput("in1").setConnecteeName("../a/outL:2"); + b->updInput("in1").setConnecteePath("../a/outL:2"); SimTK_TEST_MUST_THROW_EXC(model.connect(), OpenSim::Exception); } { // list output -> list input. @@ -1440,7 +1450,7 @@ void testExceptionsForConnecteeTypeMismatch() { A* a = new A(); a->setName("a"); B* b = new B(); b->setName("b"); model.add(a); model.add(b); - b->updInput("inL").appendConnecteeName("../a/outL:0"); + b->updInput("inL").appendConnecteePath("../a/outL:0"); SimTK_TEST_MUST_THROW_EXC(model.connect(), OpenSim::Exception); } } @@ -1796,27 +1806,27 @@ void writeTimeSeriesTableForInputConnecteeSerialization() { } void testListInputConnecteeSerialization() { - // We build a model, store the input connectee names, then + // We build a model, store the input connectee paths, then // recreate the same model from a serialization, and make sure the - // connectee names are the same. + // connectee paths are the same. // Helper function. - auto getConnecteeNames = [](const AbstractInput& in) { + auto getConnecteePaths = [](const AbstractInput& in) { const auto numConnectees = in.getNumConnectees(); - std::vector connecteeNames(numConnectees); + std::vector connecteePaths(numConnectees); for (unsigned ic = 0u; ic < numConnectees; ++ic) { - connecteeNames[ic] = in.getConnecteeName(ic); + connecteePaths[ic] = in.getConnecteePath(ic); } - return connecteeNames; + return connecteePaths; }; // Build a model and serialize it. std::string modelFileName = "testComponentInterface_" "testListInputConnecteeSerialization_world.xml"; - std::vector expectedConnecteeNames{ - "../producer|column:a", - "../producer|column:c", - "../producer|column:b(berry)"}; + std::vector expectedConnecteePaths{ + "/producer|column:a", + "/producer|column:c", + "/producer|column:b(berry)"}; SimTK::Vector expectedInputValues; { // Create the "model," which just contains a reporter. @@ -1835,7 +1845,7 @@ void testListInputConnecteeSerialization() { // Add to world. world.add(source); world.add(reporter); - + // Connect, finalize, etc. const auto& output = source->getOutput("column"); // See if we preserve the ordering of the channels. @@ -1843,14 +1853,16 @@ void testListInputConnecteeSerialization() { reporter->addToReport(output.getChannel("c")); // We want to make sure aliases are preserved. reporter->addToReport(output.getChannel("b"), "berry"); + // Ensure that re-finalizing from properties does not cause Inputs + // to hold onto stale references to the outputs' channels. world.finalizeFromProperties(); world.connect(); MultibodySystem system; world.buildUpSystem(system); - // Grab the connectee names. + // Grab the connectee paths. const auto& input = reporter->getInput("inputs"); - SimTK_TEST(getConnecteeNames(input) == expectedConnecteeNames); + SimTK_TEST(getConnecteePaths(input) == expectedConnecteePaths); // Get the value of the input at some given time. State s = system.realizeTopology(); @@ -1869,11 +1881,11 @@ void testListInputConnecteeSerialization() { const auto& reporter = world.getComponent("consumer"); const auto& input = reporter.getInput("inputs"); SimTK_TEST(input.isListSocket()); - // Check connectee names before *and* after connecting, since + // Check connectee paths before *and* after connecting, since // the connecting process edits the connectee_name property. - SimTK_TEST(getConnecteeNames(input) == expectedConnecteeNames); + SimTK_TEST(getConnecteePaths(input) == expectedConnecteePaths); world.connect(); - SimTK_TEST(getConnecteeNames(input) == expectedConnecteeNames); + SimTK_TEST(getConnecteePaths(input) == expectedConnecteePaths); // Check aliases. SimTK_TEST(input.getAlias(0) == ""); // default. SimTK_TEST(input.getAlias(1) == ""); // default. @@ -1886,7 +1898,7 @@ void testListInputConnecteeSerialization() { system.realize(s, Stage::Model); s.setTime(0.3); auto actualInputValues = Input::downcast(input).getVector(s); - + SimTK_TEST_EQ(expectedInputValues, actualInputValues); } } @@ -1921,13 +1933,15 @@ void testSingleValueInputConnecteeSerialization() { // Add to world. world.add(source); world.add(foo); - + // Connect, finalize, etc. const auto& output = source->getOutput("column"); // See if we preserve the ordering of the channels. foo->connectInput_input1(output.getChannel("b")); // We want to make sure aliases are preserved. foo->connectInput_fiberLength(output.getChannel("d"), "desert"); + // Ensure that re-finalizing from properties does not cause Inputs + // to hold onto stale references to the outputs' channels. world.finalizeFromProperties(); world.connect(); MultibodySystem system; @@ -1940,9 +1954,9 @@ void testSingleValueInputConnecteeSerialization() { const auto& input1 = foo->getInput("input1"); expectedInput1Value = Input::downcast(input1).getValue(s); - // We won't wire up this input, but its connectee name should still + // We won't wire up this input, but its connectee path should still // (de)serialize. - foo->updInput("activation").setConnecteeName("non/existent"); + foo->updInput("activation").setConnecteePath("non/existent"); // Serialize. world.print(modelFileName); @@ -1962,16 +1976,16 @@ void testSingleValueInputConnecteeSerialization() { SimTK_TEST(!fiberLength.isListSocket()); SimTK_TEST(!activation.isListSocket()); - // Check connectee names before *and* after connecting, since + // Check connectee paths before *and* after connecting, since // the connecting process edits the connectee_name property. - SimTK_TEST(input1.getConnecteeName() == "../producer|column:b"); - SimTK_TEST(fiberLength.getConnecteeName() == - "../producer|column:d(desert)"); + SimTK_TEST(input1.getConnecteePath() == "/producer|column:b"); + SimTK_TEST(fiberLength.getConnecteePath() == + "/producer|column:d(desert)"); // Even if we hadn't wired this up, its name still deserializes: - SimTK_TEST(activation.getConnecteeName() == "non/existent"); + SimTK_TEST(activation.getConnecteePath() == "non/existent"); // Now we must clear this before trying to connect, since the connectee // doesn't exist. - activation.setConnecteeName(""); + activation.setConnecteePath(""); // Connect. world.connect(); @@ -1981,9 +1995,9 @@ void testSingleValueInputConnecteeSerialization() { SimTK_TEST(!fiberLength.isListSocket()); SimTK_TEST(!activation.isListSocket()); - SimTK_TEST(input1.getConnecteeName() == "../producer|column:b"); - SimTK_TEST(fiberLength.getConnecteeName() == - "../producer|column:d(desert)"); + SimTK_TEST(input1.getConnecteePath() == "/producer|column:b"); + SimTK_TEST(fiberLength.getConnecteePath() == + "/producer|column:d(desert)"); // Check aliases. SimTK_TEST(input1.getAlias(0) == ""); @@ -2013,7 +2027,7 @@ void testSingleValueInputConnecteeSerialization() { // Hack into the Foo and modify its properties! The typical interface // for editing the input's connectee_name does not allow multiple - // connectee names for a single-value input. + // connectee paths for a single-value input. auto& connectee_name = Property::updAs( foo->updPropertyByName("input_input1")); connectee_name.setAllowableListSize(0, 10); @@ -2041,9 +2055,9 @@ void testSingleValueInputConnecteeSerialization() { auto* foo = new Foo(); world.add(foo); auto& input1 = foo->updInput("input1"); - input1.setConnecteeName("abc+def"); // '+' is invalid for ComponentPath. + input1.setConnecteePath("abc+def"); // '+' is invalid for ComponentPath. // The check for invalid names occurs in - // AbstractSocket::checkConnecteeNameProperty(), which is invoked + // AbstractSocket::checkConnecteePathProperty(), which is invoked // by the following function: SimTK_TEST_MUST_THROW_EXC(foo->finalizeFromProperties(), OpenSim::Exception); @@ -2059,7 +2073,7 @@ void testSingleValueInputConnecteeSerialization() { } void testAliasesAndLabels() { - TheWorld* theWorld = new TheWorld(); + auto theWorld = std::unique_ptr(new TheWorld()); theWorld->setName("world"); Foo* foo = new Foo(); foo->setName("foo"); @@ -2077,8 +2091,9 @@ void testAliasesAndLabels() { // Non-list Input, no alias. foo->connectInput_input1( bar->getOutput("Output1") ); + theWorld->connect(); SimTK_TEST(foo->getInput("input1").getAlias().empty()); - SimTK_TEST(foo->getInput("input1").getLabel() == "/world/bar|Output1"); + SimTK_TEST(foo->getInput("input1").getLabel() == "/bar|Output1"); // Set alias. foo->updInput("input1").setAlias("waldo"); @@ -2098,27 +2113,30 @@ void testAliasesAndLabels() { // Non-list Input, with alias. foo->connectInput_input1( bar->getOutput("Output1"), "baz" ); + theWorld->connect(); SimTK_TEST(foo->getInput("input1").getAlias() == "baz"); SimTK_TEST(foo->getInput("input1").getLabel() == "baz"); // List Input, no aliases. foo->connectInput_listInput1( bar->getOutput("Output1") ); foo->connectInput_listInput1( bar->getOutput("Output3") ); + theWorld->connect(); ASSERT_THROW(OpenSim::Exception, foo->getInput("listInput1").getAlias()); ASSERT_THROW(OpenSim::Exception, foo->getInput("listInput1").getLabel()); SimTK_TEST(foo->getInput("listInput1").getAlias(0).empty()); - SimTK_TEST(foo->getInput("listInput1").getLabel(0) == "/world/bar|Output1"); + SimTK_TEST(foo->getInput("listInput1").getLabel(0) == "/bar|Output1"); SimTK_TEST(foo->getInput("listInput1").getAlias(1).empty()); - SimTK_TEST(foo->getInput("listInput1").getLabel(1) == "/world/bar|Output3"); + SimTK_TEST(foo->getInput("listInput1").getLabel(1) == "/bar|Output3"); foo->updInput("listInput1").disconnect(); // List Input, with aliases. foo->connectInput_listInput1( bar->getOutput("Output1"), "plugh" ); foo->connectInput_listInput1( bar->getOutput("Output3"), "thud" ); + theWorld->connect(); SimTK_TEST(foo->getInput("listInput1").getAlias(0) == "plugh"); SimTK_TEST(foo->getInput("listInput1").getLabel(0) == "plugh"); @@ -2203,7 +2221,7 @@ int main() { SimTK_SUBTEST(testTraversePathToComponent); SimTK_SUBTEST(testGetStateVariableValue); SimTK_SUBTEST(testInputOutputConnections); - SimTK_SUBTEST(testInputConnecteeNames); + SimTK_SUBTEST(testInputConnecteePaths); SimTK_SUBTEST(testExceptionsForConnecteeTypeMismatch); SimTK_SUBTEST(testExceptionsSocketNameExistsAlready); SimTK_SUBTEST(testExceptionsInputNameExistsAlready); diff --git a/OpenSim/Common/XMLDocument.cpp b/OpenSim/Common/XMLDocument.cpp index 3378de2fb5..d3c1bb8d37 100644 --- a/OpenSim/Common/XMLDocument.cpp +++ b/OpenSim/Common/XMLDocument.cpp @@ -515,6 +515,18 @@ void XMLDocument::addPhysicalOffsetFrame30505_30517(SimTK::Xml::Element& element //frames_node->writeToString(debug); } +string XMLDocument::updateConnecteePath30517( + const std::string& connecteeSetName, + const std::string& connecteeName) { + std::string connecteePath; + if (connecteeSetName == "bodyset" && connecteeName == "ground") { + connecteePath = "/" + connecteeName; + } else{ + connecteePath = "/" + connecteeSetName + "/" + connecteeName; + } + return connecteePath; +} + SimTK::Xml::Element XMLDocument::findElementWithName( SimTK::Xml::Element& element, const std::string& name) { using namespace SimTK; diff --git a/OpenSim/Common/XMLDocument.h b/OpenSim/Common/XMLDocument.h index eba472c162..83852c7977 100644 --- a/OpenSim/Common/XMLDocument.h +++ b/OpenSim/Common/XMLDocument.h @@ -132,6 +132,17 @@ class OSIMCOMMON_API XMLDocument : public SimTK::Xml::Document { const std::string& frameName, const std::string& parentFrameName, const SimTK::Vec3& location, const SimTK::Vec3& orientation); + /** Convert component names into the appropriate paths based on where we + * know components were located in version 30000 model files. + * @param depth What's the tree depth of the component containing the + * relevant socket? + * @param connecteeSetName "bodyset", "jointset", etc. + * @param connecteeName The name of the connectee from the version 30000 + * file. + * Note: It is okay for connecteePath to be a reference to connecteeName. */ + static std::string updateConnecteePath30517( + const std::string& connecteeSetName, + const std::string& connecteeName); /** Find the first XML Element (depth-first search) with the provided `name`, anywhere in the XML document that contains `element`. If the XML document does not contain an element with name `name`, or if `name` is diff --git a/OpenSim/Examples/ExampleHopperDevice/defineDeviceAndController.h b/OpenSim/Examples/ExampleHopperDevice/defineDeviceAndController.h index c88dc912ec..a786d6eab3 100644 --- a/OpenSim/Examples/ExampleHopperDevice/defineDeviceAndController.h +++ b/OpenSim/Examples/ExampleHopperDevice/defineDeviceAndController.h @@ -88,7 +88,7 @@ class Device : public ModelComponent { double getHeight(const SimTK::State& s) const { //TODO: Provide the name of the coordinate corresponding to the // hopper's height. You found this in Step 1, Task A. - const std::string hopperHeightCoord = "/Dennis/?????"; //fill this in + const std::string hopperHeightCoord = "/?????"; //fill this in //TODO: Use "getModel().getComponent(hopperHeightCoord) // .getOutputValue(?????);" diff --git a/OpenSim/Examples/ExampleHopperDevice/defineDeviceAndController_answers.h b/OpenSim/Examples/ExampleHopperDevice/defineDeviceAndController_answers.h index 65e5c14c7b..9463b69d1b 100644 --- a/OpenSim/Examples/ExampleHopperDevice/defineDeviceAndController_answers.h +++ b/OpenSim/Examples/ExampleHopperDevice/defineDeviceAndController_answers.h @@ -126,11 +126,11 @@ class Device : public ModelComponent { double getHeight(const SimTK::State& s) const { //TODO: Provide the name of the coordinate corresponding to the // hopper's height. You found this in Step 1, Task A. - //const std::string hopperHeightCoord = "/Dennis/?????"; //fill this in + //const std::string hopperHeightCoord = "/?????"; //fill this in #pragma region Step2_TaskA_solution static const std::string hopperHeightCoord = - "/Dennis/jointset/slider/yCoord"; + "/jointset/slider/yCoord"; #pragma endregion diff --git a/OpenSim/Examples/ExampleHopperDevice/exampleHopperDevice.cpp b/OpenSim/Examples/ExampleHopperDevice/exampleHopperDevice.cpp index 3edda1d2b4..983b3fb1fa 100644 --- a/OpenSim/Examples/ExampleHopperDevice/exampleHopperDevice.cpp +++ b/OpenSim/Examples/ExampleHopperDevice/exampleHopperDevice.cpp @@ -50,20 +50,20 @@ static const std::string testbedAttachment2{"load"}; // Hint: the hopper's pelvis is attached to ground with a vertical slider // joint; see buildHopperModel.cpp and Component::printOutputInfo(). // [Step 1, Task A] -static const std::string hopperHeightCoord{"/Dennis/?????"}; //fill this in +static const std::string hopperHeightCoord{"/?????"}; //fill this in //TODO: Provide the absolute path names of the PhysicalOffsetFrames defined on // the hopper for attaching the assistive device. See buildHopperModel.cpp // and Component::printSubcomponentInfo(). // [Step 3, Task A] -static const std::string thighAttachment{"/Dennis/?????"}; //fill this in -static const std::string shankAttachment{"/Dennis/?????"}; //fill this in +static const std::string thighAttachment{"/?????"}; //fill this in +static const std::string shankAttachment{"/?????"}; //fill this in //TODO: To assist hopping, we will activate the knee device whenever the vastus // muscle is active. For convenience, we define a string "vastus" which // is the path to the vastus muscle. // [Step 3, Task B] -static const std::string vastus{"/Dennis/?????"}; //fill this in +static const std::string vastus{"/?????"}; //fill this in namespace OpenSim { @@ -219,7 +219,7 @@ void run(bool showVisualizer, double finalTime) hopper.printSubcomponentInfo(); // Show the outputs generated by the thigh body. // The argument indicates if outputs of subcomponents should be printed. - hopper.getComponent("/Dennis/bodyset/thigh").printOutputInfo(false); + hopper.getComponent("/bodyset/thigh").printOutputInfo(false); // Step 1, Task A // ============== diff --git a/OpenSim/Examples/ExampleHopperDevice/exampleHopperDevice_answers.cpp b/OpenSim/Examples/ExampleHopperDevice/exampleHopperDevice_answers.cpp index 83e3152f4c..429deffb2f 100644 --- a/OpenSim/Examples/ExampleHopperDevice/exampleHopperDevice_answers.cpp +++ b/OpenSim/Examples/ExampleHopperDevice/exampleHopperDevice_answers.cpp @@ -50,10 +50,10 @@ static const std::string testbedAttachment2{"bodyset/load"}; // Hint: the hopper's pelvis is attached to ground with a vertical slider // joint; see buildHopperModel.cpp and Component::printOutputInfo(). // [Step 1, Task A] -//static const std::string hopperHeightCoord{"/Dennis/?????"}; //fill this in +//static const std::string hopperHeightCoord{"/?????"}; //fill this in #pragma region Step1_TaskA_solution -static const std::string hopperHeightCoord{"/Dennis/jointset/slider/yCoord"}; +static const std::string hopperHeightCoord{"/jointset/slider/yCoord"}; #pragma endregion @@ -61,14 +61,14 @@ static const std::string hopperHeightCoord{"/Dennis/jointset/slider/yCoord"}; // the hopper for attaching the assistive device. See buildHopperModel.cpp // and Component::printSubcomponentInfo(). // [Step 3, Task A] -//static const std::string thighAttachment{"/Dennis/?????"}; //fill this in -//static const std::string shankAttachment{"/Dennis/?????"}; //fill this in +//static const std::string thighAttachment{"/?????"}; //fill this in +//static const std::string shankAttachment{"/?????"}; //fill this in #pragma region Step3_TaskA_solution static const std::string thighAttachment{ - "/Dennis/bodyset/thigh/deviceAttachmentPoint"}; + "/bodyset/thigh/deviceAttachmentPoint"}; static const std::string shankAttachment{ - "/Dennis/bodyset/shank/deviceAttachmentPoint"}; + "/bodyset/shank/deviceAttachmentPoint"}; #pragma endregion @@ -76,10 +76,10 @@ static const std::string shankAttachment{ // muscle is active. For convenience, we define a string "vastus" which // is the path to the vastus muscle. // [Step 3, Task B] -//static const std::string vastus{"/Dennis/?????"}; //fill this in +//static const std::string vastus{"/?????"}; //fill this in #pragma region Step3_TaskB_solution -static const std::string vastus{"/Dennis/forceset/vastus"}; +static const std::string vastus{"/forceset/vastus"}; #pragma endregion @@ -163,13 +163,13 @@ void addConsoleReporterToHopper(Model& hopper) #pragma region Step1_TaskB_solution reporter->addToReport( - hopper.getComponent("/Dennis/forceset/vastus").getOutput("activation")); + hopper.getComponent("/forceset/vastus").getOutput("activation")); #pragma endregion #pragma region Step1_TaskB_solution reporter->addToReport( - hopper.getComponent("/Dennis/jointset/knee/kneeFlexion"). + hopper.getComponent("/jointset/knee/kneeFlexion"). getOutput("value"), "knee_angle"); #pragma endregion @@ -294,7 +294,7 @@ void run(bool showVisualizer, double finalTime) hopper.printSubcomponentInfo(); // Show the outputs generated by the thigh body. // The argument indicates if outputs of subcomponents should be printed. - hopper.getComponent("/Dennis/bodyset/thigh").printOutputInfo(false); + hopper.getComponent("/bodyset/thigh").printOutputInfo(false); // Step 1, Task A // ============== diff --git a/OpenSim/Examples/ExampleLuxoMuscle/LuxoMuscle_create_and_simulate.cpp b/OpenSim/Examples/ExampleLuxoMuscle/LuxoMuscle_create_and_simulate.cpp index 83eb8edbdc..0f8c8bb7cb 100644 --- a/OpenSim/Examples/ExampleLuxoMuscle/LuxoMuscle_create_and_simulate.cpp +++ b/OpenSim/Examples/ExampleLuxoMuscle/LuxoMuscle_create_and_simulate.cpp @@ -310,7 +310,7 @@ int main(int argc, char* argv[]) { * Method for building the Luxo Jr articulating model. It sets up the system of * rigid bodies and joint articulations to define Luxo Jr lamp geometry. */ -void createLuxoJr(OpenSim::Model &model){ +void createLuxoJr(OpenSim::Model& model){ // Create base //-------------- @@ -342,7 +342,7 @@ void createLuxoJr(OpenSim::Model &model){ SimTK::CoordinateAxis::XCoordinateAxis()), Vec3(0.0, bracket_location, 0.0)); - PhysicalOffsetFrame pivot_frame_on_base("pivot_frame_on_base", + auto* pivot_frame_on_base = new PhysicalOffsetFrame("pivot_frame_on_base", *base, *shift_and_rotate); // Create bottom bracket @@ -355,7 +355,7 @@ void createLuxoJr(OpenSim::Model &model){ // Fix a frame to the bracket for attaching joint shift_and_rotate->setP(Vec3(0.0)); - PhysicalOffsetFrame pivot_frame_on_bottom_bracket( + auto* pivot_frame_on_bottom_bracket = new PhysicalOffsetFrame( "pivot_frame_on_bottom_bracket", *bottom_bracket, *shift_and_rotate); // Add visible geometry @@ -364,20 +364,20 @@ void createLuxoJr(OpenSim::Model &model){ // Make bottom bracket to twist on base with vertical pin joint. // You can create a joint from any existing physical frames attached to // rigid bodies. One way to reference them is by name, like this... - PinJoint* base_pivot = new PinJoint("base_pivot", pivot_frame_on_base, - pivot_frame_on_bottom_bracket); - - base_pivot->append_frames(pivot_frame_on_base); - base_pivot->append_frames(pivot_frame_on_bottom_bracket); + PinJoint* base_pivot = new PinJoint("base_pivot", *pivot_frame_on_base, + *pivot_frame_on_bottom_bracket); + + base_pivot->addFrame(pivot_frame_on_base); + base_pivot->addFrame(pivot_frame_on_bottom_bracket); // add base pivot joint to the model model.addJoint(base_pivot); // add some damping to the pivot // initialized to zero stiffness and damping BushingForce* pivotDamper = new BushingForce("pivot_bushing", - "pivot_frame_on_base", - "pivot_frame_on_bottom_bracket"); - + *pivot_frame_on_base, + *pivot_frame_on_bottom_bracket); + pivotDamper->set_rotational_damping(pivot_damping); model.addForce(pivotDamper); @@ -391,11 +391,11 @@ void createLuxoJr(OpenSim::Model &model){ posteriorLegBar->attachGeometry(new Mesh("Leg_meters.obj")); - PhysicalOffsetFrame posterior_knee_on_bottom_bracket( + auto* posterior_knee_on_bottom_bracket = new PhysicalOffsetFrame( "posterior_knee_on_bottom_bracket", *bottom_bracket, Transform(posterior_bracket_hinge_location) ); - PhysicalOffsetFrame posterior_knee_on_posterior_bar( + auto* posterior_knee_on_posterior_bar = new PhysicalOffsetFrame( "posterior_knee_on_posterior_bar", *posteriorLegBar, Transform(inferior_bar_hinge_location) ); @@ -403,11 +403,11 @@ void createLuxoJr(OpenSim::Model &model){ // Another way to reference physical frames in a joint is by creating them // in place, like this... OpenSim::PinJoint* posteriorKnee = new OpenSim::PinJoint("posterior_knee", - posterior_knee_on_bottom_bracket, - posterior_knee_on_posterior_bar); + *posterior_knee_on_bottom_bracket, + *posterior_knee_on_posterior_bar); // posteriorKnee will own and serialize the attachment offset frames - posteriorKnee->append_frames(posterior_knee_on_bottom_bracket); - posteriorKnee->append_frames(posterior_knee_on_posterior_bar); + posteriorKnee->addFrame(posterior_knee_on_bottom_bracket); + posteriorKnee->addFrame(posterior_knee_on_posterior_bar); // add posterior leg to model @@ -427,22 +427,22 @@ void createLuxoJr(OpenSim::Model &model){ leg_Hlink->attachGeometry(new Mesh("H_Piece_meters.obj")); - PhysicalOffsetFrame anterior_knee_on_bottom_bracket( + auto* anterior_knee_on_bottom_bracket = new PhysicalOffsetFrame( "anterior_knee_on_bottom_bracket", *bottom_bracket, Transform(anterior_bracket_hinge_location)); - PhysicalOffsetFrame anterior_knee_on_anterior_bar( + auto* anterior_knee_on_anterior_bar = new PhysicalOffsetFrame( "anterior_knee_on_anterior_bar", *leg_Hlink, Transform(inferior_Hlink_hinge_location)); // Connect anterior leg to bottom bracket via pin joint OpenSim::PinJoint* anterior_knee = new OpenSim::PinJoint("anterior_knee", - anterior_knee_on_bottom_bracket, - anterior_knee_on_anterior_bar); - anterior_knee->append_frames(anterior_knee_on_bottom_bracket); - anterior_knee->append_frames(anterior_knee_on_anterior_bar); + *anterior_knee_on_bottom_bracket, + *anterior_knee_on_anterior_bar); + anterior_knee->addFrame(anterior_knee_on_bottom_bracket); + anterior_knee->addFrame(anterior_knee_on_anterior_bar); // add anterior leg to model @@ -465,19 +465,19 @@ void createLuxoJr(OpenSim::Model &model){ SimTK::Transform pelvis_anterior_shift( anterior_superior_pelvis_pin_location); - PhysicalOffsetFrame anterior_hip_on_Hlink( + auto* anterior_hip_on_Hlink = new PhysicalOffsetFrame( "anterior_hip_on_Hlink", *leg_Hlink, Transform(superior_Hlink_hinge_location)); - PhysicalOffsetFrame anterior_hip_on_pelvis( + auto* anterior_hip_on_pelvis = new PhysicalOffsetFrame( "anterior_hip_on_pelvis", *pelvisBracket, pelvis_anterior_shift); OpenSim::PinJoint* anteriorHip = new OpenSim::PinJoint("anterior_hip", - anterior_hip_on_Hlink, - anterior_hip_on_pelvis); - anteriorHip->append_frames(anterior_hip_on_Hlink); - anteriorHip->append_frames(anterior_hip_on_pelvis); + *anterior_hip_on_Hlink, + *anterior_hip_on_pelvis); + anteriorHip->addFrame(anterior_hip_on_Hlink); + anteriorHip->addFrame(anterior_hip_on_pelvis); // add anterior leg to model model.addBody(pelvisBracket); model.addJoint(anteriorHip); @@ -494,10 +494,10 @@ void createLuxoJr(OpenSim::Model &model){ OpenSim::PointOnLineConstraint* posteriorHip = new OpenSim::PointOnLineConstraint(); - posteriorHip->setLineBodyByName(pelvisBracket->getName()); + posteriorHip->connectSocket_line_body(*pelvisBracket); posteriorHip->setLineDirection(Vec3(0.0,0.0,1.0)); posteriorHip->setPointOnLine(inferior_pelvis_pin_location); - posteriorHip->setFollowerBodyByName(posteriorLegBar->getName()); + posteriorHip->connectSocket_follower_body(*posteriorLegBar); posteriorHip->setPointOnFollower(superior_bar_hinge_location); // add constraint to model @@ -511,21 +511,21 @@ void createLuxoJr(OpenSim::Model &model){ chest->attachGeometry(new Mesh("Anterior_torso_bar.obj")); - PhysicalOffsetFrame anterior_torso_hinge_on_pelvis( + auto* anterior_torso_hinge_on_pelvis = new PhysicalOffsetFrame( "anterior_torso_hinge_on_pelvis", *pelvisBracket, Transform(anterior_superior_pelvis_pin_location) ); - PhysicalOffsetFrame anterior_torso_hinge_on_chest( + auto* anterior_torso_hinge_on_chest = new PhysicalOffsetFrame( "anterior_torso_hinge_on_chest", *chest, Transform(inferior_torso_hinge_location) ); // Attach chest piece to pelvice with pin joint OpenSim::PinJoint* anteriorTorsoHinge = new OpenSim::PinJoint( "anterior_torso_hinge", - anterior_torso_hinge_on_pelvis, - anterior_torso_hinge_on_chest); - anteriorTorsoHinge->append_frames(anterior_torso_hinge_on_pelvis); - anteriorTorsoHinge->append_frames(anterior_torso_hinge_on_chest); + *anterior_torso_hinge_on_pelvis, + *anterior_torso_hinge_on_chest); + anteriorTorsoHinge->addFrame(anterior_torso_hinge_on_pelvis); + anteriorTorsoHinge->addFrame(anterior_torso_hinge_on_chest); // add posterior leg to model model.addBody(chest); model.addJoint(anteriorTorsoHinge); @@ -541,21 +541,21 @@ void createLuxoJr(OpenSim::Model &model){ back->attachGeometry(new Mesh("Posterior_torso_bar.obj")); - PhysicalOffsetFrame posterior_torso_hinge_on_pelvis( + auto* posterior_torso_hinge_on_pelvis = new PhysicalOffsetFrame( "posterior_torso_hinge_on_pelvis", *pelvisBracket, Transform(posterior_superior_pelvis_pin_location) ); - PhysicalOffsetFrame posterior_torso_hinge_on_back( + auto* posterior_torso_hinge_on_back = new PhysicalOffsetFrame( "posterior_torso_hinge_on_back", *back, Transform(back_peg_center) ); // Attach chest piece to pelvis with pin joint OpenSim::PinJoint* posteriorTorsoHinge = new OpenSim::PinJoint( "posterior_torso_hinge", - posterior_torso_hinge_on_pelvis, - posterior_torso_hinge_on_back); - posteriorTorsoHinge->append_frames(posterior_torso_hinge_on_pelvis); - posteriorTorsoHinge->append_frames(posterior_torso_hinge_on_back); + *posterior_torso_hinge_on_pelvis, + *posterior_torso_hinge_on_back); + posteriorTorsoHinge->addFrame(posterior_torso_hinge_on_pelvis); + posteriorTorsoHinge->addFrame(posterior_torso_hinge_on_back); // add posterior leg to model model.addBody(back); model.addJoint(posteriorTorsoHinge); @@ -576,21 +576,21 @@ void createLuxoJr(OpenSim::Model &model){ // add anterior leg to model model.addBody(shoulderBracket); - PhysicalOffsetFrame anterior_thoracic_joint_on_chest( + auto* anterior_thoracic_joint_on_chest = new PhysicalOffsetFrame( "anterior_thoracic_joint_on_chest", *chest, Transform(superior_torso_hinge_location) ); - PhysicalOffsetFrame anterior_thoracic_joint_on_shoulder( + auto* anterior_thoracic_joint_on_shoulder = new PhysicalOffsetFrame( "anterior_thoracic_joint_on_shoulder", *shoulderBracket, Transform(anterior_thoracic_joint_center)); // Connect pelvis to Hlink via pin joint OpenSim::PinJoint* anteriorThoracicJoint = new OpenSim::PinJoint("anterior_thoracic_joint", - anterior_thoracic_joint_on_chest, - anterior_thoracic_joint_on_shoulder); - anteriorThoracicJoint->append_frames(anterior_thoracic_joint_on_chest); - anteriorThoracicJoint->append_frames(anterior_thoracic_joint_on_shoulder); + *anterior_thoracic_joint_on_chest, + *anterior_thoracic_joint_on_shoulder); + anteriorThoracicJoint->addFrame(anterior_thoracic_joint_on_chest); + anteriorThoracicJoint->addFrame(anterior_thoracic_joint_on_shoulder); // add back joint model.addJoint(anteriorThoracicJoint); @@ -604,12 +604,12 @@ void createLuxoJr(OpenSim::Model &model){ //------------------------------------------------------------------ // Create and configure point on line constraint OpenSim::PointOnLineConstraint* posteriorShoulder = - new OpenSim::PointOnLineConstraint(); + new OpenSim::PointOnLineConstraint(); - posteriorShoulder->setLineBodyByName(shoulderBracket->getName()); + posteriorShoulder->connectSocket_line_body(*shoulderBracket); posteriorShoulder->setLineDirection(Vec3(0.0,0.0,1.0)); posteriorShoulder->setPointOnLine(posterior_thoracic_joint_center); - posteriorShoulder->setFollowerBodyByName(back->getName()); + posteriorShoulder->connectSocket_follower_body(*back); posteriorShoulder->setPointOnFollower(superior_torso_hinge_location); // add constraint to model @@ -623,19 +623,21 @@ void createLuxoJr(OpenSim::Model &model){ head->attachGeometry(new Mesh("Bulb_meters.obj")); model.addBody(head); - PhysicalOffsetFrame cervical_joint_on_shoulder("cervical_joint_on_shoulder", + auto* cervical_joint_on_shoulder = new PhysicalOffsetFrame( + "cervical_joint_on_shoulder", *shoulderBracket, Transform(superior_shoulder_hinge_location) ); - PhysicalOffsetFrame cervical_joint_on_head("cervical_joint_on_head", + auto* cervical_joint_on_head = new PhysicalOffsetFrame( + "cervical_joint_on_head", *head, Transform(cervicle_joint_center)); // attach to shoulder via pin joint OpenSim::PinJoint* cervicalJoint = new OpenSim::PinJoint("cervical_joint", - cervical_joint_on_shoulder, - cervical_joint_on_head); + *cervical_joint_on_shoulder, + *cervical_joint_on_head); - cervicalJoint->append_frames(cervical_joint_on_shoulder); - cervicalJoint->append_frames(cervical_joint_on_head); + cervicalJoint->addFrame(cervical_joint_on_shoulder); + cervicalJoint->addFrame(cervical_joint_on_head); // add a neck joint model.addJoint(cervicalJoint); @@ -719,11 +721,18 @@ void createLuxoJr(OpenSim::Model &model){ kneeExtensorRight->set_ignore_tendon_compliance(true); model.addForce(kneeExtensorRight); - // add a second copy of this knee extensor for the left side + // create a left knee extensor Millard2012EquilibriumMuscle* kneeExtensorLeft = - new Millard2012EquilibriumMuscle(*kneeExtensorRight); - kneeExtensorLeft->setName("kneeExtensorLeft"); - + new Millard2012EquilibriumMuscle("knee_extensor_left", + knee_extensor_F0, knee_extensor_lm0, + knee_extensor_lts, pennationAngle); + + kneeExtensorLeft->addNewPathPoint("knee_extensor_left_origin", *leg_Hlink, + knee_extensor_origin); + kneeExtensorLeft->addNewPathPoint("knee_extensor_left_insertion", + *bottom_bracket, + knee_extensor_insertion); + // flip the z coordinates of all path points PathPointSet& points = kneeExtensorLeft->updGeometryPath().updPathPointSet(); for (int i=0; iset_ignore_tendon_compliance(true); model.addForce(kneeExtensorLeft); - // add a back extensor to controll the upper 4-bar linkage + // add a back extensor to control the upper 4-bar linkage Millard2012EquilibriumMuscle* backExtensorRight = new Millard2012EquilibriumMuscle( "back_extensor_right", back_extensor_F0, back_extensor_lm0, @@ -746,12 +755,16 @@ void createLuxoJr(OpenSim::Model &model){ backExtensorRight->set_ignore_tendon_compliance(true); model.addForce(backExtensorRight); - // copy right back extensor and use to make left extensor + // add another back extensor. Millard2012EquilibriumMuscle* backExtensorLeft = - new Millard2012EquilibriumMuscle(*backExtensorRight); - - backExtensorLeft->setName("back_extensor_left"); - + new Millard2012EquilibriumMuscle("back_extensor_left", + back_extensor_F0, back_extensor_lm0, + back_extensor_lts, pennationAngle); + backExtensorLeft->addNewPathPoint("back_extensor_left_origin", *chest, + back_extensor_origin); + backExtensorLeft->addNewPathPoint("back_extensor_left_insertion", *back, + back_extensor_insertion); + PathPointSet& pointsLeft = backExtensorLeft->updGeometryPath() .updPathPointSet(); for (int i=0; igetValueAs(bodyName); // PathPoints in pre-4.0 models are necessarily 3 levels deep - // (model, muscle, geometry path), and Bodies are necessarily - // 1 level deep: prepend "../../../" to get the correct - // relative path. - if (!bodyName.empty()) bodyName = "../../../" + bodyName; + // (model, muscle, geometry path), and Bodies are + // necessarily 1 levels deep; here we create the correct + // relative path (accounting for sets being components). + bodyName = XMLDocument::updateConnecteePath30517("bodyset", + bodyName); XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "parent_frame", bodyName); } diff --git a/OpenSim/Simulation/Model/BushingForce.cpp b/OpenSim/Simulation/Model/BushingForce.cpp index c5177f26ea..8767c4ffe7 100644 --- a/OpenSim/Simulation/Model/BushingForce.cpp +++ b/OpenSim/Simulation/Model/BushingForce.cpp @@ -47,16 +47,39 @@ BushingForce::BushingForce() : TwoFrameLinker() constructProperties(); } +BushingForce::BushingForce(const std::string& name, + const PhysicalFrame& frame1, + const PhysicalFrame& frame2) + : Super(name, frame1, frame2) +{ + setNull(); + constructProperties(); +} + BushingForce::BushingForce( const std::string& name, const std::string& frame1Name, const std::string& frame2Name) - : TwoFrameLinker(name, frame1Name, frame2Name) + : Super(name, frame1Name, frame2Name) { setNull(); constructProperties(); } -/* Convenience construction with BushingForce's material properties */ +BushingForce::BushingForce(const std::string& name, + const PhysicalFrame& frame1, + const PhysicalFrame& frame2, + const SimTK::Vec3& transStiffness, + const SimTK::Vec3& rotStiffness, + const SimTK::Vec3& transDamping, + const SimTK::Vec3& rotDamping) + : BushingForce(name, frame1, frame2) +{ + set_rotational_stiffness(rotStiffness); + set_translational_stiffness(transStiffness); + set_rotational_damping(rotDamping); + set_translational_damping(transDamping); +} + BushingForce::BushingForce( const std::string &name, const std::string& frame1Name, const std::string& frame2Name, @@ -72,6 +95,23 @@ BushingForce::BushingForce( const std::string &name, set_translational_damping(transDamping); } +BushingForce::BushingForce(const std::string& name, const PhysicalFrame& frame1, + const SimTK::Transform& transformInFrame1, + const PhysicalFrame& frame2, + const SimTK::Transform& transformInFrame2, + const SimTK::Vec3& transStiffness, + const SimTK::Vec3& rotStiffness, + const SimTK::Vec3& transDamping, + const SimTK::Vec3& rotDamping) + : Super(name, frame1, transformInFrame1, frame2, transformInFrame2) +{ + setNull(); + constructProperties(); + set_rotational_stiffness(rotStiffness); + set_translational_stiffness(transStiffness); + set_rotational_damping(rotDamping); + set_translational_damping(transDamping); +} BushingForce::BushingForce(const std::string& name, const std::string& frame1Name, const SimTK::Transform& transformInFrame1, @@ -80,8 +120,7 @@ BushingForce::BushingForce(const std::string& name, const SimTK::Vec3& rotStiffness, const SimTK::Vec3& transDamping, const SimTK::Vec3& rotDamping) - : TwoFrameLinker(name, - frame1Name, transformInFrame1, frame2Name, transformInFrame2) + : Super(name,frame1Name, transformInFrame1, frame2Name, transformInFrame2) { setNull(); constructProperties(); diff --git a/OpenSim/Simulation/Model/BushingForce.h b/OpenSim/Simulation/Model/BushingForce.h index 762b72467c..89a1c42ca0 100644 --- a/OpenSim/Simulation/Model/BushingForce.h +++ b/OpenSim/Simulation/Model/BushingForce.h @@ -71,6 +71,16 @@ OpenSim_DECLARE_CONCRETE_OBJECT(BushingForce, TwoFrameLinker); stiffness and damping properties to zero. **/ BushingForce(); + /** Convenience Constructor. + Create a BushingForce between two PhysicalFrames, frame1 and frame2. + @param[in] name the name of this BushingForce + @param[in] frame1 the bushing's first PhysicalFrame + @param[in] frame2 the bushing's second PhysicalFrame + */ + BushingForce(const std::string& name, + const PhysicalFrame& frame1, + const PhysicalFrame& frame2); + /** Convenience Constructor. Create a BushingForce between two PhysicalFrames, frame1 and frame2. @param[in] name the name of this BushingForce @@ -81,9 +91,22 @@ OpenSim_DECLARE_CONCRETE_OBJECT(BushingForce, TwoFrameLinker); const std::string& frame1Name, const std::string& frame2Name); + /** Construct a BushingForce given physical frames that it + * tries to keep aligned by generating a passive force according to the + * physical properties of the bushing. See property declarations for more + * information. */ + BushingForce(const std::string& name, + const PhysicalFrame& frame1, + const PhysicalFrame& frame2, + const SimTK::Vec3& transStiffness, + const SimTK::Vec3& rotStiffness, + const SimTK::Vec3& transDamping, + const SimTK::Vec3& rotDamping); + /** Construct a BushingForce given the names of physical frames that it - tries to keep aligned by generating a passive force according to the physical - properties of the bushing. See property declarations for more information. */ + * tries to keep aligned by generating a passive force according to the + * physical properties of the bushing. See property declarations for more + * information. */ BushingForce(const std::string& name, const std::string& frame1Name, const std::string& frame2Name, @@ -92,6 +115,28 @@ OpenSim_DECLARE_CONCRETE_OBJECT(BushingForce, TwoFrameLinker); const SimTK::Vec3& transDamping, const SimTK::Vec3& rotDamping); + /** Convenience Constructor + Construct a BushingForce between two frames with offset transforms on the + respective frames. + + @param[in] name the name of this BushingForce + @param[in] frame1 first PhysicalFrame that the bushing connects + @param[in] transformInFrame1 offset Transform on the first frame + @param[in] frame2 second PhysicalFrame that the bushing connects + @param[in] transformInFrame2 offset Transform on the second frame + @param[in] transStiffness translational (dx, dy, dz) stiffnesses + @param[in] rotStiffness rotational (dq_x, dq_y, dq_z) stiffnesses + @param[in] transDamping translational (dx/dt, dy/dt, dz/dt) damping + @param[in] rotDamping rotational (dq_x/dt, dq_y/dt, dq_z/dt) damping + */ + BushingForce(const std::string &name, + const PhysicalFrame& frame1, const SimTK::Transform& transformInFrame1, + const PhysicalFrame& frame2, const SimTK::Transform& transformInFrame2, + const SimTK::Vec3& transStiffness, + const SimTK::Vec3& rotStiffness, + const SimTK::Vec3& transDamping, + const SimTK::Vec3& rotDamping); + /** Convenience Constructor Construct a BushingForce where the two frames are specified by the name and offset transforms on the respective frames. diff --git a/OpenSim/Simulation/Model/ConditionalPathPoint.cpp b/OpenSim/Simulation/Model/ConditionalPathPoint.cpp index d276f6660f..52a846f241 100644 --- a/OpenSim/Simulation/Model/ConditionalPathPoint.cpp +++ b/OpenSim/Simulation/Model/ConditionalPathPoint.cpp @@ -85,10 +85,14 @@ void ConditionalPathPoint::updateFromXMLNode(SimTK::Xml::Element& node, coordElem.getParentElement().getOptionalAttributeValue("name"); // PathPoints in pre-4.0 models are necessarily // 3 levels deep (model, muscle, geometry path), and Coordinates - // are necessarily 2 levels deep: prepend "../../..//" - // to get the correct relative path. - if (!jointName.empty()) - connectee_name = "../../../" + jointName + "/" + coordName; + // are necessarily 2 levels deep. + // Here we create the correct relative path (accounting for sets + // being components). + if (jointName.empty()) + jointName = IO::Lowercase( + coordElem.getParentElement().getElementTag()); + connectee_name = XMLDocument::updateConnecteePath30517( + "jointset", jointName + "/" + coordName); } XMLDocument::addConnector(node, "Connector_Coordinate_", "coordinate", diff --git a/OpenSim/Simulation/Model/ContactGeometry.cpp b/OpenSim/Simulation/Model/ContactGeometry.cpp index 5f826b7dd0..001889a866 100644 --- a/OpenSim/Simulation/Model/ContactGeometry.cpp +++ b/OpenSim/Simulation/Model/ContactGeometry.cpp @@ -127,9 +127,11 @@ void ContactGeometry::updateFromXMLNode(SimTK::Xml::Element& node, bodyElement->getValueAs(body_name); } // ContactGeometry in pre-4.0 models are necessarily 1 level deep - // (model, contact_geom), and Bodies are necessarily 1 level deep: - // prepend "../" to get the correct relative path. - if (!body_name.empty()) body_name = "../" + body_name; + // (model, contact_geom), and Bodies are necessarily 1 level deep. + // Here we create the correct relative path (accounting for sets + // being components). + body_name = XMLDocument::updateConnecteePath30517("bodyset", + body_name); XMLDocument::addConnector(node, "Connector_PhysicalFrame_", "frame", body_name); } diff --git a/OpenSim/Simulation/Model/ExpressionBasedBushingForce.cpp b/OpenSim/Simulation/Model/ExpressionBasedBushingForce.cpp index 3e78892f90..8bfd4c3b2f 100644 --- a/OpenSim/Simulation/Model/ExpressionBasedBushingForce.cpp +++ b/OpenSim/Simulation/Model/ExpressionBasedBushingForce.cpp @@ -50,8 +50,16 @@ std::string to_string(T const& value) { //_____________________________________________________________________________ // Default constructor. -ExpressionBasedBushingForce::ExpressionBasedBushingForce() : - TwoFrameLinker() +ExpressionBasedBushingForce::ExpressionBasedBushingForce() +{ + setNull(); + constructProperties(); +} + +ExpressionBasedBushingForce::ExpressionBasedBushingForce( + const std::string& name, const PhysicalFrame& frame1, + const PhysicalFrame& frame2) + : Super(name, frame1, frame2) { setNull(); constructProperties(); @@ -62,13 +70,25 @@ ExpressionBasedBushingForce:: ExpressionBasedBushingForce(const std::string& name, const std::string& frame1Name, const std::string& frame2Name) - : TwoFrameLinker(name, frame1Name, frame2Name) + : Super(name, frame1Name, frame2Name) { setNull(); constructProperties(); } +ExpressionBasedBushingForce::ExpressionBasedBushingForce( + const std::string& name, const PhysicalFrame& frame1, + const SimTK::Vec3& point1, const SimTK::Vec3& orientation1, + const PhysicalFrame& frame2, const SimTK::Vec3& point2, + const SimTK::Vec3& orientation2) + : Super(name, frame1, point1, orientation1, frame2, point2, + orientation2) +{ + setNull(); + constructProperties(); +} + // Convenience constructor for zero value force functions. ExpressionBasedBushingForce:: ExpressionBasedBushingForce(const string& name, @@ -78,14 +98,36 @@ ExpressionBasedBushingForce(const string& name, const string& frame2Name, const Vec3& point2, const Vec3& orientation2) - : TwoFrameLinker(name, - frame1Name, point1, orientation1, - frame2Name, point2, orientation2) + : Super(name, + frame1Name, point1, orientation1, + frame2Name, point2, orientation2) { setNull(); constructProperties(); } +ExpressionBasedBushingForce::ExpressionBasedBushingForce( + const std::string& name, const PhysicalFrame& frame1, + const SimTK::Vec3& point1, const SimTK::Vec3& orientation1, + const PhysicalFrame& frame2, const SimTK::Vec3& point2, + const SimTK::Vec3& orientation2, const SimTK::Vec3& transStiffness, + const SimTK::Vec3& rotStiffness, const SimTK::Vec3& transDamping, + const SimTK::Vec3& rotDamping) + : ExpressionBasedBushingForce(name, frame1, point1, orientation1, + frame2, point2, orientation2) +{ + // populate moments and forces as linear (ramp) expressions based on + // stiffness + setMxExpression( to_string(rotStiffness[0]) + string("*theta_x") ); + setMyExpression( to_string(rotStiffness[1]) + string("*theta_y") ); + setMzExpression( to_string(rotStiffness[2]) + string("*theta_z") ); + setFxExpression( to_string(transStiffness[0]) + string("*delta_x") ); + setFyExpression( to_string(transStiffness[1]) + string("*delta_y") ); + setFzExpression( to_string(transStiffness[2]) + string("*delta_z") ); + set_rotational_damping(rotDamping); + set_translational_damping(transDamping); +} + // Convenience constructor for linear functions. ExpressionBasedBushingForce::ExpressionBasedBushingForce( const std::string& name, @@ -103,7 +145,8 @@ ExpressionBasedBushingForce::ExpressionBasedBushingForce( frame1Name, point1, orientation1, frame2Name, point2, orientation2) { - // populate moments and forces as linear (ramp) expressions based on stiffness + // populate moments and forces as linear (ramp) expressions based on + // stiffness setMxExpression( to_string(rotStiffness[0]) + string("*theta_x") ); setMyExpression( to_string(rotStiffness[1]) + string("*theta_y") ); setMzExpression( to_string(rotStiffness[2]) + string("*theta_z") ); diff --git a/OpenSim/Simulation/Model/ExpressionBasedBushingForce.h b/OpenSim/Simulation/Model/ExpressionBasedBushingForce.h index 85ba047817..2c3ace22bb 100644 --- a/OpenSim/Simulation/Model/ExpressionBasedBushingForce.h +++ b/OpenSim/Simulation/Model/ExpressionBasedBushingForce.h @@ -100,12 +100,28 @@ OpenSim_DECLARE_CONCRETE_OBJECT(ExpressionBasedBushingForce, TwoFrameLinker); * to be at their body origins, and sets all bushing parameters to zero. **/ ExpressionBasedBushingForce(); + /** This convenience constructor sets the bushing frames and sets all + * bushing functions to zero. **/ + ExpressionBasedBushingForce(const std::string& name, + const PhysicalFrame& frame1, + const PhysicalFrame& frame2); + /** This convenience constructor defines and sets the bushing frames by name - * and sets all bushing functions to zero. **/ + * and sets all bushing functions to zero. **/ ExpressionBasedBushingForce(const std::string& name, const std::string& frame1Name, const std::string& frame2Name); + /** This convenience constructor defines and sets the bushing frames on + * each body, and sets all bushing functions to zero. **/ + ExpressionBasedBushingForce(const std::string& name, + const PhysicalFrame& frame1, + const SimTK::Vec3& point1, + const SimTK::Vec3& orientation1, + const PhysicalFrame& frame2, + const SimTK::Vec3& point2, + const SimTK::Vec3& orientation2); + /** This convenience constructor defines and sets the bushing frames on * each body, and sets all bushing functions to zero. **/ ExpressionBasedBushingForce(const std::string& name, @@ -115,6 +131,22 @@ OpenSim_DECLARE_CONCRETE_OBJECT(ExpressionBasedBushingForce, TwoFrameLinker); const std::string& frame2Name, const SimTK::Vec3& point2, const SimTK::Vec3& orientation2); + + /** This convenience constructor defines a bushing that behaves like a + * primitive bushing. Stiffnesses are used to define linear functions for + * force deflection profiles.**/ + ExpressionBasedBushingForce(const std::string& name, + const PhysicalFrame& frame1, + const SimTK::Vec3& point1, + const SimTK::Vec3& orientation1, + const PhysicalFrame& frame2, + const SimTK::Vec3& point2, + const SimTK::Vec3& orientation2, + const SimTK::Vec3& transStiffness, + const SimTK::Vec3& rotStiffness, + const SimTK::Vec3& transDamping, + const SimTK::Vec3& rotDamping); + /** This convenience constructor defines a bushing that behaves like a * primitive bushing. Stiffnesses are used to define linear functions for * force deflection profiles.**/ diff --git a/OpenSim/Simulation/Model/Frame.cpp b/OpenSim/Simulation/Model/Frame.cpp index 00bb8fbcb8..0a52c73cb0 100644 --- a/OpenSim/Simulation/Model/Frame.cpp +++ b/OpenSim/Simulation/Model/Frame.cpp @@ -44,10 +44,6 @@ Frame::Frame() : ModelComponent() { setAuthors("Matt DeMers, Ajay Seth"); - FrameGeometry default_frame_geometry; - default_frame_geometry.setName("frame_geometry"); - constructProperty_frame_geometry(default_frame_geometry); - constructProperty_attached_geometry(); } @@ -56,7 +52,7 @@ void Frame::extendConnectToModel(Model& model) Super::extendConnectToModel(model); // All the Geometry attached to this Frame should have // their frame connections automatically set to this Frame. - upd_frame_geometry().setFrame(*this); + updMemberSubcomponent(frameGeometryIdx).setFrame(*this); int nag = getProperty_attached_geometry().size(); for (int i = 0; i < nag; ++i) { upd_attached_geometry(i).setFrame(*this); @@ -180,6 +176,8 @@ void Frame::attachGeometry(OpenSim::Geometry* geom) geom->setFrame(*this); updProperty_attached_geometry().adoptAndAppendValue(geom); + finalizeFromProperties(); + prependComponentPathToConnecteePath(*geom); } void Frame::scaleAttachedGeometry(const SimTK::Vec3& scaleFactors) diff --git a/OpenSim/Simulation/Model/Frame.h b/OpenSim/Simulation/Model/Frame.h index 3d0585b1ca..39e2ef5155 100644 --- a/OpenSim/Simulation/Model/Frame.h +++ b/OpenSim/Simulation/Model/Frame.h @@ -83,8 +83,6 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Frame, ModelComponent); //============================================================================== // PROPERTIES //============================================================================== - OpenSim_DECLARE_PROPERTY(frame_geometry, FrameGeometry, - "The geometry used to display the axes of this Frame."); OpenSim_DECLARE_LIST_PROPERTY(attached_geometry, Geometry, "List of geometry attached to this Frame. Note, the geometry " "are treated as fixed to the frame and they share the transform " @@ -378,6 +376,10 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Frame, ModelComponent); /** Extend how concrete Frame determines its base Frame. */ virtual const Frame& extendFindBaseFrame() const = 0; virtual SimTK::Transform extendFindTransformInBaseFrame() const = 0; + + // The geometry used to display the axes of this Frame. + MemberSubcomponentIndex frameGeometryIdx { + constructSubcomponent("frame_geometry") }; SimTK::ResetOnCopy _transformIndex; SimTK::ResetOnCopy _velocityIndex; diff --git a/OpenSim/Simulation/Model/FunctionBasedBushingForce.cpp b/OpenSim/Simulation/Model/FunctionBasedBushingForce.cpp index b336129c6a..824fddc941 100644 --- a/OpenSim/Simulation/Model/FunctionBasedBushingForce.cpp +++ b/OpenSim/Simulation/Model/FunctionBasedBushingForce.cpp @@ -40,13 +40,25 @@ using namespace OpenSim; //_____________________________________________________________________________ // Default constructor. -FunctionBasedBushingForce::FunctionBasedBushingForce() : - TwoFrameLinker() +FunctionBasedBushingForce::FunctionBasedBushingForce() { setNull(); constructProperties(); } +FunctionBasedBushingForce::FunctionBasedBushingForce( + const std::string& name, + const PhysicalFrame& frame1, + const SimTK::Vec3& point1, + const SimTK::Vec3& orientation1, + const PhysicalFrame& frame2, + const SimTK::Vec3& point2, + const SimTK::Vec3& orientation2) + : Super(name, frame1, point1, orientation1, frame2, point2, orientation2) +{ + setNull(); + constructProperties(); +} // Convenience constructor for zero value force functions. FunctionBasedBushingForce::FunctionBasedBushingForce(const string& name, @@ -56,14 +68,41 @@ FunctionBasedBushingForce::FunctionBasedBushingForce(const string& name, const string& frame2Name, const Vec3& point2, const Vec3& orientation2) - : TwoFrameLinker(name, - frame1Name, point1, orientation1, - frame2Name, point2, orientation2) + : Super(name, + frame1Name, point1, orientation1, + frame2Name, point2, orientation2) { setNull(); constructProperties(); } +FunctionBasedBushingForce::FunctionBasedBushingForce( + const std::string& name, + const PhysicalFrame& frame1, + const SimTK::Vec3& point1, + const SimTK::Vec3& orientation1, + const PhysicalFrame& frame2, + const SimTK::Vec3& point2, + const SimTK::Vec3& orientation2, + const SimTK::Vec3& transStiffness, + const SimTK::Vec3& rotStiffness, + const SimTK::Vec3& transDamping, + const SimTK::Vec3& rotDamping) + : FunctionBasedBushingForce(name, + frame1, point1, orientation1, + frame2, point2, orientation2) +{ + // populate m_ii and f_ii as LinearFunction based on stiffness + set_m_x_theta_x_function( LinearFunction( rotStiffness[0], 0.0) ); + set_m_y_theta_y_function( LinearFunction( rotStiffness[1], 0.0) ); + set_m_z_theta_z_function( LinearFunction( rotStiffness[2], 0.0) ); + set_f_x_delta_x_function( LinearFunction( transStiffness[0], 0.0) ); + set_f_y_delta_y_function( LinearFunction( transStiffness[1], 0.0) ); + set_f_z_delta_z_function( LinearFunction( transStiffness[2], 0.0) ); + set_rotational_damping(rotDamping); + set_translational_damping(transDamping); +} + // Convenience constructor for linear functions. FunctionBasedBushingForce::FunctionBasedBushingForce( const std::string& name, diff --git a/OpenSim/Simulation/Model/FunctionBasedBushingForce.h b/OpenSim/Simulation/Model/FunctionBasedBushingForce.h index 8b3d10186e..998ac8b3db 100644 --- a/OpenSim/Simulation/Model/FunctionBasedBushingForce.h +++ b/OpenSim/Simulation/Model/FunctionBasedBushingForce.h @@ -88,8 +88,18 @@ OpenSim_DECLARE_CONCRETE_OBJECT(FunctionBasedBushingForce, TwoFrameLinker); /** Default constructor leaves bodies unspecified, sets the bushing frames * to be at their body origins, and sets all bushing parameters to zero. **/ FunctionBasedBushingForce(); - /** This convenience constructor defines and sets the bushing frames on + /** This convenience constructor defines and sets the bushing frames on * each body, and sets all bushing functions to zero. **/ + FunctionBasedBushingForce(const std::string& name, + const PhysicalFrame& frame1, + const SimTK::Vec3& point1, + const SimTK::Vec3& orientation1, + const PhysicalFrame& frame2, + const SimTK::Vec3& point2, + const SimTK::Vec3& orientation2); + /** This convenience constructor defines and sets the bushing frames on + * each body, and sets all bushing functions to zero. The frames are + * specified by name (path). **/ FunctionBasedBushingForce(const std::string& name, const std::string& frame1Name, const SimTK::Vec3& point1, @@ -101,16 +111,30 @@ OpenSim_DECLARE_CONCRETE_OBJECT(FunctionBasedBushingForce, TwoFrameLinker); * primitive bushing. Stiffnesses are used to define linear functions for * force deflection profiles.**/ FunctionBasedBushingForce(const std::string& name, - const std::string& frame1Name, - const SimTK::Vec3& point1, - const SimTK::Vec3& orientation1, - const std::string& frame2Name, - const SimTK::Vec3& point2, - const SimTK::Vec3& orientation2, - const SimTK::Vec3& transStiffness, - const SimTK::Vec3& rotStiffness, - const SimTK::Vec3& transDamping, - const SimTK::Vec3& rotDamping); + const PhysicalFrame& frame1, + const SimTK::Vec3& point1, + const SimTK::Vec3& orientation1, + const PhysicalFrame& frame2, + const SimTK::Vec3& point2, + const SimTK::Vec3& orientation2, + const SimTK::Vec3& transStiffness, + const SimTK::Vec3& rotStiffness, + const SimTK::Vec3& transDamping, + const SimTK::Vec3& rotDamping); + /** This convenience constructor defines a bushing that behaves like a + * primitive bushing. Stiffnesses are used to define linear functions for + * force deflection profiles. The frames are specified by name (path). **/ + FunctionBasedBushingForce(const std::string& name, + const std::string& frame1Name, + const SimTK::Vec3& point1, + const SimTK::Vec3& orientation1, + const std::string& frame2Name, + const SimTK::Vec3& point2, + const SimTK::Vec3& orientation2, + const SimTK::Vec3& transStiffness, + const SimTK::Vec3& rotStiffness, + const SimTK::Vec3& transDamping, + const SimTK::Vec3& rotDamping); // Uses default (compiler-generated) destructor, copy constructor, and copy // assignment operator. diff --git a/OpenSim/Simulation/Model/Geometry.cpp b/OpenSim/Simulation/Model/Geometry.cpp index bcc80ec9e2..a72ce4d6da 100644 --- a/OpenSim/Simulation/Model/Geometry.cpp +++ b/OpenSim/Simulation/Model/Geometry.cpp @@ -44,7 +44,7 @@ Geometry::Geometry() { void Geometry::setFrame(const Frame& frame) { - updSocket("frame").setConnecteeName(frame.getRelativePathName(*this)); + updSocket("frame").setConnecteePath(frame.getRelativePathString(*this)); } const OpenSim::Frame& Geometry::getFrame() const @@ -52,9 +52,9 @@ const OpenSim::Frame& Geometry::getFrame() const return getSocket("frame").getConnectee(); } -void Geometry::extendConnect(Component& root) +void Geometry::extendFinalizeConnections(Component& root) { - Super::extendConnect(root); + Super::extendFinalizeConnections(root); bool attachedToFrame = getSocket("frame").isConnected(); bool hasInputTransform = getInput("transform").isConnected(); diff --git a/OpenSim/Simulation/Model/Geometry.h b/OpenSim/Simulation/Model/Geometry.h index 10b3d6e07b..6af11c69fa 100644 --- a/OpenSim/Simulation/Model/Geometry.h +++ b/OpenSim/Simulation/Model/Geometry.h @@ -153,7 +153,7 @@ class OSIMSIMULATION_API Geometry : public Component { virtual void implementCreateDecorativeGeometry( SimTK::Array_&) const = 0; - void extendConnect(Component& root) override; + void extendFinalizeConnections(Component& root) override; private: // Compute Transform of this geometry relative to its base frame, utilizing diff --git a/OpenSim/Simulation/Model/Marker.cpp b/OpenSim/Simulation/Model/Marker.cpp index b963d3b275..ca01adea16 100644 --- a/OpenSim/Simulation/Model/Marker.cpp +++ b/OpenSim/Simulation/Model/Marker.cpp @@ -87,7 +87,7 @@ void Marker::constructProperties() void Marker::setParentFrameName(const string& name) { - updSocket("parent_frame").setConnecteeName(name); + updSocket("parent_frame").setConnecteePath(name); } //_____________________________________________________________________________ @@ -98,7 +98,7 @@ void Marker::setParentFrameName(const string& name) const string& Marker::getParentFrameName() const { - return getSocket("parent_frame").getConnecteeName(); + return getSocket("parent_frame").getConnecteePath(); } @@ -146,9 +146,10 @@ void Marker::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionNumber) frameElement.setAttributeValue("name", "parent_frame"); SimTK::Xml::Element connecteeElement("connectee_name"); // Markers in pre-4.0 models are necessarily 1 level deep - // (model, markers), and Bodies were necessarily 1 level deep: - // prepend "../" to get the correct relative path. - if (!bName.empty()) bName = "../" + bName; + // (model, markers), and Bodies were necessarily 1 level deep; + // here we create the correct relative path (accounting for sets + // being components). + bName = XMLDocument::updateConnecteePath30517("bodyset", bName); connecteeElement.setValue(bName); frameElement.insertNodeAfter(frameElement.node_end(), connecteeElement); aNode.insertNodeAfter(bIter, connectorsElement); diff --git a/OpenSim/Simulation/Model/Model.cpp b/OpenSim/Simulation/Model/Model.cpp index 995893f86e..6a42220456 100644 --- a/OpenSim/Simulation/Model/Model.cpp +++ b/OpenSim/Simulation/Model/Model.cpp @@ -1003,6 +1003,7 @@ void Model::addModelComponent(ModelComponent* component) if(component){ upd_ComponentSet().adoptAndAppend(component); finalizeFromProperties(); + prependComponentPathToConnecteePath(*component); } } @@ -1012,6 +1013,7 @@ void Model::addBody(OpenSim::Body* body) if (body){ updBodySet().adoptAndAppend(body); finalizeFromProperties(); + prependComponentPathToConnecteePath(*body); } } @@ -1021,6 +1023,7 @@ void Model::addMarker(OpenSim::Marker* marker) if (marker){ updMarkerSet().adoptAndAppend(marker); finalizeFromProperties(); + prependComponentPathToConnecteePath(*marker); } } @@ -1031,6 +1034,7 @@ void Model::addJoint(Joint* joint) updJointSet().adoptAndAppend(joint); finalizeFromProperties(); updCoordinateSet().populate(*this); + prependComponentPathToConnecteePath(*joint); } } @@ -1040,6 +1044,7 @@ void Model::addConstraint(OpenSim::Constraint *constraint) if(constraint){ updConstraintSet().adoptAndAppend(constraint); finalizeFromProperties(); + prependComponentPathToConnecteePath(*constraint); } } @@ -1049,6 +1054,7 @@ void Model::addForce(OpenSim::Force *force) if(force){ updForceSet().adoptAndAppend(force); finalizeFromProperties(); + prependComponentPathToConnecteePath(*force); } } @@ -1058,6 +1064,7 @@ void Model::addProbe(OpenSim::Probe *probe) if(probe){ updProbeSet().adoptAndAppend(probe); finalizeFromProperties(); + prependComponentPathToConnecteePath(*probe); } } @@ -1075,6 +1082,7 @@ void Model::addContactGeometry(OpenSim::ContactGeometry *contactGeometry) if (contactGeometry) { updContactGeometrySet().adoptAndAppend(contactGeometry); finalizeFromProperties(); + prependComponentPathToConnecteePath(*contactGeometry); } } @@ -1084,6 +1092,7 @@ void Model::addController(Controller *controller) if (controller) { updControllerSet().adoptAndAppend(controller); finalizeFromProperties(); + prependComponentPathToConnecteePath(*controller); } } //_____________________________________________________________________________ @@ -1098,7 +1107,7 @@ void Model::setup() // automatically marks properties that are Components as subcomponents finalizeFromProperties(); //now connect the Model and all its subcomponents all up - finalizeConnections(*this); + finalizeConnections(); } //_____________________________________________________________________________ diff --git a/OpenSim/Simulation/Model/Model.h b/OpenSim/Simulation/Model/Model.h index e78cedd16d..cefb73258b 100644 --- a/OpenSim/Simulation/Model/Model.h +++ b/OpenSim/Simulation/Model/Model.h @@ -266,6 +266,14 @@ OpenSim_OBJECT_NONTEMPLATE_DEFS(Model, ModelComponent); **/ explicit Model(const std::string& filename) SWIG_DECLARE_EXCEPTION; + /** Satisfy all connections (Sockets and Inputs) in the model, using this + * model as the root Component. This is a convenience form of + * Component::finalizeConnections() that uses this model as root. + */ + void finalizeConnections() { finalizeConnections(*this); } + // Allow overloading. + using Component::finalizeConnections; + /** * Perform some set up functions that happen after the * object has been deserialized. TODO: this method is diff --git a/OpenSim/Simulation/Model/ModelComponent.cpp b/OpenSim/Simulation/Model/ModelComponent.cpp index dfe3100dc9..9e2ed08e24 100644 --- a/OpenSim/Simulation/Model/ModelComponent.cpp +++ b/OpenSim/Simulation/Model/ModelComponent.cpp @@ -61,9 +61,9 @@ Model& ModelComponent::updModel() } -void ModelComponent::extendConnect(Component &root) +void ModelComponent::extendFinalizeConnections(Component& root) { - Super::extendConnect(root); + Super::extendFinalizeConnections(root); Model* model = dynamic_cast(&root); // Allow (model) component to include its own subcomponents // before calling the base method which automatically invokes diff --git a/OpenSim/Simulation/Model/ModelComponent.h b/OpenSim/Simulation/Model/ModelComponent.h index c6a8b1c4f7..f892c5eb38 100644 --- a/OpenSim/Simulation/Model/ModelComponent.h +++ b/OpenSim/Simulation/Model/ModelComponent.h @@ -261,9 +261,10 @@ template friend class ModelComponentSet; private: /** Satisfy the general Component interface, but this is not part of the - * ModelComponent interface. ModelComponent::extendConnect() ensures that - * extendConnectToModel() on ModelComponent subcomponents are invoked. **/ - void extendConnect(Component& root) override final; + * ModelComponent interface. ModelComponent::extendFinalizeConnections() + * ensures that extendConnectToModel() on ModelComponent subcomponents are + * invoked. **/ + void extendFinalizeConnections(Component& root) override final; const SimTK::DefaultSystemSubsystem& getDefaultSubsystem() const; const SimTK::DefaultSystemSubsystem& updDefaultSubsystem(); diff --git a/OpenSim/Simulation/Model/MovingPathPoint.cpp b/OpenSim/Simulation/Model/MovingPathPoint.cpp index b852f2e41a..81e4b8a585 100644 --- a/OpenSim/Simulation/Model/MovingPathPoint.cpp +++ b/OpenSim/Simulation/Model/MovingPathPoint.cpp @@ -190,10 +190,13 @@ void MovingPathPoint::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionN jointElem.getOptionalAttributeValue("name"); // PathPoints in pre-4.0 models are necessarily 3 levels deep // (model, muscle, geometry path), and Coordinates were - // necessarily 2 level deep: prepend "../../..//" - // to get the correct relative path. - if (!jointName.empty()) - connectee_name = "../../../" + jointName + "/" + coordName; + // necessarily 2 level deep. + // Here we create the correct relative path (accounting for sets + // being components). + if (jointName.empty()) + jointName = IO::Lowercase(jointElem.getElementTag()); + connectee_name = XMLDocument::updateConnecteePath30517( + "jointset", jointName + "/" + coordName); } return connectee_name; }; diff --git a/OpenSim/Simulation/Model/OffsetFrame.h b/OpenSim/Simulation/Model/OffsetFrame.h index 752f99c42f..8268bbdcfa 100644 --- a/OpenSim/Simulation/Model/OffsetFrame.h +++ b/OpenSim/Simulation/Model/OffsetFrame.h @@ -223,7 +223,7 @@ OffsetFrame::OffsetFrame(const std::string& name, : OffsetFrame() { this->setName(name); - this->template updSocket("parent").setConnecteeName(parentName); + this->template updSocket("parent").setConnecteePath(parentName); setOffsetTransform(offset); } @@ -358,7 +358,7 @@ template void OffsetFrame::extendConnectToModel(Model& model) { Super::extendConnectToModel(model); - OPENSIM_THROW_IF(*this == getParentFrame(), Exception, + OPENSIM_THROW_IF(this == &getParentFrame(), Exception, getConcreteClassName() + " cannot connect to itself!"); } diff --git a/OpenSim/Simulation/Model/PathPoint.cpp b/OpenSim/Simulation/Model/PathPoint.cpp index 19e549d12e..a7424fc28f 100644 --- a/OpenSim/Simulation/Model/PathPoint.cpp +++ b/OpenSim/Simulation/Model/PathPoint.cpp @@ -53,7 +53,7 @@ void PathPoint::extendFinalizeFromProperties() Super::extendFinalizeFromProperties(); updStation().upd_location() = get_location(); updStation().updSocket("parent_frame"). - setConnecteeName(updSocket("parent_frame").getConnecteeName()); + setConnecteePath(updSocket("parent_frame").getConnecteePath()); } void PathPoint::setLocation(const SimTK::Vec3& location) { diff --git a/OpenSim/Simulation/Model/PhysicalFrame.cpp b/OpenSim/Simulation/Model/PhysicalFrame.cpp index 97a9fa3a2f..1d76df290f 100644 --- a/OpenSim/Simulation/Model/PhysicalFrame.cpp +++ b/OpenSim/Simulation/Model/PhysicalFrame.cpp @@ -70,7 +70,7 @@ SimTK::MobilizedBody& PhysicalFrame::updMobilizedBody() void PhysicalFrame::setMobilizedBodyIndex(const SimTK::MobilizedBodyIndex& mbix) const { OPENSIM_THROW_IF_FRMOBJ(!mbix.isValid(), Exception, - "Assigned an invalid SimTK::MobilizedBodyIndex"); + "Attempting to assign an invalid SimTK::MobilizedBodyIndex"); const_cast(this)->_mbIndex = mbix; } diff --git a/OpenSim/Simulation/Model/PointToPointSpring.cpp b/OpenSim/Simulation/Model/PointToPointSpring.cpp index e72074c5e4..ee9b5b33c3 100644 --- a/OpenSim/Simulation/Model/PointToPointSpring.cpp +++ b/OpenSim/Simulation/Model/PointToPointSpring.cpp @@ -213,14 +213,17 @@ void PointToPointSpring::updateFromXMLNode(SimTK::Xml::Element& aNode, int versi // extract their values. // Forces in pre-4.0 models are necessarily 1 level deep // Bodies are also necessarily 1 level deep. - // Prepend "../" to get the correct relative path. + // Here we create the correct relative path (accounting for sets + // being components). if (body1Element != aNode.element_end()) { body1Element->getValueAs(body1_name); - body1_name = "../" + body1_name; + body1_name = XMLDocument::updateConnecteePath30517("bodyset", + body1_name); } if (body2Element != aNode.element_end()) { body2Element->getValueAs(body2_name); - body2_name = "../" + body2_name; + body2_name = XMLDocument::updateConnecteePath30517("bodyset", + body2_name); } XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "body1", body1_name); diff --git a/OpenSim/Simulation/Model/PrescribedForce.cpp b/OpenSim/Simulation/Model/PrescribedForce.cpp index 72426cf609..893fc7b168 100644 --- a/OpenSim/Simulation/Model/PrescribedForce.cpp +++ b/OpenSim/Simulation/Model/PrescribedForce.cpp @@ -83,8 +83,10 @@ void PrescribedForce::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionN bodyElement->getValueAs(frame_name); // Forces in pre-4.0 models are necessarily 1 level deep // (model, forces), and Bodies are necessarily 1 level deep. - // Prepend "../" to get the correct relative path. - if (!frame_name.empty()) frame_name = "../" + frame_name; + // Here we create the correct relative path (accounting for sets + // being components). + frame_name = XMLDocument::updateConnecteePath30517("bodyset", + frame_name); XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "frame", frame_name); } @@ -126,10 +128,10 @@ void PrescribedForce::constructProperties() } void PrescribedForce::setFrameName(const std::string& frameName) { - updSocket("frame").setConnecteeName(frameName); + updSocket("frame").setConnecteePath(frameName); } const std::string& PrescribedForce::getFrameName() const { - return getSocket("frame").getConnecteeName(); + return getSocket("frame").getConnecteePath(); } void PrescribedForce::setForceFunctions(Function* forceX, Function* forceY, Function* forceZ) diff --git a/OpenSim/Simulation/Model/TwoFrameLinker.h b/OpenSim/Simulation/Model/TwoFrameLinker.h index eb1a682a7d..513051c38f 100644 --- a/OpenSim/Simulation/Model/TwoFrameLinker.h +++ b/OpenSim/Simulation/Model/TwoFrameLinker.h @@ -79,6 +79,15 @@ class TwoFrameLinker : public C { /** By default, the TwoFrameLinker is not connected to any frames. */ TwoFrameLinker(); + /** Convenience Constructor. + Create a TwoFrameLinker Component between two Frames. + + @param[in] name the name of this TwoFrameLinker component + @param[in] frame1 the name of the first Frame being linked + @param[in] frame2 the name of the second Frame being linked + */ + TwoFrameLinker(const std::string &name, const F& frame1, const F& frame2); + /** Convenience Constructor. Create a TwoFrameLinker Component between two Frames identified by name. @@ -120,6 +129,28 @@ class TwoFrameLinker : public C { const std::string& frame2Name, const SimTK::Transform& offsetOnFrame2); + /** Backwards compatible Convenience Constructor + TwoFrameLinker with offsets specified in terms of the location and + orientation in respective PhysicalFrames. + + @param[in] name the name of this TwoFrameLinker component + @param[in] frame1 the first Frame being linked + @param[in] locationInFrame1 Vec3 of offset location on the first frame + @param[in] orientationInFrame1 Vec3 of orientation offset expressed as + XYZ body-fixed Euler angles w.r.t frame1. + @param[in] frame2 the second Frame being linked + @param[in] locationInFrame2 Vec3 of offset location on the second frame + @param[in] orientationInFrame2 Vec3 of orientation offset expressed as + XYZ body-fixed Euler angles w.r.t frame2. + */ + TwoFrameLinker(const std::string &name, + const PhysicalFrame& frame1, + const SimTK::Vec3& locationInFrame1, + const SimTK::Vec3& orientationInFrame1, + const PhysicalFrame& frame2, + const SimTK::Vec3& locationInFrame2, + const SimTK::Vec3& orientationInFrame2); + /** Backwards compatible Convenience Constructor TwoFrameLinker with offsets specified in terms of the location and orientation in respective PhysicalFrames. @@ -253,6 +284,16 @@ TwoFrameLinker::TwoFrameLinker() : C() this->constructProperties(); } +template +TwoFrameLinker::TwoFrameLinker(const std::string &name, + const F& frame1, + const F& frame2) : TwoFrameLinker() +{ + this->setName(name); + this->template updSocket("frame1").connect(frame1); + this->template updSocket("frame2").connect(frame2); +} + // Convenience constructors template TwoFrameLinker::TwoFrameLinker(const std::string &name, @@ -260,8 +301,8 @@ TwoFrameLinker::TwoFrameLinker(const std::string &name, const std::string& frame2Name) : TwoFrameLinker() { this->setName(name); - this->template updSocket("frame1").setConnecteeName(frame1Name); - this->template updSocket("frame2").setConnecteeName(frame2Name); + this->template updSocket("frame1").setConnecteePath(frame1Name); + this->template updSocket("frame2").setConnecteePath(frame2Name); } template @@ -314,6 +355,25 @@ TwoFrameLinker::TwoFrameLinker(const std::string &name, this->connectSocket_frame2(get_frames(ix2)); } +template +TwoFrameLinker::TwoFrameLinker(const std::string &name, + const PhysicalFrame& frame1, + const SimTK::Vec3& locationInFrame1, + const SimTK::Vec3& orientationInFrame1, + const PhysicalFrame& frame2, + const SimTK::Vec3& locationInFrame2, + const SimTK::Vec3& orientationInFrame2) + : TwoFrameLinker(name, + frame1, SimTK::Transform(SimTK::Rotation(SimTK::BodyRotationSequence, + orientationInFrame1[0], SimTK::XAxis, + orientationInFrame1[1], SimTK::YAxis, + orientationInFrame1[2], SimTK::ZAxis), locationInFrame1), + frame2, SimTK::Transform(SimTK::Rotation(SimTK::BodyRotationSequence, + orientationInFrame2[0], SimTK::XAxis, + orientationInFrame2[1], SimTK::YAxis, + orientationInFrame2[2], SimTK::ZAxis), locationInFrame2)) +{} + template TwoFrameLinker::TwoFrameLinker(const std::string& name, const std::string& frame1Name, @@ -604,10 +664,10 @@ void TwoFrameLinker::updateFromXMLNode(SimTK::Xml::Element& aNode, // in the ConstraintSet and ForceSet, which means we need to go // two levels up (../../) and into the bodyset to find the // Bodies (frames) being linked. - else if(frame1Name != "ground") { - frame1_connectee_name = "../../bodyset/" + frame1Name; - } else { - frame1_connectee_name = "../../" + frame1Name; + else { + frame1_connectee_name = + XMLDocument::updateConnecteePath30517("bodyset", + frame1Name); } // again for the offset frame on the child @@ -618,10 +678,10 @@ void TwoFrameLinker::updateFromXMLNode(SimTK::Xml::Element& aNode, frame2_connectee_name, frame2Name, locationInFrame2, orientationInFrame2); body2Element->setValue(frame2Name + "_offset"); - } else if (frame2Name != "ground") { - frame2_connectee_name = "../../bodyset/" + frame2Name; } else { - frame2_connectee_name = "../../" + frame2Name; + frame2_connectee_name = + XMLDocument::updateConnecteePath30517("bodyset", + frame2Name); } diff --git a/OpenSim/Simulation/SimbodyEngine/Body.cpp b/OpenSim/Simulation/SimbodyEngine/Body.cpp index 5983c9fdb2..9a7a318991 100644 --- a/OpenSim/Simulation/SimbodyEngine/Body.cpp +++ b/OpenSim/Simulation/SimbodyEngine/Body.cpp @@ -80,6 +80,7 @@ void Body::extendFinalizeFromProperties() Super::extendFinalizeFromProperties(); const SimTK::MassProperties& massProps = getMassProperties(); _internalRigidBody = SimTK::Body::Rigid(massProps); + _slaves.clear(); } //_____________________________________________________________________________ diff --git a/OpenSim/Simulation/SimbodyEngine/ConstantDistanceConstraint.cpp b/OpenSim/Simulation/SimbodyEngine/ConstantDistanceConstraint.cpp index 148128133d..0ccbe98199 100644 --- a/OpenSim/Simulation/SimbodyEngine/ConstantDistanceConstraint.cpp +++ b/OpenSim/Simulation/SimbodyEngine/ConstantDistanceConstraint.cpp @@ -70,10 +70,9 @@ ConstantDistanceConstraint::ConstantDistanceConstraint( setNull(); constructProperties(); - setBody1ByName(body1.getName()); - setBody2ByName(body2.getName()); + connectSocket_body_1(body1); + connectSocket_body_2(body2); set_location_body_1(locationBody1); - set_location_body_2(locationBody2); set_constant_distance(distance); } @@ -138,12 +137,12 @@ const PhysicalFrame& ConstantDistanceConstraint::getBody2() const * Following methods set attributes of the constraint */ void ConstantDistanceConstraint::setBody1ByName(const std::string& aBodyName) { - updSocket("body_1").setConnecteeName(aBodyName); + updSocket("body_1").setConnecteePath(aBodyName); } void ConstantDistanceConstraint::setBody2ByName(const std::string& aBodyName) { - updSocket("body_2").setConnecteeName(aBodyName); + updSocket("body_2").setConnecteePath(aBodyName); } /** Set the location for point on body 1*/ @@ -178,14 +177,17 @@ void ConstantDistanceConstraint::updateFromXMLNode(SimTK::Xml::Element& aNode, i // extract their values. // Constraints in pre-4.0 models are necessarily 1 level deep // (model, constraints), and Bodies are necessarily 1 level deep. - // Prepend "../" to get the correct relative path. + // Here we create the correct relative path (accounting for sets + // being components). if (body1Element != aNode.element_end()) { body1Element->getValueAs(body1_name); - body1_name = "../" + body1_name; + body1_name = XMLDocument::updateConnecteePath30517("bodyset", + body1_name); } if (body2Element != aNode.element_end()) { body2Element->getValueAs(body2_name); - body2_name = "../" + body2_name; + body2_name = XMLDocument::updateConnecteePath30517("bodyset", + body2_name); } XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "body_1", body1_name); diff --git a/OpenSim/Simulation/SimbodyEngine/Joint.cpp b/OpenSim/Simulation/SimbodyEngine/Joint.cpp index dad1c367b1..0a56241da3 100644 --- a/OpenSim/Simulation/SimbodyEngine/Joint.cpp +++ b/OpenSim/Simulation/SimbodyEngine/Joint.cpp @@ -258,6 +258,17 @@ bool Joint::isCoordinateUsed(const Coordinate& aCoordinate) const return false; } + +void Joint::addFrame(PhysicalOffsetFrame* frame) +{ + OPENSIM_THROW_IF(isComponentInOwnershipTree(frame), + ComponentAlreadyPartOfOwnershipTree, + frame->getName(), getName()); + updProperty_frames().adoptAndAppendValue(frame); + finalizeFromProperties(); + prependComponentPathToConnecteePath(*frame); +} + const SimTK::MobilizedBodyIndex Joint:: getMobilizedBodyIndex(const OpenSim::Body& body) const { diff --git a/OpenSim/Simulation/SimbodyEngine/Joint.h b/OpenSim/Simulation/SimbodyEngine/Joint.h index f642d4e3bf..384e15aa8d 100644 --- a/OpenSim/Simulation/SimbodyEngine/Joint.h +++ b/OpenSim/Simulation/SimbodyEngine/Joint.h @@ -225,6 +225,11 @@ OpenSim_DECLARE_ABSTRACT_OBJECT(Joint, ModelComponent); // Utility bool isCoordinateUsed(const Coordinate& aCoordinate) const; + /** Add a frame to the *frames* property in this Joint. The frame is + * adopted, and should have been dynamically allocated. + * Use this function instead of append_frames(). */ + void addFrame(PhysicalOffsetFrame* frame); + // Computation /** Given some system mobility (generalized) forces, calculate the equivalent spatial body force for this Joint. Keep in mind that there are diff --git a/OpenSim/Simulation/SimbodyEngine/PointConstraint.cpp b/OpenSim/Simulation/SimbodyEngine/PointConstraint.cpp index 7e66c97c1a..dbc9b7461c 100644 --- a/OpenSim/Simulation/SimbodyEngine/PointConstraint.cpp +++ b/OpenSim/Simulation/SimbodyEngine/PointConstraint.cpp @@ -129,12 +129,12 @@ void PointConstraint::extendAddToSystem(SimTK::MultibodySystem& system) const * Following methods set attributes of the frames of constraint */ void PointConstraint::setBody1ByName(const std::string& aBodyName) { - updSocket("body_1").setConnecteeName(aBodyName); + updSocket("body_1").setConnecteePath(aBodyName); } void PointConstraint::setBody2ByName(const std::string& aBodyName) { - updSocket("body_2").setConnecteeName(aBodyName); + updSocket("body_2").setConnecteePath(aBodyName); } /** Set the location for point on body 1*/ @@ -183,14 +183,17 @@ void PointConstraint::updateFromXMLNode(SimTK::Xml::Element& aNode, int versionN // extract their values. // Constraints in pre-4.0 models are necessarily 1 level deep // (model, constraints), and Bodies are necessarily 1 level deep. - // Prepend "../" to get the correct relative path. + // Here we create the correct relative path (accounting for sets + // being components). if (body1Element != aNode.element_end()) { body1Element->getValueAs(body1_name); - body1_name = "../" + body1_name; + body1_name = XMLDocument::updateConnecteePath30517("bodyset", + body1_name); } if (body2Element != aNode.element_end()) { body2Element->getValueAs(body2_name); - body2_name = "../" + body2_name; + body2_name = XMLDocument::updateConnecteePath30517("bodyset", + body2_name); } XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "body_1", body1_name); diff --git a/OpenSim/Simulation/SimbodyEngine/PointOnLineConstraint.cpp b/OpenSim/Simulation/SimbodyEngine/PointOnLineConstraint.cpp index 631d9a58ec..c55ef2379c 100644 --- a/OpenSim/Simulation/SimbodyEngine/PointOnLineConstraint.cpp +++ b/OpenSim/Simulation/SimbodyEngine/PointOnLineConstraint.cpp @@ -140,12 +140,12 @@ void PointOnLineConstraint::extendAddToSystem(SimTK::MultibodySystem& system) co * Following methods set attributes of the point on line constraint */ void PointOnLineConstraint::setLineBodyByName(const std::string& aBodyName) { - updSocket("line_body").setConnecteeName(aBodyName); + updSocket("line_body").setConnecteePath(aBodyName); } void PointOnLineConstraint::setFollowerBodyByName(const std::string& aBodyName) { - updSocket("follower_body").setConnecteeName(aBodyName); + updSocket("follower_body").setConnecteePath(aBodyName); } @@ -182,14 +182,17 @@ void PointOnLineConstraint::updateFromXMLNode(SimTK::Xml::Element& aNode, int ve // extract their values. // Constraints in pre-4.0 models are necessarily 1 level deep // (model, constraints), and Bodies are necessarily 1 level deep. - // Prepend "../" to get the correct relative path. + // Here we create the correct relative path (accounting for sets + // being components). if (body1Element != aNode.element_end()) { body1Element->getValueAs(body1_name); - body1_name = "../" + body1_name; + body1_name = XMLDocument::updateConnecteePath30517("bodyset", + body1_name); } if (body2Element != aNode.element_end()) { body2Element->getValueAs(body2_name); - body2_name = "../" + body2_name; + body2_name = XMLDocument::updateConnecteePath30517("bodyset", + body2_name); } XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "line_body", body1_name); diff --git a/OpenSim/Simulation/SimbodyEngine/RollingOnSurfaceConstraint.cpp b/OpenSim/Simulation/SimbodyEngine/RollingOnSurfaceConstraint.cpp index e9b01b3fbc..116c8c1527 100644 --- a/OpenSim/Simulation/SimbodyEngine/RollingOnSurfaceConstraint.cpp +++ b/OpenSim/Simulation/SimbodyEngine/RollingOnSurfaceConstraint.cpp @@ -171,12 +171,12 @@ extendSetPropertiesFromState(const SimTK::State& state) { * Following methods set attributes of the weld constraint */ void RollingOnSurfaceConstraint::setRollingBodyByName(const std::string& aBodyName) { - updSocket("rolling_body").setConnecteeName(aBodyName); + updSocket("rolling_body").setConnecteePath(aBodyName); } void RollingOnSurfaceConstraint::setSurfaceBodyByName(const std::string& aBodyName) { - updSocket("surface_body").setConnecteeName(aBodyName); + updSocket("surface_body").setConnecteePath(aBodyName); } /** Set the point of contact on the rolling body that will be in contact with the surface */ @@ -409,14 +409,17 @@ void RollingOnSurfaceConstraint::updateFromXMLNode(SimTK::Xml::Element& aNode, i // extract their values. // Constraints in pre-4.0 models are necessarily 1 level deep // (model, constraints), and Bodies are necessarily 1 level deep. - // Prepend "../" to get the correct relative path. + // Here we create the correct relative path (accounting for sets + // being components). if (body1Element != aNode.element_end()) { body1Element->getValueAs(body1_name); - if (!body1_name.empty()) body1_name = "../" + body1_name; + body1_name = XMLDocument::updateConnecteePath30517("bodyset", + body1_name); } if (body2Element != aNode.element_end()) { body2Element->getValueAs(body2_name); - if (!body2_name.empty()) body2_name = "../" + body2_name; + body2_name = XMLDocument::updateConnecteePath30517("bodyset", + body2_name); } XMLDocument::addConnector(aNode, "Connector_PhysicalFrame_", "rolling_body", body1_name); diff --git a/OpenSim/Simulation/SimbodyEngine/Test/testConstraints.cpp b/OpenSim/Simulation/SimbodyEngine/Test/testConstraints.cpp index 9b765a884a..e395665227 100644 --- a/OpenSim/Simulation/SimbodyEngine/Test/testConstraints.cpp +++ b/OpenSim/Simulation/SimbodyEngine/Test/testConstraints.cpp @@ -430,41 +430,43 @@ void testConstantDistanceConstraint() //========================================================================================================== // Setup OpenSim model - Model *osimModel = new Model; + Model osimModel; //OpenSim bodies - const Ground& ground = osimModel->getGround();; + const Ground& ground = osimModel.getGround(); //OpenSim foot - OpenSim::Body osim_foot("foot", footMass.getMass(), footMass.getMassCenter(), footMass.getInertia()); + auto* osim_foot = new OpenSim::Body("foot", footMass.getMass(), + footMass.getMassCenter(), + footMass.getInertia()); // create foot as a free joint - FreeJoint footJoint("footToGround", ground, Vec3(0), Vec3(0), osim_foot, Vec3(0), Vec3(0)); + auto* footJoint = new FreeJoint("footToGround", ground, Vec3(0), Vec3(0), + *osim_foot, Vec3(0), Vec3(0)); // Add the thigh body which now also contains the hip joint to the model - osimModel->addBody(&osim_foot); - osimModel->addJoint(&footJoint); + osimModel.addBody(osim_foot); + osimModel.addJoint(footJoint); // add a constant distance constraint - ConstantDistanceConstraint rodConstraint(ground, pointOnGround, osim_foot, pointOnFoot,rodLength); - osimModel->addConstraint(&rodConstraint); + auto* rodConstraint = new ConstantDistanceConstraint( + ground, pointOnGround, *osim_foot, pointOnFoot, rodLength); + osimModel.addConstraint(rodConstraint); - // BAD: have to set memoryOwner to false or program will crash when this test is complete. - osimModel->disownAllComponents(); - - osimModel->setGravity(gravity_vec); + osimModel.setGravity(gravity_vec); //Add analyses before setting up the model for simulation - Kinematics *kinAnalysis = new Kinematics(osimModel); + Kinematics* kinAnalysis = new Kinematics(&osimModel); kinAnalysis->setInDegrees(false); - osimModel->addAnalysis(kinAnalysis); + osimModel.addAnalysis(kinAnalysis); - // Need to setup model before adding an analysis since it creates the AnalysisSet - // for the model if it does not exist. - State& osim_state = osimModel->initSystem(); + // Need to setup model before adding an analysis since it creates the + // AnalysisSet for the model if it does not exist. + State& osim_state = osimModel.initSystem(); - //========================================================================================================== + //========================================================================= // Compare Simbody system and OpenSim model simulations - compareSimulations(system, state, osimModel, osim_state, "testConstantDistanceConstraint FAILED\n"); + compareSimulations(system, state, &osimModel, osim_state, + "testConstantDistanceConstraint FAILED\n"); } void testCoordinateLocking() { @@ -909,6 +911,7 @@ void testCoordinateCouplerConstraint() osimModel->disownAllComponents(); // write out the model to file + osimModel->finalizeConnections(); osimModel->print("testCouplerConstraint.osim"); //wipe-out the model just constructed @@ -1027,8 +1030,8 @@ void testRollingOnSurfaceConstraint() // add a point on line constraint auto roll = new RollingOnSurfaceConstraint(); - roll->setRollingBodyByName("rod"); - roll->setSurfaceBodyByName("ground"); + roll->connectSocket_rolling_body(*osim_rod); + roll->connectSocket_surface_body(ground); /*double h = */roll->get_surface_height(); diff --git a/OpenSim/Simulation/SimbodyEngine/Test/testJoints.cpp b/OpenSim/Simulation/SimbodyEngine/Test/testJoints.cpp index c343dfff9d..2be45856c6 100644 --- a/OpenSim/Simulation/SimbodyEngine/Test/testJoints.cpp +++ b/OpenSim/Simulation/SimbodyEngine/Test/testJoints.cpp @@ -207,7 +207,7 @@ int main() // test that kinematic loops are broken to form a tree with constraints try { ++itc; testAutomaticLoopJointBreaker(); } catch (const std::exception& e){ - cout << e.what() <upd_frame_geometry().setColor(SimTK::Vec3(0, 1, 0)); // GREEN + // pelvis->upd_frame_geometry().setColor(SimTK::Vec3(0, 1, 0)); // GREEN - thigh->upd_frame_geometry().setColor(SimTK::Vec3(0, 0, 1)); // BLUE + // thigh->upd_frame_geometry().setColor(SimTK::Vec3(0, 0, 1)); // BLUE //ModelComponent::addGeometry makes a copy of the passed in Geometry shank->attachGeometry(new Cylinder(0.02, 0.243800)); - shank->upd_attached_geometry(0).setColor(SimTK::Vec3(0, 1, 1)); // CYAN + // shank->upd_attached_geometry(0).setColor(SimTK::Vec3(0, 1, 1)); // CYAN foot->attachGeometry(new Brick(SimTK::Vec3(0.09, 0.025, 0.06))); - foot->upd_attached_geometry(0).setColor(SimTK::Vec3(1, 0, 0)); // RED + // foot->upd_attached_geometry(0).setColor(SimTK::Vec3(1, 0, 0)); // RED // add them to the model model.addBody(foot); @@ -2168,7 +2162,7 @@ void testAutomaticJointReversal() cfoot, zvec, zvec, cground, footInGround, zvec); modelConstrained.addConstraint(footConstraint); - auto fcpath = footConstraint->getRelativePathName(cfoot); + auto fcpath = footConstraint->getRelativePathString(cfoot); auto& off1 = footConstraint->getFrame1(); auto& sock1 = off1.getSocket("parent"); @@ -2178,11 +2172,11 @@ void testAutomaticJointReversal() auto off1Path = off1.getAbsolutePathString(); auto off2Path = off2.getAbsolutePathString(); - /*auto& pathOff1 = */sock1.getConnecteeName(); - /*auto& pathOff2 = */sock2.getConnecteeName(); + /*auto& pathOff1 = */sock1.getConnecteePath(); + /*auto& pathOff2 = */sock2.getConnecteePath(); - auto relPathOff1 = cfoot.getRelativePathName(off1); - auto relPathOff2 = cground.getRelativePathName(off2); + auto relPathOff1 = cfoot.getRelativePathString(off1); + auto relPathOff2 = cground.getRelativePathString(off2); //modelConstrained.setUseVisualizer(true); modelConstrained.printSubcomponentInfo(); @@ -2241,7 +2235,7 @@ void testUserJointReversal() // Open model. auto model = Model("double_pendulum_testReverse.osim"); - model.finalizeConnections(model); //calls finalizeFromProperties internally + model.finalizeConnections(); //calls finalizeFromProperties internally // In this model file: // - pin1's parent is ground and child is rod1 diff --git a/OpenSim/Simulation/Test/testForces.cpp b/OpenSim/Simulation/Test/testForces.cpp index 8c76ce9186..c24765e4c3 100644 --- a/OpenSim/Simulation/Test/testForces.cpp +++ b/OpenSim/Simulation/Test/testForces.cpp @@ -76,7 +76,7 @@ int main() catch (const std::exception& e){ cout << e.what() <set_translational_stiffness(transStiffness); + spring->set_rotational_stiffness(rotStiffness); + spring->set_translational_damping(transDamping); + spring->set_rotational_damping(rotDamping); osimModel.addForce(spring); const BushingForce& bushingForce = @@ -622,7 +625,7 @@ void testBushingForce() // To print (serialize) the latest connections of the model, it is // necessary to finalizeConnections() first. - osimModel.finalizeConnections(osimModel); + osimModel.finalizeConnections(); osimModel.print("BushingForceModel.osim"); Model previousVersionModel("BushingForceModel_30000.osim"); @@ -723,11 +726,11 @@ void testTwoFrameLinkerUpdateFromXMLNode() { osimModel.setGravity(gravity_vec); auto* spring = new BushingForce("bushing", - "ground", + ground, Transform(Rotation(BodyRotationSequence, -0.5, XAxis, 0, YAxis, 0.5, ZAxis), Vec3(1, 2, 3)), - "ball", + *ball, Transform(Rotation(BodyRotationSequence, 0.1, XAxis, 0.2, YAxis, 0.3, ZAxis), Vec3(4, 5, 6)), @@ -739,14 +742,14 @@ void testTwoFrameLinkerUpdateFromXMLNode() { const BushingForce& bushingForce = osimModel.getComponent("./forceset/bushing"); - // It's necessary to correct the connectee names in the BushingForce, which + // It's necessary to correct the connectee paths in the BushingForce, which // we can do with finalizeConnections() (they are incorrect otherwise // because `spring` is initially orphaned). - osimModel.finalizeConnections(osimModel); + osimModel.finalizeConnections(); osimModel.print("BushingForceOffsetModel.osim"); Model previousVersionModel("BushingForceOffsetModel_30000.osim"); - previousVersionModel.finalizeConnections(osimModel); + previousVersionModel.finalizeConnections(); previousVersionModel.print("BushingForceOffsetModel_30000_in_Latest.osim"); const BushingForce& bushingForceFromPrevious = @@ -800,8 +803,8 @@ void testFunctionBasedBushingForce() osimModel.setGravity(gravity_vec); FunctionBasedBushingForce spring("linear_bushing", - "ground", Vec3(0), Vec3(0), - "ball", Vec3(0), Vec3(0), + ground, Vec3(0), Vec3(0), + ball, Vec3(0), Vec3(0), transStiffness, rotStiffness, transDamping, rotDamping); osimModel.addForce(&spring); @@ -915,8 +918,8 @@ void testExpressionBasedBushingForceTranslational() Vec3 transDamping(0); ExpressionBasedBushingForce spring("linear_bushing", - "base_body", Vec3(0), Vec3(0), - "ball", Vec3(0), Vec3(0), + base, Vec3(0), Vec3(0), + ball, Vec3(0), Vec3(0), transStiffness, rotStiffness, transDamping, rotDamping); spring.setName("translational_linear_bushing"); @@ -1031,8 +1034,8 @@ void testExpressionBasedBushingForceRotational() Vec3 transDamping(0); ExpressionBasedBushingForce spring("rotatinal_spring", - "base_body", Vec3(0), Vec3(0), - "ball", Vec3(0), Vec3(0), + base, Vec3(0), Vec3(0), + ball, Vec3(0), Vec3(0), transStiffness, rotStiffness, transDamping, rotDamping); spring.setName("rotational_linear_bushing"); @@ -1302,6 +1305,7 @@ void testCoordinateLimitForce() // BAD: have to set memoryOwner to false or program will crash when this test is complete. osimModel->disownAllComponents(); + osimModel->finalizeConnections(); osimModel->print("CoordinateLimitForceTest.osim"); // Check serialization and deserialization diff --git a/OpenSim/Simulation/Test/testModelInterface.cpp b/OpenSim/Simulation/Test/testModelInterface.cpp index 3c8f4b03fa..a6ec4c8604 100644 --- a/OpenSim/Simulation/Test/testModelInterface.cpp +++ b/OpenSim/Simulation/Test/testModelInterface.cpp @@ -110,7 +110,7 @@ void testModelFinalizePropertiesAndConnections() // Test for the effects of calling finalizeConnections() on the model // after initSystem() has been called. // In this case, there are no changes to the connections to be finalized. - model.finalizeConnections(model); + model.finalizeConnections(); // verify that finalizeConnections() does not wipe out the underlying // System when there are no changes to the connections @@ -131,7 +131,7 @@ void testModelFinalizePropertiesAndConnections() elbow.connectSocket_parent_frame(*elbowInHumerus); // satisfy the new connections in the model - model.finalizeConnections(model); + model.finalizeConnections(); // now finalizing the connections will invalidate the System because // a Component (the elbow Joint and its connection) was updated @@ -193,9 +193,9 @@ void testModelTopologyErrors() Model degenerate; - auto frame1 = new PhysicalOffsetFrame("frame1", model.getGround(), + auto frame1 = new PhysicalOffsetFrame("frame1", degenerate.getGround(), SimTK::Transform(SimTK::Vec3(0, -0.1, 0))); - auto frame2 = new PhysicalOffsetFrame("frame2", model.getGround(), + auto frame2 = new PhysicalOffsetFrame("frame2", degenerate.getGround(), SimTK::Transform(SimTK::Vec3(0, 0.2, 0))); degenerate.addComponent(frame1); @@ -210,7 +210,7 @@ void testModelTopologyErrors() // Expose infinite recursion in the case that Joint explicitly invokes // finalizeConnections on its parent and child frames AND the Joint itself // is a subcomponent of either the parent or child frame. This test is why - // the Joint cannot resolve whether two frames have the same base frame. + // the Joint cannot resolve whether two frames have the same base frame. frame1->addComponent(joint1); // Parent and child frames of a Joint cannot be the same frame diff --git a/OpenSim/Simulation/Test/testPrescribedForce.cpp b/OpenSim/Simulation/Test/testPrescribedForce.cpp index b4c342ad6e..fa60fbdb92 100644 --- a/OpenSim/Simulation/Test/testPrescribedForce.cpp +++ b/OpenSim/Simulation/Test/testPrescribedForce.cpp @@ -120,7 +120,7 @@ void testPrescribedForce(OpenSim::Function* forceX, OpenSim::Function* forceY, O // Setup OpenSim model Model *osimModel = new Model; //OpenSim bodies - const Ground& ground = osimModel->getGround();; + const Ground& ground = osimModel->getGround(); OpenSim::Body ball; ball.setName("ball"); @@ -158,6 +158,7 @@ void testPrescribedForce(OpenSim::Function* forceX, OpenSim::Function* forceY, O ball.setInertia(ballMass.getInertia()); osimModel->setGravity(gravity_vec); + osimModel->finalizeConnections(); osimModel->print("TestPrescribedForceModel.osim"); delete osimModel; diff --git a/OpenSim/Simulation/Test/testReportersWithModel.cpp b/OpenSim/Simulation/Test/testReportersWithModel.cpp index a4eddedcd5..e3aeba7784 100644 --- a/OpenSim/Simulation/Test/testReportersWithModel.cpp +++ b/OpenSim/Simulation/Test/testReportersWithModel.cpp @@ -50,15 +50,14 @@ void testConsoleReporterLabels() { reporter->addToReport(slider->getCoordinate().getOutput("value"), "height"); model.addComponent(reporter); - // Redirect cout to stringstream so ConsoleReporter output can be tested. - stringstream buf; - streambuf* oldBuf = cout.rdbuf(buf.rdbuf()); - - // Simulate. State& state = model.initSystem(); Manager manager(model); state.setTime(0.0); manager.initialize(state); + + // Redirect cout to stringstream so ConsoleReporter output can be tested. + stringstream buf; + streambuf* oldBuf = cout.rdbuf(buf.rdbuf()); manager.integrate(1.0); // Restore original destination for cout and display ConsoleReporter output. @@ -109,9 +108,9 @@ void testTableReporterLabels() { manager.integrate(1.0); // Check column headings for dependent variables reported by TableReporter, - // which should be "/world/slider/sliderCoord/value" and "height". + // which should be "slider/sliderCoord/value" and "height". const auto headings = reporter->getTable().getColumnLabels(); - SimTK_TEST(headings[0] == "/world/jointset/slider/sliderCoord|value"); + SimTK_TEST(headings[0] == "/jointset/slider/sliderCoord|value"); SimTK_TEST(headings[1] == "height"); } diff --git a/OpenSim/Tests/Components/testComponents.cpp b/OpenSim/Tests/Components/testComponents.cpp index 02a6a032f9..b9270afac7 100644 --- a/OpenSim/Tests/Components/testComponents.cpp +++ b/OpenSim/Tests/Components/testComponents.cpp @@ -249,8 +249,8 @@ void testComponent(const Component& instanceToTest) addObjectAsComponentToModel(dependency.release(), model); // Connect the socket. This should come after adding the - // dependency to the model, otherwise the "connectee name" - // relative path will be incorrect. + // dependency to the model, otherwise the connectee path may + // be incorrect. socket.connect(*depRawPtr); } } @@ -273,7 +273,7 @@ void testComponent(const Component& instanceToTest) // Special case: Geometry cannot have both its input and socket // connected. if (dynamic_cast(&sub) && inputName == "transform") { - input.setConnecteeName(""); + input.setConnecteePath(""); continue; } @@ -286,7 +286,7 @@ void testComponent(const Component& instanceToTest) for (const auto& ito : outputGen->getOutputs()) { const AbstractOutput* output = ito.second.get(); if (dependencyTypeName == output->getTypeName()) { - input.setConnecteeName(output->getChannel("").getPathName()); + input.setConnecteePath(output->getChannel("").getPathName()); foundAnOutput = true; } } diff --git a/OpenSim/Tests/README/testREADME.cpp b/OpenSim/Tests/README/testREADME.cpp index 39142c3927..4ae06a1790 100644 --- a/OpenSim/Tests/README/testREADME.cpp +++ b/OpenSim/Tests/README/testREADME.cpp @@ -101,11 +101,11 @@ int main() { bodyGeometry.setColor(Gray); // Attach an ellipsoid to a frame located at the center of each body. PhysicalOffsetFrame* humerusCenter = new PhysicalOffsetFrame( - "humerusCenter", "humerus", Transform(Vec3(0, 0.5, 0))); + "humerusCenter", *humerus, Transform(Vec3(0, 0.5, 0))); humerus->addComponent(humerusCenter); humerusCenter->attachGeometry(bodyGeometry.clone()); PhysicalOffsetFrame* radiusCenter = new PhysicalOffsetFrame( - "radiusCenter", "radius", Transform(Vec3(0, 0.5, 0))); + "radiusCenter", *radius, Transform(Vec3(0, 0.5, 0))); radius->addComponent(radiusCenter); radiusCenter->attachGeometry(bodyGeometry.clone()); diff --git a/OpenSim/Tools/Test/BuiltinGeometry.osim b/OpenSim/Tools/Test/BuiltinGeometry.osim index fe3364a3bc..ca82f756f6 100644 --- a/OpenSim/Tools/Test/BuiltinGeometry.osim +++ b/OpenSim/Tools/Test/BuiltinGeometry.osim @@ -1,114 +1,137 @@ - + + + + + + + + .. + + 0.20000000000000001 0.20000000000000001 0.20000000000000001 + + + ../ground + + 0 0.050000000000000003 0.34999999999999998 + + -0 0 -0 + + + + + + .. + + 0.20000000000000001 0.20000000000000001 0.20000000000000001 + + + ../ground + + 0 0.050000000000000003 -0.34999999999999998 + + -0 0 -0 + + + + + + .. + + 0.20000000000000001 0.20000000000000001 0.20000000000000001 + + + ../ground + + -0.20000000000000001 0 0 + + -0 0 -0 + + + + + + .. + + 0.20000000000000001 0.20000000000000001 0.20000000000000001 + + + ../ground + + -0.59999999999999998 0.59999999999999998 0 + + -0 0 -0 + + - - - - - ../ - - + + ../ 1 1 1 0.5 0.01 0.5 - - - - - - ../../LeftAnchor - - + + + ../../LeftAnchor 5 1 1 0.050000000000000003 0.050000000000000003 0.050000000000000003 - - - - - - ../../RightAnchor - - + + + ../../RightAnchor 5 1 1 0.050000000000000003 0.050000000000000003 0.050000000000000003 - - - - - ../../CylAnchor - - + + ../../CylAnchor 0.20000000000000001 0.29999999999999999 - - - - - ../../EllipsoidAnchor - - + + ../../EllipsoidAnchor 0.20000000000000001 0.69999999999999996 0.5 - - - - - ../ - - + + .. 0.20000000000000001 0.20000000000000001 0.20000000000000001 - + - - - - - ../ - - + + .. 0.10000000000000001 - - - - - ../ - - + + .. 0.20000000000000001 0.20000000000000001 0.20000000000000001 @@ -122,200 +145,72 @@ - - - - - - - - - ../ground - - - - - - - - - ../ - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - 0 0.050000000000000003 0.34999999999999998 - - -0 0 -0 - - - - - - - ../ground - - - - - - - - - ../ - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - 0 0.050000000000000003 -0.34999999999999998 - - -0 0 -0 - - - - - - - ../ground - - - - - - - - - ../ - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - -0.20000000000000001 0 0 - - -0 0 -0 - - - - - - - ../ground - - - - - - - - - ../ - - - - 0.20000000000000001 0.20000000000000001 0.20000000000000001 - - - -0.59999999999999998 0.59999999999999998 0 - - -0 0 -0 - - - - - + - - - - - ./ground_offset - - - - ../block - - - - - - - - -1.5707963267949001 1.5707963267949001 - - false - - - - -1.5707963267949001 1.5707963267949001 - - false - - - - -1.5707963267949001 1.5707963267949001 - - false - - - - 0.20000000000000001 - - -1 1 - - false - - - - -0.0019613299999999998 - - -1 1 - - false - - - - -1 1 - - false - - - - - - false - + + ground_offset + + ../../bodyset/block + + + + + -1.5707963267949001 1.5707963267949001 + + false + + + + -1.5707963267949001 1.5707963267949001 + + false + + + + -1.5707963267949001 1.5707963267949001 + + false + + + + 0.20000000000000001 + + -1 1 + + false + + + + -0.0019613299999999998 + + -1 1 + + false + + + + -1 1 + + false + + + - - - - - ../../ground - - - - - - - ../ - - + + .. 0.20000000000000001 0.20000000000000001 0.20000000000000001 - + + ../../../ground + 0 0.050000000000000003 0 - + 0 0 0 @@ -324,7 +219,7 @@ - + @@ -346,20 +241,13 @@ - + - - - - - ../ground - - - - ../block - - + + ../../ground + + ../../bodyset/block 0 0.050000000000000003 0 @@ -371,43 +259,34 @@ - + - - 0 - - 1 - - + + - - - - - ../../../ground - - - + + ../../../../ground + 0 0.050000000000000003 -0.34999999999999998 - - - - - ../../../block - - - + + ../../../../bodyset/block + 0 0 -0.050000000000000003 + + + + 0.80000000000000004 0.10000000000000001 0.10000000000000001 + 1000 @@ -423,40 +302,31 @@ 0.25 - - 0 - - 1 - - + + - - - - - ../../../ground - - - + + ../../../../ground + 0 0.050000000000000003 0.34999999999999998 - - - - - ../../../block - - - + + ../../../../bodyset/block + 0 0 0.050000000000000003 + + + + 0.80000000000000004 0.10000000000000001 0.10000000000000001 + 1000 @@ -472,13 +342,8 @@ 0.25 - - - - - ../block - - + + ../../bodyset/block @@ -515,7 +380,7 @@ - + diff --git a/OpenSim/Tools/Test/testVisualization.cpp b/OpenSim/Tools/Test/testVisualization.cpp index 4d16832c00..e109403961 100644 --- a/OpenSim/Tools/Test/testVisualization.cpp +++ b/OpenSim/Tools/Test/testVisualization.cpp @@ -135,8 +135,8 @@ int main() testVisModelAgainstStandard(testModel3, standard); std::cout << "double_pendulum33 test Passed" << std::endl; - // Now a model from 3.3 where both GeometrySet and individual DisplayGeometry - // have a non-trivial transform. + // Now a model from 3.3 where both GeometrySet and individual + // DisplayGeometry have a non-trivial transform. Model composedTransformsModel("doubletransform33.osim"); composedTransformsModel.updDisplayHints().set_show_frames(true); populate_composedTransformPrimitives(standard); @@ -303,6 +303,11 @@ void populate_doublePendulumPrimitives(SimTK::Array_& stdPri DecorativeFrame(1.0).setBodyId(0).setColor(SimTK::White) .setIndexOnBody(0).setScale(0.2).setOpacity(1) .setRepresentation(SimTK::DecorativeGeometry::DrawSurface)); + // Frame rod 1 + stdPrimitives.push_back( + DecorativeFrame(1.0).setBodyId(1).setColor(SimTK::White) + .setIndexOnBody(0).setScale(0.2).setOpacity(1) + .setRepresentation(SimTK::DecorativeGeometry::DrawSurface)); // Offset frame rod1 stdPrimitives.push_back( DecorativeFrame(1.0).setBodyId(1).setColor(SimTK::White).setIndexOnBody(0).setScale(0.2) @@ -314,17 +319,17 @@ void populate_doublePendulumPrimitives(SimTK::Array_& stdPri .setIndexOnBody(0).setScaleFactors(Vec3{ 0.02,0.5,0.02 }).setOpacity(1) .setRepresentation(SimTK::DecorativeGeometry::DrawSurface) .setTransform(SimTK::Transform(Vec3{ 0., .25, 0 }))); - // Frame rod 1 - stdPrimitives.push_back( - DecorativeFrame(1.0).setBodyId(1).setColor(SimTK::White) - .setIndexOnBody(0).setScale(0.2).setOpacity(1) - .setRepresentation(SimTK::DecorativeGeometry::DrawSurface)); // Block rod 1 stdPrimitives.push_back( DecorativeMeshFile("block.vtp").setBodyId(1).setColor(SimTK::White) .setIndexOnBody(0).setScale(1).setOpacity(1) .setRepresentation(SimTK::DecorativeGeometry::DrawSurface)); + // Frame body 2 + stdPrimitives.push_back( + DecorativeFrame(1.0).setBodyId(2).setColor(SimTK::White) + .setIndexOnBody(0).setScale(0.2).setOpacity(1) + .setRepresentation(SimTK::DecorativeGeometry::DrawSurface)); // Offset frame rod2 stdPrimitives.push_back( DecorativeFrame(1.0).setBodyId(2).setColor(SimTK::White) @@ -337,11 +342,6 @@ void populate_doublePendulumPrimitives(SimTK::Array_& stdPri .setIndexOnBody(0).setScaleFactors(Vec3{ 0.02,0.5,0.02 }).setOpacity(1) .setRepresentation(SimTK::DecorativeGeometry::DrawSurface) .setTransform(SimTK::Transform(Vec3{ 0., .25, 0 }))); - // Frame body 2 - stdPrimitives.push_back( - DecorativeFrame(1.0).setBodyId(2).setColor(SimTK::White) - .setIndexOnBody(0).setScale(0.2).setOpacity(1) - .setRepresentation(SimTK::DecorativeGeometry::DrawSurface)); // Block rod 2 stdPrimitives.push_back( DecorativeMeshFile("block.vtp").setBodyId(2).setColor(SimTK::White) @@ -379,6 +379,10 @@ void populate_composedTransformPrimitives(SimTK::Array_& std DecorativeFrame(1.0).setBodyId(0).setColor(SimTK::White) .setIndexOnBody(0).setScale(0.2).setOpacity(1) .setRepresentation(SimTK::DecorativeGeometry::DrawSurface)); + stdPrimitives.push_back( + DecorativeFrame(1.0).setBodyId(1).setColor(SimTK::White) + .setIndexOnBody(0).setScale(0.2).setOpacity(1) + .setRepresentation(SimTK::DecorativeGeometry::DrawSurface)); // This the frame of the composed transform and attached geometry stdPrimitives.push_back( DecorativeFrame(1.0).setBodyId(1).setColor(SimTK::White) @@ -391,10 +395,6 @@ void populate_composedTransformPrimitives(SimTK::Array_& std .setRepresentation(SimTK::DecorativeGeometry::DrawSurface) .setTransform(SimTK::Transform(Vec3{ 0.3, 0.3, 0.3 }))); - stdPrimitives.push_back( - DecorativeFrame(1.0).setBodyId(1).setColor(SimTK::White) - .setIndexOnBody(0).setScale(0.2).setOpacity(1) - .setRepresentation(SimTK::DecorativeGeometry::DrawSurface)); stdPrimitives.push_back( diff --git a/OpenSim/Tools/Test/vis_BuiltinGeometry.txt b/OpenSim/Tools/Test/vis_BuiltinGeometry.txt index 249da1b892..be1840c365 100644 --- a/OpenSim/Tools/Test/vis_BuiltinGeometry.txt +++ b/OpenSim/Tools/Test/vis_BuiltinGeometry.txt @@ -22,6 +22,12 @@ DecorativeFrame:1 bodyId:0 color:~[1,1,1] indexOnBody:0 Opacity:1 Rep:3 Scale:~[ [0,0,1,0] [0,0,0,1] +DecorativeFrame:1 bodyId:0 color:~[1,1,1] indexOnBody:0 Opacity:1 Rep:3 Scale:~[0.2,0.2,0.2] Transform: +[1,0,0,0] +[0,1,0,0] +[0,0,1,0] +[0,0,0,1] + DecorativeBrick:~[0.5,0.01,0.5] bodyId:0 color:~[1,1,1] indexOnBody:0 Opacity:1 Rep:3 Scale:~[1,1,1] Transform: [1,0,0,0] [0,1,0,0] @@ -52,7 +58,7 @@ DecorativeEllipsoid:~[0.2,0.7,0.5] bodyId:0 color:~[1,1,1] indexOnBody:0 Opacity [0,0,1,0] [0,0,0,1] -DecorativeFrame:1 bodyId:0 color:~[1,1,1] indexOnBody:0 Opacity:1 Rep:3 Scale:~[0.2,0.2,0.2] Transform: +DecorativeFrame:1 bodyId:1 color:~[1,1,1] indexOnBody:0 Opacity:1 Rep:3 Scale:~[0.2,0.2,0.2] Transform: [1,0,0,0] [0,1,0,0] [0,0,1,0] @@ -64,12 +70,6 @@ DecorativeSphere:0.1 bodyId:1 color:~[1,1,1] indexOnBody:0 Opacity:1 Rep:3 Scale [0,0,1,0] [0,0,0,1] -DecorativeFrame:1 bodyId:1 color:~[1,1,1] indexOnBody:0 Opacity:1 Rep:3 Scale:~[0.2,0.2,0.2] Transform: -[1,0,0,0] -[0,1,0,0] -[0,0,1,0] -[0,0,0,1] - DecorativeFrame:1 bodyId:0 color:~[1,1,1] indexOnBody:0 Opacity:1 Rep:3 Scale:~[0.2,0.2,0.2] Transform: [1,0,0,0] [0,1,0,0.05] diff --git a/OpenSim/Tools/Test/visualize_contacts.osim b/OpenSim/Tools/Test/visualize_contacts.osim index 0d458c0722..64c9cafa3e 100644 --- a/OpenSim/Tools/Test/visualize_contacts.osim +++ b/OpenSim/Tools/Test/visualize_contacts.osim @@ -1,5 +1,5 @@ - + @@ -25,17 +25,10 @@ - - - - - ground_offset - - - - ball_offset - - + + ground_offset + + ball_offset @@ -57,34 +50,22 @@ - - false - + - - - - - ../../model_/ground - - - + + ../../../ground + 0 0 0 - + 0 0 0 - - - - - ball - - - + + ../../../bodyset/ball + 0 0 0 - + 0 0 0 @@ -111,24 +92,7 @@ - - - - - - - ball3 plane - 1000000 - 0.001 - 0 - 0 - 0 - - - - - - + @@ -136,13 +100,8 @@ - - - - - model_/ground - - + + ../../ground 1 2 0 @@ -151,13 +110,8 @@ sphere.vtp - - - - - model_/ball - - + + ../../bodyset/ball 1 1 0 @@ -165,51 +119,41 @@ sphere.vtp - - - - - - model_/ball - - - - 0 1 0 - - 0 0 0 - - 0.250000000000000001 - - - - - - - model_/ground - - - - - - 0 0 0 - - 0 0 .5 - - - - true - - 0.7 - - 0 1 1 - - - - 3 - - - - + + + ../../bodyset/ball + + 0 1 0 + + 0 0 0 + + 0.25 + + + + + + ../../ground + + 0 0 0 + + 0 0 0.5 + + + + true + + 0.69999999999999996 + + 0 1 1 + + + + 3 + + + + diff --git a/OpenSim/Utilities/simmFileWriterDLL/SimbodySimmModel.cpp b/OpenSim/Utilities/simmFileWriterDLL/SimbodySimmModel.cpp index 7f1a11fcb5..42f4922baf 100644 --- a/OpenSim/Utilities/simmFileWriterDLL/SimbodySimmModel.cpp +++ b/OpenSim/Utilities/simmFileWriterDLL/SimbodySimmModel.cpp @@ -1045,7 +1045,8 @@ bool SimbodySimmModel::writeMuscle(Muscle& aMuscle, const ForceSet& aActuatorSet aStream << " ranges 1 " << coord.getName() << " (" << range[0] << ", " << range[1] << ")" << endl; } else { aStream << " ranges 1 " - << mvp->getSocket("coordinate").getConnecteeName() + << mvp->getSocket( + "coordinate").getConnecteePath() << " (0.0, 1.0)" << endl; } } else if (pt.getConcreteClassName()==("MovingPathPoint")) { diff --git a/README.md b/README.md index 30f6c16d1e..3f1eccddc3 100644 --- a/README.md +++ b/README.md @@ -94,11 +94,11 @@ int main() { bodyGeometry.setColor(Gray); // Attach an ellipsoid to a frame located at the center of each body. PhysicalOffsetFrame* humerusCenter = new PhysicalOffsetFrame( - "humerusCenter", "humerus", Transform(Vec3(0, 0.5, 0))); + "humerusCenter", *humerus, Transform(Vec3(0, 0.5, 0))); humerus->addComponent(humerusCenter); humerusCenter->attachGeometry(bodyGeometry.clone()); PhysicalOffsetFrame* radiusCenter = new PhysicalOffsetFrame( - "radiusCenter", "radius", Transform(Vec3(0, 0.5, 0))); + "radiusCenter", *radius, Transform(Vec3(0, 0.5, 0))); radius->addComponent(radiusCenter); radiusCenter->attachGeometry(bodyGeometry.clone()); diff --git a/doc/APIGuide.md b/doc/APIGuide.md index f96951a02e..405bf8587f 100644 --- a/doc/APIGuide.md +++ b/doc/APIGuide.md @@ -485,7 +485,7 @@ All components are given the opportunity finalize their specification from their 2. Similarly, Sockets are handled automatically by the base Component, which establishes that the dependency exists and is connected (throws an Exception otherwise). Additional connection details or checks are often necessary, in which case you must override: ~~~cpp - void OpenSim::Component::extendConnect(Component& root) + void OpenSim::Component::extendFinalizeConnections(Component& root) ~~~ for a Component, or ~~~cpp