Make this into elaborate notes using tables and flowcharts so I can write it as an answer for a 50 mark question on pitchfork analysis. Don't skip any detail.

Reading File
Running Command

cd /tmp/workspace/attachments/daed2362-4634-43ac-9ef5-64f2c2cdf655 && python3 -c " import pdfplumber with pdfplumber.open('pitchfork analysis.pdf') as pdf: print(f'Total pages: {len(pdf.pages)}') for i, page in enumerate(pdf.pages): text = page.extract_text() print(f'\n========== PAGE {i+1} ==========') print(text) "

Reading File
Running Command

mkdir -p /tmp/workspace/pitchfork-notes && ls /tmp/workspace/pitchfork-notes/

Running Command

cat << 'PYEOF' > /tmp/workspace/pitchfork-notes/build_notes.py from docx import Document from docx.shared import Pt, Inches, RGBColor, Cm from docx.enum.text import WD_ALIGN_PARAGRAPH from docx.enum.table import WD_TABLE_ALIGNMENT, WD_ALIGN_VERTICAL from docx.oxml.ns import qn from docx.oxml import OxmlElement import copy doc = Document() # ── Page margins ────────────────────────────────────────────────────────────── section = doc.sections[0] section.page_width = Inches(8.5) section.page_height = Inches(11) section.left_margin = Inches(1) section.right_margin = Inches(1) section.top_margin = Inches(1) section.bottom_margin = Inches(1) # ── Helpers ─────────────────────────────────────────────────────────────────── def set_cell_bg(cell, hex_color): tc = cell._tc tcPr = tc.get_or_add_tcPr() shd = OxmlElement('w:shd') shd.set(qn('w:val'), 'clear') shd.set(qn('w:color'), 'auto') shd.set(qn('w:fill'), hex_color) tcPr.append(shd) def set_cell_border(cell, **kwargs): tc = cell._tc tcPr = tc.get_or_add_tcPr() tcBorders = OxmlElement('w:tcBorders') for side in ['top','left','bottom','right']: border = OxmlElement(f'w:{side}') border.set(qn('w:val'), kwargs.get(side, 'single')) border.set(qn('w:sz'), '6') border.set(qn('w:space'), '0') border.set(qn('w:color'), kwargs.get('color', '2E4057')) tcBorders.append(border) tcPr.append(tcBorders) def bold_para(cell, text, size=11, color='FFFFFF', align=WD_ALIGN_PARAGRAPH.CENTER): p = cell.paragraphs[0] p.alignment = align run = p.add_run(text) run.bold = True run.font.size = Pt(size) run.font.color.rgb = RGBColor.from_string(color) return p def normal_para(cell, text, size=10.5, bold=False, color='1A1A2E'): p = cell.paragraphs[0] p.alignment = WD_ALIGN_PARAGRAPH.LEFT run = p.add_run(text) run.bold = bold run.font.size = Pt(size) run.font.color.rgb = RGBColor.from_string(color) return p def add_section_heading(doc, text, level=1): colors = {1: '1B4F72', 2: '1A5276', 3: '2E86C1'} p = doc.add_paragraph() p.alignment = WD_ALIGN_PARAGRAPH.LEFT run = p.add_run(text) run.bold = True run.font.size = Pt({1:16, 2:13.5, 3:12}[level]) run.font.color.rgb = RGBColor.from_string(colors[level]) if level == 1: run.font.size = Pt(16) # add bottom border via paragraph XML pPr = p._p.get_or_add_pPr() pBdr = OxmlElement('w:pBdr') bottom = OxmlElement('w:bottom') bottom.set(qn('w:val'), 'single') bottom.set(qn('w:sz'), '8') bottom.set(qn('w:space'), '1') bottom.set(qn('w:color'), '1B4F72') pBdr.append(bottom) pPr.append(pBdr) p.paragraph_format.space_before = Pt(14) p.paragraph_format.space_after = Pt(4) return p def add_body(doc, text, size=10.5, bold=False, italic=False, indent=0, bullet=False, color='1A1A2E'): p = doc.add_paragraph() if bullet: p.style = 'List Bullet' run = p.add_run(text) run.bold = bold run.italic = italic run.font.size = Pt(size) run.font.color.rgb = RGBColor.from_string(color) p.paragraph_format.left_indent = Inches(indent) p.paragraph_format.space_after = Pt(2) return p def add_flowchart_box(doc, steps, title="", box_color="2E86C1", arrow=True): """Create a vertical flowchart using a single-column table.""" if title: pt = doc.add_paragraph() pt.alignment = WD_ALIGN_PARAGRAPH.CENTER rt = pt.add_run(title) rt.bold = True rt.font.size = Pt(11) rt.font.color.rgb = RGBColor.from_string('1B4F72') pt.paragraph_format.space_after = Pt(2) for i, step in enumerate(steps): tbl = doc.add_table(rows=1, cols=1) tbl.alignment = WD_TABLE_ALIGNMENT.CENTER cell = tbl.cell(0, 0) set_cell_bg(cell, box_color if i == 0 else ('EBF5FB' if i % 2 == 0 else 'D6EAF8')) set_cell_border(cell, color=box_color) cell.width = Inches(5.5) p = cell.paragraphs[0] p.alignment = WD_ALIGN_PARAGRAPH.CENTER p.paragraph_format.space_before = Pt(4) p.paragraph_format.space_after = Pt(4) if isinstance(step, tuple): label, detail = step r1 = p.add_run(label) r1.bold = True r1.font.size = Pt(10.5) r1.font.color.rgb = RGBColor.from_string('FFFFFF' if i == 0 else '1B4F72') r2 = p.add_run('\n' + detail) r2.font.size = Pt(10) r2.font.color.rgb = RGBColor.from_string('FFFFFF' if i == 0 else '2C3E50') else: r = p.add_run(step) r.bold = (i == 0) r.font.size = Pt(10.5) r.font.color.rgb = RGBColor.from_string('FFFFFF' if i == 0 else '1B4F72') if arrow and i < len(steps) - 1: ap = doc.add_paragraph() ap.alignment = WD_ALIGN_PARAGRAPH.CENTER ar = ap.add_run('▼') ar.font.size = Pt(13) ar.font.color.rgb = RGBColor.from_string(box_color) ap.paragraph_format.space_before = Pt(0) ap.paragraph_format.space_after = Pt(0) doc.add_paragraph() # ══════════════════════════════════════════════════════════════════════════════ # TITLE PAGE BLOCK # ══════════════════════════════════════════════════════════════════════════════ p = doc.add_paragraph() p.alignment = WD_ALIGN_PARAGRAPH.CENTER r = p.add_run('PITCHFORK ANALYSIS') r.bold = True r.font.size = Pt(22) r.font.color.rgb = RGBColor.from_string('1B4F72') p2 = doc.add_paragraph() p2.alignment = WD_ALIGN_PARAGRAPH.CENTER r2 = p2.add_run('An Integrated Cephalometric Analysis of Orthodontic Change') r2.italic = True r2.font.size = Pt(13) r2.font.color.rgb = RGBColor.from_string('2E86C1') p3 = doc.add_paragraph() p3.alignment = WD_ALIGN_PARAGRAPH.CENTER r3 = p3.add_run('Based on Johnston LE Jr (1996) — British Journal of Orthodontics, 23(2): 93–102') r3.font.size = Pt(10) r3.font.color.rgb = RGBColor.from_string('7F8C8D') doc.add_paragraph() # ══════════════════════════════════════════════════════════════════════════════ # SECTION 1 — INTRODUCTION & RATIONALE # ══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '1. INTRODUCTION & RATIONALE', level=1) add_body(doc, 'The cephalometric technique has over 60 years of history, yet its potential for documenting treatment efficacy is rarely fully utilized. The Pitchfork Analysis was developed to fill this gap — to create an internally consistent, integrated accounting of all anteroposterior (A-P) changes that contribute to the final occlusal outcome.', size=10.5) add_body(doc, 'Author: Lysle E. Johnston Jr, DDS, MS, PhD, FDS RCS(Eng), University of Michigan, Ann Arbor.', size=10, italic=True) doc.add_paragraph() # Table 1 — Why pitchfork? add_section_heading(doc, 'Table 1: Why a New Analysis Was Needed', level=2) t = doc.add_table(rows=4, cols=2) t.style = 'Table Grid' t.alignment = WD_TABLE_ALIGNMENT.CENTER headers = ['Problem with Existing Approaches', 'How Pitchfork Solves It'] for j, h in enumerate(headers): cell = t.cell(0, j) set_cell_bg(cell, '1B4F72') bold_para(cell, h, size=11) rows_data = [ ('Proof of treatment efficacy rarely sought — any result considered "good enough"', 'Requires measuring all component displacements; final result is their algebraic sum'), ('Discredited treatments (expansion, bite-jumping) repeatedly resurrected without evidence', 'Provides data-driven hypothesis testing; forces demonstration of average treatment effect'), ('No means to compare treatments on magnitude AND source of change', 'Separates skeletal vs dental contributions; enables direct comparison across treatment philosophies'), ] for i, (c1, c2) in enumerate(rows_data): for j, txt in enumerate([c1, c2]): cell = t.cell(i+1, j) set_cell_bg(cell, 'EBF5FB' if i % 2 == 0 else 'D6EAF8') normal_para(cell, txt, size=10.5) doc.add_paragraph() # ══════════════════════════════════════════════════════════════════════════════ # SECTION 2 — FUNDAMENTAL CONCEPT # ══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '2. THE FUNDAMENTAL CONCEPT: THE ALGEBRAIC SUM', level=1) add_body(doc, 'The core idea: molar relationship change and overjet change each equal the ALGEBRAIC SUM of component skeletal and dental displacements. Every component must be given a sign based on its effect on Class II correction:', size=10.5) doc.add_paragraph() # Sign convention table add_section_heading(doc, 'Table 2: Sign Convention', level=2) t2 = doc.add_table(rows=6, cols=3) t2.style = 'Table Grid' t2.alignment = WD_TABLE_ALIGNMENT.CENTER h2 = ['Movement / Growth', 'Direction', 'Sign'] for j, h in enumerate(h2): cell = t2.cell(0, j) set_cell_bg(cell, '2E86C1') bold_para(cell, h, size=11) sign_data = [ ('Forward growth of mandible', 'Tends to correct Class II / reduce overjet', '+ (POSITIVE)'), ('Mesial movement of lower molars/incisors', 'Tends to correct Class II / reduce overjet', '+ (POSITIVE)'), ('Forward growth of maxilla', 'Increases overjet / worsens Class II', '− (NEGATIVE)'), ('Mesial movement of upper dentition', 'Increases overjet / worsens Class II', '− (NEGATIVE)'), ('Distal movement of lower dentition', 'Increases overjet / worsens Class II', '− (NEGATIVE)'), ] for i, row in enumerate(sign_data): for j, txt in enumerate(row): cell = t2.cell(i+1, j) bg = 'EBF5FB' if i % 2 == 0 else 'D6EAF8' if j == 2: bg = 'D5F5E3' if '+' in txt else 'FADBD8' set_cell_bg(cell, bg) p = cell.paragraphs[0] run = p.add_run(txt) run.font.size = Pt(10.5) run.bold = (j == 2) if '+' in txt and j == 2: run.font.color.rgb = RGBColor.from_string('1E8449') elif '−' in txt and j == 2: run.font.color.rgb = RGBColor.from_string('C0392B') else: run.font.color.rgb = RGBColor.from_string('1A1A2E') doc.add_paragraph() # The master equations add_section_heading(doc, 'The Master Equations', level=2) eq_tbl = doc.add_table(rows=2, cols=1) eq_tbl.style = 'Table Grid' eq_tbl.alignment = WD_TABLE_ALIGNMENT.CENTER eq_data = [ 'ABCH + U6 + L6 = 6/6 Change (Molar Relationship)', 'ABCH + U1 + L1 = OJ Change (Overjet)', ] eq_colors = ['1B4F72', '117A65'] for i, eq in enumerate(eq_data): cell = eq_tbl.cell(i, 0) set_cell_bg(cell, eq_colors[i]) p = cell.paragraphs[0] p.alignment = WD_ALIGN_PARAGRAPH.CENTER p.paragraph_format.space_before = Pt(5) p.paragraph_format.space_after = Pt(5) r = p.add_run(eq) r.bold = True r.font.size = Pt(12) r.font.color.rgb = RGBColor.from_string('FFFFFF') doc.add_paragraph() # Component definitions table add_section_heading(doc, 'Table 3: Components of the Pitchfork (The Tines)', level=2) t3 = doc.add_table(rows=7, cols=3) t3.style = 'Table Grid' t3.alignment = WD_TABLE_ALIGNMENT.CENTER h3 = ['Symbol', 'Full Name', 'Definition'] for j, h in enumerate(h3): cell = t3.cell(0, j) set_cell_bg(cell, '117A65') bold_para(cell, h, size=11) comp_data = [ ('MAX', 'Maxillary Advancement', 'Translatory forward growth of the maxilla relative to cranial base; measured at Wing point (W) parallel to MFOP'), ('MAND', 'Mandibular Displacement', 'Total displacement of the mandible relative to cranial base. Calculated: MAND = ABCH + MAX (or ABCH − MAX depending on sign)'), ('ABCH', 'Apical Base Change', 'Net skeletal effect = sum of maxillary and mandibular translatory growth relative to cranial base. Usually positive (mandible out-grows maxilla). Measured as displacement of D-point parallel to MFOP from a maxillary superimposition'), ('U6', 'Upper Molar Movement', 'Movement of upper first molar crown (mesial contact point) relative to maxillary basal bone, measured parallel to MFOP'), ('L6', 'Lower Molar Movement', 'Movement of lower first molar crown (mesial contact point) relative to mandibular basal bone, measured parallel to MFOP'), ('U1', 'Upper Incisor Movement', 'Displacement of incisal edge of upper central incisor relative to maxillary basal bone, measured parallel to MFOP'), ('L1', 'Lower Incisor Movement', 'Displacement of incisal edge of lower central incisor relative to mandibular basal bone, measured parallel to MFOP'), ] for i, row in enumerate(comp_data): for j, txt in enumerate(row): cell = t3.cell(i+1, j) set_cell_bg(cell, 'E9F7EF' if i % 2 == 0 else 'D5F5E3') p = cell.paragraphs[0] r = p.add_run(txt) r.font.size = Pt(10) r.bold = (j == 0) r.font.color.rgb = RGBColor.from_string('117A65' if j == 0 else '1A1A2E') doc.add_paragraph() # ══════════════════════════════════════════════════════════════════════════════ # SECTION 3 — SUPERIMPOSITION # ══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '3. SUPERIMPOSITION: PRINCIPLES AND TECHNIQUE', level=1) add_body(doc, 'Superimposition is the foundation of all measurements. It consists of two operations — registration and orientation — both MUST be based on stable (non-remodeling) reference structures.', size=10.5) add_body(doc, 'Key Rule: Cephalograms must be traced at a SINGLE SITTING, side-by-side, in temporally adjacent pairs (T1-T2, T2-T3, etc.). Each bony detail common to both films is traced in parallel.', size=10.5, bold=True, color='C0392B') doc.add_paragraph() # Flowchart 1: Superimposition Concept add_flowchart_box(doc, steps=[ ('REGISTRATION', 'Placing (stacking) two tracings so that a defined point/structure aligns — the "pivot"'), ('ORIENTATION', 'Rotating the tracings until a specified angular relationship is achieved (usually coincidence or parallelism of a reference line)'), ('RESULT', 'The spatial separation of structures between the two films = their displacement during the observed period'), ('CAUTION', 'Landmarks subject to surface remodeling (e.g., S, Na, SNB points) are INVALID as registration points in growing subjects because they are physically different at T1 vs T2'), ], title='FLOWCHART 1: How Superimposition Works', box_color='2E86C1' ) # Table 4: The three superimpositions add_section_heading(doc, 'Table 4: The Three Regional Superimpositions', level=2) t4 = doc.add_table(rows=4, cols=4) t4.style = 'Table Grid' t4.alignment = WD_TABLE_ALIGNMENT.CENTER h4 = ['Level', 'Registration Point', 'Orientation', 'What It Measures'] for j, h in enumerate(h4): cell = t4.cell(0, j) set_cell_bg(cell, '6C3483') bold_para(cell, h, size=11) sup_data = [ ('CRANIAL BASE', 'Anterior cranial base natural reference structures: anterior wall of sella turcica, greater wings of sphenoid (Wing Point W), cribriform plate, orbital roofs, inner surface of frontal bone (De Coster\'s basal line)', 'Bony anatomy from anterior half of sella turcica to region of foramen caecum and internal outline of frontal bone', 'Displacement of maxilla (MAX) and mandible (MAND) relative to cranial base. W point is the cranial-base reference from which all jaw displacements are measured.'), ('MAXILLA (Regional)', 'Zygomatic process of maxilla (key ridge) — both R and L sides averaged + bony details superior to incisors', 'Horizontal structures of hard palate (superior and inferior surfaces of posterior hard palate). IMPORTANT: ensure pterygomaxillary fissure of older tracing is AT OR BEHIND that of younger tracing', 'Displacement of D-point = ABCH (apical base change). Also used to transfer W-point. Reveals differential jaw growth and dentoalveolar compensations.'), ('MANDIBLE (Regional)', 'Facial half of the symphysis (bony architecture), mandibular canal, molar tooth germs (prior to root formation)', 'Mandibular canal alignment (or tooth germs). If unavailable: mandibular plane as substitute — only valid if minimal growth has occurred', 'Used primarily to: (a) standardize D-point through the series, (b) visualize overall mandibular growth pattern. NOT used directly to measure tooth movement.'), ] row_colors = [('F5EEF8','EBE2EF'), ('E8F8F5','D5F5E3'), ('EBF5FB','D6EAF8')] for i, row in enumerate(sup_data): for j, txt in enumerate(row): cell = t4.cell(i+1, j) set_cell_bg(cell, row_colors[i][0] if j % 2 == 0 else row_colors[i][1]) p = cell.paragraphs[0] r = p.add_run(txt) r.font.size = Pt(10) r.bold = (j == 0) r.font.color.rgb = RGBColor.from_string('6C3483' if j == 0 else '1A1A2E') doc.add_paragraph() # ── Cranial Base detail ─────────────────────────────────────────────────────── add_section_heading(doc, '3a. Cranial Base Superimposition — Detailed Notes', level=3) cb_points = [ '• S-Na (commonly used) is INVALID: both S and Na undergo local remodeling during growth (Ford 1958; Scott 1958; Latham 1972; Melsen 1974).', '• Bjork & Skieller (1983) recommended "natural reference structures": anterior wall of sella, greater wings of sphenoid, cribriform plate, orbital roofs, inner surface of frontal bone.', '• Wing Point (W): the point at which the averaged outline of the greater wings of the sphenoid crosses jugum sphenoidale (Knott 1969). Used as the cranial-base reference point from which MAX and MAND are measured.', '• A "fiducial line" — a long arbitrary line with crosses at each end — is drawn above the orbital plates of one tracing. Cranial base superimposition passes this line to all other tracings in the series.', '• Structures between the dashed vertical lines only are used (posterior half of sella and nasion region structures are IGNORED).', ] for pt in cb_points: add_body(doc, pt, size=10.5, indent=0.2) doc.add_paragraph() # ── Maxillary detail ────────────────────────────────────────────────────────── add_section_heading(doc, '3b. Maxillary Superimposition — Detailed Notes', level=3) mx_points = [ '• ANS-PNS method introduces considerable bias, especially for vertical displacement of molars and incisors (Luder 1981; Baumrind et al. 1987a,b; Nielsen 1989; Doppel et al. 1994).', '• Bjork\'s "structural method" (1955, 1964, 1968; Bjork & Skieller 1972–1983): based on zygomatic process of maxilla. Provides useful approximation of an implant superimposition.', '• Problem: anterior surface of zygomatic process is difficult to see and too short for reliable palatal plane orientation. Nielsen (1989) found it unusable ~50% of the time.', '• Best-fit registration on BOTH zygomatic process (both sides averaged) AND bony details superior to incisors.', '• Orientation: superior and inferior surfaces of posterior hard palate.', '• Critical check: pterygomaxillary fissure of the OLDER tracing must lie at or BEHIND that of the younger tracing to avoid A-P registration error.', '• Maxillary advancement (MAX) is measured at Wing point (W), parallel to MFOP.', '• Mandibular displacement relative to maxilla (ABCH) is measured at D-point, parallel to MFOP.', ] for pt in mx_points: add_body(doc, pt, size=10.5, indent=0.2) doc.add_paragraph() # ── Mandibular detail ───────────────────────────────────────────────────────── add_section_heading(doc, '3c. Mandibular Superimposition — Detailed Notes', level=3) md_points = [ '• Registration: bony architecture of FACIAL HALF of symphysis.', '• Orientation: mandibular canal alignment (primary) OR molar tooth germs prior to root formation.', '• Fallback orientation: mandibular plane — only valid when minimal growth has occurred between films.', '• Rule of thumb: if minimal overall size change, a superimposition showing marked growth rotation is WRONG.', '• Primary purpose here: to standardize D-point (centre of bony symphysis by inspection) throughout the series.', '• Tooth movement for A-P analysis is NOT measured from this superimposition directly — a modified D-point perpendicular + MFOP orientation is used instead (see Section 5).', ] for pt in md_points: add_body(doc, pt, size=10.5, indent=0.2) doc.add_paragraph() # ══════════════════════════════════════════════════════════════════════════════ # SECTION 4 — FIDUCIAL LINES # ══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '4. FIDUCIAL LINES', level=1) fid_points = [ 'Definition: An arbitrary straight line, several inches long, with registration crosses (×) at each end, drawn adjacent to cranial base, maxilla, and mandible of one tracing (preferably the MIDDLE tracing of a series).', 'Purpose: (a) Permanently records each regional superimposition so it can be reproduced and re-measured. (b) Provides a greatly simplified visual picture of translatory displacement and rotation from the vantage point of any facial region. (c) The line itself encodes all positional information of the basal bone from which it was drawn — the fiducial line BECOMES the structure.', 'Procedure: The appropriate regional superimposition transfers fiducial lines forward and backward, pairwise, throughout the series.', 'INVIOLATE RULE: Once a tracing has been used in a superimposition, its fiducial lines MUST NOT be altered. Even if the tracing is subsequently re-inked to show anatomical details for the next film, the existing fiducial lines are sacrosanct.', 'Visualization: After fiducial lines have been transferred, cranial base fiducial superimposition shows the separation of maxillary and mandibular fiducial lines = translatory growth of jaws relative to cranial base, in both amount and angulation.', 'Extended application: Fiducial lines can be used to examine post-surgical stability (e.g., mandibular advancement surgery) by regional superimposition in proximal and distal segments.', ] for pt in fid_points: add_body(doc, '• ' + pt, size=10.5, indent=0.1) doc.add_paragraph() # ══════════════════════════════════════════════════════════════════════════════ # SECTION 5 — MEASUREMENT OF CHANGE / MFOP # ══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '5. MEASUREMENT OF CHANGE & THE FUNCTIONAL OCCLUSAL PLANE', level=1) add_section_heading(doc, '5a. Why the Occlusal Plane Matters', level=3) add_body(doc, 'All measurements in the Pitchfork Analysis are projected onto (i.e., measured PARALLEL TO) the Mean Functional Occlusal Plane (MFOP). The occlusion represents the "bottom line" — the site where changes in both jaws are integrated.', size=10.5) doc.add_paragraph() # Table: Two occlusal planes compared add_section_heading(doc, 'Table 5: Downs Occlusal Plane vs Functional Occlusal Plane (FOP)', level=2) t5 = doc.add_table(rows=5, cols=3) t5.style = 'Table Grid' t5.alignment = WD_TABLE_ALIGNMENT.CENTER h5 = ['Feature', 'Downs Occlusal Plane', 'Functional Occlusal Plane (FOP) — Used Here'] for j, h in enumerate(h5): cell = t5.cell(0, j) set_cell_bg(cell, '922B21') bold_para(cell, h, size=11) plane_data = [ ('Definition', 'Bisects first molar cusp height and incisal overbite; connects the two with a straight line (Downs 1948)', 'Best-fit line through occlusal overlap of BUCCAL teeth: canine, premolars, first permanent molar (Jenkins 1955)'), ('Sensitivity to incisor movement', 'HIGH — angulation is directly a function of incisor position', 'LOW — defined by premolars and first molars; incisors deliberately excluded'), ('Stability over time', 'Relatively unstable — changes with incisor movement', 'Relatively stable; angulation decreases slightly and progressively as mandible outgrows maxilla'), ('Validity for A-P analysis', 'Poor — superficial reference', 'Good — representative of the bulk of buccal occlusion'), ] for i, row in enumerate(plane_data): for j, txt in enumerate(row): cell = t5.cell(i+1, j) bg = 'FADBD8' if i % 2 == 0 else 'F5B7B1' if j == 2: bg = 'D5F5E3' if i % 2 == 0 else 'ABEBC6' set_cell_bg(cell, bg) p = cell.paragraphs[0] r = p.add_run(txt) r.font.size = Pt(10) r.bold = (j == 0) r.font.color.rgb = RGBColor.from_string('1A1A2E') doc.add_paragraph() add_section_heading(doc, '5b. How to Establish FOP and MFOP', level=3) fop_steps = [ '1. FOP is determined by the PREMOLARS and FIRST PERMANENT MOLARS only. Second, third molars and incisors are IGNORED.', '2. Placed BY INSPECTION, using either radio-opacities (cuspal overlap) or radiolucencies between cusps along the line of occlusion (author prefers radiolucencies).', '3. Technique: a strip of acetate inscribed with a single straight line is slid between the film and the tracing. By trial-and-error manipulation, the line is positioned over the buccal occlusion to get the best-fit orientation, then copied to the tracing.', '4. For a two-film series: Maxillae are superimposed first, then the two FOPs are averaged by inspection (using lined acetate strip) to yield the MEAN FUNCTIONAL OCCLUSAL PLANE (MFOP), which is then passed through to each tracing.', '5. For a series of more than two films: MFOP is obtained by averaging the INITIAL and FINAL functional occlusal planes.', '6. Once established, MFOP is transferred to ALL tracings in the series and serves as the reference for every measurement.', '7. Note: pre-treatment FOP tends to cant downward a few degrees relative to the Downs occlusal plane (DOP); at end of treatment, the two commonly coincide.', ] for pt in fop_steps: add_body(doc, pt, size=10.5, indent=0.15) doc.add_paragraph() # ══════════════════════════════════════════════════════════════════════════════ # SECTION 6 — SKELETAL MEASUREMENTS # ══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '6. SKELETAL MEASUREMENTS (JAW DISPLACEMENT)', level=1) add_section_heading(doc, 'Table 6: Step-by-Step Skeletal Measurement Procedure', level=2) t6 = doc.add_table(rows=5, cols=3) t6.style = 'Table Grid' t6.alignment = WD_TABLE_ALIGNMENT.CENTER h6 = ['Step', 'Measurement', 'Method'] for j, h in enumerate(h6): cell = t6.cell(0, j) set_cell_bg(cell, '1B4F72') bold_para(cell, h, size=11) skel_data = [ ('1', 'Establish Wing Point (W)', 'From the middle tracing: W is where the averaged outline of the greater wings of sphenoid crosses jugum sphenoidale. The full anterior cranial base fiducial line transfers W to all other tracings.'), ('2', 'Measure MAX (Maxillary Advancement)', 'Using maxillary fiducial lines superimposed, measure the separation of W-points PARALLEL TO MFOP. Forward = positive; backward = negative.'), ('3', 'Standardize D-Point (centre of bony symphysis)', 'Using mandibular regional superimposition, transfer D-point from one tracing to all others — so D reflects only basal bone displacement, not surface remodeling.'), ('4', 'Measure ABCH (Apical Base Change)', 'From the maxillary superimposition: measure separation of D-points PARALLEL TO MFOP. If mandible outgrows maxilla (usual), ABCH is positive. NOTE: D-point displacement can result from growth, a functional shift, or both — cephalometrics CANNOT differentiate between these causes.'), ] for i, row in enumerate(skel_data): for j, txt in enumerate(row): cell = t6.cell(i+1, j) set_cell_bg(cell, 'EBF5FB' if i % 2 == 0 else 'D6EAF8') p = cell.paragraphs[0] r = p.add_run(txt) r.font.size = Pt(10) r.bold = (j <= 1) r.font.color.rgb = RGBColor.from_string('1B4F72' if j <= 1 else '1A1A2E') doc.add_paragraph() # Derived calculation for MAND add_section_heading(doc, 'Derived Calculation: MAND (Total Mandibular Displacement Relative to Cranial Base)', level=3) calc_tbl = doc.add_table(rows=1, cols=1) calc_tbl.style = 'Table Grid' cell = calc_tbl.cell(0, 0) set_cell_bg(cell, '1B4F72') p = cell.paragraphs[0] p.alignment = WD_ALIGN_PARAGRAPH.CENTER p.paragraph_format.space_before = Pt(6) p.paragraph_format.space_after = Pt(6) r = p.add_run('MAND = ABCH + MAX\n\nExample: If MAX = −3 mm (3 mm forward) and ABCH = +4 mm,\nthen MAND = 4 − (−3) = 7 mm forward') r.font.size = Pt(11) r.font.color.rgb = RGBColor.from_string('FFFFFF') r.bold = True doc.add_paragraph() add_body(doc, 'Note on maxillary rotation: Clockwise rotation increases both MAX and MAND measurements; anticlockwise decreases both. However, average maxillary basal rotation is minimal, so its effect on the analysis is probably negligible.', size=10, italic=True) doc.add_paragraph() # Flowchart 2: Skeletal measurement order add_flowchart_box(doc, steps=[ ('CRANIAL BASE SUPERIMPOSITION', 'Establish fiducial line; locate Wing Point (W)'), ('TRANSFER W to all tracings', 'Using anterior cranial base fiducial line'), ('MAXILLARY SUPERIMPOSITION', 'Superimpose maxillary fiducial lines'), ('MEASURE MAX at W', 'Separation of W-points parallel to MFOP = Maxillary Advancement'), ('MANDIBULAR SUPERIMPOSITION', 'Superimpose on facial symphysis; align mandibular canal'), ('TRANSFER D-POINT throughout series', 'Standardizes D-point relative to mandibular basal bone'), ('BACK TO MAXILLARY SUPERIMPOSITION', 'Measure separation of D-points parallel to MFOP'), ('= ABCH (Apical Base Change)', 'Then: MAND = ABCH + MAX'), ], title='FLOWCHART 2: Order of Skeletal Measurements', box_color='1B4F72' ) # ══════════════════════════════════════════════════════════════════════════════ # SECTION 7 — TOOTH MOVEMENT # ══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '7. TOOTH MOVEMENT RELATIVE TO BASAL BONE', level=1) add_body(doc, 'Tracing teeth for this analysis requires care and skill ABOVE the usual orthodontic cephalometric norm. Tooth-like cartoons drawn with plastic templates and thick pencils are NOT adequate. Precise outlines, long axes, and contact points are required.', size=10.5, bold=True, color='C0392B') doc.add_paragraph() add_section_heading(doc, 'Tracing Technique for Teeth', level=3) tracing_pts = [ 'Option 1 — Custom Template: Make a custom template from the best film (or composite of films) in the series. Add long axis, contact points, etc. Use best-fit superimposition on each film to transfer the template outline to each tracing. This standardizes tooth form, size, and long-axis orientation — optimizing measurement of CHANGE rather than absolute position.', 'Option 2 — Parallel tracing: Each bony detail common to T1 and T2 is traced in parallel — one line on one tracing, the same line executed the same way on the next. This ensures internal consistency.', ] for pt in tracing_pts: add_body(doc, pt, size=10.5, indent=0.15) doc.add_paragraph() # Table 7: Molar measurement add_section_heading(doc, 'Table 7: How to Measure Molar Movement', level=2) t7 = doc.add_table(rows=4, cols=3) t7.style = 'Table Grid' t7.alignment = WD_TABLE_ALIGNMENT.CENTER h7 = ['Component', 'How Measured', 'Notes'] for j, h in enumerate(h7): cell = t7.cell(0, j) set_cell_bg(cell, '873600') bold_para(cell, h, size=11) molar_data = [ ('Crown Movement (Total)', 'Displacement of mesial contact point measured parallel to MFOP from the relevant superimposition (maxillary for upper molar; modified D-perp + MFOP for lower molar)', 'This is the primary clinical measurement. "Upper molar movement" = U6; "Lower molar movement" = L6'), ('Root Movement (Bodily)', 'Displacement of the point where the long axis crosses a line between apices of buccal roots, measured parallel to MFOP', 'Represents pure translation of the root apex, i.e., bodily movement'), ('Tipping Component', 'TIPPING = Crown Movement − Root Movement (algebraic subtraction)', 'Allows resolution of total crown movement into bodily and tipping components, which is clinically important for anchorage analysis'), ] for i, row in enumerate(molar_data): for j, txt in enumerate(row): cell = t7.cell(i+1, j) set_cell_bg(cell, 'FEF9E7' if i % 2 == 0 else 'FDEBD0') p = cell.paragraphs[0] r = p.add_run(txt) r.font.size = Pt(10) r.bold = (j == 0) r.font.color.rgb = RGBColor.from_string('873600' if j == 0 else '1A1A2E') doc.add_paragraph() # Table 8: Incisor measurement add_section_heading(doc, 'Table 8: How to Measure Incisor Movement', level=2) t8 = doc.add_table(rows=3, cols=3) t8.style = 'Table Grid' t8.alignment = WD_TABLE_ALIGNMENT.CENTER h8 = ['Tooth', 'Measurement Point', 'Notes'] for j, h in enumerate(h8): cell = t8.cell(0, j) set_cell_bg(cell, '1A5276') bold_para(cell, h, size=11) inc_data = [ ('Upper incisor (U1)', 'Incisal edge of averaged upper central incisor, measured parallel to MFOP from maxillary superimposition', 'Same tipping vs. bodily decomposition can be applied as for molars, but for most purposes, incisal edge displacement is sufficient'), ('Lower incisor (L1)', 'Incisal edge of averaged lower central incisor, measured parallel to MFOP from the D-perp + MFOP superimposition', 'Lower incisor measured from same modified mandibular superimposition as lower molar (D-point perpendicular + MFOP orientation)'), ] for i, row in enumerate(inc_data): for j, txt in enumerate(row): cell = t8.cell(i+1, j) set_cell_bg(cell, 'EBF5FB' if i % 2 == 0 else 'D6EAF8') p = cell.paragraphs[0] r = p.add_run(txt) r.font.size = Pt(10) r.bold = (j == 0) r.font.color.rgb = RGBColor.from_string('1A5276' if j == 0 else '1A1A2E') doc.add_paragraph() # The modified mandibular superimposition add_section_heading(doc, 'Modified Mandibular Superimposition for Tooth Movement', level=3) mod_pts = [ '• Orientation: along MFOP (requires rotation of the mandibular corpus).', '• Registration: perpendicular from MFOP erected through D-point.', '• Measurements: displacement of (a) mesial contact point of averaged first molars, (b) incisal edge of averaged central incisors — all parallel to MFOP.', '• Key trade-off: this setup eliminates the vertical component of mandibular tooth movement and greatly underestimates vertical change — but simplifies and validates A-P measurement, which is the goal of this analysis.', '• Mandibular fiducial lines are NOT used in this tooth-movement superimposition.', ] for pt in mod_pts: add_body(doc, pt, size=10.5, indent=0.2) doc.add_paragraph() # ══════════════════════════════════════════════════════════════════════════════ # SECTION 8 — DIRECT MEASUREMENT & VERIFICATION # ══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '8. DIRECT MEASUREMENT OF OVERJET AND MOLAR CHANGE (VERIFICATION)', level=1) add_body(doc, 'The sum of the pitchfork tines MUST be verified against a direct MFOP superimposition. If the summed components do not agree with the direct measurement to within 0.2–0.3 mm, ALL measurements are re-done.', size=10.5, bold=True, color='C0392B') doc.add_paragraph() add_section_heading(doc, 'Table 9: Direct Measurement Technique', level=2) t9 = doc.add_table(rows=3, cols=2) t9.style = 'Table Grid' t9.alignment = WD_TABLE_ALIGNMENT.CENTER h9 = ['Measurement', 'Procedure'] for j, h in enumerate(h9): cell = t9.cell(0, j) set_cell_bg(cell, '922B21') bold_para(cell, h, size=11) direct_data = [ ('Change in Molar Relationship (6/6)', 'Register on mesial contact point of one arch\'s first molar (upper or lower). Measure separation of contact point of the opposing first molar — parallel to MFOP.'), ('Change in Overjet (OJ)', 'Register on the averaged incisal edge of upper or lower incisors. Measure displacement of the averaged incisal edge in the opposing arch — parallel to MFOP.'), ] for i, row in enumerate(direct_data): for j, txt in enumerate(row): cell = t9.cell(i+1, j) set_cell_bg(cell, 'FADBD8' if i % 2 == 0 else 'F5B7B1') p = cell.paragraphs[0] r = p.add_run(txt) r.font.size = Pt(10.5) r.bold = (j == 0) r.font.color.rgb = RGBColor.from_string('922B21' if j == 0 else '1A1A2E') doc.add_paragraph() # Flowchart 3: Verification check add_flowchart_box(doc, steps=[ ('Calculate pitchfork sum', 'ABCH + U6 + L6 = predicted 6/6 change\nABCH + U1 + L1 = predicted OJ change'), ('Perform direct MFOP superimposition', 'Measure 6/6 change and OJ change directly at occlusal plane'), ('Compare the two values', 'Are they within 0.2–0.3 mm of each other?'), ('YES → Accept measurements', 'Record all values; proceed to pitchfork diagram'), ('NO → Re-do all measurements', 'Error detected somewhere in tracing, superimposition, or measurement'), ], title='FLOWCHART 3: Internal Consistency Verification', box_color='922B21' ) # ══════════════════════════════════════════════════════════════════════════════ # SECTION 9 — RELIABILITY # ══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '9. RELIABILITY OF THE TECHNIQUE', level=1) add_body(doc, 'Reliability was assessed from double-determinations on randomly selected 5–10% of subjects. Error standard deviations calculated using Dahlberg\'s formula:', size=10.5) eq2_tbl = doc.add_table(rows=1, cols=1) cell = eq2_tbl.cell(0, 0) set_cell_bg(cell, '1B4F72') p = cell.paragraphs[0] p.alignment = WD_ALIGN_PARAGRAPH.CENTER p.paragraph_format.space_before = Pt(5) p.paragraph_format.space_after = Pt(5) r = p.add_run('S_dh = √(Σd²/2N) where d = difference between double-determinations') r.bold = True r.font.size = Pt(11) r.font.color.rgb = RGBColor.from_string('FFFFFF') doc.add_paragraph() add_section_heading(doc, 'Table 10: Reliability Results', level=2) t10 = doc.add_table(rows=6, cols=3) t10.style = 'Table Grid' t10.alignment = WD_TABLE_ALIGNMENT.CENTER h10 = ['Measure', 'Error SD (approx.)', 'Comment'] for j, h in enumerate(h10): cell = t10.cell(0, j) set_cell_bg(cell, '117A65') bold_para(cell, h, size=11) rel_data = [ ('Most skeletal and dental measures', '0.5 – 0.7 mm', 'Based on N=73 double-determination sets'), ('Best measures', '~0.53 mm', 'Achieved with collaborative team approach'), ('Worst measures', '~1.09 mm', 'Still acceptable for clinical research purposes'), ('Sample size required', '~30 subjects', 'Gives 80–90% power to detect treatment effects of 0.5–1.0 mm'), ('Collaborative protocol', 'One person traces + fiducial lines; second person independently verifies rendering of anatomical detail, landmark placement (condyles, porion, orbitale, teeth), and all regional superimposition details (registration + orientation). Verifier is BLINDED to identity of series.', ''), ] for i, row in enumerate(rel_data): for j, txt in enumerate(row): cell = t10.cell(i+1, j) set_cell_bg(cell, 'E9F7EF' if i % 2 == 0 else 'D5F5E3') p = cell.paragraphs[0] r = p.add_run(txt) r.font.size = Pt(10) r.bold = (j == 0) r.font.color.rgb = RGBColor.from_string('117A65' if j == 0 else '1A1A2E') doc.add_paragraph() add_body(doc, 'Important caveat: This collaborative approach yields SMALLER errors than single-investigator work. Errors reported here are thus somewhat optimistic.', size=10, italic=True) doc.add_paragraph() # ══════════════════════════════════════════════════════════════════════════════ # SECTION 10 — PITCHFORK DIAGRAM SUMMARY # ══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '10. THE PITCHFORK DIAGRAM — STRUCTURE & READING', level=1) add_body(doc, 'The "pitchfork" metaphor: The diagram has a HANDLE (representing ABCH — the net skeletal A-P change) and TINES (representing individual tooth movements relative to basal bone). The various tines converge at the OCCLUSAL PLANE — the bottom line.', size=10.5) doc.add_paragraph() # Schematic representation using table add_section_heading(doc, 'Table 11: Structure of the Pitchfork Diagram', level=2) t11 = doc.add_table(rows=3, cols=2) t11.style = 'Table Grid' t11.alignment = WD_TABLE_ALIGNMENT.CENTER parts = [ ('HANDLE\n(Single bar)', 'Represents ABCH — Apical Base Change\n= Net differential skeletal growth\n(mandible relative to maxilla relative to cranial base)\nUsually positive in growing patients'), ('UPPER TINES\n(Two lines from handle)', 'U6: Upper molar movement (relative to maxillary basal bone)\nU1: Upper incisor movement (relative to maxillary basal bone)\nNegative = mesial movement of uppers (worsens Class II)\nPositive = distal movement of uppers (corrects Class II)'), ('LOWER TINES\n(Two lines from handle)', 'L6: Lower molar movement (relative to mandibular basal bone)\nL1: Lower incisor movement (relative to mandibular basal bone)\nPositive = mesial movement of lowers (corrects Class II)\nNegative = distal movement of lowers (worsens Class II)'), ('CONVERGENCE POINT\n(Tip of tines)', 'Occlusal plane — where all changes integrate\nSum = actual 6/6 change OR OJ change\nInternal consistency is mandatory'), ] part_colors = [('1B4F72','2E86C1'), ('117A65','1E8449'), ('873600','B7770D'), ('6C3483','7D3C98')] for i, (label, detail) in enumerate(parts): row_idx = i // 2 col_idx = i % 2 cell = t11.cell(row_idx, col_idx) set_cell_bg(cell, part_colors[i][0]) p = cell.paragraphs[0] p.alignment = WD_ALIGN_PARAGRAPH.CENTER p.paragraph_format.space_before = Pt(5) p.paragraph_format.space_after = Pt(5) r1 = p.add_run(label + '\n') r1.bold = True r1.font.size = Pt(11) r1.font.color.rgb = RGBColor.from_string('FFFFFF') r2 = p.add_run(detail) r2.font.size = Pt(10) r2.font.color.rgb = RGBColor.from_string('FFFFFF') doc.add_paragraph() # ASCII pitchfork diagram in a box add_section_heading(doc, 'Schematic of the Pitchfork Diagram', level=2) ascii_tbl = doc.add_table(rows=1, cols=1) ascii_cell = ascii_tbl.cell(0, 0) set_cell_bg(ascii_cell, '1A1A2E') p_ascii = ascii_cell.paragraphs[0] p_ascii.alignment = WD_ALIGN_PARAGRAPH.CENTER p_ascii.paragraph_format.space_before = Pt(8) p_ascii.paragraph_format.space_after = Pt(8) ascii_text = ( "CRANIAL BASE\n" " |\n" " | MAX (maxillary advancement)\n" " |\n" " W ──────────────────────────────────────\n" " | \n" " | ABCH (apical base change = HANDLE) \n" " | \n" " D ──────────────────────────────────────\n" " / \\ \n" " / \\ \n" " U6 L6 (MOLAR TINES) \n" " | | \n" " U1 L1 (INCISOR TINES) \n" " \\ / \n" " \\ / \n" " V \n" " OCCLUSAL PLANE \n" " 6/6 Change = ABCH + U6 + L6 \n" " OJ Change = ABCH + U1 + L1 " ) r_ascii = p_ascii.add_run(ascii_text) r_ascii.font.name = 'Courier New' r_ascii.font.size = Pt(10) r_ascii.font.color.rgb = RGBColor.from_string('A9CCE3') doc.add_paragraph() # ══════════════════════════════════════════════════════════════════════════════ # SECTION 11 — CLINICAL APPLICATIONS & CONTROVERSIES # ══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '11. CLINICAL APPLICATIONS & CONTROVERSIES ADDRESSED', level=1) add_body(doc, 'The analysis generates data directly relevant to long-standing orthodontic controversies. Example applications include:', size=10.5) doc.add_paragraph() add_section_heading(doc, 'Table 12: Clinical Questions the Pitchfork Analysis Can Answer', level=2) t12 = doc.add_table(rows=8, cols=2) t12.style = 'Table Grid' t12.alignment = WD_TABLE_ALIGNMENT.CENTER h12 = ['Clinical Question', 'How Pitchfork Addresses It'] for j, h in enumerate(h12): cell = t12.cell(0, j) set_cell_bg(cell, '2E86C1') bold_para(cell, h, size=11) clin_data = [ ('Do functional appliances produce more skeletal change than conventional fixed appliances?', 'Compare ABCH (and MAND) between functional vs. fixed appliance groups; dental changes isolated via U6, L6, U1, L1'), ('Does anchorage preparation preserve anchorage?', 'Measure U6 movement (should be near zero or distal with good anchorage preparation)'), ('Do "straight wire" appliances "burn" anchorage?', 'Compare U6 movement in straight wire vs. standard edgewise groups'), ('What are the penalties for failing to use extra-oral traction?', 'Compare U6 mesial drift in patients with and without headgear'), ('Does the effect of a given appliance differ between children and adults?', 'Compare ABCH and tooth movements across age-stratified groups'), ('Does premolar extraction "dish in" the profile? If so, how much?', 'Compare U1 retraction and U6 mesial drift in extraction vs. non-extraction groups'), ('What is the impact of normal (excess mandibular) growth on tooth movement?', 'Measure ABCH in growing vs. non-growing controls; relate to U6/L6 and U1/L1'), ] for i, (q, a) in enumerate(clin_data): for j, txt in enumerate([q, a]): cell = t12.cell(i+1, j) set_cell_bg(cell, 'EBF5FB' if i % 2 == 0 else 'D6EAF8') p = cell.paragraphs[0] r = p.add_run(txt) r.font.size = Pt(10) r.font.color.rgb = RGBColor.from_string('1A1A2E') doc.add_paragraph() add_section_heading(doc, 'The "Mean Effects Are Irrelevant" Argument — Johnston\'s Rebuttal', level=3) rebuttal_pts = [ 'Some clinicians argue: "I treat my patients one at a time — means are irrelevant." Johnston calls this a "red herring."', 'Rebuttal: If the average monthly extra mandibular advancement from a functional appliance is 0.1 mm, and surgery produces effects an order of magnitude greater, the two treatments are NOT interchangeable for treatment planning — regardless of individual variation.', 'Conclusion: Valid estimates of central tendency ARE adequate to settle major clinical controversies (e.g., is a functional appliance a substitute for surgery, or just another way to move teeth?).', ] for pt in rebuttal_pts: add_body(doc, '• ' + pt, size=10.5, indent=0.1) doc.add_paragraph() # ══════════════════════════════════════════════════════════════════════════════ # SECTION 12 — STEP-BY-STEP COMPLETE FLOWCHART # ══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '12. COMPLETE STEP-BY-STEP PROTOCOL SUMMARY', level=1) add_flowchart_box(doc, steps=[ ('STEP 1: TRACING', 'Trace cephalograms at a single sitting, side-by-side, in temporally adjacent pairs. Trace every bony detail in parallel. For teeth: use custom template or meticulous parallel tracing.'), ('STEP 2: CRANIAL BASE SUPERIMPOSITION', 'Register and orient on stable anterior cranial base structures (De Coster\'s basal line: sella wall, greater sphenoid wings, cribriform plate, orbital roofs, frontal bone inner surface). Locate W-point. Draw fiducial line. Transfer W and fiducial line forward and backward through series.'), ('STEP 3: MAXILLARY SUPERIMPOSITION', 'Register on zygomatic process (both sides) + bony details above incisors. Orient on posterior hard palate (superior + inferior surfaces). Check: PTV fissure of older tracing ≥ younger. Draw fiducial line. Transfer W-point separation → measure MAX (parallel to MFOP).'), ('STEP 4: MANDIBULAR SUPERIMPOSITION', 'Register on facial symphysis architecture. Orient on mandibular canal / tooth germs. Transfer D-point throughout series. Draw fiducial line (carries all basal bone positional info).'), ('STEP 5: ESTABLISH MFOP', 'Identify FOP on each film (premolars + first molars only; ignore incisors and 2nd/3rd molars). Average FOPs by inspection on maxillary superimposition → MFOP. Transfer MFOP to ALL tracings in series.'), ('STEP 6: MEASURE ABCH', 'Back on maxillary superimposition: measure separation of D-points parallel to MFOP → ABCH. Calculate: MAND = ABCH + MAX.'), ('STEP 7: MEASURE UPPER TOOTH MOVEMENT (U6, U1)', 'Maxillary superimposition + MFOP orientation. Measure displacement of upper first molar mesial contact point (→ U6) and upper central incisor incisal edge (→ U1) parallel to MFOP. Optionally decompose into bodily + tipping.'), ('STEP 8: MEASURE LOWER TOOTH MOVEMENT (L6, L1)', 'D-point perpendicular + MFOP orientation. Measure displacement of lower first molar mesial contact point (→ L6) and lower central incisor incisal edge (→ L1) parallel to MFOP.'), ('STEP 9: VERIFICATION', 'Compare pitchfork sums with direct MFOP superimposition measurements:\n• ABCH + U6 + L6 vs. direct 6/6 measurement\n• ABCH + U1 + L1 vs. direct OJ measurement\nTolerance: ≤ 0.2–0.3 mm. If exceeded → re-do all measurements.'), ('STEP 10: DRAW PITCHFORK DIAGRAM', 'Plot ABCH as the handle; U6, L6, U1, L1 as the tines. The diagram integrates all components visually, allowing comparison across treatment groups.'), ], title='FLOWCHART 4: Complete Pitchfork Analysis Protocol', box_color='1B4F72' ) # ══════════════════════════════════════════════════════════════════════════════ # SECTION 13 — KEY POINTS / COMMON ERRORS # ══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '13. KEY POINTS & COMMON ERRORS TO AVOID', level=1) add_section_heading(doc, 'Table 13: Common Pitfalls and Correct Practice', level=2) t13 = doc.add_table(rows=8, cols=2) t13.style = 'Table Grid' t13.alignment = WD_TABLE_ALIGNMENT.CENTER h13 = ['Common Mistake / Pitfall', 'Correct Approach'] for j, h in enumerate(h13): cell = t13.cell(0, j) set_cell_bg(cell, 'C0392B') bold_para(cell, h, size=11) pitfall_data = [ ('Using S, Na, or SNB for cranial base superimposition in growing patients', 'Use De Coster\'s basal line / Bjork & Skieller natural reference structures only'), ('Using ANS-PNS method for maxillary superimposition', 'Use zygomatic process (structural method) + bony detail superior to incisors; verify with PTV check'), ('Using mandibular plane + symphysis for mandibular superimposition', 'Use mandibular canal + facial symphysis architecture; fallback to mandibular plane only if minimal growth'), ('Tracing teeth with templates + thick pencil ("cartoon teeth")', 'Trace individual tooth outlines in detail; use custom template or parallel tracing; use magnifying glass + vernier calipers for measurement'), ('Measuring change relative to a landmark subject to surface remodeling', 'Measure only from landmarks verified to be physically the same across timepoints (implant-validated studies)'), ('Forgetting to alter fiducial lines during re-inking', 'Fiducial lines are INVIOLATE once placed. Never alter them, even when re-inking for subsequent superimpositions'), ('Using Downs occlusal plane instead of FOP', 'Downs occlusal plane is angulation-sensitive to incisors. Use the functional occlusal plane (premolars + first molars) for a stable MFOP reference'), ] for i, (err, fix) in enumerate(pitfall_data): for j, txt in enumerate([err, fix]): cell = t13.cell(i+1, j) set_cell_bg(cell, 'FADBD8' if j == 0 else 'D5F5E3') p = cell.paragraphs[0] r = p.add_run(txt) r.font.size = Pt(10) r.font.color.rgb = RGBColor.from_string('1A1A2E') doc.add_paragraph() # ══════════════════════════════════════════════════════════════════════════════ # SECTION 14 — INTELLECTUAL HERITAGE # ══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '14. INTELLECTUAL HERITAGE & KEY CITATIONS', level=1) add_section_heading(doc, 'Table 14: Key Preceding Works & Their Contribution to Pitchfork Analysis', level=2) t14 = doc.add_table(rows=6, cols=3) t14.style = 'Table Grid' t14.alignment = WD_TABLE_ALIGNMENT.CENTER h14 = ['Author(s)', 'Contribution', 'Referenced For'] for j, h in enumerate(h14): cell = t14.cell(0, j) set_cell_bg(cell, '4A235A') bold_para(cell, h, size=11) heritage_data = [ ('Wylie WL (1947)', '"Assessment of Anteroposterior Dysplasia" — foundational concept of integrating component changes', 'Conceptual framework for algebraic summation'), ('Jenkins DH (1955)', 'Advocated measuring maxillo-mandibular relationship as distance between A and B points parallel to occlusal plane', 'Origin of MFOP measurement concept; functional occlusal plane definition'), ('Jacobson A (1975)', '"Wits" appraisal of jaw disharmony — borrows same analytic methods', 'Closely related measurement framework'), ('Bjork A & Skieller V (1972–1983)', 'Implant studies defining stable cranial base and maxillary/mandibular reference structures; "structural method" of superimposition', 'Validation of superimposition structures; natural reference structures for cranial base and maxilla'), ('De Coster L (1951)', '"Basal line" — defines the stable cranial base region for superimposition', 'Cranial base superimposition landmarks'), ] for i, row in enumerate(heritage_data): for j, txt in enumerate(row): cell = t14.cell(i+1, j) set_cell_bg(cell, 'F5EEF8' if i % 2 == 0 else 'EBE2EF') p = cell.paragraphs[0] r = p.add_run(txt) r.font.size = Pt(10) r.bold = (j == 0) r.font.color.rgb = RGBColor.from_string('4A235A' if j == 0 else '1A1A2E') doc.add_paragraph() # ══════════════════════════════════════════════════════════════════════════════ # FINAL SUMMARY BOX # ══════════════════════════════════════════════════════════════════════════════ add_section_heading(doc, '15. SUMMARY: STRENGTHS & LIMITATIONS', level=1) add_section_heading(doc, 'Table 15: Strengths and Limitations of Pitchfork Analysis', level=2) t15 = doc.add_table(rows=6, cols=2) t15.style = 'Table Grid' t15.alignment = WD_TABLE_ALIGNMENT.CENTER h15 = ['STRENGTHS', 'LIMITATIONS'] for j, h in enumerate(h15): color = '1E8449' if j == 0 else 'C0392B' cell = t15.cell(0, j) set_cell_bg(cell, color) bold_para(cell, h, size=12) sl_data = [ ('Internally consistent: components ALWAYS sum to total occlusal change', 'Technically demanding: requires meticulous tracing and reliable stable landmark identification'), ('Separates skeletal (ABCH) from dental (U6, L6, U1, L1) contributions', 'Cannot differentiate between growth and functional shift as causes of mandibular displacement'), ('Allows comparison across treatment modalities in both magnitude AND source of change', 'Limited to anteroposterior plane; vertical and transverse changes require separate analyses'), ('Validated against metallic implant superimpositions', 'Relies on trained personnel; single-operator reliability is lower than team approach'), ('Enables evidence-based comparison of treatment protocols at population level', 'Commercial cephalometric software not yet reliable enough to fully automate this analysis'), ] for i, (s, l) in enumerate(sl_data): for j, txt in enumerate([s, l]): cell = t15.cell(i+1, j) set_cell_bg(cell, 'D5F5E3' if j == 0 else 'FADBD8') p = cell.paragraphs[0] r = p.add_run(txt) r.font.size = Pt(10.5) r.font.color.rgb = RGBColor.from_string('1A1A2E') doc.add_paragraph() # Save out_path = '/tmp/workspace/pitchfork-notes/Pitchfork_Analysis_Notes.docx' doc.save(out_path) print(f'Saved: {out_path}') PYEOF python3 /tmp/workspace/pitchfork-notes/build_notes.py

Running Command

python3 -c " # Check: comp_data has 7 items, table needs rows=8 (header + 7 data rows) # Also t4 has 3 data rows -> rows=4 OK # Let me grep the issue import re with open('/tmp/workspace/pitchfork-notes/build_notes.py') as f: txt = f.read() # Find all add_table calls for line in txt.split('\n'): if 'add_table' in line: print(line.strip()) "

Running Command

python3 -c " with open('/tmp/workspace/pitchfork-notes/build_notes.py') as f: txt = f.read() # find the t3 section idx = txt.find('t3 = doc.add_table') print(txt[idx:idx+600]) "

Editing File

~/pitchfork-notes/build_notes.py

Successfully replaced 1 instance(s) of the string in '/tmp/workspace/pitchfork-notes/build_notes.py'
Running Command

python3 /tmp/workspace/pitchfork-notes/build_notes.py

Your notes are ready:

Pitchfork Analysis Notes

Word Document · DOCX


Here is a full outline of everything included in the document, structured for a 50-mark answer:

What's Inside — Section by Section

1. Introduction & Rationale

  • Why the analysis was developed (clinical complacency, recycled therapies, lack of proof of efficacy)
  • Table 1: Problems with existing approaches vs. how Pitchfork solves them

2. The Fundamental Concept: The Algebraic Sum

  • The core principle: molar correction and overjet change = algebraic sum of all component skeletal and dental displacements
  • Table 2: Sign convention (positive vs. negative based on effect on Class II correction)
  • Master equations in colored boxes:
    • ABCH + U6 + L6 = 6/6 Change
    • ABCH + U1 + L1 = OJ Change
  • Table 3: All 7 components of the pitchfork (MAX, MAND, ABCH, U6, L6, U1, L1) defined in detail

3. Superimposition: Principles & Technique

  • Registration vs. orientation, stable landmarks only
  • Flowchart 1: How superimposition works, including the caution about remodeling landmarks (S, Na)
  • Table 4: All three regional superimpositions — level, registration point, orientation reference, and what each measures
  • Detailed subsections on cranial base, maxillary, and mandibular superimposition with specific landmark guidance and known failure points

4. Fiducial Lines

  • Definition, purpose, transfer procedure
  • The "inviolate rule" — fiducial lines must never be altered once placed

5. Measurement of Change & the Functional Occlusal Plane

  • Table 5: Downs occlusal plane vs. FOP — definition, stability, validity
  • Step-by-step guide to establishing FOP and MFOP (including the acetate strip technique)

6. Skeletal Measurements

  • Table 6: Step-by-step for MAX, ABCH, and MAND with formulae
  • Formula box: MAND = ABCH + MAX with worked example
  • Flowchart 2: Entire skeletal measurement order from cranial base through to ABCH

7. Tooth Movement

  • Custom template technique vs. parallel tracing
  • Table 7: Molar crown, root (bodily), and tipping component — how each is measured and calculated
  • Table 8: Upper and lower incisor measurements
  • Modified mandibular superimposition for tooth movement (D-perp + MFOP orientation, trade-offs explained)

8. Verification

  • The internal consistency check (±0.2–0.3 mm tolerance)
  • Table 9: Direct measurement of 6/6 change and OJ change
  • Flowchart 3: Decision tree for the verification step

9. Reliability

  • Dahlberg's formula explained
  • Table 10: Error SDs (0.5–0.7 mm for most measures), sample size requirements, collaborative protocol
  • Caveat: team approach underestimates single-operator error

10. The Pitchfork Diagram

  • Handle (ABCH) and tines (dental components) metaphor
  • Table 11: Structure of the diagram — handle, upper tines, lower tines, convergence at occlusal plane
  • ASCII pitchfork schematic showing spatial relationships of all components

11. Clinical Applications

  • Table 12: 7 major orthodontic controversies and how Pitchfork addresses each
  • Johnston's rebuttal to the "means are irrelevant" argument

12. Complete Protocol Summary

  • Flowchart 4: 10-step complete protocol from tracing to final diagram

13. Common Errors

  • Table 13: 7 common mistakes (red column) paired with correct practice (green column)

14. Intellectual Heritage

  • Table 14: Wylie, Jenkins, Jacobson, Bjork & Skieller, De Coster — their contributions

15. Strengths & Limitations

  • Table 15: Side-by-side 5-point comparison
This is a shared conversation. Sign in to Orris to start your own chat.