Orthopaedic disease with examination
Look → Feel → Move → Special Tests

| Movement | Normal Range |
|---|---|
| Flexion | 0-180° |
| Extension | 0-60° |
| Abduction | 0-180° |
| Adduction | 0-50° |
| Internal rotation | 0-90° |
| External rotation | 0-60° |
| Test | Technique | Significance |
|---|---|---|
| Impingement sign (Neer) | Passive forward flexion >90° | Pain = impingement syndrome |
| Hawkins' test | Passive FF to 90° + internal rotation | Pain = impingement |
| Jobe's test (Empty can) | Resisted pronation/FF at 90° in scapular plane | Pain = supraspinatus lesion |
| Drop-arm test | Arm placed in abduction then released | Cannot maintain = supraspinatus rupture |
| Hornblower sign | Resisted ER with arm at 90° abduction | Pain = infraspinatus / teres minor lesion |
| Lift-off test (Gerber) | Arm in internal rotation behind back | Cannot lift off = subscapularis tear |
| Bear-hug test | Patient's hand on opposite shoulder; examiner lifts it | Cannot maintain = subscapularis lesion |
| Belly-push test | Elbow held anteriorly with abduction pressure | Cannot hold elbow forward = subscapularis |
| Apprehension test | Supine, 90° abduction + ER | Apprehension = anterior instability |
| Relocation test | Posterior force during apprehension test | Relief = anterior instability |
| Sulcus sign | Inferior traction on arm at side | Gap below acromion = inferior laxity |
| O'Brien test | 10° adduction, 90° FF, maximal pronation; resist | Pain = SLAP lesion or AC joint pathology |
| Speed's test | Resisted FF with elbow extended, forearm supinated | Pain in bicipital groove = biceps tendinopathy |
| Stage | Name | Duration | Features |
|---|---|---|---|
| 1 | Pre-adhesive | Weeks-months | Nocturnal pain, full ROM initially |
| 2 | Freezing | 3-9 months | Pain + progressive loss of ROM |
| 3 | Frozen | 9-15 months | Stiffness predominates; pain decreases |
| 4 | Thawing | 15-24 months | Gradual ROM recovery |
| Movement | Normal |
|---|---|
| Flexion-Extension | -5° (hyperextension) to 150° |
| Pronation | 70° |
| Supination | 90° |
| Movement | Normal |
|---|---|
| Flexion | 75-80° |
| Extension | 70-75° |
| Radial deviation | 15° |
| Ulnar deviation | 30-40° |
| Test | Method | Significance |
|---|---|---|
| Tinel's sign | Tap over carpal tunnel at wrist flexor retinaculum | Paraesthesia in median nerve distribution |
| Phalen's manoeuvre | Wrist fully flexed (dorsal surfaces back to back) for 60 seconds | Reproduces symptoms - most specific |
| Carpal compression test | Direct pressure over carpal tunnel | Most sensitive test |
| Reverse Phalen (prayer sign) | Wrist extended back to back | Symptom reproduction |
| Condition | Location | Key Sign | Investigation | Treatment |
|---|---|---|---|---|
| Frozen shoulder | GHJ | Equal active = passive loss of ER | X-ray (normal), MRI | Physio, steroid injection, arthroscopic release |
| Supraspinatus tear | Shoulder | Drop-arm test, painful arc | MRI | Physio → surgical repair |
| Tennis elbow | Lateral epicondyle | Cozen's test, Mill's test | Clinical/MRI | Rest, brace, steroid injection |
| Golfer's elbow | Medial epicondyle | Resisted wrist flexion pain | Clinical | Same as tennis elbow |
| Colles' fracture | Distal radius | Dinner-fork deformity | X-ray | Cast; ORIF if unstable |
| Scaphoid fracture | Anatomical snuffbox | Snuffbox tenderness | MRI (gold standard) | Thumb spica; Herbert screw |
| Carpal Tunnel Syndrome | Wrist | Tinel's, Phalen's, thenar wasting | NCS/EMG | Splinting, injection; CTD surgery |
| Dupuytren's | Palm | Tabletop test | Clinical | Fasciectomy, collagenase |
| De Quervain's | Radial styloid | Finkelstein's test | Clinical | Splint, injection, release |
Generate a summary document or PDF guide of upper limb exam techniques
ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace empty or not foun…
mkdir -p /home/daytona/workspace/upper-limb-guide && echo "dir created"
~/upper-limb-guide/generate_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate
from reportlab.lib.colors import HexColor
OUTPUT = "/home/daytona/workspace/upper-limb-guide/Upper_Limb_Exam_Guide.pdf"
# ── Colour palette ──────────────────────────────────────────────────────────
C_NAVY = HexColor("#1B3A5C")
C_TEAL = HexColor("#1A7A8A")
C_LTBLUE = HexColor("#D6EAF8")
C_MINT = HexColor("#E8F8F5")
C_GOLD = HexColor("#F0A500")
C_WHITE = colors.white
C_BLACK = colors.black
C_LGREY = HexColor("#F4F6F7")
C_DGREY = HexColor("#555555")
C_RED = HexColor("#C0392B")
C_GREEN = HexColor("#1E8449")
# ── Page numbering ───────────────────────────────────────────────────────────
def on_page(canvas, doc):
canvas.saveState()
w, h = A4
# Header bar
canvas.setFillColor(C_NAVY)
canvas.rect(0, h - 22*mm, w, 22*mm, fill=1, stroke=0)
canvas.setFillColor(C_WHITE)
canvas.setFont("Helvetica-Bold", 10)
canvas.drawString(15*mm, h - 13*mm, "UPPER LIMB ORTHOPAEDIC EXAMINATION GUIDE")
canvas.setFont("Helvetica", 9)
canvas.drawRightString(w - 15*mm, h - 13*mm, "Clinical Reference")
# Footer
canvas.setFillColor(C_NAVY)
canvas.rect(0, 0, w, 12*mm, fill=1, stroke=0)
canvas.setFillColor(C_WHITE)
canvas.setFont("Helvetica", 8)
canvas.drawString(15*mm, 4*mm, "Sources: Bailey & Love 28th Ed | Miller's Review of Orthopaedics 9th Ed | Campbell's Operative Orthopaedics 15th Ed 2026")
canvas.drawRightString(w - 15*mm, 4*mm, f"Page {doc.page}")
canvas.restoreState()
# ── Document setup ───────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
topMargin=28*mm,
bottomMargin=18*mm,
leftMargin=18*mm,
rightMargin=18*mm,
title="Upper Limb Orthopaedic Examination Guide",
author="Orris Medical Reference",
)
styles = getSampleStyleSheet()
# Custom styles
def S(name, parent="Normal", **kwargs):
return ParagraphStyle(name, parent=styles[parent], **kwargs)
sTitle = S("sTitle", "Title", fontSize=26, textColor=C_WHITE, alignment=TA_CENTER, spaceAfter=4)
sSubtitle = S("sSubtitle", "Normal", fontSize=12, textColor=HexColor("#AED6F1"), alignment=TA_CENTER, spaceAfter=6)
sH1 = S("sH1", "Heading1",fontSize=14, textColor=C_WHITE, spaceAfter=4, spaceBefore=2, leading=18)
sH2 = S("sH2", "Heading2",fontSize=12, textColor=C_NAVY, spaceAfter=3, spaceBefore=8, leading=16)
sH3 = S("sH3", "Heading3",fontSize=10, textColor=C_TEAL, spaceAfter=2, spaceBefore=6, leading=14)
sBody = S("sBody", "Normal", fontSize=9, textColor=C_BLACK, spaceAfter=3, leading=13, alignment=TA_JUSTIFY)
sBullet = S("sBullet", "Normal", fontSize=9, textColor=C_BLACK, spaceAfter=2, leading=12, leftIndent=12, bulletIndent=0)
sNote = S("sNote", "Normal", fontSize=8, textColor=C_DGREY, spaceAfter=2, leading=11, leftIndent=6, fontName="Helvetica-Oblique")
sCaption = S("sCaption", "Normal", fontSize=8, textColor=C_DGREY, alignment=TA_CENTER, spaceAfter=4)
sTH = S("sTH", "Normal", fontSize=8, textColor=C_WHITE, fontName="Helvetica-Bold", leading=11)
sTD = S("sTD", "Normal", fontSize=8, textColor=C_BLACK, leading=11)
sTD2 = S("sTD2", "Normal", fontSize=8, textColor=C_BLACK, leading=11, fontName="Helvetica-Bold")
sAlert = S("sAlert", "Normal", fontSize=9, textColor=C_RED, fontName="Helvetica-Bold", spaceAfter=3, leading=12)
sGreen = S("sGreen", "Normal", fontSize=9, textColor=C_GREEN, fontName="Helvetica-Bold", spaceAfter=3, leading=12)
# ── Helpers ──────────────────────────────────────────────────────────────────
def section_header(title, subtitle=""):
"""Navy banner heading."""
w = A4[0] - 36*mm
data = [[Paragraph(title, sH1)]]
t = Table(data, colWidths=[w])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_NAVY),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("ROUNDEDCORNERS", [4,4,4,4]),
]))
items = [t]
if subtitle:
items.append(Paragraph(subtitle, sNote))
items.append(Spacer(1, 3*mm))
return items
def subsection(title):
return [Paragraph(title, sH2), HRFlowable(width="100%", thickness=1, color=C_TEAL, spaceAfter=3)]
def sub2(title):
return [Paragraph(title, sH3)]
def bullet(text, bold_prefix=""):
if bold_prefix:
full = f"<b>{bold_prefix}</b> {text}"
else:
full = text
return Paragraph(f"\u2022 {full}", sBullet)
def note(text):
return Paragraph(f"<i>{text}</i>", sNote)
def alert(text):
return Paragraph(f"⚠ {text}", sAlert)
def tip(text):
return Paragraph(f"✓ {text}", sGreen)
def make_table(headers, rows, col_widths=None, alt_rows=True):
w = A4[0] - 36*mm
if col_widths is None:
n = len(headers)
col_widths = [w/n]*n
header_row = [Paragraph(h, sTH) for h in headers]
table_data = [header_row]
for r in rows:
table_data.append([Paragraph(str(c), sTD) for c in r])
t = Table(table_data, colWidths=col_widths, repeatRows=1)
style = [
("BACKGROUND", (0,0), (-1,0), C_NAVY),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_WHITE, C_LGREY] if alt_rows else [C_WHITE]),
("GRID", (0,0), (-1,-1), 0.4, HexColor("#CCCCCC")),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 6),
("RIGHTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "TOP"),
]
t.setStyle(TableStyle(style))
return t
def highlight_box(text, bg=C_LTBLUE, border=C_TEAL):
w = A4[0] - 36*mm
t = Table([[Paragraph(text, sBody)]], colWidths=[w])
t.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("LINEABOVE", (0,0), (-1,0), 2, border),
("LINEBELOW", (0,-1),(-1,-1),2, border),
("LEFTPADDING", (0,0), (-1,-1), 10),
("RIGHTPADDING", (0,0), (-1,-1), 10),
("TOPPADDING", (0,0), (-1,-1), 6),
("BOTTOMPADDING", (0,0), (-1,-1), 6),
]))
return t
# ── Content builder ──────────────────────────────────────────────────────────
story = []
# ── COVER PAGE ───────────────────────────────────────────────────────────────
w_page, h_page = A4
# Title block
story.append(Spacer(1, 20*mm))
cover_title = Table([[Paragraph(
"<font color='white'><b>UPPER LIMB</b></font>",
S("CT", fontSize=36, textColor=C_WHITE, alignment=TA_CENTER, leading=42))
]], colWidths=[A4[0]-36*mm])
cover_title.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_NAVY),
("TOPPADDING", (0,0),(-1,-1), 14),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 10),
]))
story.append(cover_title)
cover_sub = Table([[Paragraph(
"<font color='white'>Orthopaedic Examination Guide</font>",
S("CS", fontSize=18, textColor=C_WHITE, alignment=TA_CENTER))
]], colWidths=[A4[0]-36*mm])
cover_sub.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_TEAL),
("TOPPADDING", (0,0),(-1,-1), 8),
("BOTTOMPADDING", (0,0),(-1,-1), 8),
("LEFTPADDING", (0,0),(-1,-1), 10),
]))
story.append(cover_sub)
story.append(Spacer(1, 8*mm))
# Cover info box
cover_info = [
["JOINT", "CONDITIONS COVERED"],
["Shoulder", "Frozen shoulder, Rotator cuff tears, Dislocation, Impingement"],
["Elbow", "Tennis elbow, Golfer's elbow, Supracondylar fracture, OA"],
["Wrist", "Colles' fracture, Scaphoid fracture, De Quervain's"],
["Hand", "Carpal tunnel syndrome, Dupuytren's contracture"],
]
cw = [(A4[0]-36*mm)*0.25, (A4[0]-36*mm)*0.75]
ct = Table(cover_info, colWidths=cw)
ct.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,0), C_TEAL),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_LTBLUE, C_WHITE]),
("TEXTCOLOR", (0,0), (-1,0), C_WHITE),
("FONTNAME", (0,0), (-1,0), "Helvetica-Bold"),
("FONTNAME", (0,1), (0,-1), "Helvetica-Bold"),
("FONTSIZE", (0,0), (-1,-1), 9),
("GRID", (0,0), (-1,-1), 0.5, HexColor("#AAAAAA")),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 8),
]))
story.append(ct)
story.append(Spacer(1, 8*mm))
# Exam framework reminder
story.append(highlight_box(
"<b>UNIVERSAL EXAMINATION SEQUENCE</b> \u2192 "
"<b>LOOK</b> (inspect) \u2192 <b>FEEL</b> (palpate) \u2192 <b>MOVE</b> (active \u2192 passive \u2192 resisted) \u2192 <b>SPECIAL TESTS</b> \u2192 <b>NEUROVASCULAR</b>",
bg=C_MINT, border=C_GREEN
))
story.append(Spacer(1, 5*mm))
story.append(note("Sources: Bailey & Love's Short Practice of Surgery 28th Ed | Miller's Review of Orthopaedics 9th Ed | Campbell's Operative Orthopaedics 15th Ed 2026 | S Das Manual on Clinical Surgery 13th Ed"))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════════════════════
# SECTION 1 – SHOULDER
# ═══════════════════════════════════════════════════════════════════════════
story += section_header("SECTION 1 — THE SHOULDER", "Glenohumeral joint examination & common conditions")
story += subsection("Anatomy Reminders")
story.append(bullet("Ball-and-socket joint — greatest ROM, least intrinsic stability"))
story.append(bullet("Rotator cuff: <b>S</b>upraspinatus, <b>I</b>nfraspinatus, <b>T</b>eres minor, <b>S</b>ubscapularis (SITS)"))
story.append(bullet("Pain anterolateral; referred pain from cervical spine, heart, mediastinum, diaphragm"))
story.append(bullet("Axillary nerve supplies deltoid + 'regimental badge area' of lateral arm"))
story.append(Spacer(1, 3*mm))
story += subsection("LOOK")
story.append(bullet("Strip to waist. Inspect front, side, back — compare both sides"))
story.append(bullet("Attitude: Clavicle fracture / anterior dislocation → patient supports flexed elbow with other hand"))
story.append(bullet("Deformity: Flattening = dislocation (greater tuberosity displaced medially); step deformity at ACJ"))
story.append(bullet("Muscle wasting: Deltoid wasting = axillary nerve palsy; supraspinous/infraspinous fossa wasting = rotator cuff"))
story.append(bullet("Scars: Anterior (deltopectoral) | Lateral (deltoid-splitting) | Posterior ports (arthroscopy)"))
story.append(Spacer(1, 3*mm))
story += subsection("FEEL")
story.append(bullet("Test 'regimental badge area' sensation (upper lateral arm) — loss = axillary nerve injury"))
story.append(bullet("Palpate: Sternoclavicular joint → clavicle → AC joint → acromion → coracoid → greater tuberosity → bicipital groove"))
story.append(bullet("Localised ACJ pain = acromioclavicular pathology; diffuse = glenohumeral or referred"))
story.append(Spacer(1, 3*mm))
story += subsection("MOVE")
story.append(bullet("Stabilise scapula: thumb on coracoid + fingers on scapular spine — prevents scapulothoracic compensation"))
story.append(bullet("Start: arms at sides, elbows extended, palms forward (anatomical position)"))
story.append(bullet("Note pain throughout range — painful arc 60°–120° = supraspinatus/impingement"))
story.append(Spacer(1, 2*mm))
rom_data = [
["Movement", "Normal Range", "Clinical Note"],
["Flexion", "0–180°", "Loss = adhesive capsulitis, GHJ OA"],
["Extension", "0–60°", ""],
["Abduction", "0–180°", "Painful arc 60–120° = impingement"],
["Adduction", "0–50°", ""],
["External Rotation", "0–60°", "FIRST lost in frozen shoulder"],
["Internal Rotation", "0–90°", "Test: thumb to spine level"],
]
story.append(make_table(rom_data[0], rom_data[1:], col_widths=[(A4[0]-36*mm)*0.28,(A4[0]-36*mm)*0.22,(A4[0]-36*mm)*0.50]))
story.append(Spacer(1, 4*mm))
story += subsection("SPECIAL TESTS — SHOULDER")
story.append(Spacer(1, 2*mm))
story += sub2("Impingement / Rotator Cuff")
imp_data = [
["Test", "Technique", "Positive Finding & Meaning"],
["Impingement sign (Neer)", "Passive forward flexion >90°", "Pain = subacromial impingement"],
["Hawkins' test", "Passive FF 90° + internal rotation", "Pain = impingement syndrome"],
["Jobe's test (Empty can)", "Resisted pronation/FF at 90° in scapular plane", "Pain/weakness = supraspinatus lesion"],
["Drop-arm test", "Arm placed in abduction then released", "Cannot maintain = supraspinatus rupture"],
["Hornblower sign", "Resisted ER at 90° abduction", "Pain = infraspinatus / teres minor lesion"],
["Lift-off test (Gerber)", "Arm in IR behind back; lift off", "Cannot lift = subscapularis tear"],
["Bear-hug test", "Hand on opposite shoulder; examiner tries to lift", "Cannot maintain = subscapularis lesion"],
["Belly-push test", "Elbow held forward with abduction pressure", "Cannot hold elbow forward = subscapularis"],
]
story.append(make_table(imp_data[0], imp_data[1:],
col_widths=[(A4[0]-36*mm)*0.28,(A4[0]-36*mm)*0.35,(A4[0]-36*mm)*0.37]))
story.append(Spacer(1, 4*mm))
story += sub2("Instability Tests")
inst_data = [
["Test", "Technique", "Positive Finding & Meaning"],
["Apprehension test", "Supine: 90° abduction + ER", "Apprehension = anterior instability"],
["Relocation test", "Posterior force during apprehension", "Relief = anterior instability confirmed"],
["Load-and-shift test", "Ant/post force on humeral head", "Degree of translation = laxity"],
["Sulcus sign", "Inferior traction on arm at side", "Gap below acromion = inferior laxity"],
]
story.append(make_table(inst_data[0], inst_data[1:],
col_widths=[(A4[0]-36*mm)*0.28,(A4[0]-36*mm)*0.35,(A4[0]-36*mm)*0.37]))
story.append(Spacer(1, 4*mm))
story += sub2("Labrum / Biceps Tests")
lab_data = [
["Test", "Technique", "Positive Finding & Meaning"],
["O'Brien (Active compression)", "10° adduction, 90° FF, max pronation; resist", "Pain = SLAP lesion / ACJ pathology"],
["Speed's test", "Resisted FF, elbow extended, forearm supinated", "Pain in bicipital groove = biceps tendinopathy"],
["Yergason's test", "Resisted supination with elbow at 90°", "Pain in groove = biceps tendinopathy / SLAP"],
]
story.append(make_table(lab_data[0], lab_data[1:],
col_widths=[(A4[0]-36*mm)*0.28,(A4[0]-36*mm)*0.38,(A4[0]-36*mm)*0.34]))
story.append(Spacer(1, 3*mm))
story.append(alert("Always obtain X-rays before diagnosing frozen shoulder — exclude GHJ osteoarthritis and locked posterior dislocation (both cause selective ER loss)."))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════════════════════
# SECTION 2 – SHOULDER CONDITIONS
# ═══════════════════════════════════════════════════════════════════════════
story += section_header("SECTION 2 — SHOULDER CONDITIONS")
story += subsection("Frozen Shoulder (Adhesive Capsulitis)")
story.append(bullet("Age 40–70 years; female predominance; nondominant side more common"))
story.append(bullet("Associations: Diabetes mellitus (disproportionately affected, worse outcomes), thyroid disease, post-breast/chest surgery, prolonged immobilisation"))
story.append(bullet("Pathology: Fibrosis of CHL and rotator interval capsule; type III collagen + myofibroblasts (resembles Dupuytren histology)"))
story.append(Spacer(1, 2*mm))
stage_data = [
["Stage", "Name", "Duration", "Features"],
["1", "Pre-adhesive", "Weeks–months", "Nocturnal pain; ROM initially preserved"],
["2", "Freezing", "3–9 months", "Pain + progressive ROM loss"],
["3", "Frozen", "9–15 months", "Stiffness dominates; pain decreases"],
["4", "Thawing", "15–24 months", "Gradual ROM recovery"],
]
story.append(make_table(stage_data[0], stage_data[1:],
col_widths=[(A4[0]-36*mm)*0.08,(A4[0]-36*mm)*0.20,(A4[0]-36*mm)*0.22,(A4[0]-36*mm)*0.50]))
story.append(Spacer(1, 3*mm))
story.append(Paragraph("Key Examination Findings", sH3))
story.append(bullet("Global loss of all shoulder movements — active ROM = passive ROM"))
story.append(bullet("External rotation is FIRST and MOST affected movement"))
story.append(highlight_box(
"<b>KEY DISTINGUISHER:</b> Active ROM = Passive ROM \u2192 Frozen shoulder | Active < Passive ROM \u2192 Rotator cuff tear",
bg=C_LTBLUE, border=C_TEAL
))
story.append(Spacer(1, 2*mm))
story.append(Paragraph("Investigations & Treatment", sH3))
frozen_rx = [
["Modality", "Detail"],
["X-ray", "Normal — mandatory to exclude GHJ OA and posterior dislocation"],
["Arthrography", "Reduced joint volume (<10 mL vs normal 35 mL); loss of axillary recess"],
["MRI", "Capsular thickening, CHL thickening, obliterated subcoracoid fat triangle"],
["Conservative (90%)", "NSAIDs + physiotherapy (pendulum/Codman exercises) + intraarticular steroid injection"],
["Distention arthrography", "Hydrodistention — inflates and stretches capsule"],
["Surgical", "Closed manipulation under anaesthesia; arthroscopic capsular release (if 12–16 wks conservative fails)"],
]
story.append(make_table(frozen_rx[0], frozen_rx[1:],
col_widths=[(A4[0]-36*mm)*0.30,(A4[0]-36*mm)*0.70]))
story.append(Spacer(1, 5*mm))
story += subsection("Rotator Cuff Tears")
story.append(bullet("Supraspinatus most commonly torn (exits supraspinous fossa, passes under coracoacromial arch — 'critical zone' of poor vascularity)"))
story.append(bullet("Presentation: Painful arc, weakness on abduction/ER, nocturnal pain; may be acute (trauma) or degenerative (gradual)"))
story.append(bullet("Drop-arm test positive in complete supraspinatus rupture"))
story.append(bullet("No restriction of passive ROM — distinguishes from frozen shoulder"))
story.append(bullet("Investigations: X-ray (superior head migration in massive tear), Ultrasound (dynamic, good for tears), MRI (gold standard — size, retraction, fatty atrophy)"))
story.append(bullet("Treatment: Physiotherapy + subacromial steroid injection; arthroscopic/open cuff repair for full-thickness tears"))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════════════════════
# SECTION 3 – ELBOW
# ═══════════════════════════════════════════════════════════════════════════
story += section_header("SECTION 3 — THE ELBOW", "Hinge joint examination & common conditions")
story += subsection("Anatomy Reminders")
story.append(bullet("Hinge (trochleoulnar) + pivot (radioulnar) joint combined"))
story.append(bullet("Normal carrying angle: 9–14° valgus (physiological cubitus valgus); greater in females"))
story.append(bullet("Hueter's triangle: Medial epicondyle + lateral epicondyle + olecranon tip = equilateral triangle at 90° flexion"))
story.append(bullet("Normal range: −5° (hyperextension) to 150° flexion | Pronation 70° | Supination 90°"))
story.append(Spacer(1, 3*mm))
story += subsection("LOOK")
story.append(bullet("Attitude: Elbow held in flexion after most injuries. Child with swollen flexed elbow = supracondylar fracture until proven otherwise"))
story.append(bullet("Inspect from FRONT: Carrying angle, position (extended/flexed, pronated/supinated)"))
story.append(bullet("From BEHIND: Olecranon prominence posteriorly"))
story.append(bullet("From THE SIDE: Anteroposterior broadening = posterior dislocation or supracondylar fracture"))
story.append(Spacer(1, 2*mm))
carrying_data = [
["Deformity", "Definition", "Common Cause", "Complication"],
["Cubitus valgus", "Increased carrying angle >15–20°", "Malunion lateral condyle fracture (child)", "Tardy ulnar nerve palsy"],
["Cubitus varus\n(gun-stock deformity)", "Reversed/decreased carrying angle", "Malunited supracondylar fracture", "Mainly cosmetic"],
]
story.append(make_table(carrying_data[0], carrying_data[1:],
col_widths=[(A4[0]-36*mm)*0.25,(A4[0]-36*mm)*0.25,(A4[0]-36*mm)*0.27,(A4[0]-36*mm)*0.23]))
story.append(Spacer(1, 3*mm))
story += subsection("FEEL")
story.append(bullet("Cross-fluctuation test for joint effusion"))
story.append(bullet("Ulnar nerve: Roll under fingers between medial epicondyle and olecranon; assess distal ulnar sensation"))
story.append(bullet("Radial head: Palpate with thumb while pronating/supinating — feel for rotation, tenderness, irregularity"))
story.append(bullet("Springing the radius: Squeeze radius + ulna together distally → referred pain at upper radius = fracture head/neck radius"))
story.append(highlight_box(
"<b>Hueter's Triangle Rule:</b> Equilateral triangle at 90° = preserved in <b>supracondylar fracture</b> "
"(distal fragment moves as one). Triangle DISRUPTED in <b>posterior elbow dislocation</b> "
"(olecranon displaced posteriorly relative to epicondyles).",
bg=C_MINT, border=C_GREEN
))
story.append(Spacer(1, 3*mm))
story += subsection("MOVE")
story.append(bullet("Flexion–Extension: −5° to 150°"))
story.append(bullet("Pronation: 70° | Supination: 90° — tested with elbows at 90°"))
story.append(Spacer(1, 3*mm))
story += subsection("Elbow Conditions")
story += sub2("Lateral Epicondylitis (Tennis Elbow)")
story.append(bullet("Degenerative tendinopathy at origin of extensor carpi radialis brevis (ECRB) — NOT true inflammation"))
story.append(bullet("Peak: 5th decade; more common in non-athletes; risk factors: female, smoking, manual labour, statins"))
story.append(bullet("Mechanism: Repetitive supination/pronation with elbow near full extension"))
story.append(bullet("Tenderness: 5 mm distal and anterior to midpoint of lateral epicondyle"))
story.append(bullet("Pain: Exacerbated by resisted wrist dorsiflexion and forearm supination, gripping objects"))
story.append(Spacer(1, 2*mm))
te_tests = [
["Test", "Technique", "Positive"],
["Cozen's test", "Resisted wrist extension, elbow extended", "Pain at lateral epicondyle"],
["Mill's test", "Passive wrist flexion, elbow extended", "Pain at lateral epicondyle"],
["Middle finger test", "Resisted extension of middle finger", "Pain at ECRB origin (most specific for ECRB)"],
]
story.append(make_table(te_tests[0], te_tests[1:],
col_widths=[(A4[0]-36*mm)*0.25,(A4[0]-36*mm)*0.43,(A4[0]-36*mm)*0.32]))
story.append(Spacer(1, 2*mm))
story.append(bullet("X-ray: Usually normal (occasionally calcific tendinitis). MRI: Tendon thickening, increased T1/T2 signal at ECRB"))
story.append(bullet("Treatment: Conservative (84–95% respond): rest, ice, counter-force brace, physio, steroid injection"))
story.append(bullet("Surgical: Débridement/release of ECRB origin (open or arthroscopic) if conservative fails at 6 months"))
story.append(Spacer(1, 3*mm))
story += sub2("Medial Epicondylitis (Golfer's Elbow)")
story.append(bullet("Flexor-pronator origin tendinopathy at medial epicondyle (flexor carpi radialis, pronator teres)"))
story.append(bullet("Tenderness at medial epicondyle; pain with resisted wrist flexion + forearm pronation"))
story.append(bullet("Must exclude ulnar nerve entrapment at elbow (coexists in ~60% of cases)"))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════════════════════
# SECTION 4 – WRIST
# ═══════════════════════════════════════════════════════════════════════════
story += section_header("SECTION 4 — THE WRIST", "Examination and FOOSH injuries")
story += subsection("Anatomy Reminders")
story.append(bullet("Wrist ROM: Flexion 75–80° | Extension 70–75° | Radial deviation 15° | Ulnar deviation 30–40°"))
story.append(bullet("Normal parameters (X-ray): Volar tilt 11° | Radial inclination 22° | Radial height 12 mm"))
story.append(bullet("Lister's tubercle: Palpable on dorsal distal radius; 1 cm distal = scaphoid"))
story.append(bullet("Anatomical snuffbox: Between APL/EPB (radial border) and EPL (ulnar border) — SCAPHOID lies below"))
story.append(Spacer(1, 3*mm))
story += subsection("Colles' Fracture")
story.append(bullet("Transverse fracture of distal radius within 2.5 cm of wrist"))
story.append(bullet("Commonest fracture in adults >40 years; elderly osteoporotic women after FOOSH most typical"))
story.append(Spacer(1, 2*mm))
colles_data = [
["Feature", "Description"],
["Displacement (5Ds)", "Dorsal displacement, Dorsal angulation, radial Deviation, Dinner-fork Deformity, impacteD"],
["Examination", "Dinner-fork deformity on lateral view; radial deviation; local swelling and bruising"],
["X-ray (AP + Lateral)", "Confirm fracture; measure volar tilt, radial inclination, radial height"],
["Acceptable reduction", "Volar tilt ≥0°, radial inclination ≥15°, radial height shortening ≤3 mm"],
["Treatment", "Undisplaced: Below-elbow cast 6 wks. Displaced: Closed reduction (haematoma block or Bier's) + cast. Unstable: K-wires or volar locking plate (ORIF)"],
["Complications", "CRPS (Sudeck's atrophy), malunion, median nerve injury, EPL rupture, carpal tunnel syndrome"],
]
story.append(make_table(colles_data[0], colles_data[1:],
col_widths=[(A4[0]-36*mm)*0.28,(A4[0]-36*mm)*0.72]))
story.append(Spacer(1, 5*mm))
story += subsection("Scaphoid Fracture")
story.append(alert("Most commonly MISSED fracture — 30% have normal initial X-ray. Normal X-ray does NOT exclude scaphoid fracture."))
story.append(bullet("Mechanism: FOOSH with wrist in dorsiflexion and radial deviation"))
story.append(bullet("Blood supply enters distally — proximal pole fractures risk avascular necrosis (AVN)"))
story.append(Spacer(1, 2*mm))
scaph_tests = [
["Clinical Test", "Technique", "Positive Finding"],
["Anatomical snuffbox tenderness", "Palpate dorsal snuffbox with wrist in ulnar deviation", "Tenderness = scaphoid # until proven otherwise"],
["Scaphoid tubercle tenderness", "Palpate volar tubercle at wrist crease", "Tenderness (more specific than snuffbox)"],
["Scaphoid compression test", "Axial compression along axis of thumb", "Pain at wrist"],
["Telescoping test", "Telescoping the thumb proximally", "Pain at scaphoid"],
]
story.append(make_table(scaph_tests[0], scaph_tests[1:],
col_widths=[(A4[0]-36*mm)*0.30,(A4[0]-36*mm)*0.38,(A4[0]-36*mm)*0.32]))
story.append(Spacer(1, 3*mm))
scaph_rx = [
["Investigation", "Role"],
["X-ray (AP, lateral, scaphoid views)", "First line; may be NORMAL acutely — repeat at 10–14 days if clinical suspicion"],
["MRI", "Most sensitive and specific — detects fracture within 24–48 hours"],
["CT", "Best for assessing displacement and union"],
["Bone scan", "Sensitive but non-specific; use if MRI unavailable"],
]
story.append(make_table(scaph_rx[0], scaph_rx[1:],
col_widths=[(A4[0]-36*mm)*0.38,(A4[0]-36*mm)*0.62]))
story.append(Spacer(1, 3*mm))
story += sub2("Treatment")
story.append(bullet("Undisplaced waist: Thumb spica cast 8–12 weeks"))
story.append(bullet("Displaced (>1 mm) or proximal pole: Surgical fixation (Herbert screw)"))
story.append(bullet("Non-union/AVN: Bone grafting + fixation; vascularised bone graft (1,2-ICSRA graft)"))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════════════════════
# SECTION 5 – HAND
# ═══════════════════════════════════════════════════════════════════════════
story += section_header("SECTION 5 — THE HAND", "Carpal tunnel syndrome, Dupuytren's, De Quervain's")
story += subsection("Carpal Tunnel Syndrome (CTS)")
story.append(bullet("Most common entrapment neuropathy — median nerve compressed under flexor retinaculum"))
story.append(bullet("Anatomy: Carpal tunnel = carpal bones (3 sides) + transverse carpal ligament (floor). Contains 9 flexor tendons + median nerve"))
story.append(bullet("Epidemiology: More common in women; ~3% of adults; common in pregnancy"))
story.append(Spacer(1, 2*mm))
cts_aet = [
["Category", "Causes"],
["Inflammatory", "Rheumatoid arthritis, tenosynovitis (most common cause)"],
["Metabolic/Endocrine", "Hypothyroidism, diabetes mellitus, acromegaly, pregnancy"],
["Space-occupying", "Ganglion, lipoma, carpal fracture malunion, amyloidosis"],
["Occupation", "Repetitive wrist flexion/extension, vibrating tools"],
]
story.append(make_table(cts_aet[0], cts_aet[1:],
col_widths=[(A4[0]-36*mm)*0.28,(A4[0]-36*mm)*0.72]))
story.append(Spacer(1, 3*mm))
story.append(Paragraph("Clinical Features", sH3))
story.append(bullet("Pain, numbness, paraesthesia in radial 3½ digits (thumb, index, middle, radial half of ring)"))
story.append(bullet("Worse at night and with repetitive hand motion — 'flick sign' (shaking hand relieves symptoms)"))
story.append(bullet("Thenar wasting = late sign indicating chronic compression"))
story.append(bullet("Weakness of thumb abduction (abductor pollicis brevis)"))
story.append(Spacer(1, 2*mm))
cts_tests = [
["Test", "Technique", "Sensitivity / Significance"],
["Tinel's sign", "Tap over carpal tunnel at wrist flexor retinaculum", "Paraesthesia in median nerve distribution"],
["Phalen's manoeuvre", "Wrist fully flexed for 60 seconds (dorsal surfaces back to back)", "Symptom reproduction — most specific"],
["Carpal compression test", "Direct pressure over tunnel for 30 seconds", "Most sensitive clinical test"],
["Reverse Phalen", "Wrists extended back to back", "Symptom reproduction"],
["Abductor pollicis brevis test", "Resisted thumb abduction against resistance", "Weakness = thenar denervation"],
]
story.append(make_table(cts_tests[0], cts_tests[1:],
col_widths=[(A4[0]-36*mm)*0.27,(A4[0]-36*mm)*0.40,(A4[0]-36*mm)*0.33]))
story.append(Spacer(1, 3*mm))
story.append(Paragraph("Investigations & Treatment", sH3))
cts_rx = [
["Step", "Detail"],
["NCS / EMG", "Confirms diagnosis; prolonged sensory latency before motor latency; mandatory before surgery; 25% false-negative rate"],
["Conservative", "Night wrist splinting in neutral; activity modification; nerve gliding exercises; corticosteroid injection"],
["Surgical", "Carpal tunnel decompression — open or endoscopic division of flexor retinaculum. Equivalent long-term outcomes. Excellent results."],
["Indication for surgery", "Failed conservative measures OR thenar wasting (indicating muscle denervation)"],
]
story.append(make_table(cts_rx[0], cts_rx[1:],
col_widths=[(A4[0]-36*mm)*0.28,(A4[0]-36*mm)*0.72]))
story.append(Spacer(1, 5*mm))
story += subsection("Dupuytren's Contracture")
story.append(bullet("Progressive palmar fascial fibrosis → flexion contracture (ring and little fingers most common)"))
story.append(bullet("Pathology: Myofibroblast proliferation, type III collagen — histologically similar to frozen shoulder capsule"))
story.append(bullet("Associations: Male sex, Northern European descent, diabetes, alcohol, phenytoin, vibration exposure, HIV"))
story.append(bullet("Examination: Palmar pitting/dimpling, palpable nodules along fascial bands, MCPj and PIPj flexion deformity"))
story.append(bullet("Hueston tabletop test: Cannot place palm flat on table = significant contracture"))
story.append(bullet("Treatment: Observation if mild | Needle fasciotomy, collagenase injection (Xiaflex) | Fasciectomy (surgical)"))
story.append(bullet("Surgery indicated: MCP contracture ≥30° OR any degree of PIP contracture"))
story.append(Spacer(1, 5*mm))
story += subsection("De Quervain's Tenosynovitis")
story.append(bullet("Stenosing tenosynovitis of 1st dorsal extensor compartment: APL (abductor pollicis longus) + EPB (extensor pollicis brevis)"))
story.append(bullet("Common in new mothers (lifting infant); repetitive pinch-grip activities"))
story.append(bullet("Tenderness over radial styloid and 1st dorsal compartment; crepitus on movement"))
story.append(highlight_box(
"<b>Finkelstein's test:</b> Patient makes a fist with thumb inside fingers. "
"Examiner passively ulnar deviates the wrist. "
"Sharp pain at radial styloid = POSITIVE (De Quervain's).",
bg=C_LTBLUE, border=C_TEAL
))
story.append(Spacer(1, 2*mm))
story.append(bullet("Treatment: Thumb spica splint + NSAIDs → corticosteroid injection → surgical release of 1st compartment"))
story.append(PageBreak())
# ═══════════════════════════════════════════════════════════════════════════
# SECTION 6 – QUICK REFERENCE SUMMARY TABLE
# ═══════════════════════════════════════════════════════════════════════════
story += section_header("SECTION 6 — QUICK REFERENCE SUMMARY")
story.append(Spacer(1, 3*mm))
summary_data = [
["Condition", "Site", "Key Sign/Test", "Investigation", "1st-Line Tx", "Surgical Tx"],
["Frozen shoulder", "GHJ", "Equal active=passive loss; ER first", "X-ray (normal), MRI", "Physio, steroid inj", "Arthroscopic capsular release"],
["Rotator cuff tear", "Shoulder", "Drop-arm, painful arc, Jobe's", "MRI", "Physio, subacromial inj", "Arthroscopic repair"],
["Shoulder dislocation (ant)", "GHJ", "Flattening, anterior bulge", "X-ray AP + lateral", "Reduction (Kocher/Hippocratic)", "Latarjet / Bankart repair (recurrent)"],
["Tennis elbow", "Lateral epicondyle", "Cozen's, Mill's test", "Clinical ± MRI", "Brace, steroid inj", "ECRB release"],
["Golfer's elbow", "Medial epicondyle", "Resisted wrist flexion", "Clinical", "Brace, steroid inj", "Flexor-pronator release"],
["Supracondylar # humerus", "Elbow", "Posterior displacement; Hueter's intact", "X-ray", "MUA + K-wires", "ORIF if NV compromise"],
["Colles' fracture", "Distal radius", "Dinner-fork deformity", "X-ray", "Closed reduction + cast", "Volar locking plate ORIF"],
["Scaphoid fracture", "Wrist", "Snuffbox tenderness", "MRI (gold)", "Thumb spica 8–12 wks", "Herbert screw"],
["Carpal tunnel", "Wrist", "Phalen's, Tinel's, thenar wasting", "NCS/EMG", "Night splint, steroid inj", "CTD (open/endoscopic)"],
["Dupuytren's", "Palm", "Tabletop test", "Clinical", "Observation if mild", "Fasciectomy / Collagenase"],
["De Quervain's", "Radial styloid", "Finkelstein's test", "Clinical ± USS", "Splint + NSAID + inj", "1st compartment release"],
]
story.append(make_table(
summary_data[0], summary_data[1:],
col_widths=[
(A4[0]-36*mm)*0.16,
(A4[0]-36*mm)*0.10,
(A4[0]-36*mm)*0.20,
(A4[0]-36*mm)*0.16,
(A4[0]-36*mm)*0.18,
(A4[0]-36*mm)*0.20,
]
))
story.append(Spacer(1, 5*mm))
story += subsection("Classic Examination Mnemonics & Key Rules")
rules = [
("Regimental badge area", "Upper lateral arm sensation → axillary nerve. Loss after shoulder dislocation = axillary nerve palsy."),
("Active = Passive ROM loss", "Frozen shoulder (capsular contracture)"),
("Active < Passive ROM loss", "Rotator cuff tear (muscle/tendon discontinuity)"),
("Hueter's triangle INTACT", "Supracondylar fracture (distal fragment moves as one unit)"),
("Hueter's triangle DISRUPTED", "Posterior elbow dislocation (olecranon displaced)"),
("Anatomical snuffbox tenderness", "Scaphoid fracture until proven otherwise — treat + investigate even with normal X-ray"),
("Normal X-ray ≠ No fracture", "Scaphoid: 30% missed on initial films. Get MRI if clinically suspected."),
("Equal active = passive ROM", "Frozen shoulder — capsular disease"),
("Dinner-fork deformity", "Colles' fracture — dorsal displacement + angulation of distal radius"),
("Radial 3½ digits + night sx", "Carpal tunnel syndrome (median nerve)"),
("Ring + little finger contracture", "Dupuytren's contracture (ulnar palmar fascia)"),
("Finkelstein positive", "De Quervain's stenosing tenosynovitis"),
]
for rule, explanation in rules:
story.append(bullet(f"<b>{rule}:</b> {explanation}"))
story.append(Spacer(1, 5*mm))
story.append(highlight_box(
"<b>NEUROVASCULAR CHECK — Always at end of upper limb examination:</b> "
"Radial pulse | Capillary refill | Sensation in median / ulnar / radial nerve distributions | "
"Motor function of intrinsic hand muscles",
bg=C_MINT, border=C_GREEN
))
story.append(Spacer(1, 8*mm))
story.append(Paragraph(
"Sources: Bailey & Love's Short Practice of Surgery 28th Ed | Miller's Review of Orthopaedics 9th Ed | "
"Campbell's Operative Orthopaedics 15th Ed 2026 | S Das Manual on Clinical Surgery 13th Ed | "
"Textbook of Family Medicine 9th Ed",
sNote
))
# ── Build ────────────────────────────────────────────────────────────────────
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print("PDF generated:", OUTPUT)
cd /home/daytona/workspace/upper-limb-guide && python generate_pdf.py 2>&1
ls -lh /home/daytona/workspace/upper-limb-guide/Upper_Limb_Exam_Guide.pdf
Upper Limb Exam Guide
PDF Document · PDF
| Section | Content |
|---|---|
| Cover | Contents overview + universal exam sequence reminder |
| Section 1 — Shoulder Exam | Look/Feel/Move with ROM table + full special tests tables (impingement, instability, labrum/biceps) |
| Section 2 — Shoulder Conditions | Frozen shoulder (stages table, distinguisher box), Rotator cuff tears |
| Section 3 — Elbow | Look/Feel/Move + Hueter's triangle rule + Tennis elbow / Golfer's elbow with special tests |
| Section 4 — Wrist | Colles' fracture (5 Ds), Scaphoid fracture (clinical tests + imaging choice) |
| Section 5 — Hand | CTS (aetiology table, tests, treatment ladder), Dupuytren's, De Quervain's + Finkelstein's |
| Section 6 — Quick Reference | Master summary table of all 11 conditions + 12 classic clinical rules/mnemonics |
Lower limb
~/upper-limb-guide/generate_lower_limb_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.lib.colors import HexColor
OUTPUT = "/home/daytona/workspace/upper-limb-guide/Lower_Limb_Exam_Guide.pdf"
# ── Colour palette ──────────────────────────────────────────────────────────
C_NAVY = HexColor("#1B3A5C")
C_TEAL = HexColor("#1A7A8A")
C_LTBLUE = HexColor("#D6EAF8")
C_MINT = HexColor("#E8F8F5")
C_GOLD = HexColor("#F0A500")
C_WHITE = colors.white
C_BLACK = colors.black
C_LGREY = HexColor("#F4F6F7")
C_DGREY = HexColor("#555555")
C_RED = HexColor("#C0392B")
C_GREEN = HexColor("#1E8449")
def on_page(canvas, doc):
canvas.saveState()
w, h = A4
canvas.setFillColor(C_NAVY)
canvas.rect(0, h - 22*mm, w, 22*mm, fill=1, stroke=0)
canvas.setFillColor(C_WHITE)
canvas.setFont("Helvetica-Bold", 10)
canvas.drawString(15*mm, h - 13*mm, "LOWER LIMB ORTHOPAEDIC EXAMINATION GUIDE")
canvas.setFont("Helvetica", 9)
canvas.drawRightString(w - 15*mm, h - 13*mm, "Clinical Reference")
canvas.setFillColor(C_NAVY)
canvas.rect(0, 0, w, 12*mm, fill=1, stroke=0)
canvas.setFillColor(C_WHITE)
canvas.setFont("Helvetica", 8)
canvas.drawString(15*mm, 4*mm, "Sources: Bailey & Love 28th Ed | Miller's Review of Orthopaedics 9th Ed | Campbell's Operative Orthopaedics 15th Ed 2026 | S Das 13th Ed")
canvas.drawRightString(w - 15*mm, 4*mm, f"Page {doc.page}")
canvas.restoreState()
doc = SimpleDocTemplate(
OUTPUT, pagesize=A4,
topMargin=28*mm, bottomMargin=18*mm,
leftMargin=18*mm, rightMargin=18*mm,
title="Lower Limb Orthopaedic Examination Guide",
author="Orris Medical Reference",
)
styles = getSampleStyleSheet()
def S(name, parent="Normal", **kwargs):
return ParagraphStyle(name, parent=styles[parent], **kwargs)
sH1 = S("sH1","Heading1",fontSize=14,textColor=C_WHITE,spaceAfter=4,spaceBefore=2,leading=18)
sH2 = S("sH2","Heading2",fontSize=12,textColor=C_NAVY,spaceAfter=3,spaceBefore=8,leading=16)
sH3 = S("sH3","Heading3",fontSize=10,textColor=C_TEAL,spaceAfter=2,spaceBefore=6,leading=14)
sBody = S("sBody","Normal",fontSize=9,textColor=C_BLACK,spaceAfter=3,leading=13,alignment=TA_JUSTIFY)
sBullet= S("sBullet","Normal",fontSize=9,textColor=C_BLACK,spaceAfter=2,leading=12,leftIndent=12)
sNote = S("sNote","Normal",fontSize=8,textColor=C_DGREY,spaceAfter=2,leading=11,leftIndent=6,fontName="Helvetica-Oblique")
sTH = S("sTH","Normal",fontSize=8,textColor=C_WHITE,fontName="Helvetica-Bold",leading=11)
sTD = S("sTD","Normal",fontSize=8,textColor=C_BLACK,leading=11)
sAlert = S("sAlert","Normal",fontSize=9,textColor=C_RED,fontName="Helvetica-Bold",spaceAfter=3,leading=12)
sGreen = S("sGreen","Normal",fontSize=9,textColor=C_GREEN,fontName="Helvetica-Bold",spaceAfter=3,leading=12)
def section_header(title, subtitle=""):
w = A4[0] - 36*mm
data = [[Paragraph(title, sH1)]]
t = Table(data, colWidths=[w])
t.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1),C_NAVY),
("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6),
("LEFTPADDING",(0,0),(-1,-1),10),("RIGHTPADDING",(0,0),(-1,-1),10),
]))
items = [t]
if subtitle:
items.append(Paragraph(subtitle, sNote))
items.append(Spacer(1,3*mm))
return items
def subsection(title):
return [Paragraph(title, sH2), HRFlowable(width="100%",thickness=1,color=C_TEAL,spaceAfter=3)]
def sub2(title):
return [Paragraph(title, sH3)]
def bullet(text):
return Paragraph(f"\u2022 {text}", sBullet)
def note(text):
return Paragraph(f"<i>{text}</i>", sNote)
def alert(text):
return Paragraph(f"⚠ {text}", sAlert)
def tip(text):
return Paragraph(f"✓ {text}", sGreen)
def make_table(headers, rows, col_widths=None):
w = A4[0] - 36*mm
if col_widths is None:
n = len(headers)
col_widths = [w/n]*n
table_data = [[Paragraph(h, sTH) for h in headers]]
for r in rows:
table_data.append([Paragraph(str(c), sTD) for c in r])
t = Table(table_data, colWidths=col_widths, repeatRows=1)
t.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_NAVY),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_WHITE,C_LGREY]),
("GRID",(0,0),(-1,-1),0.4,HexColor("#CCCCCC")),
("TOPPADDING",(0,0),(-1,-1),4),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),6),("RIGHTPADDING",(0,0),(-1,-1),6),
("VALIGN",(0,0),(-1,-1),"TOP"),
]))
return t
def hbox(text, bg=C_LTBLUE, border=C_TEAL):
w = A4[0] - 36*mm
t = Table([[Paragraph(text, sBody)]], colWidths=[w])
t.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,-1),bg),
("LINEABOVE",(0,0),(-1,0),2,border),("LINEBELOW",(0,-1),(-1,-1),2,border),
("LEFTPADDING",(0,0),(-1,-1),10),("RIGHTPADDING",(0,0),(-1,-1),10),
("TOPPADDING",(0,0),(-1,-1),6),("BOTTOMPADDING",(0,0),(-1,-1),6),
]))
return t
# ────────────────────────────────────────────────────────────────────────────
story = []
# ── COVER ────────────────────────────────────────────────────────────────────
story.append(Spacer(1,18*mm))
ct = Table([[Paragraph("<font color='white'><b>LOWER LIMB</b></font>",
S("CT",fontSize=36,textColor=C_WHITE,alignment=TA_CENTER,leading=42))]],
colWidths=[A4[0]-36*mm])
ct.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_NAVY),
("TOPPADDING",(0,0),(-1,-1),14),("BOTTOMPADDING",(0,0),(-1,-1),4),
("LEFTPADDING",(0,0),(-1,-1),10)]))
story.append(ct)
cs = Table([[Paragraph("<font color='white'>Orthopaedic Examination Guide</font>",
S("CS",fontSize=18,textColor=C_WHITE,alignment=TA_CENTER))]],
colWidths=[A4[0]-36*mm])
cs.setStyle(TableStyle([("BACKGROUND",(0,0),(-1,-1),C_TEAL),
("TOPPADDING",(0,0),(-1,-1),8),("BOTTOMPADDING",(0,0),(-1,-1),8),
("LEFTPADDING",(0,0),(-1,-1),10)]))
story.append(cs)
story.append(Spacer(1,8*mm))
cover_info = [
["JOINT","CONDITIONS COVERED"],
["Hip","NOF fracture, Dislocation, OA, Perthes', SCFE, Developmental dysplasia"],
["Knee","ACL/PCL tears, Meniscal tears, OA, MCL/LCL, Patellofemoral syndrome"],
["Ankle","Ankle sprain (lateral ligament), Achilles tendon rupture"],
["Foot","Hallux valgus, Pes planus, Pes cavus, Plantar fasciitis, Metatarsalgia"],
]
cw = [(A4[0]-36*mm)*0.20,(A4[0]-36*mm)*0.80]
ci = Table(cover_info, colWidths=cw)
ci.setStyle(TableStyle([
("BACKGROUND",(0,0),(-1,0),C_TEAL),
("ROWBACKGROUNDS",(0,1),(-1,-1),[C_LTBLUE,C_WHITE]),
("TEXTCOLOR",(0,0),(-1,0),C_WHITE),
("FONTNAME",(0,0),(-1,0),"Helvetica-Bold"),
("FONTNAME",(0,1),(0,-1),"Helvetica-Bold"),
("FONTSIZE",(0,0),(-1,-1),9),
("GRID",(0,0),(-1,-1),0.5,HexColor("#AAAAAA")),
("TOPPADDING",(0,0),(-1,-1),5),("BOTTOMPADDING",(0,0),(-1,-1),5),
("LEFTPADDING",(0,0),(-1,-1),8),
]))
story.append(ci)
story.append(Spacer(1,8*mm))
story.append(hbox(
"<b>UNIVERSAL EXAMINATION SEQUENCE</b> \u2192 "
"<b>LOOK</b> (inspect) \u2192 <b>FEEL</b> (palpate) \u2192 "
"<b>MOVE</b> (active \u2192 passive \u2192 resisted) \u2192 "
"<b>SPECIAL TESTS</b> \u2192 <b>GAIT & NEUROVASCULAR</b>",
bg=C_MINT, border=C_GREEN
))
story.append(Spacer(1,5*mm))
story.append(note("Sources: Bailey & Love's Short Practice of Surgery 28th Ed | Miller's Review of Orthopaedics 9th Ed | "
"Campbell's Operative Orthopaedics 15th Ed 2026 | S Das Manual on Clinical Surgery 13th Ed | "
"Rheumatology 2022 Elsevier"))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# SECTION 1 – HIP
# ════════════════════════════════════════════════════════════════════════════
story += section_header("SECTION 1 — THE HIP",
"Ball-and-socket joint — examine spine, abdomen, pelvis, groin, thigh & consider gynaecological causes in women")
story += subsection("Anatomy Reminders")
story.append(bullet("Ball-and-socket synovial joint: femoral head + acetabulum"))
story.append(bullet("Key bony landmarks: ASIS, iliac crest, greater trochanter, ischial tuberosity, pubic tubercle"))
story.append(bullet("Femoral artery: palpated at midpoint of inguinal ligament (ASIS to pubic tubercle)"))
story.append(bullet("Nerve supply: femoral nerve (L2–L4), obturator nerve (L2–L4), sciatic nerve (L4–S3)"))
story.append(Spacer(1,3*mm))
story += subsection("GAIT (Observe First — Before the Patient Lies Down)")
story.append(bullet("<b>Trendelenburg gait (gluteus medius lurch):</b> Pelvis drops to contralateral side during stance; trunk leans to ipsilateral side to compensate. Causes: hip OA, NOF fracture, superior gluteal nerve palsy, DDH"))
story.append(bullet("<b>Antalgic gait:</b> Short stance phase on painful side — minimises time weight-bearing on affected hip"))
story.append(bullet("<b>Scissors gait:</b> Spastic hip adductors — knees cross midline (cerebral palsy)"))
story.append(Spacer(1,3*mm))
story += subsection("LOOK (Standing → Supine)")
story.append(Paragraph("<b>Standing — inspect front, side, back:</b>", sBody))
story.append(bullet("Pelvic tilt: One ASIS higher than the other (true/apparent leg length discrepancy)"))
story.append(bullet("Rotational deformity: foot progression angle (in-toeing vs. out-toeing)"))
story.append(bullet("Gluteal wasting: abductor weakness; scoliosis secondary to pelvic tilt; lumbar lordosis"))
story.append(Paragraph("<b>Supine:</b>", sBody))
story.append(bullet("Scars and sinuses (previous surgery, septic arthritis)"))
story.append(bullet("Rotational deformity: patellae pointing outward/inward"))
story.append(bullet("Fixed adduction deformity (OA, cerebral palsy) → apparent shortening due to pelvic tilt"))
story.append(Spacer(1,3*mm))
story += subsection("FEEL")
story.append(bullet("Greater trochanter: tenderness = trochanteric bursitis or abductor enthesopathy"))
story.append(bullet("ASIS, iliac crest, pubic tubercle (bony landmarks for measurements)"))
story.append(bullet("Inguinal ligament: lymphadenopathy, hernia"))
story.append(bullet("Femoral pulse: palpate at midinguinal point. Absent in posterior dislocation (head of femur no longer supports artery from behind)"))
story.append(bullet("Posterior hip: ischial tuberosity tenderness (hamstring origin)"))
story.append(Spacer(1,3*mm))
story += subsection("MOVE")
story.append(Paragraph("<b>Passive Hip Movements (normal ranges):</b>", sBody))
hip_rom = [
["Movement","Normal Range","How to Test"],
["Flexion","0–120°","Supine; flex hip+knee. Modified Thomas' test for fixed flexion."],
["Extension","0–10°","Prone; lift leg off couch. (Or Thomas' test)"],
["Abduction","0–45°","Supine; stabilise contralateral ASIS; slide leg out"],
["Adduction","0–30°","Supine; cross leg over midline"],
["Internal rotation","0–45°","Hip+knee at 90°; swing foot outward"],
["External rotation","0–45°","Hip+knee at 90°; swing foot inward"],
]
story.append(make_table(hip_rom[0],hip_rom[1:],
col_widths=[(A4[0]-36*mm)*0.22,(A4[0]-36*mm)*0.18,(A4[0]-36*mm)*0.60]))
story.append(Spacer(1,2*mm))
story.append(alert("First movement lost in hip OA: Internal rotation — always test this!"))
story.append(Spacer(1,3*mm))
story += subsection("SPECIAL TESTS — HIP")
story.append(Spacer(1,2*mm))
hip_tests = [
["Test","Technique","Positive Finding & Meaning"],
["Thomas' test\n(fixed flexion deformity)","Patient supine. Flex both hips fully. Hold one hip flexed (flattens lumbar lordosis). Allow other leg to drop to couch.",
"Leg unable to reach couch = fixed flexion deformity of that hip. Angle = degree of FFD"],
["Trendelenburg test\n(abductor integrity)","Patient stands on one leg. Examiner stands behind.",
"Pelvis drops on contralateral (unsupported) side = POSITIVE. Weak abductors on standing leg (gluteus medius)"],
["Leg length measurement\n(True LLD)","ASIS to medial malleolus",
"Difference indicates true shortening (femoral/tibial). Compare both sides."],
["Apparent LLD","Xiphisternum to medial malleolus",
"Difference due to pelvic tilt/adduction contracture, not actual bone shortening"],
["Bryant's triangle","Patient supine. Vertical line from ASIS. Horizontal line from GT to meet it. Measure horizontal limb.",
"Shortened horizontal limb = upward displacement of GT (NOF #, posterior dislocation)"],
["Nelaton's line","Line from ASIS to ischial tuberosity in lateral decubitus",
"GT lies above line = upward displacement (NOF #, dislocation)"],
["FABER/Patrick test","Flex, Abduct, Externally Rotate hip (figure-of-4 position)",
"Anterior hip pain = hip joint pathology. Posterior pain = SI joint / L5–S1 referred"],
["FADIR/Impingement test","Flex hip 90°, Adduct, Internally Rotate",
"Anterior groin pain = femoroacetabular impingement (FAI) or labral tear"],
["Stinchfield test","Active straight-leg raise ~20 cm against mild resistance",
"Anterior hip pain = hip joint pathology (contracts iliopsoas and compresses joint)"],
["Ober's test","Lateral decubitus: lower leg flexed. Extend and abduct upper leg then let drop.",
"Leg fails to adduct below horizontal = tight iliotibial band (ITB)"],
["Log roll (Roll test)","Supine: rotate leg in/out gently at calf level",
"Stiffness or pain = hip joint irritability (useful in acute hip pathology)"],
]
story.append(make_table(hip_tests[0],hip_tests[1:],
col_widths=[(A4[0]-36*mm)*0.22,(A4[0]-36*mm)*0.38,(A4[0]-36*mm)*0.40]))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# SECTION 2 – HIP CONDITIONS
# ════════════════════════════════════════════════════════════════════════════
story += section_header("SECTION 2 — HIP CONDITIONS")
story += subsection("Hip Osteoarthritis (OA)")
story.append(bullet("Most common joint disease. Primary (idiopathic) or secondary (DDH, Perthes', SCFE, trauma)"))
story.append(bullet("Presentation: Groin pain (referred to knee), stiffness worse in morning/rest, antalgic or Trendelenburg gait"))
story.append(Paragraph("<b>Examination Findings:</b>", sBody))
story.append(bullet("Antalgic/Trendelenburg gait"))
story.append(bullet("Fixed flexion deformity (Thomas' test positive)"))
story.append(bullet("Internal rotation FIRST lost; then all movements restricted"))
story.append(bullet("Shortening of limb (advanced OA with superior/posterior head migration)"))
story.append(Paragraph("<b>Investigations:</b>", sBody))
story.append(bullet("X-ray (AP pelvis + lateral frog-leg): Loss of joint space (superolateral), subchondral sclerosis, osteophytes, subchondral cysts (LOSS)"))
story.append(bullet("MRI: Early cartilage loss, avascular necrosis, labral tears"))
story.append(Paragraph("<b>Treatment:</b>", sBody))
oa_rx = [
["Stage","Treatment"],
["Mild","Analgesia (paracetamol, NSAIDs), physiotherapy, weight loss, activity modification, walking aids"],
["Moderate","Intraarticular steroid injection, hyaluronic acid injection, bracing"],
["Severe / Failed conservative","Total Hip Replacement (THR) — gold standard; excellent long-term outcomes"],
]
story.append(make_table(oa_rx[0],oa_rx[1:],col_widths=[(A4[0]-36*mm)*0.18,(A4[0]-36*mm)*0.82]))
story.append(Spacer(1,5*mm))
story += subsection("Neck of Femur (NOF) Fracture")
story.append(alert("Elderly patient lying helplessly with externally rotated, shortened lower limb = NOF fracture until proven otherwise"))
story.append(Spacer(1,2*mm))
story.append(bullet("Commonest serious fracture in elderly; high morbidity/mortality (1-year mortality ~30%)"))
story.append(bullet("Mechanism: Low-energy fall in osteoporotic patients; high-energy trauma in young"))
story.append(Paragraph("<b>Garden Classification (Subcapital):</b>", sBody))
garden = [
["Grade","Description","Blood Supply"],
["I","Incomplete/impacted — valgus impaction","Usually intact"],
["II","Complete, non-displaced","Usually intact"],
["III","Complete, partial displacement — head partially rotated","Disrupted"],
["IV","Complete, full displacement — head rotated, trabeculae not aligned","Disrupted — HIGH AVN risk"],
]
story.append(make_table(garden[0],garden[1:],
col_widths=[(A4[0]-36*mm)*0.12,(A4[0]-36*mm)*0.55,(A4[0]-36*mm)*0.33]))
story.append(Spacer(1,3*mm))
story.append(Paragraph("<b>Examination Findings:</b>", sBody))
story.append(bullet("Lying helpless; cannot weight bear; extreme pain on any movement"))
story.append(bullet("Lower limb: <b>shortened, externally rotated</b> (sternomastoid + iliacus/iliopsoas retract and rotate fragment)"))
story.append(bullet("Bony tenderness on attempted rotation of shaft of femur (transcervical/subcapital)"))
story.append(bullet("Bryant's triangle: horizontal limb shortened (upward GT displacement)"))
story.append(bullet("Nelaton's line: GT above line"))
story.append(Paragraph("<b>Investigations:</b>", sBody))
story.append(bullet("X-ray (AP pelvis + lateral): Always obtain both views. Shenton's line disrupted."))
story.append(bullet("MRI: Most sensitive — detects occult fractures within 24–48 hours (superior to bone scan)"))
story.append(Paragraph("<b>Treatment (operative for almost all):</b>", sBody))
nof_rx = [
["Fracture Type","Patient","Treatment"],
["Intracapsular undisplaced (Garden I/II)","Young + elderly","DHS or cannulated screws"],
["Intracapsular displaced (Garden III/IV)","Elderly (>65)","Hemiarthroplasty (cemented Austin Moore/Thompson) or THR"],
["Intracapsular displaced (Garden III/IV)","Young (<65)","Reduction + internal fixation (preserve head)"],
["Extracapsular (intertrochanteric)","Any age","Dynamic Hip Screw (DHS)"],
["Subtrochanteric","Any","Intramedullary nail (e.g. PFNA)"],
]
story.append(make_table(nof_rx[0],nof_rx[1:],
col_widths=[(A4[0]-36*mm)*0.34,(A4[0]-36*mm)*0.22,(A4[0]-36*mm)*0.44]))
story.append(Spacer(1,5*mm))
story += subsection("Hip Dislocation")
story.append(Paragraph("<b>Posterior Dislocation (90% of hip dislocations):</b>", sBody))
story.append(bullet("Mechanism: Dashboard injury (knee hits dashboard forcing femoral head posteriorly) — high-energy RTA"))
story.append(bullet("Attitude: <b>Flexion, adduction, internal rotation</b> of the thigh"))
story.append(bullet("Limb: Shortened; fixed in above posture"))
story.append(bullet("Femoral pulse: Difficult to palpate (head absent from acetabulum)"))
story.append(bullet("Complications: Sciatic nerve injury (10–20%), avascular necrosis of femoral head, post-traumatic OA"))
story.append(Spacer(1,2*mm))
story.append(Paragraph("<b>Anterior Dislocation (rare):</b>", sBody))
story.append(bullet("Attitude: <b>Extension, abduction, external rotation</b> of the thigh"))
story.append(bullet("Femoral head palpable in groin (pubic/obturator type)"))
story.append(bullet("Treatment: Emergency closed reduction under GA; post-reduction CT to check for fragment"))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# SECTION 3 – KNEE
# ════════════════════════════════════════════════════════════════════════════
story += section_header("SECTION 3 — THE KNEE",
"Three compartments: medial, lateral, patellofemoral | Ligaments: ACL, PCL, MCL, LCL, posterolateral corner")
story += subsection("Anatomy Reminders")
story.append(bullet("Synovial hinge joint (+ slight rotation in last 15° of extension — 'screw-home mechanism')"))
story.append(bullet("ACL: Primary restraint to anterior tibial translation (resists anterior draw + rotational instability)"))
story.append(bullet("PCL: Primary restraint to posterior tibial translation (90°)"))
story.append(bullet("MCL (medial): Resists valgus stress + external rotation forces"))
story.append(bullet("LCL (lateral): Resists varus stress"))
story.append(bullet("Menisci: Shock absorption, load distribution, joint stability, lubrication"))
story.append(bullet("Extensor mechanism: Quadriceps → quadriceps tendon → patella → patellar tendon → tibial tuberosity"))
story.append(Spacer(1,3*mm))
story += subsection("LOOK")
story.append(bullet("<b>Standing:</b> Alignment — varus ('bow-legged', medial compartment OA) or valgus ('knock-knee'); measure intermalleolar/intercondylar distance"))
story.append(bullet("Fixed flexion deformity (FFD) from the side; recurvatum (hyperextension)"))
story.append(bullet("Quadriceps wasting — universal sign of chronic knee pathology"))
story.append(bullet("Gait: Antalgic (OA), varus thrust (medial compartment collapse), high-stepping (foot drop)"))
story.append(bullet("<b>Supine:</b> Swelling pattern — prepatellar bursa, Baker's cyst (popliteal), diffuse effusion"))
story.append(bullet("Scars (previous arthroscopy, ligament reconstruction, TKR)"))
story.append(Spacer(1,3*mm))
story += subsection("FEEL")
story.append(Paragraph("<b>Effusion Tests:</b>", sBody))
story.append(bullet("<b>Fluid displacement (stroke/bulge test):</b> Stroke fluid from medial side into suprapatellar pouch; press pouch inferiorly; fluid returns to medial side as a visible bulge — SMALL effusion"))
story.append(bullet("<b>Patellar tap test:</b> Compress fluid into joint; tap patella; floats off the trochlea — LARGE effusion"))
story.append(Spacer(1,2*mm))
story.append(Paragraph("<b>Palpation Points:</b>", sBody))
story.append(bullet("Joint line (medial and lateral) — tenderness = meniscal pathology or compartment OA"))
story.append(bullet("Tibial tuberosity — Osgood-Schlatter disease (adolescents); patellar tendon insertion"))
story.append(bullet("Inferior pole of patella — patellar tendinopathy ('jumper's knee')"))
story.append(bullet("Medial epicondyle of femur — MCL origin"))
story.append(bullet("Popliteal fossa — Baker's cyst (communicating with joint via posterior capsule); popliteal aneurysm"))
story.append(Spacer(1,3*mm))
story += subsection("MOVE")
story.append(bullet("Flexion–Extension: −5° (hyperextension) to 135°"))
story.append(bullet("<b>Lag test (extensor mechanism):</b> Ask patient to lift straight leg off bed (SLR). Then flex knee and try to straighten against gravity. Cannot re-straighten = extensor mechanism failure"))
story.append(bullet("Fixed flexion deformity: Patient prone — measure angle of FFD or height of heel off couch"))
story.append(Spacer(1,3*mm))
story += subsection("SPECIAL TESTS — KNEE")
story.append(Spacer(1,2*mm))
story += sub2("Cruciate Ligaments")
cr_tests = [
["Test","Technique","Positive Finding"],
["Lachman test (best for ACL)","Knee at 15–30° flexion; pull proximal tibia anteriorly",
"Excessive anterior translation with soft/absent end-point = ACL rupture. Most sensitive ACL test."],
["Anterior draw test (ACL)","Knee at 90°; sit on foot; draw tibia forward. Grade I <5 mm, II 5–10 mm, III >10 mm",
"Anterior translation = ACL injury. Also check for posterior sag before drawing."],
["Posterior draw test (PCL)","Knee at 90°; push tibia posteriorly. >10 mm = combined PCL + PLC",
"Posterior translation = PCL rupture"],
["Posterior sag sign (PCL)","Knees flexed 90°; look from side at tibial tuberosity level",
"Posterior sag of tibia = PCL rupture"],
["Pivot shift test (ACL)","Valgus + internal rotation force on flexed knee; then extend",
"Clunk as lateral tibial plateau reduces at ~30° = rotatory instability (ACL deficiency)"],
]
story.append(make_table(cr_tests[0],cr_tests[1:],
col_widths=[(A4[0]-36*mm)*0.27,(A4[0]-36*mm)*0.40,(A4[0]-36*mm)*0.33]))
story.append(Spacer(1,3*mm))
story += sub2("Collateral Ligaments")
col_tests = [
["Test","Technique","Positive Finding"],
["Valgus stress test (MCL)","Apply valgus force at 0° and 30° flexion",
"Laxity/pain at 30° = MCL tear. Laxity at 0° = complete MCL + cruciate injury."],
["Varus stress test (LCL)","Apply varus force at 0° and 30° flexion",
"Laxity/pain at 30° = LCL tear. Laxity at 0° = severe posterolateral corner injury."],
]
story.append(make_table(col_tests[0],col_tests[1:],
col_widths=[(A4[0]-36*mm)*0.27,(A4[0]-36*mm)*0.40,(A4[0]-36*mm)*0.33]))
story.append(Spacer(1,3*mm))
story += sub2("Menisci")
men_tests = [
["Test","Technique","Positive Finding"],
["Joint line tenderness","Flex knee 90°; palpate joint line with thumb + index",
"Tenderness = most sensitive clinical test for meniscal tear"],
["McMurray's test","Supine. Fully flex knee. Externally rotate + extend (medial); internally rotate + extend (lateral).",
"Palpable/audible click or pain at joint line = meniscal tear"],
["Thessaly test","Patient stands on one leg, flexes knee 20°, rotates body medially + laterally 3 times",
"Joint line pain or sensation of locking = meniscal tear (good sensitivity/specificity)"],
["Apley grind test","Prone; flex knee 90°; compress + rotate (grind) then distract + rotate",
"Pain with compression + rotation = meniscal tear; pain with distraction = ligament injury"],
]
story.append(make_table(men_tests[0],men_tests[1:],
col_widths=[(A4[0]-36*mm)*0.27,(A4[0]-36*mm)*0.40,(A4[0]-36*mm)*0.33]))
story.append(Spacer(1,3*mm))
story += sub2("Patellofemoral Joint")
pf_tests = [
["Test","Technique","Positive Finding"],
["Patellar apprehension\n(Fairbank's) test","Attempt to push patella laterally with knee extended. Also at 30° flexion.",
"Patient contracts quads / grabs examiner / complains of pain = lateral patellar instability"],
["J-sign / Patellar tracking","Patient extends knee slowly from 90° — observe patella path",
"Lateral jump at end of extension = maltracking (VMO weakness)"],
["Clarke's test (patellar grind)","Push patella distally; patient tenses quads",
"Pain = patellofemoral syndrome / chondromalacia patellae"],
]
story.append(make_table(pf_tests[0],pf_tests[1:],
col_widths=[(A4[0]-36*mm)*0.27,(A4[0]-36*mm)*0.40,(A4[0]-36*mm)*0.33]))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# SECTION 4 – KNEE CONDITIONS
# ════════════════════════════════════════════════════════════════════════════
story += section_header("SECTION 4 — KNEE CONDITIONS")
story += subsection("ACL Rupture")
story.append(bullet("Most common serious knee ligament injury; young athletic population (pivoting sports)"))
story.append(bullet("Mechanism: Non-contact deceleration + valgus collapse + internal rotation (most common); direct blow"))
story.append(bullet("Presentation: Haemarthrosis within 2 hours, 'pop' heard, immediate inability to continue sport"))
story.append(Paragraph("<b>Examination:</b>", sBody))
story.append(bullet("Lachman test positive (most sensitive, best performed acutely)"))
story.append(bullet("Anterior draw test positive (less sensitive acutely — hamstring guarding at 90°)"))
story.append(bullet("Pivot shift test positive (pathognomonic of rotatory instability but difficult acutely)"))
story.append(Paragraph("<b>Investigations:</b>", sBody))
story.append(bullet("X-ray: Segond fracture (avulsion of lateral tibial plateau = pathognomonic for ACL rupture)"))
story.append(bullet("MRI: Gold standard — shows ligament signal change/discontinuity, bone bruising, meniscal tears"))
story.append(Paragraph("<b>Treatment:</b>", sBody))
story.append(bullet("Conservative: Physiotherapy, quadriceps strengthening — for low-demand patients"))
story.append(bullet("Surgical: ACL reconstruction (hamstring/patellar tendon/quadriceps tendon graft) — for young, active patients or those with instability; arthroscopic"))
story.append(Spacer(1,5*mm))
story += subsection("Meniscal Tear")
story.append(bullet("Medial meniscus more commonly torn than lateral (less mobile; attached to MCL)"))
story.append(bullet("Mechanism: Twisting injury in young; degenerative in elderly"))
story.append(bullet("Presentation: Joint line pain, swelling, locking (bucket-handle tear), giving way"))
story.append(Paragraph("<b>Examination:</b>", sBody))
story.append(bullet("Joint line tenderness (most sensitive)"))
story.append(bullet("McMurray's test, Apley grind test positive"))
story.append(bullet("Locked knee (cannot achieve full extension) = bucket-handle meniscal tear"))
story.append(Paragraph("<b>Investigations:</b>", sBody))
story.append(bullet("MRI: Grade I = intrameniscal signal; Grade II = signal not reaching surface; Grade III = tear reaching articular surface (surgical)"))
story.append(Paragraph("<b>Treatment:</b>", sBody))
story.append(bullet("Conservative: RICE, physiotherapy for stable peripheral tears"))
story.append(bullet("Surgical: Arthroscopic meniscal repair (peripheral vascular zone — red zone) or partial meniscectomy (avascular — white zone)"))
story.append(Spacer(1,5*mm))
story += subsection("Knee Osteoarthritis")
story.append(bullet("Most common: medial compartment (varus knee → medial compartment loading)"))
story.append(bullet("Presentation: Insidious onset pain, crepitus, stiffness, deformity, functional limitation"))
story.append(Paragraph("<b>Examination:</b>", sBody))
story.append(bullet("Varus/valgus deformity; fixed flexion deformity; quadriceps wasting"))
story.append(bullet("Joint line tenderness; bony enlargement (osteophytes); crepitus on movement"))
story.append(bullet("Reduced ROM — flexion most affected"))
story.append(Paragraph("<b>Investigations:</b>", sBody))
story.append(bullet("Weight-bearing X-ray: Loss of joint space (medial > lateral), subchondral sclerosis, osteophytes, varus/valgus alignment (Kellgren-Lawrence grading)"))
story.append(Paragraph("<b>Treatment:</b>", sBody))
knee_oa_rx = [
["Stage","Treatment"],
["Mild–moderate","Analgesia, NSAIDs, physiotherapy, weight loss, activity modification, knee brace (unloader brace for unicompartmental OA)"],
["Moderate","Intraarticular steroid injection; hyaluronic acid injection"],
["Severe","Total Knee Replacement (TKR) or Unicompartmental Knee Replacement (UKR) — for isolated compartment disease in lower-demand patients"],
]
story.append(make_table(knee_oa_rx[0],knee_oa_rx[1:],
col_widths=[(A4[0]-36*mm)*0.18,(A4[0]-36*mm)*0.82]))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# SECTION 5 – ANKLE & FOOT
# ════════════════════════════════════════════════════════════════════════════
story += section_header("SECTION 5 — ANKLE & FOOT",
"Hindfoot (talus, calcaneus) | Midfoot (navicular, cuboid, cuneiforms) | Forefoot (metatarsals, phalanges)")
story += subsection("Anatomy Reminders")
story.append(bullet("Ankle (talocrural joint): Mortise joint — tibia, fibula, talus. Plantarflexion/dorsiflexion."))
story.append(bullet("Subtalar joint: Inversion/eversion of hindfoot"))
story.append(bullet("Lateral ligament complex: ATFL (anterior talofibular) + CFL (calcaneofibular) + PTFL (posterior talofibular)"))
story.append(bullet("ATFL: Most commonly torn in lateral ankle sprain (plantarflexion + inversion mechanism)"))
story.append(bullet("Medial deltoid ligament: Strong; rarely torn in isolation"))
story.append(bullet("Achilles tendon: Gastrocnemius + soleus → calcaneal insertion. 'Watershed zone' 2–6 cm above insertion"))
story.append(Spacer(1,3*mm))
story += subsection("LOOK (Standing → Supine)")
story.append(Paragraph("<b>Standing (weight-bearing assessment):</b>", sBody))
story.append(bullet("Overall limb alignment: Pelvic obliquity → LLD → knee valgus/varus → foot posture"))
story.append(bullet("Hindfoot (from behind): Achilles + calcaneus angle. Normal heel valgus 5–7°. Too many toes sign (>2 toes visible from behind = pes planus + forefoot abduction)"))
story.append(bullet("Medial longitudinal arch (from side): Absent = pes planus (flat foot); Exaggerated = pes cavus (high arch)"))
story.append(bullet("Forefoot: Hallux valgus (bunion), hallux rigidus; hammer/claw/mallet toe deformities"))
story.append(Spacer(1,2*mm))
toe_table = [
["Deformity","MTPj","PIPj","DIPj"],
["Claw toe","Hyperextension","Flexion","Flexion"],
["Hammer toe","Normal","Flexion","Extension or flexion"],
["Mallet toe","Normal","Normal","Flexion"],
["Hallux valgus","Valgus (lateral deviation)","Normal","—"],
]
story.append(make_table(toe_table[0],toe_table[1:],
col_widths=[(A4[0]-36*mm)*0.28,(A4[0]-36*mm)*0.24,(A4[0]-36*mm)*0.24,(A4[0]-36*mm)*0.24]))
story.append(Spacer(1,3*mm))
story.append(Paragraph("<b>Gait:</b>", sBody))
story.append(bullet("High-stepping gait = foot drop (common peroneal nerve palsy, L4 radiculopathy)"))
story.append(bullet("Antalgic gait = ankle/foot joint pain; short propulsive phase = forefoot pain"))
story.append(Paragraph("<b>Footwear inspection:</b>", sBody))
story.append(bullet("Normal wear: posterolateral heel (heel strike) + under big toe ball (toe-off)"))
story.append(bullet("Medial heel wear = hindfoot valgus/pes planus; lateral = hindfoot varus/pes cavus"))
story.append(Spacer(1,3*mm))
story += subsection("FEEL")
story.append(bullet("Skin: Reduced sensation in glove-and-stocking distribution = diabetes peripheral neuropathy"))
story.append(bullet("Pulses: Dorsalis pedis (dorsum of foot) + posterior tibial (behind medial malleolus)"))
story.append(bullet("Medial malleolus, lateral malleolus, base of 5th metatarsal, navicular: Specific bony tenderness points"))
story.append(bullet("Ottawa Rules tender points: Posterior 6 cm of fibula/tibia; base 5th MT; navicular → X-ray required"))
story.append(bullet("Achilles tendon: Palpate for defect, tenderness 2–6 cm above insertion (watershed zone)"))
story.append(bullet("Plantar fascia: Tenderness at calcaneal origin (plantar fasciitis)"))
story.append(Spacer(1,3*mm))
story += subsection("MOVE")
ankle_rom = [
["Movement","Joint","Normal Range"],
["Dorsiflexion","Talocrural","0–20°"],
["Plantarflexion","Talocrural","0–50°"],
["Inversion","Subtalar","0–35°"],
["Eversion","Subtalar","0–15°"],
["Toe extension/flexion","MTP/IP joints","Individually assessed"],
]
story.append(make_table(ankle_rom[0],ankle_rom[1:],
col_widths=[(A4[0]-36*mm)*0.30,(A4[0]-36*mm)*0.30,(A4[0]-36*mm)*0.40]))
story.append(Spacer(1,3*mm))
story += subsection("SPECIAL TESTS — ANKLE & FOOT")
ankle_tests = [
["Test","Technique","Positive Finding & Meaning"],
["Anterior draw test (ATFL)","Stabilise distal tibia; pull heel anteriorly in slight plantarflexion",
"Anterior translation of talus > 3–5 mm (or > other side) = ATFL tear"],
["Talar tilt test (CFL)","Invert heel with ankle in neutral; compare with other side",
"Increased tilt = CFL tear (combined ATFL + CFL = severe lateral ligament complex injury)"],
["Thompson (Simmonds') test\n(Achilles tendon integrity)","Patient prone, knee at 90°. Squeeze calf (gastrocnemius bulk).",
"No plantarflexion = POSITIVE = complete Achilles tendon rupture"],
["Single heel rise test","Stand on one foot; rise up onto tiptoe",
"Unable to rise = tibialis posterior dysfunction / Achilles weakness"],
["Silfverskiold test","Dorsiflexion measured with knee extended vs. flexed",
"Improved DF with knee flexed = gastrocnemius tightness (not combined gastrosoleus)"],
["Ottawa ankle rules","Bony tenderness at: posterior 6 cm fibula/tibia; base 5th MT; navicular",
"Any positive point = X-ray required to exclude fracture"],
]
story.append(make_table(ankle_tests[0],ankle_tests[1:],
col_widths=[(A4[0]-36*mm)*0.25,(A4[0]-36*mm)*0.38,(A4[0]-36*mm)*0.37]))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# SECTION 6 – ANKLE/FOOT CONDITIONS
# ════════════════════════════════════════════════════════════════════════════
story += section_header("SECTION 6 — ANKLE & FOOT CONDITIONS")
story += subsection("Lateral Ankle Sprain")
story.append(bullet("Most common musculoskeletal injury. Inversion + plantarflexion mechanism"))
story.append(bullet("Lateral ligament complex: ATFL (first), then CFL, then PTFL (most severe)"))
story.append(Paragraph("<b>Examination:</b>", sBody))
story.append(bullet("Swelling + bruising over lateral malleolus + ATFL territory"))
story.append(bullet("Anterior draw test + talar tilt test positive (acute = difficult due to guarding)"))
story.append(bullet("Apply Ottawa rules — X-ray if bony tenderness present"))
story.append(Paragraph("<b>Treatment:</b>", sBody))
story.append(bullet("RICE in acute phase; early functional rehabilitation; ankle brace"))
story.append(bullet("Chronic instability: Bröstrom repair (anatomical ligament reconstruction)"))
story.append(Spacer(1,5*mm))
story += subsection("Achilles Tendon Rupture")
story.append(alert("Thompson's test: Absence of plantarflexion on calf squeeze = complete Achilles rupture"))
story.append(bullet("Peak age: 30–50 years; 'weekend warriors'; fluoroquinolone use increases risk"))
story.append(bullet("Mechanism: Sudden explosive push-off (squash, tennis, basketball)"))
story.append(Paragraph("<b>Examination:</b>", sBody))
story.append(bullet("Sudden pain ('felt like being shot/kicked')"))
story.append(bullet("Palpable gap in tendon 2–6 cm above insertion (watershed zone)"))
story.append(bullet("Thompson's (Simmonds') test POSITIVE — most important clinical test"))
story.append(bullet("Patient can weakly plantarflex using long toe flexors (do not be falsely reassured)"))
story.append(Paragraph("<b>Investigations:</b>", sBody))
story.append(bullet("USS: Confirms tear, gap size, apposition in equinus"))
story.append(bullet("MRI: Detailed anatomy, partial vs. complete"))
story.append(Paragraph("<b>Treatment:</b>", sBody))
story.append(bullet("Non-operative: Functional bracing in equinus (progressive rehabilitation) — similar outcomes to surgery in some studies"))
story.append(bullet("Surgical: End-to-end repair — preferred in young, active patients; lower re-rupture rate"))
story.append(Spacer(1,5*mm))
story += subsection("Foot Conditions Summary")
foot_conds = [
["Condition","Typical Patient","Key Finding","Treatment"],
["Plantar fasciitis","Middle-aged, overweight, runners","Heel pain worst in morning 1st steps; tenderness at calcaneal origin of plantar fascia","Stretching, orthotics, steroid injection, ESWT"],
["Hallux valgus (bunion)","Middle-aged women; tight shoes","Lateral deviation of hallux; medial prominence; MTPj bursa","Shoes modification; osteotomy (scarf/chevron) if symptomatic"],
["Hallux rigidus","Adults 30–60","Stiff, painful 1st MTPj; dorsal osteophyte; reduced dorsiflexion","Stiff-soled shoes, orthotics; 1st MTPj fusion or cheilectomy"],
["Pes planus (flat foot)","All ages","Collapsed medial arch; too many toes sign; tibialis posterior tenderness","Physiotherapy, orthotics; corrective surgery for rigid flat foot"],
["Pes cavus","Neurological cause (CMT, spina bifida)","High arch; clawing of toes; calluses under metatarsal heads","Assess neurological cause; orthotics; corrective osteotomy"],
["Morton's neuroma","Middle-aged women","Burning/shooting pain 3rd–4th web space; Mulder's click","Wide shoes, metatarsal dome pad, steroid injection; surgical excision"],
["Ankle OA","Post-traumatic (recurrent sprains/fractures)","Reduced ankle ROM; joint line tenderness; varus/valgus deformity","Physiotherapy, bracing; ankle fusion (arthrodesis) or total ankle replacement"],
]
story.append(make_table(foot_conds[0],foot_conds[1:],
col_widths=[(A4[0]-36*mm)*0.18,(A4[0]-36*mm)*0.18,(A4[0]-36*mm)*0.31,(A4[0]-36*mm)*0.33]))
story.append(PageBreak())
# ════════════════════════════════════════════════════════════════════════════
# SECTION 7 – QUICK REFERENCE SUMMARY
# ════════════════════════════════════════════════════════════════════════════
story += section_header("SECTION 7 — QUICK REFERENCE SUMMARY")
story.append(Spacer(1,3*mm))
summary = [
["Condition","Site","Attitude/Deformity","Key Test","Investigation","Treatment"],
["Hip OA","Hip","Fixed flexion (Thomas'+)","IR first lost","X-ray: LOSS","Analgesia → THR"],
["NOF fracture","Hip","Short, ER, helpless","Bryant's triangle short","X-ray ± MRI","DHS/Hemiarthroplasty/THR"],
["Post. dislocation hip","Hip","Flex, adduct, IR","Head in buttock; posterior","X-ray (AP + lateral)","Urgent closed reduction"],
["Ant. dislocation hip","Hip","Extend, abduct, ER","Head in groin","X-ray","Closed reduction"],
["ACL rupture","Knee","Haemarthrosis","Lachman + pivot shift","MRI","Physio / ACL recon"],
["PCL rupture","Knee","Posterior sag","Posterior draw","MRI","Bracing / PCL recon"],
["Meniscal tear","Knee","Joint line pain","McMurray, joint line TTP","MRI","Repair or partial meniscectomy"],
["Knee OA","Knee","Varus; FFD","Crepitus, reduced ROM","WB X-ray","Analgesia → TKR/UKR"],
["Lat. ankle sprain","ATFL/CFL","Swelling lateral malleolus","Anterior draw, talar tilt","X-ray if Ottawa +","RICE, rehab, brace"],
["Achilles rupture","Tendo-Achilles","Palpable gap","Thompson + (no PF)","USS/MRI","Functional brace / repair"],
["Plantar fasciitis","Heel","Morning pain","Calcaneal origin TTP","Clinical ± USS","Stretching, steroid inj"],
["Hallux valgus","1st MTPj","Lateral hallux deviation","Bunion; MTPj ROM","X-ray (WB)","Shoes; osteotomy"],
]
story.append(make_table(summary[0],summary[1:],
col_widths=[
(A4[0]-36*mm)*0.18,
(A4[0]-36*mm)*0.08,
(A4[0]-36*mm)*0.19,
(A4[0]-36*mm)*0.18,
(A4[0]-36*mm)*0.16,
(A4[0]-36*mm)*0.21,
]))
story.append(Spacer(1,5*mm))
story += subsection("Classic Rules & Mnemonics")
rules = [
("<b>Trendelenburg gait</b>", "Pelvis drops CONTRALATERAL to weak abductor. Trunk leans IPSILATERAL to compensate."),
("<b>Thomas' test positive</b>", "Fixed flexion deformity of hip — hip cannot reach neutral extension."),
("<b>First movement lost in hip OA</b>", "Internal rotation."),
("<b>NOF fracture attitude</b>", "Shortened, externally rotated lower limb — helpless on floor."),
("<b>Posterior hip dislocation attitude</b>", "Flexion + adduction + internal rotation (FAIR)."),
("<b>Anterior hip dislocation attitude</b>", "Extension + abduction + external rotation."),
("<b>Haemarthrosis within 2 hours</b>", "ACL rupture, osteochondral fracture, peripheral meniscal tear (vascular zone), tibial plateau fracture."),
("<b>Lachman test</b>", "Most sensitive clinical test for ACL rupture. Perform at 15–30° flexion."),
("<b>Fluid displacement test</b>", "Small effusion. Patellar tap: large effusion."),
("<b>Joint line tenderness</b>", "Most sensitive clinical test for meniscal tear."),
("<b>Thompson's test positive</b>", "No plantarflexion on calf squeeze = complete Achilles rupture."),
("<b>Too many toes sign</b>", "Forefoot abduction + hindfoot valgus = pes planus."),
("<b>Ottawa ankle rules</b>", "Bony tenderness posterior fibula/tibia, base 5th MT, or navicular → X-ray."),
("<b>Segond fracture</b>", "Lateral tibial plateau avulsion on X-ray = pathognomonic ACL rupture."),
("<b>Shenton's line disrupted</b>", "Hip fracture or dislocation (smooth arc from inferior femoral neck to superior obturator foramen)."),
]
for rule, explanation in rules:
story.append(bullet(f"{rule}: {explanation}"))
story.append(Spacer(1,5*mm))
story.append(hbox(
"<b>NEUROVASCULAR CHECK — Always at end of lower limb examination:</b> "
"Femoral + popliteal + dorsalis pedis + posterior tibial pulses | Capillary refill | "
"Sensation in femoral / obturator / sciatic (common peroneal + tibial) distributions | "
"Motor function: hip flexion (L1–L2), knee extension (L3–L4), dorsiflexion (L4), plantarflexion (S1–S2)",
bg=C_MINT, border=C_GREEN
))
story.append(Spacer(1,8*mm))
story.append(note(
"Sources: Bailey & Love's Short Practice of Surgery 28th Ed | Miller's Review of Orthopaedics 9th Ed | "
"Campbell's Operative Orthopaedics 15th Ed 2026 | S Das Manual on Clinical Surgery 13th Ed | "
"Rheumatology 2-Volume Set 2022 Elsevier"
))
# ── Build ────────────────────────────────────────────────────────────────────
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print("PDF generated:", OUTPUT)
cd /home/daytona/workspace/upper-limb-guide && python generate_lower_limb_pdf.py…
ls -lh /home/daytona/workspace/upper-limb-guide/
Lower Limb Exam Guide
PDF Document · PDF
| Gait | Description | Cause |
|---|---|---|
| Trendelenburg gait | Pelvis drops to contralateral side; trunk leans ipsilateral | Weak gluteus medius (hip OA, NOF#, DDH, superior gluteal nerve palsy) |
| Antalgic gait | Short stance phase on affected side | Pain of any cause |
| Scissors gait | Knees cross midline | Spastic hip adductors (cerebral palsy) |
| Movement | Normal | Note |
|---|---|---|
| Flexion | 0–120° | Modified Thomas' test |
| Extension | 0–10° | Prone |
| Abduction | 0–45° | Stabilise opposite ASIS |
| Adduction | 0–30° | Cross over midline |
| Internal rotation | 0–45° | Hip+knee at 90°; swing foot out |
| External rotation | 0–45° | Swing foot in |
First movement lost in hip OA = Internal rotation (always test this)
| Test | Technique | Positive Meaning |
|---|---|---|
| Thomas' test | Hold one hip fully flexed; other leg drops to couch | Leg cannot reach couch = fixed flexion deformity; angle = degree of FFD |
| Trendelenburg test | Stand on one leg; examiner stands behind | Pelvis drops to unsupported side = positive = weak abductors on standing leg |
| True leg length (ASIS → medial malleolus) | Tape measure | Difference = true shortening (bone) |
| Apparent leg length (xiphisternum → medial malleolus) | Tape measure | Difference = pelvic tilt/adduction contracture |
| Bryant's triangle | Vertical from ASIS + horizontal from GT; measure horizontal limb | Shortened = upward GT displacement (NOF#, dislocation) |
| Nelaton's line | ASIS to ischial tuberosity line | GT above line = upward displacement |
| FABER/Patrick test | Figure-of-4 position | Anterior hip pain = hip joint; posterior pain = SI joint/L5-S1 |
| FADIR/Impingement test | Flex 90° + adduct + IR | Anterior groin pain = FAI or labral tear |
| Stinchfield test | Resisted SLR ~20 cm | Anterior hip pain = hip joint pathology |
| Ober's test | Lateral decubitus; extend and abduct upper leg; let drop | Cannot adduct = tight ITB |
Classic picture: Elderly patient lying helplessly with shortened, externally rotated lower limb.
| Type | Attitude | Complication |
|---|---|---|
| Posterior (90%) | Flexion, adduction, internal rotation | Sciatic nerve injury (10-20%), AVN, post-traumatic OA |
| Anterior | Extension, abduction, external rotation | Femoral nerve/artery injury |
| Test | Technique | Significance |
|---|---|---|
| Lachman test | Knee 15-30°; pull proximal tibia anteriorly | Anterior translation + soft end-point = ACL rupture. Most sensitive ACL test. |
| Anterior draw | Knee 90°; draw tibia forward; grade I/II/III | ACL injury (less sensitive acutely) |
| Posterior draw | Knee 90°; push tibia posteriorly | PCL rupture |
| Posterior sag sign | Knees flexed 90°; look from side | Posterior sag = PCL rupture |
| Pivot shift | Valgus + IR while extending | Clunk = rotatory instability (ACL deficiency); pathognomonic |
| Test | Stress | Positive |
|---|---|---|
| Valgus stress (MCL) | At 30° and 0° | Laxity at 30° = MCL; at 0° = MCL + cruciate |
| Varus stress (LCL) | At 30° and 0° | Laxity at 30° = LCL; at 0° = posterolateral corner |
| Test | Technique | Positive |
|---|---|---|
| Joint line tenderness | Flex 90°; palpate joint line | Most sensitive test for meniscal tear |
| McMurray's test | Fully flex → ER + extend (medial); IR + extend (lateral) | Click/pain at joint line |
| Thessaly test | Stand on one leg, knee 20° flexed, rotate body | Joint line pain = meniscal tear |
| Apley grind | Prone; compression + rotation vs. distraction + rotation | Compression pain = meniscus; distraction pain = ligament |
| Test | Positive Meaning |
|---|---|
| Patellar apprehension (Fairbank's) | Lateral instability (pushes patella laterally at 0° and 30°) |
| J-sign | Maltracking (lateral jump on last degrees of extension) |
| Clarke's test | Patellofemoral syndrome / chondromalacia patellae |
| Deformity | MTPj | PIPj | DIPj |
|---|---|---|---|
| Claw toe | Hyperextension | Flexion | Flexion |
| Hammer toe | Normal | Flexion | Flexion |
| Mallet toe | Normal | Normal | Flexion |
| Hallux valgus | Valgus | Normal | - |
| Test | Technique | Positive |
|---|---|---|
| Anterior draw test | Pull heel anteriorly in slight plantarflexion | >3-5 mm anterior translation = ATFL tear |
| Talar tilt test | Invert heel in neutral | Increased tilt = CFL tear |
| Thompson's (Simmonds') test | Squeeze calf (prone, knee 90°) | No plantarflexion = complete Achilles rupture |
| Single heel rise test | Rise on tiptoe | Cannot rise = tibialis posterior dysfunction |
| Silfverskiold test | Dorsiflexion with knee extended vs. flexed | Improved with knee flexed = gastrocnemius tightness |
| Condition | Site | Attitude/Deformity | Key Test | Investigation | Treatment |
|---|---|---|---|---|---|
| Hip OA | Hip | Fixed flexion (Thomas'+) | IR first lost | X-ray: LOSS | Analgesia → THR |
| NOF fracture | Hip | Short, ER, helpless | Bryant's triangle | X-ray ± MRI | DHS/Hemiarthroplasty/THR |
| Post. dislocation | Hip | Flex + adduct + IR | Head in buttock | X-ray | Urgent reduction |
| Ant. dislocation | Hip | Extend + abduct + ER | Head in groin | X-ray | Closed reduction |
| ACL rupture | Knee | Haemarthrosis | Lachman + Pivot shift | MRI | Physio / ACL reconstruction |
| PCL rupture | Knee | Posterior sag | Posterior draw | MRI | Bracing / PCL reconstruction |
| Meniscal tear | Knee | Joint line pain, locking | McMurray, JL tenderness | MRI | Repair or meniscectomy |
| Knee OA | Knee | Varus, FFD | Crepitus, reduced ROM | WB X-ray | Analgesia → TKR/UKR |
| Lateral ankle sprain | ATFL/CFL | Swelling lateral | Anterior draw | X-ray (Ottawa) | RICE, rehab, brace |
| Achilles rupture | Tendo-Achilles | Palpable gap | Thompson's + | USS/MRI | Functional brace / repair |
| Plantar fasciitis | Heel | Morning pain | Calcaneal origin TTP | Clinical | Stretching, steroid injection |
| Hallux valgus | 1st MTPj | Lateral deviation | Bunion, ROM | WB X-ray | Shoes → osteotomy |
Lower Limb Exam Guide
PDF Document · PDF
Lower limb
| Section | Content |
|---|---|
| Hip Exam | Look/Feel/Move, gait analysis, special tests (Thomas', Trendelenburg, Bryant's, FABER, FADIR, Stinchfield, Ober's) |
| Hip Conditions | OA, NOF fracture (Garden classification), hip dislocation (anterior vs. posterior attitudes) |
| Knee Exam | Look/Feel/Move, effusion tests (stroke test, patellar tap), joint line palpation |
| Knee Special Tests | ACL (Lachman, anterior draw, pivot shift), PCL (posterior draw, sag sign), Menisci (McMurray, Thessaly, Apley), Patellofemoral (apprehension, J-sign) |
| Knee Conditions | ACL rupture, meniscal tear, knee OA |
| Ankle & Foot Exam | Look/Feel/Move, Ottawa rules, gait, footwear inspection, foot deformity classification |
| Ankle Special Tests | Anterior draw, talar tilt, Thompson's (Achilles), Silfverskiold, single heel rise |
| Foot Conditions | Lateral ankle sprain, Achilles rupture, plantar fasciitis, hallux valgus, pes planus/cavus, Morton's neuroma |
| Quick Reference | Full 12-condition summary table + 14 classic rules/mnemonics |
Lower Limb Exam Guide
PDF Document · PDF
The pdf of both upper limb above & lower limb are not opening so give it in a text format
| Movement | Normal Range | Clinical Note |
|---|---|---|
| Flexion | 0–180° | Loss = adhesive capsulitis, GHJ OA |
| Extension | 0–60° | |
| Abduction | 0–180° | Painful arc 60–120° = impingement |
| Adduction | 0–50° | |
| External Rotation | 0–60° | FIRST lost in frozen shoulder |
| Internal Rotation | 0–90° | Test: thumb to spine level |
| Test | Technique | Positive Meaning |
|---|---|---|
| Impingement sign (Neer) | Passive forward flexion >90° | Pain = subacromial impingement |
| Hawkins' test | Passive FF 90° + internal rotation | Pain = impingement syndrome |
| Jobe's test (Empty can) | Resisted pronation/FF at 90° in scapular plane | Pain/weakness = supraspinatus lesion |
| Drop-arm test | Arm placed in abduction then released | Cannot maintain = supraspinatus rupture |
| Hornblower sign | Resisted ER at 90° abduction | Pain = infraspinatus/teres minor lesion |
| Lift-off test (Gerber) | Arm in IR behind back; lift off | Cannot lift = subscapularis tear |
| Bear-hug test | Hand on opposite shoulder; examiner tries to lift | Cannot maintain = subscapularis lesion |
| Belly-push test | Elbow held forward with abduction pressure | Cannot hold elbow forward = subscapularis |
| Test | Technique | Positive Meaning |
|---|---|---|
| Apprehension test | Supine: 90° abduction + ER | Apprehension = anterior instability |
| Relocation test | Posterior force during apprehension | Relief = anterior instability confirmed |
| Load-and-shift test | Ant/post force on humeral head | Degree of translation = laxity |
| Sulcus sign | Inferior traction on arm at side | Gap below acromion = inferior laxity |
| Test | Technique | Positive Meaning |
|---|---|---|
| O'Brien (Active compression) | 10° adduction, 90° FF, max pronation; resist | Pain = SLAP lesion / ACJ pathology |
| Speed's test | Resisted FF, elbow extended, forearm supinated | Pain in bicipital groove = biceps tendinopathy |
| Yergason's test | Resisted supination with elbow at 90° | Pain in groove = biceps tendinopathy/SLAP |
⚠ Always obtain X-rays before diagnosing frozen shoulder — exclude GHJ OA and locked posterior dislocation (both cause selective ER loss).
| Stage | Name | Duration | Features |
|---|---|---|---|
| 1 | Pre-adhesive | Weeks–months | Nocturnal pain; ROM initially preserved |
| 2 | Freezing | 3–9 months | Pain + progressive ROM loss |
| 3 | Frozen | 9–15 months | Stiffness dominates; pain decreases |
| 4 | Thawing | 15–24 months | Gradual ROM recovery |
| Modality | Detail |
|---|---|
| X-ray | Normal — mandatory to exclude GHJ OA and posterior dislocation |
| Arthrography | Reduced joint volume (<10 mL vs. normal 35 mL); loss of axillary recess |
| MRI | Capsular thickening, CHL thickening, obliterated subcoracoid fat triangle |
| Conservative (90%) | NSAIDs + physiotherapy (pendulum/Codman exercises) + intraarticular steroid injection |
| Distention arthrography | Hydrodistention — inflates and stretches capsule |
| Surgical | Closed manipulation under anaesthesia; arthroscopic capsular release (if 12–16 wks conservative fails) |
| Deformity | Definition | Common Cause | Complication |
|---|---|---|---|
| Cubitus valgus | Increased carrying angle >15–20° | Malunion lateral condyle fracture (child) | Tardy ulnar nerve palsy |
| Cubitus varus (gun-stock) | Reversed/decreased carrying angle | Malunited supracondylar fracture | Mainly cosmetic |
✅ Hueter's Triangle Rule: Equilateral triangle at 90° — PRESERVED in supracondylar fracture | DISRUPTED in posterior elbow dislocation
| Test | Technique | Positive |
|---|---|---|
| Cozen's test | Resisted wrist extension, elbow extended | Pain at lateral epicondyle |
| Mill's test | Passive wrist flexion, elbow extended | Pain at lateral epicondyle |
| Middle finger test | Resisted extension of middle finger | Pain at ECRB origin (most specific) |
| Feature | Description |
|---|---|
| Examination | Dinner-fork deformity on lateral view; radial deviation; local swelling and bruising |
| X-ray (AP + Lateral) | Confirm fracture; measure volar tilt, radial inclination, radial height |
| Acceptable reduction | Volar tilt ≥0°, radial inclination ≥15°, radial height shortening ≤3 mm |
| Treatment | Undisplaced: Below-elbow cast 6 wks. Displaced: Closed reduction (haematoma block or Bier's) + cast. Unstable: K-wires or volar locking plate (ORIF) |
| Complications | CRPS (Sudeck's atrophy), malunion, median nerve injury, EPL rupture, carpal tunnel syndrome |
⚠ Most commonly MISSED fracture — 30% have normal initial X-ray. Normal X-ray does NOT exclude scaphoid fracture.
| Clinical Test | Technique | Positive Finding |
|---|---|---|
| Anatomical snuffbox tenderness | Palpate dorsal snuffbox with wrist in ulnar deviation | Tenderness = scaphoid fracture until proven otherwise |
| Scaphoid tubercle tenderness | Palpate volar tubercle at wrist crease | More specific than snuffbox |
| Scaphoid compression test | Axial compression along axis of thumb | Pain at wrist |
| Telescoping test | Telescoping the thumb proximally | Pain at scaphoid |
| Investigation | Role |
|---|---|
| X-ray (AP, lateral, scaphoid views) | First line; may be NORMAL — repeat at 10–14 days |
| MRI | Most sensitive — detects fracture within 24–48 hours |
| CT | Best for displacement assessment and union |
| Bone scan | Sensitive but non-specific |
| Category | Causes |
|---|---|
| Inflammatory | Rheumatoid arthritis, tenosynovitis (most common) |
| Metabolic/Endocrine | Hypothyroidism, diabetes, acromegaly, pregnancy |
| Space-occupying | Ganglion, lipoma, carpal fracture malunion, amyloidosis |
| Occupation | Repetitive wrist flexion/extension, vibrating tools |
| Test | Technique | Significance |
|---|---|---|
| Tinel's sign | Tap over carpal tunnel at wrist | Paraesthesia in median nerve distribution |
| Phalen's manoeuvre | Wrists fully flexed for 60 seconds (dorsal surfaces back to back) | Symptom reproduction — most specific |
| Carpal compression test | Direct pressure over tunnel for 30 seconds | Most sensitive clinical test |
| Reverse Phalen | Wrists extended back to back | Symptom reproduction |
| APB test | Resisted thumb abduction | Weakness = thenar denervation |
| Step | Detail |
|---|---|
| NCS/EMG | Confirms diagnosis; prolonged sensory latency before motor; mandatory before surgery; 25% false-negative rate |
| Conservative | Night wrist splinting in neutral; activity modification; nerve gliding exercises; corticosteroid injection |
| Surgical | Carpal tunnel decompression — open or endoscopic division of flexor retinaculum; equivalent long-term outcomes; excellent results |
| Indication for surgery | Failed conservative measures OR thenar wasting |
✅ Finkelstein's test: Patient makes fist with thumb inside fingers. Examiner passively ulnar deviates the wrist. Sharp pain at radial styloid = POSITIVE (De Quervain's).
| Condition | Site | Key Sign/Test | Investigation | 1st-Line Tx | Surgical Tx |
|---|---|---|---|---|---|
| Frozen shoulder | GHJ | Equal active=passive loss; ER first | X-ray (normal), MRI | Physio, steroid inj | Arthroscopic capsular release |
| Rotator cuff tear | Shoulder | Drop-arm, painful arc, Jobe's | MRI | Physio, subacromial inj | Arthroscopic repair |
| Shoulder dislocation (ant) | GHJ | Flattening, anterior bulge | X-ray AP + lateral | Reduction (Kocher/Hippocratic) | Latarjet/Bankart (recurrent) |
| Tennis elbow | Lateral epicondyle | Cozen's, Mill's test | Clinical ± MRI | Brace, steroid inj | ECRB release |
| Golfer's elbow | Medial epicondyle | Resisted wrist flexion | Clinical | Brace, steroid inj | Flexor-pronator release |
| Supracondylar # humerus | Elbow | Posterior displacement; Hueter's intact | X-ray | MUA + K-wires | ORIF if NV compromise |
| Colles' fracture | Distal radius | Dinner-fork deformity | X-ray | Closed reduction + cast | Volar locking plate ORIF |
| Scaphoid fracture | Wrist | Snuffbox tenderness | MRI (gold) | Thumb spica 8–12 wks | Herbert screw |
| Carpal tunnel | Wrist | Phalen's, Tinel's, thenar wasting | NCS/EMG | Night splint, steroid inj | CTD (open/endoscopic) |
| Dupuytren's | Palm | Tabletop test | Clinical | Observation if mild | Fasciectomy/Collagenase |
| De Quervain's | Radial styloid | Finkelstein's test | Clinical ± USS | Splint + NSAID + inj | 1st compartment release |
| Gait | Description | Cause |
|---|---|---|
| Trendelenburg gait | Pelvis drops contralateral; trunk leans ipsilateral to compensate | Weak gluteus medius — hip OA, NOF#, DDH, superior gluteal nerve palsy |
| Antalgic gait | Short stance phase on painful side | Pain of any cause |
| Scissors gait | Knees cross midline | Spastic hip adductors (cerebral palsy) |
| Movement | Normal Range | How to Test |
|---|---|---|
| Flexion | 0–120° | Supine; flex hip + knee. Modified Thomas' test for FFD |
| Extension | 0–10° | Prone; lift leg off couch |
| Abduction | 0–45° | Supine; stabilise contralateral ASIS; slide leg out |
| Adduction | 0–30° | Cross leg over midline |
| Internal rotation | 0–45° | Hip + knee at 90°; swing foot outward |
| External rotation | 0–45° | Hip + knee at 90°; swing foot inward |
⚠ First movement lost in hip OA = Internal rotation — always test this!
| Test | Technique | Positive Finding & Meaning |
|---|---|---|
| Thomas' test | Patient supine. Flex both hips fully. Hold one hip flexed (flattens lumbar lordosis). Allow other leg to drop. | Leg unable to reach couch = fixed flexion deformity. Angle = degree of FFD |
| Trendelenburg test | Patient stands on one leg. Examiner stands behind. | Pelvis drops on contralateral (unsupported) side = POSITIVE = weak abductors on standing leg |
| True leg length | ASIS to medial malleolus | Difference = true shortening (bone) |
| Apparent leg length | Xiphisternum to medial malleolus | Difference = pelvic tilt/adduction contracture |
| Bryant's triangle | Vertical from ASIS; horizontal from GT to meet it; measure horizontal limb | Shortened horizontal limb = upward GT displacement (NOF#, dislocation) |
| Nelaton's line | ASIS to ischial tuberosity line (lateral decubitus) | GT above line = upward displacement |
| FABER/Patrick test | Flex, Abduct, Externally Rotate (figure-of-4 position) | Anterior hip pain = hip joint. Posterior pain = SI joint/L5–S1 |
| FADIR/Impingement test | Flex 90° + Adduct + Internally Rotate | Anterior groin pain = FAI or labral tear |
| Stinchfield test | Active straight-leg raise ~20 cm against mild resistance | Anterior hip pain = hip joint pathology |
| Ober's test | Lateral decubitus; extend and abduct upper leg; let drop | Leg fails to adduct below horizontal = tight ITB |
| Log roll (Roll test) | Supine; rotate leg in/out gently at calf level | Stiffness or pain = hip joint irritability |
| Stage | Treatment |
|---|---|
| Mild | Analgesia (paracetamol, NSAIDs), physiotherapy, weight loss, walking aids |
| Moderate | Intraarticular steroid injection, hyaluronic acid injection |
| Severe | Total Hip Replacement (THR) — gold standard |
⚠ Elderly patient lying helplessly with shortened, externally rotated lower limb = NOF fracture until proven otherwise.
| Grade | Description | Blood Supply |
|---|---|---|
| I | Incomplete/impacted — valgus impaction | Usually intact |
| II | Complete, non-displaced | Usually intact |
| III | Complete, partial displacement — head partially rotated | Disrupted |
| IV | Complete, full displacement — trabeculae not aligned | Disrupted — HIGH AVN risk |
| Fracture Type | Patient | Treatment |
|---|---|---|
| Intracapsular undisplaced (Garden I/II) | Any | DHS or cannulated screws |
| Intracapsular displaced (Garden III/IV) | Elderly (>65) | Hemiarthroplasty (Austin Moore/Thompson) or THR |
| Intracapsular displaced (Garden III/IV) | Young (<65) | Reduction + internal fixation (preserve head) |
| Extracapsular (intertrochanteric) | Any age | Dynamic Hip Screw (DHS) |
| Subtrochanteric | Any | Intramedullary nail (e.g. PFNA) |
| Type | Attitude | Complication |
|---|---|---|
| Posterior (90%) | Flexion, Adduction, Internal Rotation (FAIR) | Sciatic nerve injury (10–20%), AVN, post-traumatic OA |
| Anterior (rare) | Extension, Abduction, External Rotation | Femoral nerve/artery injury; head in groin |
| Test | Technique | Positive Finding |
|---|---|---|
| Lachman test (best for ACL) | Knee at 15–30° flexion; pull proximal tibia anteriorly | Excessive anterior translation with soft/absent end-point = ACL rupture. Most sensitive ACL test. |
| Anterior draw test (ACL) | Knee at 90°; sit on foot; draw tibia forward. Grade I <5 mm, II 5–10 mm, III >10 mm | Anterior translation = ACL injury |
| Posterior draw test (PCL) | Knee at 90°; push tibia posteriorly. >10 mm = combined PCL + PLC | Posterior translation = PCL rupture |
| Posterior sag sign (PCL) | Knees flexed 90°; look from side at tibial tuberosity level | Posterior sag of tibia = PCL rupture |
| Pivot shift test (ACL) | Valgus + internal rotation force on flexed knee; then extend | Clunk as lateral tibial plateau reduces at ~30° = rotatory instability (ACL deficiency) |
| Test | Technique | Positive Finding |
|---|---|---|
| Valgus stress test (MCL) | Apply valgus force at 0° and 30° flexion | Laxity/pain at 30° = MCL tear. Laxity at 0° = complete MCL + cruciate injury |
| Varus stress test (LCL) | Apply varus force at 0° and 30° flexion | Laxity/pain at 30° = LCL tear. Laxity at 0° = severe posterolateral corner injury |
| Test | Technique | Positive Finding |
|---|---|---|
| Joint line tenderness | Flex knee 90°; palpate joint line with thumb + index | Tenderness = most sensitive clinical test for meniscal tear |
| McMurray's test | Fully flex knee. ER + extend (medial); IR + extend (lateral) | Palpable/audible click or pain at joint line = meniscal tear |
| Thessaly test | Stand on one leg, flexes knee 20°, rotate body medially + laterally | Joint line pain = meniscal tear |
| Apley grind test | Prone; flex knee 90°; compress + rotate (grind) then distract + rotate | Pain with compression + rotation = meniscus; distraction = ligament |
| Test | Technique | Positive Finding |
|---|---|---|
| Patellar apprehension (Fairbank's) | Push patella laterally at 0° and 30° | Patient contracts quads/grabs examiner = lateral instability |
| J-sign / Patellar tracking | Extend knee slowly from 90°; observe patella path | Lateral jump at end of extension = maltracking (VMO weakness) |
| Clarke's test (patellar grind) | Push patella distally; patient tenses quads | Pain = patellofemoral syndrome / chondromalacia patellae |
| Deformity | MTPj | PIPj | DIPj |
|---|---|---|---|
| Claw toe | Hyperextension | Flexion | Flexion |
| Hammer toe | Normal | Flexion | Flexion |
| Mallet toe | Normal | Normal | Flexion |
| Hallux valgus | Valgus (lateral deviation) | Normal | — |
| Movement | Joint | Normal Range |
|---|---|---|
| Dorsiflexion | Talocrural | 0–20° |
| Plantarflexion | Talocrural | 0–50° |
| Inversion | Subtalar | 0–35° |
| Eversion | Subtalar | 0–15° |
| Test | Technique | Positive Finding & Meaning |
|---|---|---|
| Anterior draw test (ATFL) | Stabilise distal tibia; pull heel anteriorly in slight plantarflexion | Anterior translation of talus >3–5 mm = ATFL tear |
| Talar tilt test (CFL) | Invert heel with ankle in neutral | Increased tilt = CFL tear |
| Thompson (Simmonds') test | Patient prone, knee 90°. Squeeze calf. | No plantarflexion = POSITIVE = complete Achilles rupture |
| Single heel rise test | Stand on one foot; rise on tiptoe | Unable to rise = tibialis posterior dysfunction / Achilles weakness |
| Silfverskiold test | DF measured with knee extended vs. flexed | Improved DF with knee flexed = gastrocnemius tightness (not combined gastrosoleus) |
| Ottawa ankle rules | Bony tenderness at: posterior 6 cm fibula/tibia; base 5th MT; navicular | Any positive point = X-ray required to exclude fracture |
⚠ Thompson's test: Absence of plantarflexion on calf squeeze = complete Achilles rupture
| Condition | Typical Patient | Key Finding | Treatment |
|---|---|---|---|
| Plantar fasciitis | Middle-aged, overweight, runners | Heel pain worst in morning; tenderness at calcaneal origin | Stretching, orthotics, steroid injection, ESWT |
| Hallux valgus | Middle-aged women; tight shoes | Lateral deviation of hallux; medial prominence; bursa | Shoes; osteotomy (scarf/chevron) |
| Hallux rigidus | Adults 30–60 | Stiff painful 1st MTPj; dorsal osteophyte; reduced dorsiflexion | Stiff-soled shoes; cheilectomy or 1st MTPj fusion |
| Pes planus | All ages | Collapsed medial arch; too many toes sign | Physiotherapy, orthotics; corrective surgery for rigid flat foot |
| Pes cavus | Neurological cause (CMT, spina bifida) | High arch; clawing of toes; calluses under MH | Assess neurological cause; orthotics; corrective osteotomy |
| Morton's neuroma | Middle-aged women | Burning/shooting pain 3rd–4th web space; Mulder's click | Wide shoes, metatarsal pad, steroid injection; surgical excision |
| Ankle OA | Post-traumatic | Reduced ankle ROM; joint line tenderness; deformity | Physiotherapy, bracing; arthrodesis or total ankle replacement |
| Condition | Site | Attitude/Deformity | Key Test | Investigation | Treatment |
|---|---|---|---|---|---|
| Hip OA | Hip | Fixed flexion (Thomas'+) | IR first lost | X-ray (LOSS) | Analgesia → THR |
| NOF fracture | Hip | Short, ER, helpless | Bryant's triangle | X-ray ± MRI | DHS/Hemiarthroplasty/THR |
| Posterior hip dislocation | Hip | Flex + adduct + IR (FAIR) | Head in buttock | X-ray | Urgent closed reduction |
| Anterior hip dislocation | Hip | Extend + abduct + ER | Head in groin | X-ray | Closed reduction |
| ACL rupture | Knee | Haemarthrosis | Lachman + pivot shift | MRI | Physio / ACL reconstruction |
| PCL rupture | Knee | Posterior sag | Posterior draw | MRI | Bracing / PCL reconstruction |
| Meniscal tear | Knee | Joint line pain, locking | McMurray, JL tenderness | MRI | Repair or partial meniscectomy |
| Knee OA | Knee | Varus, FFD | Crepitus, reduced ROM | WB X-ray | Analgesia → TKR/UKR |
| Lateral ankle sprain | ATFL/CFL | Swelling lateral | Anterior draw | X-ray if Ottawa + | RICE, rehab, brace |
| Achilles rupture | Achilles tendon | Palpable gap | Thompson's POSITIVE | USS/MRI | Functional brace / surgical repair |
| Plantar fasciitis | Heel | Morning pain | Calcaneal origin TTP | Clinical | Stretching, steroid injection |
| Hallux valgus | 1st MTPj | Lateral hallux deviation | Bunion; MTPj ROM | WB X-ray | Shoes → osteotomy |
Continue
| Age Group | Likely Diagnosis | Key Clue |
|---|---|---|
| Neonate–6 months | Developmental Dysplasia of Hip (DDH) | Barlow/Ortolani positive; unequal skin folds |
| 3–8 years | Transient synovitis of hip | After viral URTI; afebrile or low-grade fever |
| 4–8 years (boys) | Perthes' disease (LCPD) | Insidious limp; AVN of femoral head |
| Any child (septic) | Septic arthritis | Kocher criteria; systemically unwell; hot joint |
| 10–15 years (obese boys) | Slipped Capital Femoral Epiphysis (SCFE) | External rotation of limb; knee pain |
⚠ Hilton's Law: A joint is supplied by the same nerves as the muscles that move it. Explains why hip pathology in children often presents as KNEE PAIN — always examine the hip in any child with knee pain.
| Test | Technique | Positive Meaning |
|---|---|---|
| Barlow's test | Adduct + apply posterior force on flexed hip | Femoral head dislocates posteriorly out of acetabulum = unstable hip |
| Ortolani's test | Abduct hip while applying anterior force on GT | Clunk as femoral head reduced back into acetabulum = dislocated hip |
| Galeazzi sign (Allis sign) | Supine; flex both hips + knees; compare knee heights | Lower knee = shorter femur = unilateral DDH or femoral shortening |
| Age | Treatment |
|---|---|
| 0–6 months | Pavlik harness (maintain reduction in flexion + abduction) |
| 6–18 months | Closed reduction under GA → spica cast |
| 18 months–8 years | Open reduction ± femoral/pelvic osteotomy |
| >8 years | Palliative (secondary OA inevitable; joint salvage or THR later) |
| Stage | Name | Radiological Features |
|---|---|---|
| 1 | Ischaemia/Necrosis | Increased density of femoral head; loss of joint space |
| 2 | Fragmentation | Femoral head appears fragmented; lateral pillar affected |
| 3 | Re-ossification | New bone laid down; femoral head reshapes |
| 4 | Healed | Remodelling complete; head spherical or aspherical (deformed) |
✅ Management aims to maintain femoral head sphericity and containment within acetabulum.
| Type | Description |
|---|---|
| Stable | Can weight bear (with or without crutches) — better prognosis |
| Unstable | Cannot weight bear — HIGH risk of AVN (~50%) |
| Criterion | Septic Arthritis Risk |
|---|---|
| Fever >38.5°C | |
| Non-weight bearing | |
| ESR >40 mm/hr | |
| WBC >12,000/µL | |
| 0 criteria = 0.2% risk | 4 criteria = 99.6% risk |
⚠ Septic arthritis is an orthopaedic emergency — joint destruction occurs within 24–48 hours. If Kocher criteria positive, urgent aspiration + surgical washout is required.
| Feature | Description |
|---|---|
| Pain | Severe, out of proportion to injury — EARLIEST sign |
| Pressure | Tense, "woody" feel of the compartment |
| Paraesthesia | Pins and needles/numbness in distribution of nerve running through compartment (earliest neurological sign) |
| Paralysis | Weakness/inability to move affected muscle groups (late sign) |
| Pallor | May be present in severe cases |
| Pulselessness | VERY LATE sign — do not wait for this |
⚠ Pain on passive stretch of muscles in the compartment is the most reliable early sign. Do NOT wait for 6Ps to be complete — this is a clinical diagnosis.
| Compartment | Contents | Signs of Syndrome |
|---|---|---|
| Anterior | Tibialis anterior, EHL, EDL; deep peroneal nerve | Weakness dorsiflexion; paraesthesia 1st web space |
| Lateral (peroneal) | Peroneus longus + brevis; superficial peroneal nerve | Weakness eversion; paraesthesia dorsum of foot |
| Posterior deep | FHL, FDL, TP; posterior tibial nerve + vessels | Weakness toe flexion; paraesthesia sole of foot |
| Posterior superficial | Gastrocnemius, soleus | Weakness plantarflexion; calf pain + tenderness |
| Grade | Description |
|---|---|
| I | Open wound <1 cm; clean; simple fracture |
| II | Open wound 1–10 cm; moderate contamination |
| IIIA | Open wound >10 cm; adequate soft tissue coverage remains |
| IIIB | Open wound >10 cm; periosteal stripping; requires flap coverage |
| IIIC | Open wound with vascular injury requiring repair |
| Type | Pattern | Mechanism | Complication |
|---|---|---|---|
| I | Lateral split | Low-energy valgus | Meniscal tear |
| II | Lateral split + depression | Valgus + axial | Meniscal tear; ACL/MCL |
| III | Pure lateral depression | Axial | Less ligament injury |
| IV | Medial plateau fracture | High-energy varus | Peroneal nerve injury; popliteal artery |
| V | Bicondylar fracture | High-energy | NV injury; compartment syndrome |
| VI | Fracture + metaphyseal/diaphyseal dissociation | Very high-energy | All of the above |
| Phase | % Cycle | Activity |
|---|---|---|
| Heel strike | 0% | Heel contacts ground; loading begins |
| Foot flat | 7% | Foot fully on ground |
| Midstance | 15–40% | Single leg support |
| Heel rise | 40% | Heel lifts; propulsion begins |
| Toe-off | 60% | Foot leaves ground; swing phase begins |
| Swing | 60–100% | Foot in air; limb advances forward |
| Gait | Appearance | Cause | Joint/Problem |
|---|---|---|---|
| Antalgic | Short stance phase on affected side; leaning over affected hip | Pain in any lower limb joint | Hip/knee/ankle OA, fracture |
| Trendelenburg (abductor lurch) | Pelvis drops contralateral; trunk leans ipsilateral (compensated) | Weak gluteus medius | Hip OA, NOF#, DDH, polio, superior gluteal nerve palsy |
| High-stepping | Exaggerated hip/knee flexion to clear foot | Foot drop (cannot dorsiflex) | Common peroneal nerve palsy, L4 radiculopathy |
| Steppage | Foot slaps on ground at heel strike | Weak dorsiflexors | L4/5 nerve root, drop foot |
| Scissors | Knees cross midline | Spastic hip adductors | Cerebral palsy, spastic paraplegia |
| Spastic hemiplegic | Circumduction of leg; arm held flexed | Upper motor neurone lesion | Stroke, cerebral palsy |
| Varus thrust | Knee collapses into varus on weight-bearing | Lateral soft tissue laxity; medial OA | Medial compartment knee OA |
| Short leg (Duchenne) | Trunk shift ipsilaterally to compensate | Leg length discrepancy | Any cause of true LLD |
| Festinating | Small shuffling steps; difficulty stopping | Basal ganglia dysfunction | Parkinson's disease |
| Waddling | Bilateral Trendelenburg; pelvis rotates | Bilateral hip pathology | Bilateral hip OA, muscular dystrophy, bilateral DDH |
| Type | Measurement | Cause | Example |
|---|---|---|---|
| True LLD | ASIS → medial malleolus | Actual bone shorter | NOF fracture malunion, Perthes', growth arrest, tumour |
| Apparent LLD | Xiphisternum → medial malleolus | Pelvic tilt / adduction contracture | Hip OA with fixed adduction, scoliosis |
| Nerve | Root | Injury Site | Motor Loss | Sensory Loss | Gait Effect |
|---|---|---|---|---|---|
| Femoral nerve | L2–L4 | Inguinal region; anterior hip surgery | Quadriceps (knee extension) | Anterior thigh + medial leg | Knee buckles on weight-bearing |
| Obturator nerve | L2–L4 | Obturator foramen; pelvic surgery | Hip adductors | Medial thigh | Leg swings laterally in swing phase |
| Superior gluteal nerve | L4–S1 | Posterior hip surgery | Gluteus medius + minimus | None | Trendelenburg gait |
| Inferior gluteal nerve | L5–S2 | Posterior hip surgery | Gluteus maximus (hip extension) | None | Difficulty climbing stairs; trunk lurches forward |
| Sciatic nerve | L4–S3 | Posterior hip dislocation; hip surgery | All below knee (hamstrings + all foot/ankle muscles) | Posterior thigh; below knee | High-stepping + foot drop |
| Common peroneal nerve | L4–S2 | Neck of fibula (fracture, cast pressure) | Dorsiflexion + eversion (foot drop) | Dorsum of foot + 1st web space | High-stepping / steppage gait |
| Tibial nerve | L4–S3 | Popliteal fossa | Plantarflexion + toe flexion | Sole of foot | Weak push-off; anaesthetic sole |
| Root | Dermatome | Myotome | Reflex |
|---|---|---|---|
| L3 | Anterior thigh | Hip flexion / Knee extension | Knee jerk (with L4) |
| L4 | Medial leg + dorsum foot | Knee extension + dorsiflexion | Knee jerk (patella) |
| L5 | Dorsum foot + great toe | Dorsiflexion + big toe extension | None (or tibialis posterior) |
| S1 | Lateral foot + sole | Plantarflexion + eversion | Ankle jerk |
| S2 | Posterior thigh | Knee flexion | None |
| Stage | X-ray Finding | MRI |
|---|---|---|
| I | Normal | Signal change (early ischaemia) — MRI detects at this stage |
| II | Sclerosis ± cysts; no collapse | Confirmed |
| III | Subchondral collapse ("crescent sign") — femoral head shape preserved | Collapse |
| IV | Collapse + secondary OA (joint space loss, acetabular changes) | End-stage |
| Stage | Treatment |
|---|---|
| I–II | Core decompression (drilling) ± vascularised fibula graft to stimulate healing; bisphosphonates |
| III | Core decompression; vascularised bone graft; rotational osteotomy (to move necrotic segment away from weight-bearing area) |
| IV | Total Hip Replacement (THR) |
| Type | Morphology | Description |
|---|---|---|
| CAM impingement | Non-spherical femoral head (bony bump at head-neck junction) | Cartilage damage begins at anterosuperior acetabulum |
| PINCER impingement | Acetabular over-coverage (deep socket / coxa profunda / retroversion) | Labral damage at rim from repeated abutment |
| Mixed | Both CAM + PINCER features | Most common in clinical practice |
⚠ Most serious knee injury — popliteal artery injury in 30–40%. Peroneal nerve injury in 25–35%. Orthopaedic emergency.
| Line/Angle | Joint | Normal | Significance of Abnormality |
|---|---|---|---|
| Shenton's line | Hip | Smooth continuous arc from inferior femoral neck to superior obturator foramen | Disrupted = NOF fracture or hip dislocation |
| Hilgenreiner's line | Hip (DDH) | Horizontal through triradiate cartilage | Abnormal acetabular index if angle >30° in infants |
| Perkin's line | Hip (DDH) | Vertical through lateral acetabular edge | Femoral head ossific nucleus should be in lower medial quadrant |
| Klein's line | Hip (SCFE) | Line along superior femoral neck should intersect epiphysis | Fails to intersect epiphysis = SCFE |
| Southwick angle | Hip (SCFE) | Epiphyseal shaft angle | Mild <30°, Moderate 30–50°, Severe >50° |
| Tibiofemoral angle | Knee | 5–7° valgus | Varus = medial compartment OA; Valgus = lateral OA |
| Q angle | Knee/PFJ | <15° male; <20° female | Increased = lateral patellar subluxation tendency |
| Bohler's angle | Calcaneus | 20–40° | <20° = calcaneal fracture (compression) |
| Alpha angle (MRI/X-ray) | Hip (FAI) | <55° | >55° = CAM-type FAI |
| Centre-edge angle | Hip | 25–39° | >39° = PINCER FAI; <20° = dysplasia |
| Condition | Key Feature | Time-Critical Action |
|---|---|---|
| Compartment syndrome | Pain out of proportion + pain on passive stretch + woody compartment | Fasciotomy within 6 hours |
| Septic arthritis | Hot swollen joint + fever + Kocher criteria positive | Joint aspiration + urgent surgical washout |
| Traumatic hip dislocation | Posterior: FAIR attitude; sciatic nerve at risk | Reduction within 6 hours to reduce AVN risk |
| Tibial plateau fracture + vascular injury | Valgus force + pulseless foot | CT angiography + vascular surgery |
| Posterior knee dislocation | Gross instability + absent popliteal pulse | ABI measurement + CT angiography ± surgical exploration |
| Open long bone fracture | Wound over fracture | Antibiotics within 1 hour; debridement within 24 hours |
| Unstable SCFE | Cannot weight bear; AVN risk 50% | In situ fixation as emergency |
| Cauda equina syndrome | Bilateral leg weakness + saddle anaesthesia + bladder/bowel loss | Emergency MRI + decompression within 24 hours |