(* This figure shows the traditional version of Pappus's theorem (template "NormalForm"), and the dual version in which the roles of points and lines have been exchanged (template "DualForm"). *) PROC DrawLine(a, b, c) IS SAVE PS IN PS.MoveTo(a); PS.LineTo(b); PS.LineTo(c); PS.Close(); PS.SetWidth(1.5); PS.Stroke() END END; UI PointTool(DrawLine); PRED OnIntersect(a, b, c, d, e) IS Geometry.Colinear(b, a, c) AND Geometry.Colinear(d, a, e) END; UI PointTool(OnIntersect); PROC DrawThreeLines(a, b, c, d) IS PS.MoveTo(a); PS.LineTo(b); PS.MoveTo(a); PS.LineTo(c); PS.MoveTo(a); PS.LineTo(d); PS.SetWidth(1.5); PS.Stroke() END; UI PointTool(DrawThreeLines); PRED Colinear4(a, b, c, d) IS (d, b) PARA (c, a) AND (d, b) PARA (d, a) AND (a, c) PARA (a, d) END; UI PointTool(Colinear4); PROC NormalForm() IS IF VAR a1 = (-74.980804, 271.53912), a2 ~ (28.550434, 252.429), a3 = (118.15157, 235.89014), b1 = (-111.33514, 133.4941), b2 ~ (14.550461, 140.97948), b3 = (131.02707, 147.90538), c1 ~ (-28.571419, 203.86229), c2 ~ (41.448116, 201.66536), c3 ~ (79.490135, 200.47177) IN Geometry.Colinear(a1, a2, a3) AND Geometry.Colinear(b1, b2, b3) AND OnIntersect(c1, b1, a2, b2, a1) AND OnIntersect(c2, b1, a3, b3, a1) AND OnIntersect(c3, b2, a3, b3, a2) -> PS.SetFont("Helvetica-Bold", PS.Medium); DrawLine(a1, a2, a3); DrawLine(b1, b2, b3); DrawLine(c1, c2, c3); SAVE PS IN PS.SetColor(Color.Red); Line.Draw(a1, b2); Line.Draw(a2, b1); PS.Stroke(); PtLabel.West(c1, "C12"); PS.SetColor(Color.Blue); Line.Draw(a1, b3); Line.Draw(a3, b1); PS.Stroke(); PtLabel.South(c2, "C13"); PS.SetColor(Color.FromRGB(0, 0.7, 0)); Line.Draw(a2, b3); Line.Draw(a3, b2); PS.Stroke(); PtLabel.East(c3, "C23") END; SAVE PtLabel IN PtLabel.SetDotSize(2.5); PtLabel.North(a1, "A1"); PtLabel.North(a2, "A2"); PtLabel.North(a3, "A3"); PtLabel.South(b1, "B1"); PtLabel.South(b2, "B2"); PtLabel.South(b3, "B3") END END FI END; UI Template(NormalForm); PROC NormalForm2() IS IF VAR a1 = (-74.980804, 271.53912), a2 ~ (18.860884, 254.21753), a3 = (118.15157, 235.89014), b1 = (-111.33514, 133.4941), b2 ~ (16.748575, 141.11018), b3 = (131.02707, 147.90538), c1 ~ (-30.566229, 208.38655), c2 ~ (41.448116, 201.66536), c3 ~ (77.89583, 198.26366), a ~ (-140.05919, 131.78612), b ~ (177.15446, 150.6482), c ~ (-115.61501, 279.03952), d ~ (173.56076, 225.66252), e ~ (-97.70226, 214.65244), f ~ (170.06345, 189.66154), g ~ (160.56496, 233.61467), h ~ (164.35187, 137.28654), i ~ (148.44685, 195.6902), j ~ (-88.61368, 169.90157), k ~ (-75.73819, 235.13164), l ~ (-44.68553, 153.21481), m ~ (-24.23622, 241.95804), n ~ (45.442913, 229.82222), o ~ (43.17077, 155.49028) IN Geometry.Colinear(a1, a2, a3) AND Geometry.Colinear(b1, b2, b3) AND OnIntersect(c1, b1, a2, b2, a1) AND OnIntersect(c2, b1, a3, b3, a1) AND OnIntersect(c3, b2, a3, b3, a2) AND Colinear4(c, a1, a3, d) AND Colinear4(e, c1, c3, f) AND Colinear4(a, b1, b3, b) -> PS.SetFont("Helvetica-Bold", PS.Medium); DrawLine(c, a2, d); DrawLine(a, b2, b); DrawLine(e, c2, f); SAVE PtLabel IN PtLabel.SetDotSize(2.5); PtLabel.SetOffset(4); SAVE PS IN PS.SetColor(Color.Red); Line.Draw(a1, b2); Line.Draw(a2, b1); PS.Stroke(); PtLabel.North(c1, "C12"); PS.Type(j, "r21"); PS.Type(k, "r12"); PS.SetColor(Color.Blue); Line.Draw(a1, b3); Line.Draw(a3, b1); PS.Stroke(); PtLabel.North(c2, "C13"); PS.Type(l, "r31"); PS.Type(m, "r13"); PS.SetColor(Color.FromRGB(0, 0.7, 0)); Line.Draw(a2, b3); Line.Draw(a3, b2); PS.Stroke(); PtLabel.North(c3, "C23"); PS.Type(n, "r23"); PS.Type(o, "r32") END; PtLabel.North(a1, "A1"); PtLabel.North(a2, "A2"); PtLabel.North(a3, "A3"); PtLabel.South(b1, "B1"); PtLabel.South(b2, "B2"); PtLabel.South(b3, "B3") END; PS.Type(g, "a"); PS.Type(h, "b"); PS.Type(i, "c") END FI END; UI Template(NormalForm2); PROC DualForm() IS IF VAR Ap = (-156.77805, -76.60741), A1 = (143.90256, 8.343381), A2 = (128.75491, 65.230064), A3 = (99.217026, 135.76956), Bp = (88.61368, -96.328125), B1 = (-14.390256, 156.24876), B2 = (-65.13484, 104.6715), B3 = (-139.35826, 23.513165), P12 ~ (32.60178, -23.10224), P21 ~ (40.588882, 21.433905), P13 ~ (-21.568747, -38.406944), P31 ~ (20.569832, 70.52279), P23 ~ (-49.89758, -23.514921), P32 ~ (-15.881966, 40.28188), C12 ~ (80.88625, 246.13194), C13 ~ (86.690506, 241.44702), C23 ~ (91.373695, 241.44157), C ~ (74.30338, 209.42584), a ~ (105.276085, -18.20374), b ~ (100.73179, 38.68295), c ~ (77.25295, 106.188484), d ~ (-124.96801, -4.550935), e ~ (-67.40699, 73.57345), f ~ (-19.691929, 118.32431), g ~ (21.964075, 150.18085), h ~ (66.649605, 140.3205), i ~ (38.626476, 106.188484), j ~ (25.750984, 62.9546) IN OnIntersect(P12, Ap, A1, Bp, B2) AND OnIntersect(P21, Ap, A2, Bp, B1) AND OnIntersect(P13, Ap, A1, Bp, B3) AND OnIntersect(P31, Ap, A3, Bp, B1) AND OnIntersect(P23, Ap, A2, Bp, B3) AND OnIntersect(P32, Ap, A3, Bp, B2) AND Colinear4(P12, P21, C, C12) AND Colinear4(P13, P31, C, C13) AND (P23, C23) PARA (P32, C23) -> DrawThreeLines(Ap, A1, A2, A3); DrawThreeLines(Bp, B1, B2, B3); PS.SetFont("Helvetica-Bold", PS.Medium); PtLabel.SetDotSize(4.5); PtLabel.SetOffset(4); SAVE PS IN PS.SetColor(Color.Red); DrawLine(P12, P21, C12); PtLabel.South(P12, "R12 "); PtLabel.SE(P21, " R21"); PS.Type(h, "c12"); PS.SetColor(Color.Blue); DrawLine(P13, P31, C13); PtLabel.South(P13, "R13"); PtLabel.None(P31); PS.Type(j, "R31"); PS.Type(i, "c13"); PS.SetColor(Color.FromRGB(0, 0.5, 0)); DrawLine(P23, P32, C23); PtLabel.West(P23, "R23"); PtLabel.West(P32, "R32"); PS.Type(g, "c23") END; PtLabel.West(C, "C"); PtLabel.West(Ap, "A"); PtLabel.East(Bp, "B"); PS.Type(a, "a1"); PS.Type(b, "a2"); PS.Type(c, "a3"); PS.Type(d, "b1"); PS.Type(e, "b2"); PS.Type(f, "b3") END FI END; UI Template(DualForm);