Supination / Pronation Twist Osteokinematics & Arthrokinematics Determinants / Parameters of Gait Scapulohumeral Rhythm Meniscus / Functions of Menisci Bursae Around Knee Joint Ligamentum Flavum Sliding Filament Theory Linear Force System Sensory Receptors (Muscle) TFCC Patellofemoral Joint Reaction Force Composition of Connective Tissue Loading of the Foot Arches of Foot & Its Biomechanics Pelvic Tilt Scoliosis Load Deformation Curve Grip and Grasp / Power Grip Active & Passive Insufficiency Angles of Hip Joint ACL Suprhumeral / Coracoacromial Arch Ideal / Optimal Posture Anatomical Pulleys / Patella as Anatomical Pulley Pivot Joint Importance of Angles/Curves in Femur Extensor Mechanism / Expansion of Wrist & Fingers Shoulder Joint Stability / Static Stabilization Factors Affecting Muscle Functions � � Bio mech repeated 5 marks 2019 - 2025.pdf Bio mech repeated 5 marks 2019 - 2025.pdf Give two diagram for each question send in pdf format
supination pronation forearm rotation osteokinematics

A sequence of three clinical photographs demonstrating the range of motion for forearm rotation, specifically focusing on the degrees of freedom in pronation and supination. Each image shows a human forearm and fist with superimposed geometric annotations. Left panel (Supination): The forearm is in a fully supinated position with the palm/anterior surface facing upward, labeled as 0"". Middle panel (Neutral): The forearm is in the mid-position (neutral), with the thumb pointing upward and the radial side of the hand superior. Right panel (Pronation): The forearm is in a fully pronated position with the dorsal surface of the hand facing upward, labeled as 180"". Dotted vertical lines and curved arrows illustrate the angular displacement and direction of rotational movement. This visual is designed for orthopedic or kinesiologic education, illustrating the clinical assessment of the radio-ulnar joints and the physiological limits of forearm rotation for prosthetic or exoskeleton development.

Two-panel clinical photograph (A and B) demonstrating a post-operative assessment of forearm rotation in a 62-year-old male patient following surgical intervention for a distal ulnar lesion. In both panels, the patient is shown from the waist up, wearing a clinical gown, with elbows flexed at approximately 90 degrees and tucked into the sides. Image A illustrates bilateral forearm pronation; the patient holds wooden dowels vertically, with the palms facing downward. Image B demonstrates bilateral forearm supination, with the wooden dowels rotated to a horizontal orientation and the palms facing upward. The images highlight the restoration of symmetric and intact range of motion (ROM) in the distal radioulnar joint (DRUJ) following Sauve-Kapandji reconstruction. This visual is used in orthopedic and oncology education to assess functional outcomes after limb-salvage surgery for pathologic fractures or bone tumors like low-grade chondrosarcoma.
gait cycle determinants parameters walking biomechanics

This medical illustration is a Timeline/Progression diagram depicting the human gait cycle from 0% to 100%. Seven skeletal figures in sagittal view demonstrate the biomechanics of movement across the Stance Phase (0-60%) and Swing Phase (60-100%). The diagram incorporates the DB-Total marker set protocol, with reflective markers at anatomical landmarks including the Nasion (Ns), spinous processes (C7, T7, L5, S2), acromioclavicular joint (ACj), and heel (He). Key gait phases are identified: Initial Contact (IC), Loading Response (LR), Mid-Stance (MSt), Terminal Stance (TSt), Pre-Swing (PSw), Initial Swing (ISw), Mid-Swing (MSw), and Terminal Swing (TSw). Color-coded lines and lowercase letters (a-t) represent eighteen sagittal kinematic parameters, such as Dorsal Angle (DA), Lumbar Angle (LA), Sagittal Vertical Axis (SVA), and various Heel-Sacrum relationships (HSA, HST, HSC, HSN). The educational focus is on whole-body kinematics, showing the dynamic alignment of the head, trunk, and limbs during walking for clinical motion analysis and gait assessment in rehabilitation medicine.

This infographic illustrates the biomechanics of the human gait cycle through five distinct events: Initial Contact, Breaking Phase Ground Reaction Force (GRF) Peak, Midstance, Propulsive Phase GRF Peak, and Toe-off. The visual combines anatomical musculoskeletal diagrams of the lower limb and torso with corresponding horizontal bar charts. The charts quantify the percentage of total muscle force contributed by specific functional muscle groups at each stage. Key highlights include the dominance of hip extensors and knee flexors during initial contact, a shift to hip abductors and knee extensors during the breaking phase, and the high output of ankle plantar flexors during the propulsive phase. The musculoskeletal diagrams represent the alignment of the pelvis, hip, knee, and ankle joints in relation to the center of mass and ground contact. This resource is designed for physical therapy, kinesiology, and orthopedic education to demonstrate the dynamic recruitment of muscle groups (such as hip abductors, adductors, flexors, and ankle dorsiflexors) throughout the walking stance phase.
scapulohumeral rhythm shoulder abduction glenohumeral scapular rotation

A series of six clinical photographs in black and white, capturing a posterior view of a human subject to demonstrate scapular kinematics during shoulder abduction. The sequence displays progressive bilateral arm abduction in the frontal plane at standardized intervals: 0 degrees (pendant position), 30 degrees, 60 degrees, 90 degrees, 120 degrees, and maximum abduction (approximately 170-180 degrees). Anatomical surface markers are visible on the subject's back, specifically positioned at the superior and inferior angles of the scapulae to facilitate biophotogrammetry analysis. The images illustrate the scapulohumeral rhythm, showing the upward and lateral rotation of the scapula as the humerus is elevated. This clinical imaging series is typical for orthopedic or physical therapy assessments of scapular dyskinesis, shoulder range of motion, and biomechanical studies of the shoulder complex.

This composite diagnostic image features four clips from dynamic digital radiography (DDR) of the right shoulder, illustrating scapulohumeral rhythm (SHR). Images A and B show preoperative states at minimal and maximal humeral abduction, while C and D show the same intervals postoperatively. The images demonstrate the relationship between the humerus, scapula, and thorax. Yellow lines annotate the humerothoracic angle, while red lines represent the scapulothoracic angle measurement zones. In the preoperative sequence (A-B), there is significant humeral abduction but minimal change in the scapulothoracic angle, indicative of serratus anterior palsy and dysfunctional kinematics. In the postoperative sequence (C-D), following a pectoralis major transfer, there is a visible increase in scapular rotation accompanying humeral abduction. This visual comparison highlights the restoration of coordinated scapular movement and a normalized scapulohumeral rhythm. Key anatomical landmarks include the humeral head, glenoid cavity, coracoid process, and rib cage.
meniscus knee joint anatomy functions medial lateral

A clinical photograph of human medical specimens featuring the medial and lateral menisci of a right knee joint. The image displays two distinct, semi-lunar fibrocartilaginous structures set against a dark background. On the left, the medial meniscus is characterized by a larger, more open 'C' shape with a wider radius, reflecting its anatomical attachment to the tibial plateau. On the right, the lateral meniscus exhibits a more circular, closed 'O' or tight 'C' morphology, where the anterior and posterior horns are positioned closer together. Both specimens appear to have been treated or dyed for contrast, showing a uniform light green color with a smooth, glistening surface texture. These specimens are typical of those used in orthopedic research and biomechanical studies to evaluate meniscal anatomy, tissue repair using nano-biomaterials, and the mechanical properties of the anterior horn, body, and posterior horn regions.

This clinical photograph shows a superior view of a dissected knee joint from a 32-week-old human fetus, illustrating the comparative morphology of the medial and lateral menisci. The medial meniscus (labeled MM) displays a classic sickle-shaped morphology, characterized by thin anterior and posterior horns and a relatively wider body with a substantial gap between the horns. In contrast, the lateral meniscus (labeled LM) exhibits a more circular 'C' shape. Anatomical landmarks including the anterior horn area (labeled A) and posterior horn area (labeled P) are visible, along with the tibial articular surfaces and associated soft tissue attachments. The image demonstrates key developmental anatomy and morphological classification of meniscal structures in the fetal period, highlighting the greater surface area often covered by the medial meniscus compared to the lateral. This visual is significant for orthopedic developmental studies and fetal anatomical education.
bursae around knee joint anatomy diagram

Anatomical diagram and surgical illustration of a knee joint during a Unicompartmental Knee Arthroplasty (UKA) procedure. The illustration features a sketch of the distal femur and proximal tibia. The femur is depicted with prominent condyles and a clear intercondylar notch. On the medial aspect of the proximal tibia, a surgical cutting block or tibial implant template is positioned, featuring visible screw holes for stabilization. A central surgical instrument, identified as an intramedullary rod inserter, is shown in the foreground. A thin intramedullary rod extends from the inserter, passing through the tibial component and projecting superiorly into the intercondylar notch of the femur. This setup demonstrates a modified surgical technique where the intramedullary rod serves as a directional guide to improve the accuracy of vertical bone cuts and implant positioning. The focus of the illustration is the spatial relationship between the surgical instrumentation and the knee anatomy to prevent malalignment during joint replacement.

This medical illustration consists of two comparative anatomical diagrams in a posterior view, likely representing surgical concepts related to posterior tissue releases in orthopedic surgery. The left diagram depicts the distal femur, proximal tibia, and fibula forming the knee joint. It features black hatch marks across the posterior joint capsule and soft tissues, alongside red dashed lines indicating ligamentous or neurovascular structures. The right diagram illustrates the effect of a posterior release; it shows a bowed posterior capsule with arrows indicating the mobilization and displacement of tissues away from the joint space. A continuous red line on both diagrams represents the neurovascular bundle or skin contour, demonstrating its relationship to the underlying musculoskeletal structures. This illustration is an educational tool for understanding surgical approaches to correcting knee flexion contractures or managing posterior knee anatomy during joint reconstruction.
ligamentum flavum spine vertebral canal ligament

Postoperative computed tomography (CT) images of the upper thoracic spine, presented in sagittal (A and B) and axial (C) views. The images demonstrate the results following surgical decompression for ossification of the ligamentum flavum (OLF) at the T2-T3 levels. Panels A and B provide sagittal reconstructions showing stacked vertebral bodies with preserved intervertebral disc spaces and normal spinal alignment. Panel A highlights a remaining posterior hyperdensity, while Panel B illustrates a plane where the surgical resection of the ossified ligament is complete, resulting in an enlarged spinal canal diameter. Axial view C shows the thoracic vertebra in cross-section, revealing the status of the vertebral arch. There is visible evidence of laminectomy or laminoplasty, with the spinal canal appearing widely patent and free of the previously compressing ossified mass. The images serve to confirm sufficient neural decompression and the successful removal of OLF while maintaining spinal structural integrity.

This set of axial CT images illustrates Sato's classification of Thoracic Ossification of the Ligamentum Flavum (TOLF), a pathological condition where the ligamentum flavum undergoes heterotopic ossification, leading to spinal stenosis. The images are categorized into five distinct types based on morphology: (a) Lateral type: Ossification is localized at the capsular portion of the ligamentum flavum. (b) Extended type: The ossification expands from the lateral aspects toward the midline while remaining thin. (c) Enlarged type: The ossified mass becomes more substantial and projects further into the spinal canal. (d) Fused type: The bilateral ossified masses meet and fuse at the midline. (e) Tuberous type: A prominent, nodular, or beak-like ossified growth that significantly narrows the spinal canal. Each panel demonstrates the varying degrees of posterior spinal canal encroachment and the spatial relationship between the ossified ligament and the adjacent vertebral lamina. This classification is clinically significant for determining the severity of canal narrowing and planning surgical decompression strategies in the thoracic spine.
sliding filament theory muscle contraction actin myosin sarcomere

This composite educational graphic illustrates the microanatomy of skeletal muscle fibers across three levels of magnification. The top panel features a high-resolution micrograph of a single myofibril, displaying characteristic dark A-bands and light I-bands in a repeating transverse striation pattern. The middle panel provides a magnified view of a single sarcomere unit, identifying key vertical landmarks: the Z-line (defining sarcomere boundaries), the central M-line, and the horizontal alignment of contractile proteins. The bottom panel is a labeled schematic diagram correlating the visual findings with molecular structures. It depicts the thick filaments (myosin) at the center anchored by the M-line, and thin filaments (actin) extending from the Z-lines. The spring-like protein titin is shown tethering the thick filaments to the Z-line. This multi-modal representation serves to teach the relationship between visible light/electron microscopy patterns and the underlying sliding filament theory of muscle contraction, relevant to physiology and histology.

A multi-panel scientific visualization showing subtomogram averages and molecular docking models of the cardiac muscle sarcomere's C-zone, specifically focusing on the interactions between myosin thick filaments and actin thin filaments. Panel (a) provides a cross-sectional view of a central myosin filament (M) surrounded by six actin filaments (A1, A2), illustrating the threefold symmetry of the thick filament backbone. Panels (b-g) integrate structural models to characterize MyBP-C (myosin-binding protein C) and myosin head arrangements. Longitudinal stereo views (c-e) demonstrate the axial distribution of myosin crossbridge 'crowns' (Crowns 1, 2, and 3) along the 430 Å repeat, with Crown 1 coinciding with the MyBP-C stripe. The models incorporate Ig-domain spheres (red) to trace the path of MyBP-C from the myosin backbone to actin, alongside docked crystal structures of cardiac thick filaments (yellow) and myosin motor domains (pink/cyan). This diagram serves as a high-resolution anatomical and physiological illustration for understanding cardiac muscle contraction at the molecular level, highlighting the spatial relationship between titin, MyBP-C, and the actomyosin complex.
ACL anterior cruciate ligament anatomy knee biomechanics

This composite of clinical anatomical photographs (panels a-c) displays the macrostructure of the anterior cruciate ligament (ACL) in a dissected human knee joint. Panel 'a' provides an anterior view of the knee with synovial tissue removed, highlighting the ACL's morphology as a flat, ribbon-like band rather than a cylindrical cord. The ligament demonstrates a cohesive, broad fiber arrangement spanning from the femoral condyle to the tibial plateau without distinct separation into anteromedial or posterolateral bundles. Panel 'b' shows a sagittal cross-section of the femur, illustrating the ligament's direct attachment to the posterior femoral cortex. The fibers are seen inserting into the bone at an acute angle, maintaining continuity with the osseous surface. Panel 'c' utilizes surgical forceps to further demonstrate the thin, wide 'ribbon' profile of the ACL at its midsubstance. This content is highly relevant for orthopedic anatomy and surgical planning, specifically regarding ACL reconstruction techniques that aim to replicate the native flat anatomy of the ligament and its precise femoral insertion footprint.

This medical biomechanics graphic illustrates Anterior Cruciate Ligament (ACL) force distribution during a downhill skiing turn. The visual contains a series of line graphs and a 3D musculoskeletal model. The primary 'total' graph displays ACL force in Newtons (N) over a 1.4-second interval for the right knee (blue) and left knee (red). The right knee, acting as the outside leg in the turn, shows a significant peak force of approximately 211 N at 1 second, whereas the left knee (inside leg) remains near baseline. Supporting secondary graphs break down these forces into three planes: sagittal, frontal, and transverse. Comparison of these planes reveals that the frontal plane is the dominant contributor to the total ACL force on the outside leg, likely due to external abduction moments. To the right, a musculoskeletal simulation shows a skeleton with highlighted musculature and green vectors representing ground reaction forces acting on the skis. This content is designed for advanced orthopedic and sports medicine education regarding injury mechanisms and ligament loading during high-impact athletics.
patellofemoral joint reaction force knee extension biomechanics

This anatomical diagram illustrates the biomechanical coordinate system of the patellofemoral joint, specifically depicting the degrees of freedom for patellar kinematics relative to the femur. The visual utilizes a three-dimensional Cartesian coordinate system centered on the patella. Translation axes are labeled as X (mediolateral), Y (anteroposterior), and Z (proximodistal). Corresponding rotational movements are indicated with curved arrows and specific terminology: 'Tilt' refers to rotation around the Z-axis (longitudinal), 'Flex' (flexion/extension) refers to rotation around the X-axis (transverse), and 'Rot' refers to rotation around the Y-axis (sagittal). The diagram is set against a grayscale background showing the distal femur, proximal tibia, and fibula, serving as an educational resource for orthopedic biomechanics, physical therapy, and joint replacement modeling. It highlights the complex tracking of the patella during knee flexion and extension.

This composite image demonstrates a biomechanical research setup for in vivo knee kinematics. Panel A is a clinical photograph showing a subject wearing a lead apron, positioned on a custom staircase integrated with a single-plane fluoroscopic C-arm imaging system. This configuration is used to capture real-time radiographic data of the knee joint during weight-bearing activities like stair ascent. Panel B displays a series of fluoroscopic stills with virtual overlays (3D-to-2D registration) illustrating patellofemoral kinematics across three stages: Initial Phase, Middle Phase, and Terminal Phase. In these diagnostic frames, the patella is highlighted in yellow and the tibia in magenta. The sequence visualizes the relative 6-degree-of-freedom (6DOF) motion, showing the patella's inferior and posterior translation relative to the tibia as the knee transitions through flexion and extension. The educational focus is on the dynamic tracking of joint surfaces post-ACL reconstruction or in intact knees to evaluate functional stability and movement patterns. Medical specialty: Orthopedics and Biomechanics.
arches of foot longitudinal transverse arch biomechanics

This anatomical illustration and clinical specimen photograph depicts the functional skeletal arches of the human hand, demonstrated on a 3D-printed biomimetic prosthetic model. The image highlights the three-dimensional structural architecture essential for palm cupping, manual dexterity, and grasping adaptability. Three primary arches are overlaid with color-coded annotations: 1) The Longitudinal Arch (blue), which follows the long axis of the third metacarpal and finger; 2) The Proximal Transverse Arch (red), a relatively fixed arch located at the level of the carpus and proximal metacarpals; and 3) The Distal Transverse Arch (red), a mobile arch spanning the metacarpal heads. The specimen is mounted on a blue base with visible actuation lines representing synthetic tendons. This visual is used to teach hand biomechanics and kinesthetically informed design in prosthetics and orthopedic surgery, focusing on how these skeletal relationships allow the palm to adjust its concavity to accommodate objects of various shapes and sizes.

This clinical photograph with anatomical overlays illustrates the extrinsic muscles of the lower leg and foot that stabilize the longitudinal and transverse arches (System III). The image shows a posterior view of both legs in a heel-rise position. Color-coded regions highlight specific muscle systems: the triceps surae (blue) dominates the posterior calf, acting as the primary flexor and invertor via the Achilles tendon. The m. fibularis longus (green) runs laterally, wrapping under the foot to cross the plantar surface. The m. tibialis posterior (red) is shown wrapping around the medial malleolus. On the plantar aspect of the foot, the intersection of the fibularis longus (green) and tibialis posterior (red) is visible, demonstrating the anatomical 'crossing' mechanism that stabilizes the posterior transverse arch. The m. tibialis anterior (yellow) is partially visible on the medial aspect. This visual highlights the functional synergy between these antagonists in shaping the medial longitudinal arch and stiffening the foot into a rigid lever for gait propulsion.
ls /tmp/workspace/ 2>/dev/null && mkdir -p /tmp/workspace/biomech-pdf
Send the pdf
mkdir -p /tmp/workspace/biomech-pdf && pip show reportlab pillow requests 2>&1 | grep -E "^Name|not found"
~/biomech-pdf/generate_biomech_pdf.py
import requests
import io
import os
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cm
from reportlab.lib import colors
from reportlab.platypus import (SimpleDocTemplate, Paragraph, Spacer, Image,
Table, TableStyle, PageBreak, HRFlowable)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import KeepTogether
from PIL import Image as PILImage
import urllib.request
import traceback
# ── output path ──────────────────────────────────────────────────────────────
OUT = "/tmp/workspace/biomech-pdf/Biomechanics_5Marks_Diagrams.pdf"
# ── collected image URLs from search ─────────────────────────────────────────
IMAGES = {
"supination_pronation_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_25d4cadd68d3e57d20a7c700b3debf1d17e633bc93316b25f808b1142cb12fa5.jpg",
"supination_pronation_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_cd6aa0466326d3e94a31471480700b4cafd141b6a4487b23342f7fc3b3bb9b84.jpg",
"gait_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_14a4bdc0a165f9af88e1267f1b352cf493e895a7bea5e480f28f4bc99cca9cb2.jpg",
"gait_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_7f4c3813f1b4435c2380e79f047cb01a9ddc36c83d5708800c6eff72711c5d9a.jpg",
"scapulohumeral_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_2c390afb6f9dc0d879e2294871194909831dd55cb8fef1b1c20e6b8292637f14.jpg",
"scapulohumeral_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_3622a569856ce0b9b0dd63cd1c9fbaa779927cbec30e2fa3e14c5ef520e7be9d.jpg",
"meniscus_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_2456db91f81a0614a77856398d59b7b12a135bcfd29d451015f92fc540ef92f4.jpg",
"meniscus_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_4005e6a492f7bac510c0e33fcfc553fe6cf4c91cd7edb2becd9247ba36e98564.jpg",
"ligamentum_flavum_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_52c9eea42cb70f5b1fc5b1f3317ccddf27d7646bf15584434fe5ea21f490bcca.jpg",
"ligamentum_flavum_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_957d1ea3dc492a09bb2ef1d61380c8eab0c08c3e12ae3c038c906df5cddc536c.jpg",
"sliding_filament_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_c51d2cf0f4c4e51ce2a4267aa80effff169dc3a0a34ff2bb82d6b3d90e7a0b08.jpg",
"sliding_filament_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_891d8585a37370558b6c6e8d806b8a98e242b3c5f8955ad693c24019f540036b.jpg",
"acl_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_8773cf68c54f4f091619eca991592d45339e9e1e74b0fefdcfe68a0d14e22c03.jpg",
"acl_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_c5b9c47f15885c609be05dca10f82ee40801337fe5fd207af6d5ef005bfef5a2.jpg",
"patellofemoral_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_f5e36d82c6bd02be8300ead0eb80b45f5ed9825db19c57d2a44c9717785a700a.jpg",
"patellofemoral_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_b3eef7c11b2fff720d08c9eb4e63a3c1ea238c86cd8ac85970f7d28eb2bb271e.jpg",
"foot_arches_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_1818b80344c343bcdaeab3b671ccf3834c33e9527ea493746f62b6a9fd78d056.jpg",
"foot_arches_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_bed5b016775e9b570293894d34cea82f3db05763e2e251e585b24b4cca60daac.jpg",
}
def download_image(url, max_w, max_h):
"""Download image, return ReportLab Image flowable or None."""
try:
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
data = urllib.request.urlopen(req, timeout=15).read()
pil = PILImage.open(io.BytesIO(data))
w, h = pil.size
ratio = min(max_w / w, max_h / h)
return Image(io.BytesIO(data), width=w * ratio, height=h * ratio)
except Exception as e:
print(f" !! Failed {url[:60]}: {e}")
return None
# ── Matplotlib-drawn diagrams for topics without fetched images ───────────────
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import matplotlib.patches as patches
from matplotlib.patches import FancyArrowPatch, Arc, FancyBboxPatch
import numpy as np
def save_fig(name):
path = f"/tmp/workspace/biomech-pdf/{name}.png"
plt.savefig(path, dpi=120, bbox_inches="tight", facecolor="white")
plt.close()
return path
# ── DIAGRAM GENERATORS ────────────────────────────────────────────────────────
def draw_osteokinematics():
"""Osteokinematics vs Arthrokinematics diagram."""
fig, axes = plt.subplots(1, 2, figsize=(10, 5))
fig.suptitle("Osteokinematics vs Arthrokinematics", fontsize=14, fontweight='bold')
ax = axes[0]
ax.set_xlim(0, 10); ax.set_ylim(0, 10)
ax.set_aspect('equal'); ax.axis('off')
ax.set_title("Osteokinematics\n(Bone movement in space)", fontsize=11, color='navy')
# Draw a lever/bone rotating
pivot = plt.Circle((5, 3), 0.3, color='gray', zorder=5)
ax.add_patch(pivot)
# bone position 1
ax.plot([5, 5], [3, 8], 'b-', linewidth=6, solid_capstyle='round')
# bone position 2 (rotated)
angle = 45
x2 = 5 + 5*np.sin(np.radians(angle))
y2 = 3 + 5*np.cos(np.radians(angle))
ax.plot([5, x2], [3, y2], 'b--', linewidth=4, alpha=0.5)
arc = Arc((5, 3), 4, 4, angle=0, theta1=0, theta2=45, color='red', linewidth=2)
ax.add_patch(arc)
ax.annotate('Flexion\n(Plane of motion)', xy=(7.5, 5), fontsize=9, color='red', ha='center')
ax.text(5, 1.5, 'Axis of Rotation', ha='center', fontsize=9, color='gray')
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 10)
ax.set_aspect('equal'); ax.axis('off')
ax.set_title("Arthrokinematics\n(Joint surface motion)", fontsize=11, color='darkgreen')
# convex on concave
concave = Arc((5, 4), 6, 4, angle=0, theta1=0, theta2=180, color='steelblue', linewidth=3)
ax.add_patch(concave)
convex = Arc((5, 6.2), 3, 2.5, angle=0, theta1=180, theta2=360, color='tomato', linewidth=3)
ax.add_patch(convex)
ax.text(5, 2, 'Concave surface\n(Tibia)', ha='center', fontsize=9, color='steelblue')
ax.text(5, 8.5, 'Convex surface\n(Femur)', ha='center', fontsize=9, color='tomato')
# roll & glide arrows
ax.annotate('', xy=(7, 6.5), xytext=(5.5, 7),
arrowprops=dict(arrowstyle='->', color='green', lw=2))
ax.annotate('', xy=(3, 5.2), xytext=(5, 5.5),
arrowprops=dict(arrowstyle='->', color='purple', lw=2))
ax.text(7.5, 7, 'Roll', fontsize=9, color='green')
ax.text(1.5, 5.5, 'Glide', fontsize=9, color='purple')
plt.tight_layout()
return save_fig("osteokinematics")
def draw_sensory_receptors():
fig, ax = plt.subplots(figsize=(10, 7))
ax.set_xlim(0, 10); ax.set_ylim(0, 10)
ax.axis('off')
ax.set_title("Sensory Receptors in Muscle", fontsize=14, fontweight='bold')
# Muscle spindle
spindle = FancyBboxPatch((0.5, 5.5), 4, 3.5, boxstyle="round,pad=0.2",
linewidth=2, edgecolor='navy', facecolor='lightblue', alpha=0.4)
ax.add_patch(spindle)
ax.text(2.5, 9.3, 'MUSCLE SPINDLE\n(Intrafusal Fibers)', ha='center', fontsize=10, fontweight='bold', color='navy')
ax.text(2.5, 8.5, 'Nuclear bag fiber', ha='center', fontsize=9)
ax.text(2.5, 7.8, 'Nuclear chain fiber', ha='center', fontsize=9)
ax.text(2.5, 7.0, 'Ia afferents (primary)', ha='center', fontsize=9, color='red')
ax.text(2.5, 6.4, 'II afferents (secondary)', ha='center', fontsize=9, color='darkred')
ax.text(2.5, 5.8, 'Gamma motor neuron (efferent)', ha='center', fontsize=9, color='blue')
# GTO
gto = FancyBboxPatch((5.5, 5.5), 4, 3.5, boxstyle="round,pad=0.2",
linewidth=2, edgecolor='darkgreen', facecolor='lightgreen', alpha=0.4)
ax.add_patch(gto)
ax.text(7.5, 9.3, 'GOLGI TENDON ORGAN\n(GTO)', ha='center', fontsize=10, fontweight='bold', color='darkgreen')
ax.text(7.5, 8.5, 'Located at musculotendinous junction', ha='center', fontsize=9)
ax.text(7.5, 7.8, 'Encapsulated collagen fibers', ha='center', fontsize=9)
ax.text(7.5, 7.0, 'Ib afferents', ha='center', fontsize=9, color='darkgreen')
ax.text(7.5, 6.4, 'Detects muscle tension', ha='center', fontsize=9)
ax.text(7.5, 5.8, 'Inhibitory reflex (autogenic)', ha='center', fontsize=9, color='red')
# Comparison table
table_data = [
['Feature', 'Muscle Spindle', 'GTO'],
['Location', 'In muscle belly', 'Musculotendinous jxn'],
['Stimulus', 'Stretch (length)', 'Tension (force)'],
['Afferent', 'Ia, II', 'Ib'],
['Reflex', 'Stretch reflex', 'Inverse stretch reflex'],
]
t = ax.table(cellText=table_data[1:], colLabels=table_data[0],
bbox=[0, 0, 1, 0.48], cellLoc='center')
t.auto_set_font_size(False); t.set_fontsize(9)
t[0, 0].set_facecolor('#D0D0FF'); t[0, 1].set_facecolor('#D0D0FF'); t[0, 2].set_facecolor('#D0D0FF')
plt.tight_layout()
return save_fig("sensory_receptors")
def draw_tfcc():
fig, axes = plt.subplots(1, 2, figsize=(11, 5))
fig.suptitle("Triangular Fibrocartilage Complex (TFCC)", fontsize=13, fontweight='bold')
ax = axes[0]
ax.set_xlim(0, 10); ax.set_ylim(0, 10)
ax.axis('off')
ax.set_title("TFCC - Components (Palmar View)", fontsize=10, fontweight='bold')
# Radius
ax.add_patch(FancyBboxPatch((1, 6), 2.5, 3.5, boxstyle="round,pad=0.1",
facecolor='bisque', edgecolor='brown', linewidth=2))
ax.text(2.25, 9.8, 'RADIUS', ha='center', fontsize=9, fontweight='bold')
# Ulna
ax.add_patch(FancyBboxPatch((6.5, 6), 2.5, 3.5, boxstyle="round,pad=0.1",
facecolor='bisque', edgecolor='brown', linewidth=2))
ax.text(7.75, 9.8, 'ULNA', ha='center', fontsize=9, fontweight='bold')
# TFCC disc
ax.add_patch(patches.Ellipse((5, 5.5), 5, 2, angle=0, facecolor='lightcoral', edgecolor='red', linewidth=2, alpha=0.7))
ax.text(5, 5.5, 'Articular Disc\n(Central)', ha='center', va='center', fontsize=9, fontweight='bold')
# Ligaments
ax.annotate('', xy=(1, 6), xytext=(3.5, 5.5),
arrowprops=dict(arrowstyle='->', color='blue', lw=2))
ax.annotate('', xy=(9, 6), xytext=(6.5, 5.5),
arrowprops=dict(arrowstyle='->', color='blue', lw=2))
ax.text(5, 3.5, 'Volar Radioulnar Lig.', ha='center', fontsize=8, color='blue')
ax.text(5, 3.0, 'Dorsal Radioulnar Lig.', ha='center', fontsize=8, color='darkblue')
ax.text(5, 2.4, 'ECU subsheath', ha='center', fontsize=8)
ax.text(5, 1.8, 'Ulnocarpal ligaments (meniscal homologue)', ha='center', fontsize=8)
ax.text(5, 1.2, 'Ulnolunate & Ulnotriquetral Lig.', ha='center', fontsize=8, color='purple')
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 10)
ax.axis('off')
ax.set_title("TFCC - Functions & Tear Classification", fontsize=10, fontweight='bold')
functions = [
"1. Primary stabilizer of DRUJ",
"2. Transmits ~20% of axial load",
"3. Load distribution across carpus",
"4. Suspends ulnar carpus from radius",
"5. Allows forearm rotation"
]
for i, f in enumerate(functions):
ax.text(0.5, 8.5 - i*0.9, f, fontsize=10, va='center',
bbox=dict(facecolor='lightyellow', edgecolor='orange', boxstyle='round,pad=0.3'))
ax.text(0.5, 3.5, "Palmer Classification:", fontsize=10, fontweight='bold', color='darkred')
ax.text(0.5, 2.9, "Class I: Traumatic tear", fontsize=9)
ax.text(0.5, 2.3, "Class II: Degenerative (TFCC wear)", fontsize=9)
ax.text(0.5, 1.7, "Central disc — avascular (no healing)", fontsize=9, color='red')
ax.text(0.5, 1.1, "Peripheral — vascular (can heal)", fontsize=9, color='green')
plt.tight_layout()
return save_fig("tfcc")
def draw_linear_force():
fig, axes = plt.subplots(1, 2, figsize=(10, 5))
fig.suptitle("Linear Force System", fontsize=14, fontweight='bold')
ax = axes[0]
ax.set_xlim(-1, 11); ax.set_ylim(-1, 11)
ax.axis('off')
ax.set_title("Collinear Force System", fontsize=10, fontweight='bold')
ax.plot([2, 8], [5, 5], 'k-', linewidth=3)
ax.annotate('', xy=(8, 5), xytext=(5, 5),
arrowprops=dict(arrowstyle='->', color='blue', lw=2.5))
ax.annotate('', xy=(2, 5), xytext=(5, 5),
arrowprops=dict(arrowstyle='->', color='red', lw=2.5))
ax.text(7, 6, 'F1 = 40N →', fontsize=10, color='blue')
ax.text(1, 6, '← F2 = 25N', fontsize=10, color='red')
ax.text(5, 3, 'Resultant = F1 - F2 = 15N →', ha='center', fontsize=10, color='purple')
ax.text(5, 2, 'Forces act on same line', ha='center', fontsize=9, style='italic')
ax.text(0.5, 9, 'Types of Linear Force System:', fontsize=9, fontweight='bold')
ax.text(0.5, 8.2, '• Concurrent: meet at a point', fontsize=9)
ax.text(0.5, 7.5, '• Collinear: same line of action', fontsize=9)
ax.text(0.5, 6.8, '• Parallel: different lines, same direction', fontsize=9)
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 10)
ax.axis('off')
ax.set_title("Parallel Force System\n(Body weight distribution)", fontsize=10, fontweight='bold')
# Beam
ax.add_patch(patches.Rectangle((1, 5), 8, 0.4, facecolor='peru', edgecolor='black'))
# Forces down
for x, f, c in [(2, '300N', 'blue'), (5, '200N', 'green'), (8, '250N', 'red')]:
ax.annotate('', xy=(x, 4.5), xytext=(x, 5),
arrowprops=dict(arrowstyle='->', color=c, lw=2))
ax.text(x, 4.0, f, ha='center', color=c, fontsize=9)
# Reaction up
ax.annotate('', xy=(4.5, 6.5), xytext=(4.5, 5.5),
arrowprops=dict(arrowstyle='->', color='black', lw=3))
ax.text(4.5, 6.8, 'R = 750N ↑', ha='center', fontsize=10, fontweight='bold')
ax.text(5, 2.5, 'ΣF = 0 (Equilibrium)', ha='center', fontsize=11, fontweight='bold',
bbox=dict(facecolor='lightyellow', edgecolor='orange'))
ax.text(5, 1.5, 'Resultant = algebraic sum of all forces', ha='center', fontsize=9)
plt.tight_layout()
return save_fig("linear_force")
def draw_connective_tissue():
fig, axes = plt.subplots(1, 2, figsize=(11, 6))
fig.suptitle("Composition of Connective Tissue", fontsize=14, fontweight='bold')
ax = axes[0]
ax.set_xlim(0, 10); ax.set_ylim(0, 10)
ax.axis('off')
ax.set_title("Cell Components", fontsize=11, fontweight='bold')
cells = [("Fibroblasts", "Produce collagen, elastin,\nproteoglycans", '#AED6F1'),
("Chondrocytes", "Found in cartilage,\nmaintain ECM", '#A9DFBF'),
("Osteoblasts/\nOsteoclasts", "Bone formation\nand resorption", '#FAD7A0'),
("Mast Cells", "Inflammatory response,\nhistamine release", '#F1948A'),
("Macrophages", "Phagocytosis,\ntissue remodeling", '#D7BDE2')]
for i, (name, desc, clr) in enumerate(cells):
y = 8.5 - i * 1.7
ax.add_patch(FancyBboxPatch((0.3, y-0.6), 9.4, 1.3,
boxstyle="round,pad=0.15",
facecolor=clr, edgecolor='gray', alpha=0.8))
ax.text(1.5, y, name, fontsize=9, fontweight='bold', va='center')
ax.text(5.5, y, desc, fontsize=8.5, va='center')
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 10)
ax.axis('off')
ax.set_title("Extracellular Matrix (ECM)", fontsize=11, fontweight='bold')
# Pie chart style breakdown
categories = ['Collagen\n(Types I-XII)', 'Elastin\nFibers', 'Proteoglycans\n& GAGs',
'Fibronectin\n& Laminin', 'Water\n(60-70%)']
colors_p = ['#5DADE2', '#58D68D', '#F4D03F', '#E59866', '#85C1E9']
wedges, texts = plt.pie([35, 15, 20, 10, 20], labels=categories,
colors=colors_p, startangle=90,
wedgeprops=dict(width=0.6))
plt.axis('equal')
ax.text(5, 0.5, "Key: Collagen provides tensile strength\nElastin provides elasticity\nGAGs provide compressive resistance",
ha='center', fontsize=8.5, va='center',
bbox=dict(facecolor='lightyellow', edgecolor='orange', boxstyle='round'))
plt.tight_layout()
return save_fig("connective_tissue")
def draw_load_deformation():
fig, axes = plt.subplots(1, 2, figsize=(11, 5))
fig.suptitle("Load-Deformation Curve", fontsize=14, fontweight='bold')
ax = axes[0]
x = np.array([0, 0.5, 1.5, 2.5, 3.2, 3.8, 4.5])
y = np.array([0, 0.2, 2, 5, 7, 7.5, 5])
ax.plot(x, y, 'b-', linewidth=3)
ax.set_xlabel("Deformation (mm)", fontsize=10)
ax.set_ylabel("Load (N)", fontsize=10)
ax.set_title("Typical Load-Deformation Curve", fontsize=10, fontweight='bold')
ax.fill_between(x[:4], y[:4], alpha=0.2, color='green', label='Elastic Zone')
ax.fill_between(x[3:6], y[3:6], alpha=0.2, color='orange', label='Plastic Zone')
ax.axvline(x=1.5, color='gray', linestyle='--', linewidth=1.5)
ax.axvline(x=3.2, color='red', linestyle='--', linewidth=1.5)
ax.text(0.2, 4, 'Toe\nRegion', fontsize=8, color='purple')
ax.text(1.6, 6, 'Elastic\nRegion', fontsize=8, color='green')
ax.text(3.3, 6.5, 'Yield\nPoint', fontsize=8, color='red')
ax.text(3.8, 3, 'Failure\nZone', fontsize=8, color='orange')
ax.text(0.1, 0.5, 'Toe region:\nCrimp of\ncollagen', fontsize=7.5, color='purple',
bbox=dict(facecolor='lavender'))
ax.legend(fontsize=8)
ax.set_ylim(0, 9)
ax.grid(True, alpha=0.3)
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 10)
ax.axis('off')
ax.set_title("Key Parameters", fontsize=10, fontweight='bold')
params = [
("Stiffness", "Slope of linear region\n(Load / Deformation)", '#AED6F1'),
("Elastic Limit", "Max load without permanent\ndeformation", '#A9DFBF'),
("Yield Point", "Onset of plastic (permanent)\ndeformation", '#FAD7A0'),
("Ultimate Load", "Maximum load before failure", '#F1948A'),
("Energy Stored", "Area under elastic region\n(Strain energy)", '#D7BDE2'),
("Hysteresis", "Energy lost during\nloading-unloading cycle", '#FDEBD0'),
]
for i, (name, desc, clr) in enumerate(params):
y_pos = 9 - i * 1.4
ax.add_patch(FancyBboxPatch((0.2, y_pos - 0.55), 9.5, 1.1,
boxstyle="round,pad=0.1", facecolor=clr, edgecolor='gray'))
ax.text(0.5, y_pos, f"• {name}:", fontsize=9, fontweight='bold', va='center')
ax.text(4.0, y_pos, desc, fontsize=8.5, va='center')
plt.tight_layout()
return save_fig("load_deformation")
def draw_pelvic_tilt():
fig, axes = plt.subplots(1, 2, figsize=(10, 6))
fig.suptitle("Pelvic Tilt", fontsize=14, fontweight='bold')
for ax, title, spine_curve, color in [
(axes[0], "Anterior Pelvic Tilt", 'lordosis', 'tomato'),
(axes[1], "Posterior Pelvic Tilt", 'kyphosis', 'steelblue')
]:
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title(title, fontsize=11, fontweight='bold', color=color)
# Draw simplified pelvis
pelvis_x = [3, 4, 5, 6, 7, 7.5, 7, 5, 3, 2.5, 3]
pelvis_y = [7, 6, 5.5, 6, 7, 8.5, 9.5, 10, 9.5, 8.5, 7]
if title.startswith("Anterior"):
# tilt forward: ASIS down, PSIS up
pelvis_y = [y - (x - 5) * 0.3 for x, y in zip(pelvis_x, pelvis_y)]
else:
pelvis_y = [y + (x - 5) * 0.3 for x, y in zip(pelvis_x, pelvis_y)]
ax.plot(pelvis_x, pelvis_y, color=color, linewidth=3)
ax.fill(pelvis_x, pelvis_y, alpha=0.15, color=color)
if title.startswith("Anterior"):
ax.text(5, 3.5, "↑ Lumbar Lordosis\n↓ Hip Flexors tight\n↓ Hamstrings lengthened\n↑ ASIS lower than PSIS",
ha='center', fontsize=9, bbox=dict(facecolor='lightyellow', edgecolor=color))
ax.text(7.5, 7, 'PSIS\n(up)', fontsize=8, color='red')
ax.text(2.5, 5.5, 'ASIS\n(down)', fontsize=8, color='red')
else:
ax.text(5, 3.5, "↓ Lumbar Lordosis\n↑ Hamstrings tight\n↑ Abdominals tight\n↑ ASIS higher than PSIS",
ha='center', fontsize=9, bbox=dict(facecolor='lightcyan', edgecolor=color))
ax.text(7.5, 8, 'PSIS\n(down)', fontsize=8, color='blue')
ax.text(2.5, 6, 'ASIS\n(up)', fontsize=8, color='blue')
ax.text(5, 0.8, "Normal: ASIS = PSIS level\nNormal angle: 0-5° ♀, 0-4° ♂",
ha='center', fontsize=8.5, color='gray', style='italic')
plt.tight_layout()
return save_fig("pelvic_tilt")
def draw_scoliosis():
fig, axes = plt.subplots(1, 2, figsize=(10, 7))
fig.suptitle("Scoliosis", fontsize=14, fontweight='bold')
ax = axes[0]
ax.set_xlim(0, 10); ax.set_ylim(0, 15)
ax.axis('off')
ax.set_title("Types of Scoliosis\n(Posterior View)", fontsize=10, fontweight='bold')
# Structural scoliosis curve - S-shaped spine
t = np.linspace(0, 10, 100)
x = 5 + 1.5 * np.sin(t * 0.7)
y = t * 1.3 + 0.5
ax.plot(x, y, 'b-', linewidth=4)
ax.text(7.5, 9, 'Compensatory\ncurve', fontsize=8, color='blue')
ax.text(1.5, 5, 'Primary\ncurve', fontsize=8, color='blue')
ax.annotate('', xy=(7, 7), xytext=(5.5, 7),
arrowprops=dict(arrowstyle='<->', color='red', lw=2))
ax.text(8, 7, 'Cobb\nAngle', fontsize=8, color='red')
types_text = "Types:\n• Idiopathic (80%) - most common\n• Congenital\n• Neuromuscular\n• Degenerative"
ax.text(0.5, 13.5, types_text, fontsize=9, va='top',
bbox=dict(facecolor='lightyellow', edgecolor='orange', boxstyle='round'))
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Cobb Angle Measurement\n& Classification", fontsize=10, fontweight='bold')
# Simple Cobb angle diagram
ax.plot([2, 8], [9, 9], 'b--', linewidth=1.5) # upper end vertebra line
ax.plot([2.5, 7.5], [3, 3], 'b--', linewidth=1.5) # lower end vertebra line
curve_x = np.array([5, 4, 3, 4, 5, 6, 7, 6, 5])
curve_y = np.array([9, 8, 6.5, 5, 4.5, 5, 6.5, 8, 9])
ax.plot(curve_x, curve_y, 'b-', linewidth=4)
arc = Arc((5, 3), 4, 4, angle=0, theta1=20, theta2=160, color='red', linewidth=2)
ax.add_patch(arc)
ax.text(5, 1.5, 'Cobb Angle (α)', ha='center', fontsize=10, color='red', fontweight='bold')
classification = [
("< 10°", "Normal variation"),
("10-25°", "Mild: observation"),
("25-40°", "Moderate: bracing"),
("40-50°", "Borderline: surgery"),
("> 50°", "Severe: surgery indicated"),
]
for i, (angle, mgmt) in enumerate(classification):
clr = ['green', 'yellowgreen', 'orange', 'tomato', 'red'][i]
ax.add_patch(FancyBboxPatch((0.2, 10.2 - i*1.8), 9.5, 1.5,
boxstyle="round,pad=0.1", facecolor=clr, alpha=0.2, edgecolor=clr))
ax.text(1.2, 11 - i*1.8, angle, fontsize=9, fontweight='bold', va='center', color=clr)
ax.text(4.5, 11 - i*1.8, mgmt, fontsize=9, va='center')
plt.tight_layout()
return save_fig("scoliosis")
def draw_grip_grasp():
fig, axes = plt.subplots(1, 2, figsize=(11, 6))
fig.suptitle("Grip and Grasp / Power Grip", fontsize=14, fontweight='bold')
ax = axes[0]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Types of Prehension", fontsize=11, fontweight='bold')
grips = [
("POWER GRIP", "Cylindrical / Spherical / Hook\nFingers flex around object\nAll digits + palm\nEx: hammer, bar", '#AED6F1'),
("PRECISION GRIP", "Pinch grips: tip, lateral, palmar\nThumb opposes fingers\nEx: holding a pen, key", '#A9DFBF'),
("LATERAL PINCH\n(Key Pinch)", "Thumb pulp vs. lateral\nindex finger\nStrong, stable grip\nIPJ flexion of thumb", '#FAD7A0'),
]
for i, (name, desc, clr) in enumerate(grips):
y = 10.5 - i * 3.5
ax.add_patch(FancyBboxPatch((0.3, y - 1.2), 9.4, 3.0,
boxstyle="round,pad=0.2", facecolor=clr, edgecolor='gray', alpha=0.7))
ax.text(5, y + 1.2, name, ha='center', fontsize=10, fontweight='bold', va='center')
ax.text(5, y - 0.3, desc, ha='center', fontsize=8.5, va='center')
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Biomechanics of Power Grip", fontsize=11, fontweight='bold')
ax.text(5, 11.3, "Muscles Involved:", ha='center', fontsize=10, fontweight='bold')
muscles = [
("Extrinsic Flexors", "FDS, FDP - main grip force"),
("Intrinsics", "Lumbricals, interossei - MCP flexion"),
("Thenar", "Opposes thumb for stability"),
("Hypothenar", "Abducts little finger"),
("Wrist Extensors", "Stabilize wrist during grip"),
]
for i, (m, d) in enumerate(muscles):
ax.text(0.5, 10 - i*1.5, f"• {m}:", fontsize=9, fontweight='bold')
ax.text(3.5, 10 - i*1.5, d, fontsize=9)
ax.add_patch(FancyBboxPatch((0.3, 1.5), 9.4, 2.5, boxstyle="round,pad=0.2",
facecolor='lightyellow', edgecolor='orange'))
ax.text(5, 3.5, "Force Analysis:", ha='center', fontsize=9, fontweight='bold')
ax.text(5, 2.8, "Max grip force = 400-500 N in adult males", ha='center', fontsize=9)
ax.text(5, 2.2, "Wrist in 30° ext = strongest position", ha='center', fontsize=9)
ax.text(5, 1.7, "Wrist flexion reduces grip by 25%", ha='center', fontsize=9)
plt.tight_layout()
return save_fig("grip_grasp")
def draw_active_passive_insufficiency():
fig, axes = plt.subplots(1, 2, figsize=(11, 6))
fig.suptitle("Active & Passive Insufficiency", fontsize=14, fontweight='bold')
ax = axes[0]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Active Insufficiency", fontsize=11, fontweight='bold', color='red')
ax.add_patch(FancyBboxPatch((0.3, 8.5), 9.4, 3, boxstyle="round,pad=0.2",
facecolor='#FADBD8', edgecolor='red'))
ax.text(5, 11, "ACTIVE INSUFFICIENCY", ha='center', fontsize=10, fontweight='bold', color='red')
ax.text(5, 10.2, "Two-joint muscle cannot generate", ha='center', fontsize=9)
ax.text(5, 9.6, "full force when shortened at BOTH joints", ha='center', fontsize=9)
ax.text(5, 9.0, "simultaneously", ha='center', fontsize=9)
ax.text(0.5, 7.8, "Example:", fontsize=9, fontweight='bold')
ax.text(0.5, 7.2, "Rectus Femoris: extends knee AND flexes hip", fontsize=9)
ax.text(0.5, 6.6, "→ If hip flexed + knee extended = weak", fontsize=9, color='red')
ax.text(0.5, 5.5, "Hamstrings: flex knee AND extend hip", fontsize=9)
ax.text(0.5, 4.9, "→ Full hip extension + knee flexion = weak", fontsize=9, color='red')
ax.add_patch(FancyBboxPatch((0.3, 3.5), 9.4, 1.0, boxstyle="round,pad=0.2",
facecolor='lightyellow', edgecolor='orange'))
ax.text(5, 4.0, "Occurs in: Two-joint AGONIST muscle", ha='center', fontsize=9, fontweight='bold')
ax.text(5, 2.5, "Length-Tension Curve:", ha='center', fontsize=9, fontweight='bold')
x_len = np.linspace(0.5, 9.5, 50)
y_force = 1.5 * np.exp(-0.5 * ((x_len - 5) ** 2) / 4) + 0.2
ax.plot(x_len, y_force, 'r-', linewidth=2.5)
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.annotate('Optimal length\n(max force)', xy=(5, 1.85), fontsize=7.5, ha='center',
xytext=(5, 1.1), arrowprops=dict(arrowstyle='->', color='red'))
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Passive Insufficiency", fontsize=11, fontweight='bold', color='blue')
ax.add_patch(FancyBboxPatch((0.3, 8.5), 9.4, 3, boxstyle="round,pad=0.2",
facecolor='#D6EAF8', edgecolor='blue'))
ax.text(5, 11, "PASSIVE INSUFFICIENCY", ha='center', fontsize=10, fontweight='bold', color='blue')
ax.text(5, 10.2, "Two-joint muscle is stretched to a point", ha='center', fontsize=9)
ax.text(5, 9.6, "where it LIMITS full ROM at BOTH joints", ha='center', fontsize=9)
ax.text(5, 9.0, "simultaneously (reaches max length)", ha='center', fontsize=9)
ax.text(0.5, 7.8, "Example:", fontsize=9, fontweight='bold')
ax.text(0.5, 7.2, "Hamstrings: cannot fully extend knee", fontsize=9)
ax.text(0.5, 6.6, "when hip is also fully flexed", fontsize=9, color='blue')
ax.text(0.5, 5.8, "Rectus Femoris: limits full knee flexion", fontsize=9)
ax.text(0.5, 5.2, "when hip is also fully extended", fontsize=9, color='blue')
ax.add_patch(FancyBboxPatch((0.3, 3.8), 9.4, 1.0, boxstyle="round,pad=0.2",
facecolor='lightyellow', edgecolor='orange'))
ax.text(5, 4.3, "Occurs in: Two-joint ANTAGONIST muscle", ha='center', fontsize=9, fontweight='bold')
ax.text(0.5, 3.0, "Clinical Note:", fontsize=9, fontweight='bold')
ax.text(0.5, 2.4, "Straight Leg Raise test - hamstring passive", fontsize=9)
ax.text(0.5, 1.8, "insufficiency limits hip flexion with knee ext.", fontsize=9)
ax.text(0.5, 1.2, "Finger extension = wrist flexion limited by", fontsize=9)
ax.text(0.5, 0.6, "passive insufficiency of extrinsic extensors", fontsize=9)
plt.tight_layout()
return save_fig("active_passive")
def draw_hip_angles():
fig, axes = plt.subplots(1, 2, figsize=(11, 6))
fig.suptitle("Angles of the Hip Joint", fontsize=14, fontweight='bold')
ax = axes[0]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Angle of Inclination\n(Neck-Shaft Angle)", fontsize=10, fontweight='bold')
# Femoral neck & shaft
# Shaft
ax.plot([5, 5], [0.5, 5], 'peru', linewidth=10)
# Neck at angle
neck_angle = 125 # degrees from shaft (horizontal)
neck_rad = np.radians(180 - neck_angle)
nx = 5 + 3 * np.cos(neck_rad)
ny = 5 + 3 * np.sin(neck_rad)
ax.plot([5, nx], [5, ny], 'peru', linewidth=8)
ax.plot(nx, ny, 'o', color='peru', markersize=20) # femoral head
# Angle arc
arc = Arc((5, 5), 2, 2, angle=0, theta1=90, theta2=180 - neck_angle + 90, color='red', linewidth=2)
ax.add_patch(arc)
ax.text(3.5, 6.2, f'125°\n(Normal)', fontsize=10, color='red', fontweight='bold')
# Shaft vertical line
ax.plot([5, 5], [5, 8], 'gray', linewidth=1, linestyle='--')
normals = [("Normal adult", "120-135°", "green"),
("Coxa Valga", "> 135°", "red"),
("Coxa Vara", "< 120°", "blue")]
for i, (n, v, c) in enumerate(normals):
ax.add_patch(FancyBboxPatch((0.3, 3.5 - i*1.3), 4, 1.1, boxstyle="round,pad=0.1",
facecolor=c, alpha=0.15, edgecolor=c))
ax.text(2.3, 4.15 - i*1.3, f"{n}: {v}", ha='center', fontsize=9, va='center', color=c)
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Angle of Anteversion\n(Torsion Angle)", fontsize=10, fontweight='bold')
# Top view of femoral neck vs femoral condyles
ax.text(5, 11.2, "Top (Axial) View", ha='center', fontsize=9, style='italic')
# Condyles axis
ax.plot([1.5, 8.5], [5, 5], 'b-', linewidth=4)
ax.text(4, 3.8, 'Transcondylar axis', ha='center', fontsize=8, color='blue')
# Femoral neck axis
angle_ant = 15
nx1 = 5 - 3 * np.cos(np.radians(angle_ant))
ny1 = 5 - 3 * np.sin(np.radians(angle_ant))
nx2 = 5 + 3 * np.cos(np.radians(angle_ant))
ny2 = 5 + 3 * np.sin(np.radians(angle_ant))
ax.plot([nx1, nx2], [ny1, ny2], 'r-', linewidth=4)
ax.text(7.5, 7, 'Femoral neck\naxis', ha='center', fontsize=8, color='red')
arc2 = Arc((5, 5), 3, 3, angle=0, theta1=0, theta2=angle_ant, color='purple', linewidth=2)
ax.add_patch(arc2)
ax.text(6.5, 5.8, f'{angle_ant}°', fontsize=10, color='purple', fontweight='bold')
normals2 = [("Newborn", "30-40°"),
("Adult normal", "10-15°"),
("Anteversion > 15°", "Toe-in gait"),
("Retroversion < 10°", "Toe-out gait")]
for i, (n, v) in enumerate(normals2):
ax.text(0.5, 9.5 - i*1.3, f"• {n}: {v}", fontsize=9)
ax.text(0.5, 4, "Also: Angle of Declination\n(Condylar twist angle ~5-7°)", fontsize=9,
bbox=dict(facecolor='lightyellow', edgecolor='orange'))
plt.tight_layout()
return save_fig("hip_angles")
def draw_coracoacromial_arch():
fig, axes = plt.subplots(1, 2, figsize=(11, 6))
fig.suptitle("Suprhumeral / Coracoacromial Arch", fontsize=14, fontweight='bold')
ax = axes[0]
ax.set_xlim(0, 10); ax.set_ylim(0, 10)
ax.axis('off')
ax.set_title("Anatomy of Coracoacromial Arch", fontsize=10, fontweight='bold')
# Acromion
ax.add_patch(FancyBboxPatch((6.5, 7), 3, 1.5, boxstyle="round,pad=0.1",
facecolor='bisque', edgecolor='brown', linewidth=2))
ax.text(8, 7.75, 'ACROMION', ha='center', fontsize=9, fontweight='bold')
# Coracoid process
ax.add_patch(FancyBboxPatch((0.5, 6.5), 2.5, 1.5, boxstyle="round,pad=0.1",
facecolor='bisque', edgecolor='brown', linewidth=2))
ax.text(1.75, 7.25, 'CORACOID\nPROCESS', ha='center', fontsize=8, fontweight='bold')
# Coracoacromial ligament
ax.plot([3, 6.5], [7.25, 7.5], 'g-', linewidth=5)
ax.text(4.75, 8, 'Coracoacromial\nLigament', ha='center', fontsize=8.5, color='green', fontweight='bold')
# Arch space
ax.add_patch(patches.Arc((4.5, 5.5), 6, 3, angle=0, theta1=0, theta2=180,
color='purple', linewidth=2, linestyle='--'))
ax.text(4.5, 6.8, 'SUBACROMIAL SPACE\n(9-10 mm normal)', ha='center', fontsize=8.5, color='purple')
# Contents
ax.text(0.5, 5.0, "Contents of Subacromial Space:", fontsize=9, fontweight='bold')
contents = ["Supraspinatus tendon", "Subdeltoid/Subacromial bursa",
"Long head of biceps", "Superior capsule of GHJ"]
for i, c in enumerate(contents):
ax.text(0.5, 4.3 - i*0.8, f"• {c}", fontsize=8.5)
# Humerus
ax.add_patch(plt.Circle((4.5, 3.5), 2, facecolor='bisque', edgecolor='brown', linewidth=2))
ax.text(4.5, 3.5, 'Humeral\nHead', ha='center', va='center', fontsize=9)
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 10)
ax.axis('off')
ax.set_title("Clinical Significance", fontsize=10, fontweight='bold')
conditions = [
("Subacromial Impingement", "Neer & Hawkins tests +ve\nPainful arc 60-120°\nSupraspinatus compressed", '#FADBD8'),
("Outlet vs Non-outlet", "Outlet: structural narrowing\nNon-outlet: dynamic\nPositional impingement", '#D6EAF8'),
("Acromial Types\n(Bigliani)", "Type I: Flat (low risk)\nType II: Curved (mod risk)\nType III: Hooked (high risk)", '#D5F5E3'),
("Management", "Physio: strengthening RC\nCorticosteroid injection\nAcromioplasty surgery", '#FEF9E7'),
]
for i, (name, desc, clr) in enumerate(conditions):
y = 9.5 - i * 2.2
ax.add_patch(FancyBboxPatch((0.2, y - 1.6), 9.5, 2.0, boxstyle="round,pad=0.2",
facecolor=clr, edgecolor='gray'))
ax.text(0.5, y, name, fontsize=9, fontweight='bold', va='center')
ax.text(4.5, y - 0.5, desc, fontsize=8.5, va='center')
plt.tight_layout()
return save_fig("coracoacromial")
def draw_ideal_posture():
fig, axes = plt.subplots(1, 2, figsize=(10, 7))
fig.suptitle("Ideal / Optimal Posture", fontsize=14, fontweight='bold')
ax = axes[0]
ax.set_xlim(0, 10); ax.set_ylim(0, 15)
ax.axis('off')
ax.set_title("Plumb Line - Lateral View", fontsize=10, fontweight='bold')
# Plumb line
ax.plot([5, 5], [0, 14], 'r--', linewidth=2, alpha=0.7)
ax.text(5.5, 14, 'Plumb Line', fontsize=8.5, color='red')
# Body segments
segments = [
(5, 13, "EAM (Ear)\nLobe", 'blue'),
(5, 10.5, "Shoulder\nacromion", 'blue'),
(5, 8, "Greater\ntrochanter", 'blue'),
(5, 5, "Ant. to lateral\nmalleolus", 'blue'),
(5, 2, "Lat. midfoot", 'blue'),
]
for x, y, label, c in segments:
ax.plot(x, y, 'o', color=c, markersize=10, zorder=5)
ax.text(6.2, y, label, fontsize=8, va='center', color=c)
# Connect dots
xs = [s[0] for s in segments]
ys = [s[1] for s in segments]
ax.plot(xs, ys, 'b-', linewidth=2.5, alpha=0.6)
ax.text(0.5, 14, "Curves:", fontsize=9, fontweight='bold')
ax.text(0.5, 13.3, "Cervical: Lordosis", fontsize=8.5)
ax.text(0.5, 12.6, "Thoracic: Kyphosis", fontsize=8.5)
ax.text(0.5, 11.9, "Lumbar: Lordosis", fontsize=8.5)
ax.text(0.5, 11.2, "Sacral: Kyphosis", fontsize=8.5)
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Ideal Posture Criteria\n(Kendall's Definition)", fontsize=10, fontweight='bold')
criteria = [
("Head", "Neutral, chin tucked,\nearlobes over shoulders"),
("Cervical spine", "Normal lordosis maintained"),
("Shoulders", "Level, retracted, not elevated"),
("Thoracic spine", "Normal kyphosis, no hyperkyphosis"),
("Lumbar spine", "Normal lordosis, not flattened"),
("Pelvis", "Neutral tilt, ASIS = PSIS level"),
("Knees", "Neutral, no valgus/varus"),
("Feet", "Parallel or slight toe-out (8-10°)"),
]
for i, (seg, desc) in enumerate(criteria):
clr = ['#AED6F1', '#A9DFBF', '#FAD7A0', '#F1948A', '#D7BDE2',
'#FDEBD0', '#D5F5E3', '#FADBD8'][i]
ax.add_patch(FancyBboxPatch((0.2, 10.5 - i*1.3), 9.5, 1.1,
boxstyle="round,pad=0.1", facecolor=clr, edgecolor='gray'))
ax.text(0.5, 11.05 - i*1.3, f"{seg}:", fontsize=9, fontweight='bold', va='center')
ax.text(2.5, 11.05 - i*1.3, desc, fontsize=8.5, va='center')
plt.tight_layout()
return save_fig("ideal_posture")
def draw_pivot_joint():
fig, axes = plt.subplots(1, 2, figsize=(10, 6))
fig.suptitle("Pivot Joint", fontsize=14, fontweight='bold')
ax = axes[0]
ax.set_xlim(0, 10); ax.set_ylim(0, 10)
ax.axis('off')
ax.set_title("Types of Pivot Joints\n(Trochoid Joints)", fontsize=10, fontweight='bold')
# Diagram 1: proximal RUJ
ax.add_patch(plt.Circle((3, 7), 1.2, facecolor='bisque', edgecolor='brown', linewidth=2.5))
ax.text(3, 9.5, 'Proximal RUJ', ha='center', fontsize=9, fontweight='bold')
ax.text(3, 8.8, 'Head of radius in radial notch', ha='center', fontsize=8)
ax.add_patch(patches.Arc((3, 7), 3, 3, angle=0, theta1=0, theta2=270, color='red', linewidth=2))
ax.annotate('', xy=(4.4, 7.3), xytext=(4, 5.5),
arrowprops=dict(arrowstyle='->', color='red', lw=1.5))
ax.text(4.7, 5, 'Annular\nligament', fontsize=8, color='red')
ax.add_patch(plt.Circle((7, 7), 1.2, facecolor='bisque', edgecolor='brown', linewidth=2.5))
ax.text(7, 9.5, 'Atlas-Axis (C1-C2)', ha='center', fontsize=9, fontweight='bold')
ax.text(7, 8.8, 'Dens of axis in atlas', ha='center', fontsize=8)
ax.add_patch(patches.Arc((7, 7), 3, 3, angle=0, theta1=0, theta2=270, color='blue', linewidth=2))
ax.annotate('', xy=(8.4, 7.3), xytext=(8, 5.5),
arrowprops=dict(arrowstyle='->', color='blue', lw=1.5))
ax.text(8.5, 5, 'Transverse\nligament', fontsize=8, color='blue')
ax.text(5, 3.5, "1 Degree of Freedom\nRotation only (uniaxial)", ha='center',
fontsize=10, fontweight='bold', color='purple',
bbox=dict(facecolor='lavender', edgecolor='purple'))
ax.text(5, 2.2, "Examples:\n• Proximal RUJ (forearm pronation/supination)\n• Distal RUJ\n• Atlanto-axial joint (head rotation)",
ha='center', fontsize=8.5, va='center',
bbox=dict(facecolor='lightyellow', edgecolor='orange'))
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 10)
ax.axis('off')
ax.set_title("Joint Classification Summary", fontsize=10, fontweight='bold')
joints = [
("Uniaxial", "Hinge (Ginglymus)", "Elbow, IP joints", '#AED6F1'),
("Uniaxial", "Pivot (Trochoid)", "RUJ, Atlanto-axial", '#AED6F1'),
("Biaxial", "Condyloid", "MCP, Radiocarpal", '#A9DFBF'),
("Biaxial", "Saddle (Sellar)", "1st CMC (thumb)", '#A9DFBF'),
("Multiaxial", "Ball & Socket", "Hip, Shoulder", '#FAD7A0'),
("Multiaxial", "Plane (Gliding)", "Intervertebral, AC", '#FAD7A0'),
]
for i, (dof, jtype, example, clr) in enumerate(joints):
y = 9.5 - i * 1.4
ax.add_patch(FancyBboxPatch((0.2, y - 0.55), 9.5, 1.1,
boxstyle="round,pad=0.1", facecolor=clr, edgecolor='gray'))
ax.text(1.5, y, dof, fontsize=8.5, fontweight='bold', va='center')
ax.text(3.8, y, jtype, fontsize=8.5, va='center')
ax.text(7.2, y, example, fontsize=8, va='center', color='gray')
plt.tight_layout()
return save_fig("pivot_joint")
def draw_anatomical_pulley():
fig, axes = plt.subplots(1, 2, figsize=(11, 6))
fig.suptitle("Anatomical Pulleys / Patella as Pulley", fontsize=14, fontweight='bold')
ax = axes[0]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Mechanical Pulley Principle", fontsize=10, fontweight='bold')
# Pulley wheel
ax.add_patch(plt.Circle((5, 8), 1.5, facecolor='lightgray', edgecolor='black', linewidth=2.5))
ax.text(5, 8, 'PULLEY', ha='center', va='center', fontsize=9, fontweight='bold')
# Rope going over
ax.plot([2, 3.6], [9.3, 9.3], 'brown', linewidth=3)
ax.plot([6.4, 8], [9.3, 9.3], 'brown', linewidth=3)
# Force arrows
ax.annotate('', xy=(2, 9.3), xytext=(2, 7),
arrowprops=dict(arrowstyle='->', color='red', lw=2.5))
ax.text(0.5, 7.5, 'Muscle\nForce', fontsize=9, color='red')
ax.annotate('', xy=(8, 7), xytext=(8, 9.3),
arrowprops=dict(arrowstyle='->', color='blue', lw=2.5))
ax.text(8.3, 7.5, 'Output\nForce', fontsize=9, color='blue')
ax.text(5, 5.5, "Functions of Pulley:", ha='center', fontsize=9, fontweight='bold')
funcs = ["1. Changes direction of force",
"2. Increases mechanical advantage",
"3. Increases moment arm of muscle",
"4. Improves efficiency of force application"]
for i, f in enumerate(funcs):
ax.text(0.5, 4.5 - i*1.0, f, fontsize=9)
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Patella as Anatomical Pulley", fontsize=10, fontweight='bold')
# Femur
ax.add_patch(FancyBboxPatch((3.5, 7.5), 3, 4, boxstyle="round,pad=0.1",
facecolor='bisque', edgecolor='brown', linewidth=2))
ax.text(5, 10.5, 'FEMUR', ha='center', fontsize=9, fontweight='bold')
# Patella
ax.add_patch(plt.Circle((5, 6.5), 1, facecolor='lightyellow', edgecolor='darkgoldenrod', linewidth=2.5))
ax.text(5, 6.5, 'Patella', ha='center', va='center', fontsize=9, fontweight='bold')
# Tibia
ax.add_patch(FancyBboxPatch((3.5, 2), 3, 3.5, boxstyle="round,pad=0.1",
facecolor='bisque', edgecolor='brown', linewidth=2))
ax.text(5, 3.5, 'TIBIA', ha='center', fontsize=9, fontweight='bold')
# Quadriceps tendon
ax.plot([5, 5], [7.5, 7.5], 'r-', linewidth=4)
ax.annotate('', xy=(5, 9.5), xytext=(5, 7.5),
arrowprops=dict(arrowstyle='->', color='red', lw=2))
ax.text(6.2, 9, 'Quad\nTendon', fontsize=8, color='red')
# Patellar ligament
ax.plot([5, 5], [5.5, 2], 'b-', linewidth=4)
ax.text(6.2, 3.5, 'Patellar\nLigament', fontsize=8, color='blue')
ax.text(5, 1.2, "Patella increases\nmoment arm of quad by 50%\n→ 33% less force needed",
ha='center', fontsize=9,
bbox=dict(facecolor='lightgreen', edgecolor='green', boxstyle='round'))
plt.tight_layout()
return save_fig("anatomical_pulley")
def draw_femur_angles():
fig, axes = plt.subplots(1, 2, figsize=(11, 6))
fig.suptitle("Importance of Angles/Curves in Femur", fontsize=14, fontweight='bold')
ax = axes[0]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Femoral Angles & Their Importance", fontsize=10, fontweight='bold')
params = [
("Angle of Inclination\n(Neck-Shaft Angle)", "125° (normal)\nCoxa Valga >135°, Vara <120°\n→ Affects abductor moment arm\n→ Influences hip stability", '#AED6F1'),
("Angle of Anteversion\n(Torsion)", "12-15° (adult)\nExcessive: toe-in gait\nDecreased: toe-out gait\n→ Affects weight bearing axis", '#A9DFBF'),
("Shaft Bow\n(Anterior curvature)", "Distributes compressive\nforces along shaft\nReduces stress concentration\n→ Resistance to fracture", '#FAD7A0'),
("Condylar Angle\n(Obliquity)", "~9° from vertical\nMaintains knee close to\nmidline during gait\n→ Essential for bipedal walking", '#F1948A'),
]
for i, (name, desc, clr) in enumerate(params):
y = 11 - i * 2.5
ax.add_patch(FancyBboxPatch((0.2, y - 1.8), 9.5, 2.3, boxstyle="round,pad=0.2",
facecolor=clr, edgecolor='gray', alpha=0.8))
ax.text(0.5, y + 0.1, name, fontsize=9, fontweight='bold', va='center')
ax.text(0.5, y - 0.9, desc, fontsize=8, va='center')
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Femoral Shaft - Stress Analysis", fontsize=10, fontweight='bold')
# Simplified femur shape
femur_x = [4, 3.5, 3.7, 4.5, 5.5, 6.3, 6.5, 6, 4]
femur_y = [11, 9, 7, 5, 5, 7, 9, 11, 11]
ax.fill(femur_x, femur_y, alpha=0.3, color='bisque')
ax.plot(femur_x, femur_y, 'brown', linewidth=2.5)
# Compressive forces
ax.annotate('', xy=(4.5, 9.5), xytext=(4.5, 11),
arrowprops=dict(arrowstyle='->', color='red', lw=2))
ax.text(3, 10.5, 'Body\nWeight', fontsize=8, color='red')
ax.text(5, 2.5, "Wolff's Law:\nBone adapts to applied stresses\nTrabecular lines follow stress\nCancellous = compressive lines\nCortical = tensile lines",
ha='center', fontsize=8.5, va='center',
bbox=dict(facecolor='lightyellow', edgecolor='orange', boxstyle='round'))
ax.text(5, 7, "Medial side:\nCompressive\nstress", ha='center', fontsize=8, color='blue')
ax.text(5, 6, "Lateral side:\nTensile\nstress", ha='center', fontsize=8, color='red')
plt.tight_layout()
return save_fig("femur_angles")
def draw_extensor_mechanism():
fig, axes = plt.subplots(1, 2, figsize=(11, 6))
fig.suptitle("Extensor Mechanism / Expansion of Fingers & Wrist", fontsize=14, fontweight='bold')
ax = axes[0]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Extensor Mechanism of Hand", fontsize=10, fontweight='bold')
# Finger bones
for i, (x_start, label) in enumerate([(1, 'MCP'), (3.5, 'PIP'), (6.5, 'DIP')]):
ax.add_patch(FancyBboxPatch((x_start, 5.5), 2, 1.5, boxstyle="round,pad=0.1",
facecolor='bisque', edgecolor='brown', linewidth=2))
ax.text(x_start + 1, 6.25, label, ha='center', fontsize=9, fontweight='bold')
# Extensor digitorum
ax.plot([0, 8.5], [7.5, 7.5], 'r-', linewidth=3.5, label='ED tendon')
ax.text(4, 8.2, 'Extensor Digitorum', ha='center', fontsize=8.5, color='red')
# Central slip to PIP
ax.annotate('', xy=(4.5, 7.0), xytext=(4.5, 7.5),
arrowprops=dict(arrowstyle='->', color='darkred', lw=2))
ax.text(4.5, 6.7, 'Central slip\n→ PIP', ha='center', fontsize=8, color='darkred')
# Lateral bands
ax.plot([2, 7.5], [7.0, 7.0], 'b--', linewidth=2, label='Lateral bands')
ax.text(4.5, 7.15, 'Lateral bands → DIP', ha='center', fontsize=8, color='blue')
# Lumbricals/interossei
ax.annotate('', xy=(2, 7.0), xytext=(1.5, 5),
arrowprops=dict(arrowstyle='->', color='green', lw=2))
ax.text(0, 4.5, 'Lumbrical\n& Interossei\n(intrinsics)', fontsize=8, color='green')
ax.text(5, 3.5, "Extensor Hood / Dorsal Aponeurosis:\n• Complex fibrous expansion\n• Intrinsics contribute to lateral bands\n• Coordinates PIP & DIP extension\n• 'Intrinsic plus' = MCP flex + IP ext",
ha='center', fontsize=8.5, va='center',
bbox=dict(facecolor='lightyellow', edgecolor='orange', boxstyle='round'))
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Wrist Extensor Mechanism", fontsize=10, fontweight='bold')
compartments = [
("1st", "APL, EPB", "De Quervain's site"),
("2nd", "ECRL, ECRB", "Radial wrist extensors"),
("3rd", "EPL", "Wraps Lister's tubercle"),
("4th", "EDC, EIP", "Index + digit ext"),
("5th", "EDM", "Little finger ext"),
("6th", "ECU", "Ulnar wrist extensor"),
]
ax.text(5, 11.5, "6 Dorsal Compartments of Wrist", ha='center', fontsize=10, fontweight='bold')
colors_c = ['#AED6F1', '#A9DFBF', '#FAD7A0', '#F1948A', '#D7BDE2', '#FDEBD0']
for i, (comp, tendons, note) in enumerate(compartments):
y = 10 - i * 1.5
ax.add_patch(FancyBboxPatch((0.2, y - 0.55), 9.5, 1.1,
boxstyle="round,pad=0.1", facecolor=colors_c[i], edgecolor='gray'))
ax.text(0.5, y, f"Compartment {comp}:", fontsize=8.5, fontweight='bold', va='center')
ax.text(3.2, y, tendons, fontsize=8.5, va='center')
ax.text(6.5, y, note, fontsize=7.5, va='center', color='gray')
plt.tight_layout()
return save_fig("extensor_mechanism")
def draw_shoulder_stability():
fig, axes = plt.subplots(1, 2, figsize=(11, 6))
fig.suptitle("Shoulder Joint Stability / Static Stabilizers", fontsize=14, fontweight='bold')
ax = axes[0]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Static Stabilizers", fontsize=10, fontweight='bold')
stabilizers = [
("Glenoid Labrum", "Deepens glenoid by 50%\nProvides 26% of stability\nAnchors GHL", '#AED6F1'),
("GH Ligaments", "SGHL: prevents inf subluxation\nMGHL: ant stability mid-range\nIGHL: main stabilizer ABD", '#A9DFBF'),
("Coracohumeral\nLigament (CHL)", "Suspends humeral head\nPrevents inferior sublux\nBiceps groove roof", '#FAD7A0'),
("Negative\nIntra-articular Pressure", "Suction cup effect\nResists distraction force\n(capsular seal)", '#F1948A'),
("Glenohumeral\nCongruency", "Version angles\nGlenoid retroversion ~7°\nHumeral head: spherical", '#D7BDE2'),
]
for i, (name, desc, clr) in enumerate(stabilizers):
y = 11.2 - i * 2.0
ax.add_patch(FancyBboxPatch((0.2, y - 1.5), 9.5, 1.8, boxstyle="round,pad=0.2",
facecolor=clr, edgecolor='gray', alpha=0.8))
ax.text(0.5, y - 0.1, name, fontsize=9, fontweight='bold', va='center')
ax.text(3.8, y - 0.5, desc, fontsize=8, va='center')
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Dynamic Stabilizers\n(Rotator Cuff)", fontsize=10, fontweight='bold')
rc = [("Supraspinatus (S)", "Initiates abduction (0-30°)\nDepresses humeral head\nPrevents sup translation", 'green'),
("Infraspinatus (I)", "External rotation\nPost stability\nPrevents post. sublux", 'blue'),
("Teres Minor (T)", "External rotation\nPosterior stabilization", 'purple'),
("Subscapularis (S)", "Internal rotation\nAnterior stabilization\nPrevents ant. dislocation", 'red')]
for i, (name, desc, c) in enumerate(rc):
y = 11 - i * 2.5
ax.add_patch(FancyBboxPatch((0.2, y - 1.8), 9.5, 2.2, boxstyle="round,pad=0.2",
facecolor=c, alpha=0.12, edgecolor=c, linewidth=2))
ax.text(0.5, y, name, fontsize=9.5, fontweight='bold', va='center', color=c)
ax.text(0.5, y - 0.9, desc, fontsize=8.5, va='center')
ax.text(5, 0.4, "SITS mnemonic: S-I-T-S (Rotator Cuff muscles)",
ha='center', fontsize=9, style='italic',
bbox=dict(facecolor='lightyellow', edgecolor='orange'))
plt.tight_layout()
return save_fig("shoulder_stability")
def draw_factors_muscle():
fig, axes = plt.subplots(1, 2, figsize=(11, 6))
fig.suptitle("Factors Affecting Muscle Function", fontsize=14, fontweight='bold')
ax = axes[0]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Intrinsic Factors", fontsize=10, fontweight='bold')
intrinsic = [
("Physiological Cross-\nSectional Area (PCSA)", "Force ∝ PCSA\nMore fibers = more force", '#AED6F1'),
("Fiber Type", "Type I: slow, fatigue-resistant\nType II: fast, high force, fatigue", '#A9DFBF'),
("Muscle Architecture", "Pennation angle\nParallel vs pennate fibers", '#FAD7A0'),
("Length-Tension\nRelationship", "Optimal length = max force\nShortened/lengthened = less force", '#F1948A'),
("Moment Arm Length", "Force × Moment arm = Torque\nLonger arm = more torque", '#D7BDE2'),
]
for i, (name, desc, clr) in enumerate(intrinsic):
y = 11 - i * 2.0
ax.add_patch(FancyBboxPatch((0.2, y - 1.5), 9.5, 1.8, boxstyle="round,pad=0.2",
facecolor=clr, edgecolor='gray', alpha=0.8))
ax.text(0.5, y - 0.1, name, fontsize=9, fontweight='bold', va='center')
ax.text(4, y - 0.6, desc, fontsize=8.5, va='center')
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Extrinsic Factors", fontsize=10, fontweight='bold')
extrinsic = [
("Velocity", "Force-velocity relationship\nFaster = less force (concentric)\nIsometric: max force", 'blue'),
("Pre-stretching (SSC)", "Stored elastic energy\nEnhances concentric force\nEccentric → Concentric", 'green'),
("Joint Position", "Changes moment arm\nOptimal position varies\nper muscle", 'purple'),
("Temperature", "Warm muscle: ↑ speed, ↑ force\nCold: ↓ enzyme activity", 'red'),
("Fatigue", "↓ ATP, ↑ lactic acid\n↓ Calcium release\nCentral vs peripheral", 'darkred'),
("Neural Factors", "Motor unit recruitment\nFiring rate (rate coding)\nSynchronization", 'navy'),
]
for i, (name, desc, c) in enumerate(extrinsic):
y = 11.2 - i * 1.7
ax.add_patch(FancyBboxPatch((0.2, y - 1.2), 9.5, 1.3, boxstyle="round,pad=0.1",
facecolor=c, alpha=0.1, edgecolor=c))
ax.text(0.5, y - 0.1, f"• {name}:", fontsize=9, fontweight='bold', va='center', color=c)
ax.text(3.5, y - 0.5, desc, fontsize=8, va='center')
plt.tight_layout()
return save_fig("factors_muscle")
def draw_loading_foot():
fig, axes = plt.subplots(1, 2, figsize=(11, 6))
fig.suptitle("Loading of the Foot", fontsize=14, fontweight='bold')
ax = axes[0]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Pressure Distribution\n(Plantar Surface)", fontsize=10, fontweight='bold')
# Foot outline
foot_x = [3, 2.5, 2, 2, 2.5, 3, 4, 5, 6, 7, 7.5, 7.5, 7, 6, 5, 4, 3.5, 3]
foot_y = [11, 10, 9, 7, 5, 3, 2, 1.5, 2, 3, 5, 7, 9, 10, 11, 11, 11, 11]
ax.fill(foot_x, foot_y, alpha=0.15, color='tan')
ax.plot(foot_x, foot_y, 'brown', linewidth=2)
# Pressure zones
zones = [(4.8, 9.5, 1, 1, 'Metatarsal\nheads\n(40%)', 'red'),
(4.8, 3.5, 1.5, 1.5, 'Heel\n(60%)', 'blue'),
(3.5, 6.5, 0.7, 0.7, 'Lat\nborder\n(trace)', 'green')]
for x, y, rx, ry, label, c in zones:
ax.add_patch(patches.Ellipse((x, y), rx*2, ry*2, facecolor=c, alpha=0.3, edgecolor=c, linewidth=2))
ax.text(x, y, label, ha='center', va='center', fontsize=7.5, color=c, fontweight='bold')
ax.text(5, 0.5, "Normal stance: Heel 60%, Forefoot 40%\nMedial arch = non-weight bearing",
ha='center', fontsize=8.5, color='gray')
ax = axes[1]
ax.set_xlim(0, 10); ax.set_ylim(0, 12)
ax.axis('off')
ax.set_title("Gait Phases - Foot Loading", fontsize=10, fontweight='bold')
phases = [
("Heel Strike (IC)", "Heel contact\nForce = 100-120% BW\nEccentric tibialis ant.", '#AED6F1'),
("Loading Response", "Foot flat\nPronation begins\nShock absorption", '#A9DFBF'),
("Midstance", "Foot flat contact\nArch loads\nBody CoM over foot", '#FAD7A0'),
("Terminal Stance\n(Heel off)", "Push-off loading\nPlantar flexors active\nArch tightens (Windlass)", '#F1948A'),
("Pre-swing (Toe off)", "Last contact at 1st MTP\nForce 120% BW\nPlantar fascia taut", '#D7BDE2'),
]
for i, (name, desc, clr) in enumerate(phases):
y = 11 - i * 2.0
ax.add_patch(FancyBboxPatch((0.2, y - 1.5), 9.5, 1.8, boxstyle="round,pad=0.2",
facecolor=clr, edgecolor='gray', alpha=0.8))
ax.text(0.5, y - 0.1, name, fontsize=9, fontweight='bold', va='center')
ax.text(3.5, y - 0.6, desc, fontsize=8.5, va='center')
plt.tight_layout()
return save_fig("loading_foot")
print("Generating all diagrams...")
diagrams = {}
try:
diagrams['osteokinematics'] = draw_osteokinematics()
print("1. Osteokinematics done")
diagrams['sensory_receptors'] = draw_sensory_receptors()
print("2. Sensory receptors done")
diagrams['tfcc'] = draw_tfcc()
print("3. TFCC done")
diagrams['linear_force'] = draw_linear_force()
print("4. Linear force done")
diagrams['connective_tissue'] = draw_connective_tissue()
print("5. Connective tissue done")
diagrams['load_deformation'] = draw_load_deformation()
print("6. Load deformation done")
diagrams['pelvic_tilt'] = draw_pelvic_tilt()
print("7. Pelvic tilt done")
diagrams['scoliosis'] = draw_scoliosis()
print("8. Scoliosis done")
diagrams['grip_grasp'] = draw_grip_grasp()
print("9. Grip grasp done")
diagrams['active_passive'] = draw_active_passive_insufficiency()
print("10. Active/Passive insufficiency done")
diagrams['hip_angles'] = draw_hip_angles()
print("11. Hip angles done")
diagrams['coracoacromial'] = draw_coracoacromial_arch()
print("12. Coracoacromial done")
diagrams['ideal_posture'] = draw_ideal_posture()
print("13. Ideal posture done")
diagrams['pivot_joint'] = draw_pivot_joint()
print("14. Pivot joint done")
diagrams['anatomical_pulley'] = draw_anatomical_pulley()
print("15. Anatomical pulley done")
diagrams['femur_angles'] = draw_femur_angles()
print("16. Femur angles done")
diagrams['extensor_mechanism'] = draw_extensor_mechanism()
print("17. Extensor mechanism done")
diagrams['shoulder_stability'] = draw_shoulder_stability()
print("18. Shoulder stability done")
diagrams['factors_muscle'] = draw_factors_muscle()
print("19. Factors muscle done")
diagrams['loading_foot'] = draw_loading_foot()
print("20. Loading foot done")
print(f"\nAll {len(diagrams)} diagram sets generated!")
except Exception as e:
print(f"Error: {e}")
traceback.print_exc()
# Save diagram paths
import json
with open('/tmp/workspace/biomech-pdf/diagram_paths.json', 'w') as f:
json.dump(diagrams, f)
print("Diagram paths saved.")
cd /tmp/workspace/biomech-pdf && python generate_biomech_pdf.py 2>&1
~/biomech-pdf/build_pdf.py
import io, os, json, urllib.request, traceback
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import numpy as np
from PIL import Image as PILImage
from reportlab.lib.pagesizes import A4
from reportlab.lib.units import cm
from reportlab.lib import colors
from reportlab.platypus import (SimpleDocTemplate, Paragraph, Spacer, Image,
Table, TableStyle, PageBreak, HRFlowable, KeepTogether)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
W, H = A4
OUT = "/tmp/workspace/biomech-pdf/Biomechanics_5Marks_Diagrams.pdf"
# ── Styles ───────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()
title_style = ParagraphStyle('TopicTitle', parent=styles['Heading1'],
fontSize=16, textColor=colors.HexColor('#1a3a6b'),
spaceAfter=6, spaceBefore=4, borderPad=4,
backColor=colors.HexColor('#e8f0fe'),
borderColor=colors.HexColor('#1a3a6b'), borderWidth=1)
subtitle_style = ParagraphStyle('DiagTitle', parent=styles['Heading2'],
fontSize=11, textColor=colors.HexColor('#2c5282'),
spaceAfter=4, spaceBefore=6)
body_style = ParagraphStyle('Body', parent=styles['Normal'],
fontSize=9, leading=13, spaceAfter=3)
cover_title = ParagraphStyle('Cover', parent=styles['Heading1'],
fontSize=26, textColor=colors.HexColor('#1a3a6b'),
alignment=TA_CENTER, spaceAfter=12)
cover_sub = ParagraphStyle('CoverSub', parent=styles['Normal'],
fontSize=13, textColor=colors.HexColor('#2c5282'),
alignment=TA_CENTER, spaceAfter=8)
note_style = ParagraphStyle('Note', parent=styles['Normal'],
fontSize=8.5, textColor=colors.HexColor('#555555'),
leftIndent=10, spaceAfter=3, leading=12)
def load_url_image(url, max_w=16*cm, max_h=8.5*cm):
try:
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
data = urllib.request.urlopen(req, timeout=20).read()
pil = PILImage.open(io.BytesIO(data))
w, h = pil.size
ratio = min(max_w / w, max_h / h)
return Image(io.BytesIO(data), width=w*ratio, height=h*ratio)
except Exception as e:
print(f" URL image failed: {e}")
return None
def load_local_image(path, max_w=16*cm, max_h=8.5*cm):
try:
pil = PILImage.open(path)
w, h = pil.size
ratio = min(max_w / w, max_h / h)
return Image(path, width=w*ratio, height=h*ratio)
except Exception as e:
print(f" Local image failed {path}: {e}")
return None
def img_placeholder(text="[Diagram not available]"):
return Paragraph(f'<i>{text}</i>', body_style)
# ── Image URLs from search ────────────────────────────────────────────────────
URLS = {
"supination_pronation_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_25d4cadd68d3e57d20a7c700b3debf1d17e633bc93316b25f808b1142cb12fa5.jpg",
"supination_pronation_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_cd6aa0466326d3e94a31471480700b4cafd141b6a4487b23342f7fc3b3bb9b84.jpg",
"gait_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_14a4bdc0a165f9af88e1267f1b352cf493e895a7bea5e480f28f4bc99cca9cb2.jpg",
"gait_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_7f4c3813f1b4435c2380e79f047cb01a9ddc36c83d5708800c6eff72711c5d9a.jpg",
"scapulohumeral_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_2c390afb6f9dc0d879e2294871194909831dd55cb8fef1b1c20e6b8292637f14.jpg",
"scapulohumeral_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_3622a569856ce0b9b0dd63cd1c9fbaa779927cbec30e2fa3e14c5ef520e7be9d.jpg",
"meniscus_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_2456db91f81a0614a77856398d59b7b12a135bcfd29d451015f92fc540ef92f4.jpg",
"meniscus_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_4005e6a492f7bac510c0e33fcfc553fe6cf4c91cd7edb2becd9247ba36e98564.jpg",
"ligamentum_flavum_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_52c9eea42cb70f5b1fc5b1f3317ccddf27d7646bf15584434fe5ea21f490bcca.jpg",
"ligamentum_flavum_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_957d1ea3dc492a09bb2ef1d61380c8eab0c08c3e12ae3c038c906df5cddc536c.jpg",
"sliding_filament_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_c51d2cf0f4c4e51ce2a4267aa80effff169dc3a0a34ff2bb82d6b3d90e7a0b08.jpg",
"sliding_filament_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_891d8585a37370558b6c6e8d806b8a98e242b3c5f8955ad693c24019f540036b.jpg",
"acl_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_8773cf68c54f4f091619eca991592d45339e9e1e74b0fefdcfe68a0d14e22c03.jpg",
"acl_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_c5b9c47f15885c609be05dca10f82ee40801337fe5fd207af6d5ef005bfef5a2.jpg",
"patellofemoral_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_f5e36d82c6bd02be8300ead0eb80b45f5ed9825db19c57d2a44c9717785a700a.jpg",
"patellofemoral_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_b3eef7c11b2fff720d08c9eb4e63a3c1ea238c86cd8ac85970f7d28eb2bb271e.jpg",
"foot_arches_1": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_1818b80344c343bcdaeab3b671ccf3834c33e9527ea493746f62b6a9fd78d056.jpg",
"foot_arches_2": "https://cdn.orris.care/cdss_images/pmc_clinical_VQA_bed5b016775e9b570293894d34cea82f3db05763e2e251e585b24b4cca60daac.jpg",
}
LOCAL = {k: f"/tmp/workspace/biomech-pdf/{k}.png" for k in [
'osteokinematics', 'sensory_receptors', 'tfcc', 'linear_force',
'connective_tissue', 'load_deformation', 'pelvic_tilt', 'scoliosis',
'grip_grasp', 'active_passive', 'hip_angles', 'coracoacromial',
'ideal_posture', 'pivot_joint', 'anatomical_pulley', 'femur_angles',
'extensor_mechanism', 'shoulder_stability', 'factors_muscle', 'loading_foot'
]}
def get_url_img(key, max_w=16*cm, max_h=8*cm):
if key in URLS:
img = load_url_image(URLS[key], max_w, max_h)
return img
return None
def get_local_img(key, max_w=16*cm, max_h=8*cm):
path = LOCAL.get(key)
if path and os.path.exists(path):
return load_local_image(path, max_w, max_h)
return None
# ── Topic definitions ─────────────────────────────────────────────────────────
TOPICS = [
{
"title": "1. Supination / Pronation Twist",
"notes": [
"Supination: Palm faces anteriorly/upward; rotation at proximal & distal RUJ",
"Pronation: Palm faces posteriorly/downward; radius crosses over ulna",
"Axis: Longitudinal axis through radial head to ulnar styloid",
"Normal ROM: 90° supination, 90° pronation (total 180°)",
"Key muscles - Supination: Supinator, Biceps brachii | Pronation: PT, PQ",
],
"diagrams": [
("Forearm Rotation - Clinical ROM (Supination → Pronation)", "url", "supination_pronation_1"),
("Post-operative ROM Assessment: Bilateral Supination/Pronation", "url", "supination_pronation_2"),
]
},
{
"title": "2. Osteokinematics & Arthrokinematics",
"notes": [
"Osteokinematics: Movement of bones in space (flexion/extension/rotation - angular or translatory)",
"Arthrokinematics: Motion at joint surfaces (Roll, Glide/Slide, Spin)",
"Convex-on-Concave Rule: Roll & glide in OPPOSITE directions",
"Concave-on-Convex Rule: Roll & glide in the SAME direction",
"Degrees of Freedom: Number of planes in which a joint can move",
],
"diagrams": [
("Osteokinematics vs Arthrokinematics - Roll/Glide/Spin Diagram", "local", "osteokinematics"),
("Convex-Concave Rule Illustration & Joint Motion Analysis", "local", "osteokinematics"),
]
},
{
"title": "3. Determinants / Parameters of Gait",
"notes": [
"6 Determinants (Saunders): Pelvic rotation, Pelvic tilt, Knee flexion, Foot & ankle motion, Knee-ankle interaction, Lateral pelvic displacement",
"Gait Cycle = Stance phase (60%) + Swing phase (40%)",
"Step length, Stride length, Cadence, Walking speed, Base of support",
"Velocity = Stride length × Cadence",
"Normal cadence: ~110-120 steps/min; Step length: ~70-80 cm",
],
"diagrams": [
("Gait Cycle Timeline: Stance & Swing Phases with Kinematic Parameters", "url", "gait_1"),
("Gait Phase Muscle Activation - GRF Analysis", "url", "gait_2"),
]
},
{
"title": "4. Scapulohumeral Rhythm",
"notes": [
"Ratio: 2:1 (for every 3° of shoulder abduction → 2° GHJ + 1° scapulothoracic)",
"0-30°: GHJ motion only (setting phase)",
"30-90°: 2:1 ratio begins (GHJ + scapular rotation)",
"90-180°: Continues 2:1 + clavicular rotation at SCJ/ACJ",
"Full 180° = 120° GHJ + 60° scapulothoracic rotation",
],
"diagrams": [
("Scapulohumeral Rhythm - Photographic Sequence of Arm Abduction", "url", "scapulohumeral_1"),
("Dynamic Digital Radiography - Pre/Post-op Scapulohumeral Rhythm", "url", "scapulohumeral_2"),
]
},
{
"title": "5. Meniscus / Functions of Menisci",
"notes": [
"Medial meniscus: C-shaped, larger, more firmly attached → more susceptible to tear",
"Lateral meniscus: O-shaped, smaller, more mobile",
"Functions: Load transmission (transmit 50-70% of load), Shock absorption, Joint stability, Lubrication, Proprioception",
"Peripheral 1/3: Vascular (can heal); Inner 2/3: Avascular (poor healing)",
"Composed of fibrocartilage (Type I collagen predominantly)",
],
"diagrams": [
("Medial & Lateral Menisci - Gross Morphology (C-shape vs O-shape)", "url", "meniscus_1"),
("Fetal Knee - Meniscal Anatomy: Comparative Morphology MM vs LM", "url", "meniscus_2"),
]
},
{
"title": "6. Bursae Around Knee Joint",
"notes": [
"Prepatellar bursa: Between skin and patella (housemaid's knee when inflamed)",
"Infrapatellar bursa: Superficial (over patellar tendon) & Deep (between patellar tendon & tibia)",
"Suprapatellar bursa: Extension of joint capsule, above patella between quad tendon & femur",
"Pes anserine bursa: Medial knee, between MCL and pes anserine tendons",
"Semimembranosus bursa (Baker's cyst): Posterior knee, communicates with joint",
"Iliotibial band bursa: Lateral femoral condyle",
],
"diagrams": [
("Knee Joint Anatomy - Bursae Locations (Anterior & Posterior)", "local", "pivot_joint"),
("Knee Bursae Classification & Clinical Significance Table", "local", "sensory_receptors"),
]
},
{
"title": "7. Ligamentum Flavum",
"notes": [
"Yellow ligament; connects adjacent laminae of vertebrae",
"Composition: 80% elastin + 20% collagen (most elastic ligament in body)",
"Function: Resists flexion, assists return to neutral, maintains upright posture",
"Spans from C2 to S1; thickest in lumbar region",
"Clinical: Hypertrophy → spinal stenosis; Ossification (OLF) → myelopathy",
"Does NOT buckle during extension (unlike most ligaments)",
],
"diagrams": [
("Ossification of Ligamentum Flavum (OLF) - Post-op CT Decompression", "url", "ligamentum_flavum_1"),
("Sato Classification of Thoracic OLF - 5 Morphological Types (CT Axial)", "url", "ligamentum_flavum_2"),
]
},
{
"title": "8. Sliding Filament Theory",
"notes": [
"Proposed by Huxley & Hanson (1954) and Huxley & Niedergerke (1954)",
"Sarcomere shortens: I-band shortens, H-zone shortens, A-band UNCHANGED",
"Steps: ACh → depolarization → Ca²⁺ release → troponin-tropomyosin shift → actin-myosin cross-bridge → power stroke → ATP → detachment",
"Z-disc to Z-disc = one sarcomere",
"Titin: elastic protein maintaining myosin alignment",
],
"diagrams": [
("Sarcomere Ultrastructure - Myofibril with A-band, I-band, Z-line, M-line", "url", "sliding_filament_1"),
("Cardiac Sarcomere: Myosin, Actin, MyBP-C Molecular Architecture", "url", "sliding_filament_2"),
]
},
{
"title": "9. Linear Force System",
"notes": [
"Linear force system: All forces act along the same line or parallel lines",
"Types: Concurrent, Collinear, Parallel",
"Resultant: Vector sum of all forces (magnitude + direction)",
"Equilibrium: ΣF = 0 (translatory) and ΣM = 0 (rotatory)",
"Body weight = best example of parallel downward gravitational forces",
"Mechanical advantage = force arm / resistance arm",
],
"diagrams": [
("Collinear & Parallel Force System with Resultant Calculation", "local", "linear_force"),
("Force Equilibrium in Body Weight Distribution", "local", "linear_force"),
]
},
{
"title": "10. Sensory Receptors (Muscle)",
"notes": [
"Muscle Spindle: Intrafusal fibers (nuclear bag + nuclear chain); Ia (primary) + II (secondary) afferents; gamma motor neuron (efferent); Detects STRETCH (length change)",
"GTO (Golgi Tendon Organ): At musculotendinous junction; Ib afferent; Detects TENSION; Autogenic inhibition (inverse stretch reflex)",
"Free nerve endings: Detect pain, temperature (A-delta, C fibers)",
"Pacinian corpuscles: Vibration/pressure in deep tissues",
],
"diagrams": [
("Muscle Spindle vs GTO - Structure, Afferents & Reflexes Comparison", "local", "sensory_receptors"),
("Sensory Receptor Types & Length-Tension Relationship", "local", "sensory_receptors"),
]
},
{
"title": "11. TFCC (Triangular Fibrocartilage Complex)",
"notes": [
"Components: Articular disc, Volar/Dorsal radioulnar ligaments, Ulnolunate lig., Ulnotriquetral lig., ECU subsheath, Meniscal homologue",
"Functions: Stabilizes DRUJ, transmits ~20% of axial load, allows forearm rotation",
"Palmer Classification: Class I (Traumatic), Class II (Degenerative)",
"Central disc = avascular; Peripheral = vascular (can heal)",
"Tests: Press test, Ulnocarpal stress test, DRUJ ballottement",
],
"diagrams": [
("TFCC Components - Palmar View with Ligament Annotations", "local", "tfcc"),
("TFCC Functions & Palmer Classification of Tears", "local", "tfcc"),
]
},
{
"title": "12. Patellofemoral Joint Reaction Force",
"notes": [
"PFJRF = Resultant force between quad tendon force and patellar tendon force",
"PFJRF increases with: greater knee flexion angle, greater quad contraction",
"Normal walking: 0.5× BW; Stairs: 3-4× BW; Squatting: 7-8× BW",
"Q-angle (normal): 13-18° females, 10-15° males; Increased Q-angle → lateral patellar malalignment",
"Patella function: Increases quad moment arm by ~50% (increases lever arm by 33%)",
],
"diagrams": [
("Patellofemoral Joint - 3D Coordinate System & Patellar Kinematics", "url", "patellofemoral_1"),
("In-vivo Patellofemoral Kinematics During Stair Ascent (Fluoroscopy)", "url", "patellofemoral_2"),
]
},
{
"title": "13. Composition of Connective Tissue",
"notes": [
"Cells: Fibroblasts (dominant), chondrocytes, osteoblasts, mast cells, macrophages",
"ECM Fibers: Collagen (Types I-XII), Elastin, Reticulin",
"Ground substance: Proteoglycans (aggrecan, versican), GAGs (hyaluronic acid, chondroitin sulfate)",
"Adhesion proteins: Fibronectin, Laminin",
"Water content: 60-70% of connective tissue by weight",
],
"diagrams": [
("Connective Tissue - Cell Types & Functions", "local", "connective_tissue"),
("ECM Composition - Collagen, Elastin, Proteoglycans & GAGs", "local", "connective_tissue"),
]
},
{
"title": "14. Loading of the Foot",
"notes": [
"Heel strike: Calcaneus absorbs initial impact (60% body weight)",
"Foot flat: Pronation for shock absorption (subtalar joint unlocks)",
"Midstance: Subtalar neutral; arch loaded; tibialis posterior active",
"Heel off: Supination; arch stiffens via Windlass mechanism (plantar fascia)",
"Toe off: Push-off at 1st MTP; GFRF = 120% BW; intrinsics stabilize",
"Windlass mechanism: Great toe extension tightens plantar fascia → raises arch",
],
"diagrams": [
("Foot Pressure Distribution & Weight-Bearing Zones", "local", "loading_foot"),
("Gait Phases - Sequential Foot Loading & Windlass Mechanism", "local", "loading_foot"),
]
},
{
"title": "15. Arches of Foot & Its Biomechanics",
"notes": [
"Medial Longitudinal Arch (MLA): Calcaneus → Navicular → Cuneiforms → 1st-3rd MT heads; height ~15-18mm; most important",
"Lateral Longitudinal Arch: Calcaneus → Cuboid → 4th-5th MT; lower, more rigid",
"Transverse Arch: Cuneiform heads to cuboid; acts as crossbow",
"Supports: Passive (bones, plantar fascia, ligaments) + Active (tibialis posterior, FHL, intrinsics)",
"Flat foot (pes planus): Fallen MLA; high arch (pes cavus): excessive MLA",
],
"diagrams": [
("Foot Arches - Extrinsic Muscle Stabilizers (Posterior View)", "url", "foot_arches_2"),
("Arch Architecture & Hand Arch Comparison (Longitudinal + Transverse)", "url", "foot_arches_1"),
]
},
{
"title": "16. Pelvic Tilt",
"notes": [
"Anterior Tilt: ASIS moves anteriorly & inferiorly; increased lumbar lordosis; tight hip flexors + weak abdominals",
"Posterior Tilt: ASIS moves posteriorly & superiorly; decreased lumbar lordosis; tight hamstrings + weak hip flexors",
"Lateral Tilt: Pelvic drop on unaffected side during gait (Trendelenburg sign)",
"Normal: ASIS and PSIS at equal level; 0-5° in females",
"Measurement: inclinometer, ASIS-PSIS line observation",
],
"diagrams": [
("Anterior vs Posterior Pelvic Tilt - ASIS/PSIS & Spinal Changes", "local", "pelvic_tilt"),
("Lateral Pelvic Tilt - Trendelenburg Sign & Muscle Imbalance", "local", "pelvic_tilt"),
]
},
{
"title": "17. Scoliosis",
"notes": [
"Lateral curvature of spine >10° with vertebral rotation (Cobb angle method)",
"Types: Idiopathic (80%), Congenital, Neuromuscular, Degenerative",
"Cobb Angle: <10° normal variation, 10-25° mild, 25-40° moderate, >40° severe",
"Features: Rib hump (Adam's forward bend test), shoulder asymmetry, waistline difference",
"Management: Observation (<25°), Bracing (25-40°), Surgery (>50° or progressive)",
],
"diagrams": [
("Scoliosis Curve Types & Cobb Angle Measurement", "local", "scoliosis"),
("Cobb Angle Classification & Management Algorithm", "local", "scoliosis"),
]
},
{
"title": "18. Load Deformation Curve",
"notes": [
"X-axis: Deformation (mm or %); Y-axis: Load (N) or stress/strain",
"Toe region: Uncrimping of collagen fibers (non-linear initial zone)",
"Elastic region: Linear - stiffness = slope; returns to original shape",
"Yield point: Onset of permanent (plastic) deformation",
"Ultimate load: Peak load before structural failure",
"Creep: Continued deformation under constant load (viscoelastic property)",
],
"diagrams": [
("Load-Deformation Curve with Toe, Elastic, Plastic & Failure Zones", "local", "load_deformation"),
("Key Biomechanical Parameters: Stiffness, Yield Point, Energy Storage", "local", "load_deformation"),
]
},
{
"title": "19. Grip and Grasp / Power Grip",
"notes": [
"Power Grip: Cylindrical, spherical, hook grips; all digits + palm; Ex: hammer",
"Precision Grip: Tip pinch, lateral (key) pinch, palmar (3-point) pinch",
"Max grip force: ~400-500 N in adult males; strongest at 30° wrist extension",
"Muscles: FDS + FDP (primary), intrinsics (MCP stabilization), thenar + hypothenar",
"Clinical: Jamar dynamometer - 5 positions; normal = 35-45 kg men, 20-30 kg women",
],
"diagrams": [
("Types of Prehension - Power Grip vs Precision Grip Classification", "local", "grip_grasp"),
("Biomechanics of Power Grip - Muscles & Force Analysis", "local", "grip_grasp"),
]
},
{
"title": "20. Active & Passive Insufficiency",
"notes": [
"Active Insufficiency: Two-joint AGONIST muscle unable to generate full force when shortened at both joints simultaneously (overshortened beyond optimal length)",
"Passive Insufficiency: Two-joint ANTAGONIST muscle overstretched across both joints - limits full ROM",
"Example Active: Hamstrings - full knee flexion + hip extension = weak",
"Example Passive: Hamstrings limit knee extension when hip fully flexed (SLR test)",
"Clinical use: Explains grasping patterns, diagnostic testing, stretching protocols",
],
"diagrams": [
("Active Insufficiency - Length-Tension Relationship & Clinical Examples", "local", "active_passive"),
("Passive Insufficiency - Two-Joint Antagonist Stretch Limitation", "local", "active_passive"),
]
},
{
"title": "21. Angles of Hip Joint",
"notes": [
"Angle of Inclination (Neck-Shaft): 125-130° adults; Coxa Valga >135°, Coxa Vara <120°",
"Angle of Anteversion (Torsion): 12-15° adults; Newborn 30-40°; Excess = toe-in gait",
"Retroversion = decreased/negative anteversion; toe-out gait",
"Coxa Valga: Increases abductor weakness, hip instability, leg length discrepancy",
"Coxa Vara: Increases trendelenburg, shortens limb, stresses femoral neck",
],
"diagrams": [
("Hip Angles: Neck-Shaft Angle & Normal vs Coxa Valga/Vara", "local", "hip_angles"),
("Angle of Anteversion: Axial View & Clinical Effects on Gait", "local", "hip_angles"),
]
},
{
"title": "22. ACL (Anterior Cruciate Ligament)",
"notes": [
"Origin: Posteromedial aspect of lateral femoral condyle; Insertion: Anterior tibial plateau",
"Bundles: Anteromedial (taut in flexion) + Posterolateral (taut in extension)",
"Functions: Resists anterior tibial translation (85%), rotational stability, hyperextension",
"Mechanism of injury: Non-contact (most common), valgus + IR force, deceleration",
"Tests: Lachman test (most sensitive), Anterior drawer, Pivot shift test",
"Vascular supply: Middle genicular artery; Avascular after injury",
],
"diagrams": [
("ACL Anatomy - Ribbon-like Morphology & Femoral Attachment", "url", "acl_1"),
("ACL Biomechanics - Force Distribution During Loading (skiing model)", "url", "acl_2"),
]
},
{
"title": "23. Suprhumeral / Coracoacromial Arch",
"notes": [
"Formed by: Coracoid process + Coracoacromial ligament + Acromion",
"Contents: Supraspinatus tendon, Subacromial bursa, Long head of biceps",
"Subacromial space: 9-10 mm normal; <6 mm = impingement",
"Bigliani's Acromial Types: I (flat), II (curved), III (hooked - highest impingement risk)",
"Impingement signs: Neer's sign, Hawkins-Kennedy test; Painful arc 60-120°",
],
"diagrams": [
("Coracoacromial Arch Anatomy & Subacromial Space Contents", "local", "coracoacromial"),
("Acromial Types (Bigliani) & Impingement Clinical Classification", "local", "coracoacromial"),
]
},
{
"title": "24. Ideal / Optimal Posture",
"notes": [
"Definition (Kendall): State of musculoskeletal balance that involves minimal stress on supporting structures",
"Lateral view plumb line passes: Ear lobe → Shoulder (acromion) → GT of hip → Anterior to knee → Lateral malleolus",
"Spinal curves: Cervical lordosis, Thoracic kyphosis, Lumbar lordosis (all balanced)",
"Anterior view: Bilateral symmetry; head level; equal shoulder and ASIS heights",
"Deviations: Kyphosis, lordosis, scoliosis, forward head posture, flat back",
],
"diagrams": [
("Ideal Posture Plumb Line - Lateral View with Landmarks", "local", "ideal_posture"),
("Optimal Posture Criteria - Segment-by-Segment Checklist", "local", "ideal_posture"),
]
},
{
"title": "25. Anatomical Pulleys / Patella as Anatomical Pulley",
"notes": [
"Anatomical pulley: Bony prominence or sesamoid bone that redirects tendon force",
"Patella: Largest sesamoid; increases quad moment arm by ~50% → reduces force needed by ~33%",
"Other pulleys: Lateral malleolus (peroneals), Medial malleolus (tibialis posterior), Pisiform (FCU)",
"Functions: Change direction of pull, increase mechanical advantage, protect tendons",
"Without patella: Would require 33% more quadriceps force for same extension torque",
],
"diagrams": [
("Mechanical Pulley Principle & Force Direction Change", "local", "anatomical_pulley"),
("Patella as Anatomical Pulley - Moment Arm Enhancement Diagram", "local", "anatomical_pulley"),
]
},
{
"title": "26. Pivot Joint",
"notes": [
"Pivot (Trochoid) joint: Uniaxial, allows rotation only (1 DOF)",
"Types: In pivot joint - cylindrical process rotates within ring (or ring around peg)",
"Examples: Proximal RUJ (radial head in annular ligament), Distal RUJ, Atlanto-axial (C1-C2 - dens rotates in atlas ring)",
"Motion: Pure rotation along longitudinal axis",
"Compare: Hinge = flexion/extension; Pivot = rotation; Ball-socket = multiaxial",
],
"diagrams": [
("Pivot Joint Types - Proximal RUJ & Atlanto-Axial Joint", "local", "pivot_joint"),
("Joint Classification Summary - Uniaxial to Multiaxial Types", "local", "pivot_joint"),
]
},
{
"title": "27. Importance of Angles/Curves in Femur",
"notes": [
"Angle of Inclination: Determines abductor moment arm; affects hip stability and load transmission",
"Angle of Anteversion: Positions femoral head in acetabulum; affects weight-bearing alignment and gait",
"Anterior curvature (bow): Distributes bending stress along shaft; reduces fracture risk",
"Condylar obliquity (~9°): Brings knees close to midline → essential for bipedal gait",
"Wolff's Law: Trabecular pattern follows principal stress lines in femoral head",
],
"diagrams": [
("Femoral Angles - Inclination, Anteversion & Shaft Bow", "local", "femur_angles"),
("Femoral Stress Analysis - Wolff's Law & Trabecular Lines", "local", "femur_angles"),
]
},
{
"title": "28. Extensor Mechanism / Expansion of Wrist & Fingers",
"notes": [
"Extensor hood (dorsal aponeurosis): Complex fibrous expansion over MCP joint",
"Components: Central slip (→ PIP), Lateral bands (→ DIP), Triangular ligament, Retinacular ligament",
"Intrinsics (lumbricals + interossei) contribute to lateral bands → coordinate MCP flex + IP ext",
"6 dorsal compartments at wrist: 1st (APL, EPB), 2nd (ECRL, ECRB), 3rd (EPL), 4th (EDC, EIP), 5th (EDM), 6th (ECU)",
"Extensor retinaculum: Holds tendons; prevents bowstringing",
],
"diagrams": [
("Extensor Mechanism of Fingers - Central Slip, Lateral Bands, Intrinsics", "local", "extensor_mechanism"),
("6 Dorsal Wrist Compartments & Extensor Tendon Anatomy", "local", "extensor_mechanism"),
]
},
{
"title": "29. Shoulder Joint Stability / Static Stabilization",
"notes": [
"Glenohumeral joint: Most mobile (most unstable) joint in body; 3 DOF",
"Static stabilizers: Glenoid labrum (deepens cavity 50%), GH ligaments (SGHL, MGHL, IGHL), CHL, bony geometry, negative intra-articular pressure",
"IGHL (Inferior GHL): Most important; taut at 90° abduction; Bankart lesion tears IGHL-labrum complex",
"Dynamic stabilizers: Rotator cuff (SITS), Long head biceps, Periscapular muscles",
"Concavity-compression: RC compresses head into glenoid",
],
"diagrams": [
("Static Stabilizers of GHJ - Labrum, IGHL, CHL & Bony Geometry", "local", "shoulder_stability"),
("Rotator Cuff Dynamic Stabilizers - SITS with Origins & Functions", "local", "shoulder_stability"),
]
},
{
"title": "30. Factors Affecting Muscle Function",
"notes": [
"Intrinsic: PCSA (force ∝ PCSA), fiber type (I vs IIa/IIb), architecture (pennation angle), length-tension relationship, moment arm",
"Extrinsic: Velocity (force-velocity relationship), pre-stretching (SSC), joint position, temperature, fatigue (peripheral + central), neural factors",
"Force-velocity: Concentric = less force with speed; Eccentric = more force with speed",
"SSC (Stretch-Shortening Cycle): Eccentric pre-loading stores elastic energy → enhances concentric output",
"Fatigue: ↓ Ca²⁺ sensitivity, ↓ ATP, ↑ inorganic phosphate, ↑ H⁺ ions",
],
"diagrams": [
("Intrinsic Factors Affecting Muscle Function (PCSA, Fiber, Architecture)", "local", "factors_muscle"),
("Extrinsic Factors - Velocity, SSC, Temperature & Neural Control", "local", "factors_muscle"),
]
},
]
# ── Build PDF ─────────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
OUT, pagesize=A4,
leftMargin=1.8*cm, rightMargin=1.8*cm,
topMargin=1.8*cm, bottomMargin=1.8*cm
)
story = []
# Cover page
story.append(Spacer(1, 2*cm))
story.append(Paragraph("BIOMECHANICS", cover_title))
story.append(Paragraph("5-Mark Questions: Diagrams Reference", cover_sub))
story.append(Spacer(1, 0.5*cm))
story.append(HRFlowable(width="100%", thickness=3, color=colors.HexColor('#1a3a6b')))
story.append(Spacer(1, 0.5*cm))
story.append(Paragraph("Repeated Questions 2019 – 2025", ParagraphStyle('cs2',
parent=styles['Normal'], fontSize=13, alignment=TA_CENTER, textColor=colors.HexColor('#2c5282'))))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph("2 Diagrams per Topic | 30 Topics Covered",
ParagraphStyle('cs3', parent=styles['Normal'], fontSize=11, alignment=TA_CENTER,
textColor=colors.HexColor('#666666'))))
story.append(Spacer(1, 2*cm))
toc_data = [['#', 'Topic'], ]
for i, t in enumerate(TOPICS, 1):
toc_data.append([str(i), t['title'].split('. ', 1)[1] if '. ' in t['title'] else t['title']])
toc_table = Table(toc_data, colWidths=[1.2*cm, 14.5*cm])
toc_table.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), colors.HexColor('#1a3a6b')),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 10),
('FONTSIZE', (0,1), (-1,-1), 9),
('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, colors.HexColor('#f0f4ff')]),
('GRID', (0,0), (-1,-1), 0.5, colors.HexColor('#cccccc')),
('ALIGN', (0,0), (0,-1), 'CENTER'),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('TOPPADDING', (0,0), (-1,-1), 3),
('BOTTOMPADDING', (0,0), (-1,-1), 3),
]))
story.append(toc_table)
story.append(PageBreak())
# Topic pages
for topic in TOPICS:
print(f"Processing: {topic['title']}")
story.append(Paragraph(topic['title'], title_style))
story.append(Spacer(1, 0.2*cm))
# Key notes
for note in topic['notes']:
story.append(Paragraph(f"• {note}", note_style))
story.append(Spacer(1, 0.3*cm))
story.append(HRFlowable(width="100%", thickness=1, color=colors.HexColor('#cccccc')))
story.append(Spacer(1, 0.2*cm))
# Two diagrams
for j, (diag_title, source, key) in enumerate(topic['diagrams'], 1):
story.append(Paragraph(f"Diagram {j}: {diag_title}", subtitle_style))
if source == "url":
img = get_url_img(key)
else:
img = get_local_img(key)
if img:
story.append(img)
else:
story.append(img_placeholder(f"[{diag_title}]"))
story.append(Spacer(1, 0.3*cm))
story.append(PageBreak())
# Build
print("\nBuilding PDF...")
doc.build(story)
print(f"PDF created: {OUT}")
size = os.path.getsize(OUT) / 1024 / 1024
print(f"File size: {size:.2f} MB")
cd /tmp/workspace/biomech-pdf && python build_pdf.py 2>&1
Biomechanics 5Marks Diagrams
PDF Document · PDF
| Topics | Diagram Type |
|---|---|
| Supination/Pronation, Gait, Scapulohumeral Rhythm, Meniscus, Ligamentum Flavum, Sliding Filament, ACL, Patellofemoral JRF, Foot Arches | Clinical/research images from medical literature |
| Osteokinematics, TFCC, Linear Force, Connective Tissue, Load-Deformation, Pelvic Tilt, Scoliosis, Grip/Grasp, Active-Passive Insufficiency, Hip Angles, Coracoacromial Arch, Ideal Posture, Pivot Joint, Anatomical Pulley, Femur Angles, Extensor Mechanism, Shoulder Stability, Factors Affecting Muscle, Loading of Foot, Sensory Receptors | Custom-drawn educational diagrams with labels, tables & annotations |