% Leg Length Discrepancy Measurement, adapted from Eyeling lldm.n3.
%
% The measurement and intermediate geometry are kept in helper predicates so
% the default triple/3 materialization stays concise.  The visible output is
% the alarm plus the small set of triples explaining why the alarm fired.

measurement(meas47).

% measured landmark coordinates, in centimetres
val(meas47, p1xCm, 10.1).
val(meas47, p1yCm, 7.8).
val(meas47, p2xCm, 45.1).
val(meas47, p2yCm, 5.6).
val(meas47, p3xCm, 3.6).
val(meas47, p3yCm, 29.8).
val(meas47, p4xCm, 54.7).
val(meas47, p4yCm, 28.5).

% threshold used by the alarm rule, in centimetres
threshold(meas47, lld_alarm_threshold_cm, 1.25).

% geometric intermediate values
val(M, dx12Cm, Z) :- measurement(M), val(M, p1xCm, X), val(M, p2xCm, Y), sub(X, Y, Z).
val(M, dx51Cm, Z) :- measurement(M), val(M, p5xCm, X), val(M, p1xCm, Y), sub(X, Y, Z).
val(M, dx53Cm, Z) :- measurement(M), val(M, p5xCm, X), val(M, p3xCm, Y), sub(X, Y, Z).
val(M, dx62Cm, Z) :- measurement(M), val(M, p6xCm, X), val(M, p2xCm, Y), sub(X, Y, Z).
val(M, dx64Cm, Z) :- measurement(M), val(M, p6xCm, X), val(M, p4xCm, Y), sub(X, Y, Z).
val(M, dy12Cm, Z) :- measurement(M), val(M, p1yCm, X), val(M, p2yCm, Y), sub(X, Y, Z).
val(M, dy13Cm, Z) :- measurement(M), val(M, p1yCm, X), val(M, p3yCm, Y), sub(X, Y, Z).
val(M, dy24Cm, Z) :- measurement(M), val(M, p2yCm, X), val(M, p4yCm, Y), sub(X, Y, Z).
val(M, dy53Cm, Z) :- measurement(M), val(M, p5yCm, X), val(M, p3yCm, Y), sub(X, Y, Z).
val(M, dy64Cm, Z) :- measurement(M), val(M, p6yCm, X), val(M, p4yCm, Y), sub(X, Y, Z).
val(M, cL1, Z) :- measurement(M), val(M, dy12Cm, Y), val(M, dx12Cm, X), div(Y, X, Z).
val(M, dL3m, Z) :- measurement(M), val(M, cL1, X), div(1, X, Z).
val(M, cL3, Z) :- measurement(M), val(M, dL3m, X), sub(0, X, Z).
val(M, pL1x1Cm, Z) :- measurement(M), val(M, cL1, X), val(M, p1xCm, Y), mul(X, Y, Z).
val(M, pL1x2Cm, Z) :- measurement(M), val(M, cL1, X), val(M, p2xCm, Y), mul(X, Y, Z).
val(M, pL3x3Cm, Z) :- measurement(M), val(M, cL3, X), val(M, p3xCm, Y), mul(X, Y, Z).
val(M, pL3x4Cm, Z) :- measurement(M), val(M, cL3, X), val(M, p4xCm, Y), mul(X, Y, Z).
val(M, dd13Cm, Z) :- measurement(M), val(M, pL1x1Cm, X), val(M, pL3x3Cm, Y), sub(X, Y, Z).
val(M, ddy13Cm, Z) :- measurement(M), val(M, dd13Cm, X), val(M, dy13Cm, Y), sub(X, Y, Z).
val(M, dd24Cm, Z) :- measurement(M), val(M, pL1x2Cm, X), val(M, pL3x4Cm, Y), sub(X, Y, Z).
val(M, ddy24Cm, Z) :- measurement(M), val(M, dd24Cm, X), val(M, dy24Cm, Y), sub(X, Y, Z).
val(M, ddL13, Z) :- measurement(M), val(M, cL1, X), val(M, cL3, Y), sub(X, Y, Z).
val(M, pL1dx51Cm, Z) :- measurement(M), val(M, cL1, X), val(M, dx51Cm, Y), mul(X, Y, Z).
val(M, pL1dx62Cm, Z) :- measurement(M), val(M, cL1, X), val(M, dx62Cm, Y), mul(X, Y, Z).
val(M, p5xCm, Z) :- measurement(M), val(M, ddy13Cm, X), val(M, ddL13, Y), div(X, Y, Z).
val(M, p5yCm, Z) :- measurement(M), val(M, pL1dx51Cm, X), val(M, p1yCm, Y), add(X, Y, Z).
val(M, p6xCm, Z) :- measurement(M), val(M, ddy24Cm, X), val(M, ddL13, Y), div(X, Y, Z).
val(M, p6yCm, Z) :- measurement(M), val(M, pL1dx62Cm, X), val(M, p2yCm, Y), add(X, Y, Z).
val(M, sdx53Cm2, Z) :- measurement(M), val(M, dx53Cm, X), pow(X, 2, Z).
val(M, sdx64Cm2, Z) :- measurement(M), val(M, dx64Cm, X), pow(X, 2, Z).
val(M, sdy53Cm2, Z) :- measurement(M), val(M, dy53Cm, X), pow(X, 2, Z).
val(M, sdy64Cm2, Z) :- measurement(M), val(M, dy64Cm, X), pow(X, 2, Z).
val(M, ssd53Cm2, Z) :- measurement(M), val(M, sdx53Cm2, X), val(M, sdy53Cm2, Y), add(X, Y, Z).
val(M, ssd64Cm2, Z) :- measurement(M), val(M, sdx64Cm2, X), val(M, sdy64Cm2, Y), add(X, Y, Z).
val(M, d53Cm, Z) :- measurement(M), val(M, ssd53Cm2, X), pow(X, 0.5, Z).
val(M, d64Cm, Z) :- measurement(M), val(M, ssd64Cm2, X), pow(X, 0.5, Z).
val(M, dCm, Z) :- measurement(M), val(M, d53Cm, X), val(M, d64Cm, Y), sub(X, Y, Z).

% concise output layer
triple(M, type, lld_alarm) :- measurement(M), val(M, dCm, D), threshold(M, lld_alarm_threshold_cm, T), sub(0, T, NegT), lt(D, NegT).
triple(M, type, lld_alarm) :- measurement(M), val(M, dCm, D), threshold(M, lld_alarm_threshold_cm, T), gt(D, T).
triple(M, lld_left_length_cm, L) :- triple(M, type, lld_alarm), val(M, d53Cm, L).
triple(M, lld_right_length_cm, R) :- triple(M, type, lld_alarm), val(M, d64Cm, R).
triple(M, lld_discrepancy_cm, D) :- triple(M, type, lld_alarm), val(M, dCm, D).
triple(M, lld_threshold_cm, T) :- triple(M, type, lld_alarm), threshold(M, lld_alarm_threshold_cm, T).
triple(M, lld_reason, "discrepancy below negative threshold") :- triple(M, type, lld_alarm).
