diff --git a/ShoulderCase/@Humerus/Humerus.m b/ShoulderCase/@Humerus/Humerus.m index b08a523..a575f10 100644 --- a/ShoulderCase/@Humerus/Humerus.m +++ b/ShoulderCase/@Humerus/Humerus.m @@ -1,100 +1,105 @@ classdef Humerus < handle %HUMERUS Properties and methods associated to the humerus % Detailed explanation goes here % Author: Alexandre Terrier, EPFL-LBO % Creation date: 2018-07-01 % Revision date: 2019-06-29 % % TO DO: % Local coordinate system properties landmarks % 5 3D points insertions + insertionsRing center % Center of the humeral head (sphere fit on 5 points radius % Radius of the humeral head (sphere fit on 5 points jointRadius % Radius of cuvature of the articular surface (todo) SHSAngle % Scapulo-humeral subluxation angle SHSPA % Scapulo-humeral subluxation angle in the postero-anterior direction (posterior is negative, as for glenoid version) SHSIS % Scapulo-humeral subluxation angle in the infero-superior direction SHSAmpl % Scapulo-humeral subluxation (center ofset / radius) SHSOrient % Scapulo-humral subluxation orientation (0 degree is posterior) GHSAmpl % Gleno-humeral subluxation (center ofset / radius) GHSOrient % Gleno-humral subluxation orientation (0 degree is posterior) subluxationIndex3D shoulder end methods (Access = ?Shoulder) % Only Shoulder is allowed to construct Humerus function obj = Humerus(shoulder) %HUMERUS Construct an instance of this class % Detailed explanation goes here obj.landmarks = []; - obj.center = []; - obj.radius = []; + obj.insertionsRing = []; + obj.center = []; + obj.radius = []; obj.jointRadius = []; - obj.SHSAngle = []; - obj.SHSPA = []; - obj.SHSIS = []; - obj.SHSAmpl = []; + obj.SHSAngle = []; + obj.SHSPA = []; + obj.SHSIS = []; + obj.SHSAmpl = []; obj.SHSOrient = []; - obj.GHSAmpl = []; + obj.GHSAmpl = []; obj.GHSOrient = []; obj.shoulder = shoulder; end end methods function output = loadData(obj) % Call methods that can be run after the ShoulderCase object has % been instanciated. if obj.hasSlicerLandmarks() success = Logger.timeLogExecution(... "Humerus load landmarks (slicer): ",... @(obj) obj.loadSlicerLandmarks, obj); elseif obj.hasAmiraLandmarks() success = Logger.timeLogExecution(... "Humerus load landmarks (amira): ",... @(obj) obj.loadAmiraLandmarks, obj); else success = Logger.timeLogExecution(... "Humerus load landmarks: ",... @(message) error(message), "No landmarks file found"); end output = success; end function output = morphology(obj) % Call methods that can be run after loadData() methods has been run % by all ShoulderCase objects. success = Logger.timeLogExecution(... "Humerus center and radius: ",... @(obj) obj.measureCenterAndRadius, obj); + success = success & Logger.timeLogExecution(... + "Insertions' ring: ",... + @(obj) obj.measureInsertionsRing, obj); output = success; end function output = measureFirst(obj) % Call methods that can be run after morphology() methods has been run % by all ShoulderCase objects. success = Logger.timeLogExecution(... "Humerus scapulo-humeral subluxation: ",... @(obj) obj.measureScapuloHumeralSubluxation, obj); output = success; end function output = measureSecond(obj) % Call methods that can be run after measureFirst() methods has been run % by all ShoulderCase objects. success = Logger.timeLogExecution(... "Humerus gleno-humeral subluxation: ",... @(obj) obj.measureGlenoHumeralSubluxation, obj); success = success & Logger.timeLogExecution(... "Humerus 3D subluxation index: ",... @(obj) obj.measureSubluxationIndex3D, obj); output = success; end end end diff --git a/ShoulderCase/@Humerus/measureInsertionsRing.m b/ShoulderCase/@Humerus/measureInsertionsRing.m new file mode 100644 index 0000000..9b4e9d6 --- /dev/null +++ b/ShoulderCase/@Humerus/measureInsertionsRing.m @@ -0,0 +1,27 @@ +function measureInsertionsRing(obj) + % The insertions ring is the intersection of the plane fitted to the + % insertions' landmarks with the humeral head fitted sphere. + + insertionsArray = []; + for insertionName = string(fields(obj.insertions))' + insertionsArray = [insertionsArray; obj.insertions.(insertionName)]; + end + insertionsPlane = Plane(); + insertionsPlane.fit(insertionsArray); + + ringNormal = Vector(insertionsPlane.normal); + humerusCenterToPlanePoint = Vector(obj.center, insertionsPlane.point); + + % The ring's center is the projection of any point of the insertions' plane + % on the vector starting at the humeral head center and with the same + % direction as the insertion's plane normal direction. + ringCenter = obj.center... + + (ringNormal.dot(humerusCenterToPlanePoint) * ringNormal.vector); + + humerusCenterToRingCenter = Vector(obj.center, ringCenter); + ringRadius = sqrt(obj.radius^2 - humerusCenterToRingCenter.norm()^2); + + obj.insertionsRing.center = ringCenter; + obj.insertionsRing.radius = ringRadius; + obj.insertionsRing.normal = ringNormal; +end \ No newline at end of file