UNPKG

bowling-analysis-system

Version:

A comprehensive system for analyzing bowling techniques using video processing and metrics calculation

152 lines (124 loc) 4.42 kB
/** * @module metrics/calculations/angles/SpineAngles * @description Functions for calculating spine and trunk angles */ const { calculateAngleBetweenVectors, getSafeLandmark, createVector } = require('../MetricsUtilities'); /** * Calculate spine twist angle * @param {Array} landmarks - Array of pose landmarks * @returns {number} Spine twist angle in degrees */ function calculateSpineTwist(landmarks) { const leftShoulder = getSafeLandmark(landmarks, 11); const rightShoulder = getSafeLandmark(landmarks, 12); const leftHip = getSafeLandmark(landmarks, 23); const rightHip = getSafeLandmark(landmarks, 24); if (!leftShoulder || !rightShoulder || !leftHip || !rightHip) return null; const shoulderLine = createVector(leftShoulder, rightShoulder); const hipLine = createVector(leftHip, rightHip); // Project both lines onto horizontal plane const shoulderHorizontal = { x: shoulderLine.x, y: 0, z: shoulderLine.z }; const hipHorizontal = { x: hipLine.x, y: 0, z: hipLine.z }; return calculateAngleBetweenVectors(shoulderHorizontal, hipHorizontal); } /** * Calculate trunk flexion angle * @param {Array} landmarks - Array of pose landmarks * @returns {number} Trunk flexion angle in degrees */ function calculateTrunkFlexion(landmarks) { const neck = getSafeLandmark(landmarks, 0); const midHip = getCenterPoint( getSafeLandmark(landmarks, 23), getSafeLandmark(landmarks, 24) ); if (!neck || !midHip) return null; const trunk = createVector(midHip, neck); const vertical = { x: 0, y: 1, z: 0 }; return calculateAngleBetweenVectors(trunk, vertical); } /** * Calculate trunk lean angle * @param {Array} landmarks - Array of pose landmarks * @returns {number} Trunk lean angle in degrees */ function calculateTrunkLean(landmarks) { const leftShoulder = getSafeLandmark(landmarks, 11); const rightShoulder = getSafeLandmark(landmarks, 12); const leftHip = getSafeLandmark(landmarks, 23); const rightHip = getSafeLandmark(landmarks, 24); if (!leftShoulder || !rightShoulder || !leftHip || !rightHip) return null; // Calculate midpoints const midShoulder = getCenterPoint(leftShoulder, rightShoulder); const midHip = getCenterPoint(leftHip, rightHip); if (!midShoulder || !midHip) return null; const trunk = createVector(midHip, midShoulder); const vertical = { x: 0, y: 1, z: 0 }; return calculateAngleBetweenVectors(trunk, vertical); } /** * Calculate spine angle * @param {Array} landmarks - Array of pose landmarks * @returns {number} Spine angle in degrees */ function calculateSpineAngle(landmarks) { const neck = getSafeLandmark(landmarks, 0); const midShoulder = getCenterPoint( getSafeLandmark(landmarks, 11), getSafeLandmark(landmarks, 12) ); const midHip = getCenterPoint( getSafeLandmark(landmarks, 23), getSafeLandmark(landmarks, 24) ); if (!neck || !midShoulder || !midHip) return null; const upperSpine = createVector(midShoulder, neck); const lowerSpine = createVector(midHip, midShoulder); return calculateAngleBetweenVectors(upperSpine, lowerSpine); } /** * Calculate neck angle * @param {Array} landmarks - Array of pose landmarks * @returns {number} Neck angle in degrees */ function calculateNeckAngle(landmarks) { const head = getSafeLandmark(landmarks, 0); const neck = getSafeLandmark(landmarks, 1); const midShoulder = getCenterPoint( getSafeLandmark(landmarks, 11), getSafeLandmark(landmarks, 12) ); if (!head || !neck || !midShoulder) return null; const neckLine = createVector(neck, head); const upperSpine = createVector(midShoulder, neck); return calculateAngleBetweenVectors(neckLine, upperSpine); } /** * Get center point between two points * @param {Object} point1 - First point * @param {Object} point2 - Second point * @returns {Object} Center point */ function getCenterPoint(point1, point2) { if (!point1 || !point2) return null; return { x: (point1.x + point2.x) / 2, y: (point1.y + point2.y) / 2, z: (point1.z + point2.z) / 2 }; } module.exports = { calculateSpineTwist, calculateTrunkFlexion, calculateTrunkLean, calculateSpineAngle, calculateNeckAngle };