/*----------------------------------------------------------------------+ | Title: Slate.java | | Java class Slate extends Canvas | | | | Author: David E. Joyce | | Department of Mathematics and Computer Science | | Clark University | | Worcester, MA 01610-1477 | | U.S.A. | | | | http://aleph0.clarku.edu/~djoyce/home.html | | djoyce@clarku.edu | | | | Date: February, 1996. Version 2.0.0 May, 1997. | +----------------------------------------------------------------------*/ import java.awt.*; import java.lang.String; import java.util.StringTokenizer; public class Slate extends Canvas { int eCount; Element element[]; boolean preexists[]; int picki = -1; PointElement pick = new PointElement(); PlaneElement screen; Slate (int n) { // initialize arrays if (n < 15) n=15; element = new Element[n]; preexists = new boolean[n]; // set up the screen plane element[0] = new FixedPoint(0.0,0.0,0.0); element[0].name = "screenorigin"; element[1] = new FixedPoint(1.0,0.0,0.0); element[0].name = "screenx"; element[2] = new FixedPoint(0.0,1.0,0.0); element[0].name = "screeny"; screen = new PlaneElement((PointElement)element[0], (PointElement)element[1],(PointElement)element[2]); screen.name = "screen"; screen.isScreen = true; element[3] = screen; eCount = 4; } void extendArrays() { int len = element.length; Element newelement[] = new Element[2*len]; boolean newpreexists[] = new boolean[2*len]; for (int i=0; i= ncount) break; else ns++; } else if (datachoices[i][j].equals("PointElement")) { if (ps >= pcount) break; else ps++; } else { // it's some kind of Element if (es >= ecount) break; else if (!e[es].inClass(datachoices[i][j])) break; else es++; } } if (j == datachoices[i].length) break; } if (i == datachoices.length) { message.append("Data does not fit construction method. "); return -1; } else return i; } void createElement(int c, int m, int choice, PointElement P[], Element E[], int N[]) { switch (c) { case 0: // point constructions switch (m) { case 0: // free point construction (slide on screen) element[eCount] = new PlaneSlider(screen,N[0],N[1],0.0); return; case 1: // midpoint constructions element[eCount] = new Midpoint(P[0],P[1]); return; case 2: // intersection constructions switch (choice) { case 0: element[eCount] = new Intersection(P[0],P[1],P[2],P[3],screen); break; case 1: element[eCount] = new Intersection(P[0],P[1],P[2],P[3], (PlaneElement)E[0]); break; case 2: element[eCount] = new IntersectionPL ((PlaneElement)E[0], P[0],P[1]); break; } return; case 3: // first point of a line element[eCount] = P[0]; preexists[eCount] = true; return; case 4: // last point of a line element[eCount] = P[1]; preexists[eCount] = true; return; case 5: // center of a circle or sphere if (choice == 0) element[eCount] = ((CircleElement)E[0]).Center; else element[eCount] = ((SphereElement)E[0]).Center; preexists[eCount] = true; return; case 6: // point sliding along a line if (choice == 0) N[2] = 0; element[eCount] = new LineSlider(P[0],P[1],N[0],N[1],N[2],false); return; case 7: // point sliding along a circle if (choice == 0) N[2] = 0; element[eCount] = new CircleSlider((CircleElement)E[0],N[0],N[1],N[2]); return; case 8: // circumcenter given three points if (choice == 0) E[0] = screen; Circumcircle circ = new Circumcircle(P[0],P[1],P[2],(PlaneElement)E[0]); element[eCount++] = circ; element[eCount] = circ.Center; preexists[eCount] = true; return; case 9: // vertex of a polygon element[eCount] = ((PolygonElement)E[0]).V[N[0]-1]; preexists[eCount] = true; return; case 10: // foot constructions if (choice == 0) element[eCount] = new Foot(P[0],P[1],P[2]); else element[eCount] = new PlaneFoot(P[0],(PlaneElement)E[0]); return; case 11: // cutoff construction element[eCount] = new Layoff(P[0],P[0],P[1],P[2],P[3]); return; case 12: // extend construction element[eCount] = new Layoff(P[1],P[0],P[1],P[2],P[3]); return; case 13: // parallelogram construction element[eCount] = new Layoff(P[0],P[1],P[2],P[1],P[2]); return; case 14: // similar triangle constructions if (choice == 0) E[0] = E[1] = screen; element[eCount] = new Similar(P[0],P[1],(PlaneElement)E[0],P[2],P[3], P[4],(PlaneElement)E[1]); return; case 15: // perpendicular constructions if (choice == 0) element[eCount] = new Perpendicular(P[0],P[1],screen,P[0],P[1]); else if (choice == 1) element[eCount] = new Perpendicular(P[0],P[1],(PlaneElement)E[0],P[0],P[1]); else if (choice == 2) element[eCount] = new Perpendicular(P[0],P[1],screen,P[2],P[3]); else if (choice == 3) element[eCount] = new Perpendicular(P[0],P[1],(PlaneElement)E[0],P[2],P[3]); else element[eCount] = new PlanePerpendicular(P[0],(PlaneElement)E[0],P[1],P[2]); element[eCount+1] = ((LineElement)element[eCount]).B; preexists[++eCount] = true; return; case 16: // proportion construction element[eCount] = new Proportion(P[0],P[1],P[2],P[3],P[4],P[5],P[6],P[7]); return; case 17: // invert in a circle element[eCount] = new InvertPoint(P[0],(CircleElement)E[0]); return; case 18: // meanProportional construction element[eCount] = new MeanProportional(P[0],P[1],P[2],P[3],P[4],P[5]); return; case 19: // planeSlider construction element[eCount] = new PlaneSlider((PlaneElement)E[0],N[0],N[1],N[2]); return; case 20: // sphereSlider construction element[eCount] = new SphereSlider((SphereElement)E[0],N[0],N[1],N[2]); return; case 21: // angle bisector construction if (choice == 0) E[0] = screen; element[eCount] = new AngleDivider(P[0],P[1],P[2],(PlaneElement)E[0],2); return; case 22: // angle divider construction if (choice == 0) E[0] = screen; element[eCount] = new AngleDivider(P[0],P[1],P[2],(PlaneElement)E[0],N[0]); return; case 23: // fixed point if (choice == 0) N[2] = 0; element[eCount] = new FixedPoint(N[0],N[1],N[2]); return; case 24: // point sliding along a line segment if (choice == 0) N[2] = 0; element[eCount] = new LineSlider(P[0],P[1],N[0],N[1],N[2],true); return; case 25: // fourth harmonic element[eCount] = new Harmonic(P[0],P[1],P[2]); return; } case 1: // line constructions switch (m) { case 0: // connect construction element[eCount] = new LineElement(P[0],P[1]); return; case 1: // angle bisector construction if (choice == 0) E[0] = screen; element[eCount] = new AngleDivider(P[0],P[1],P[2],(PlaneElement)E[0],2); element[++eCount] = new LineElement(P[1],(PointElement)element[eCount-1]); return; case 2: // angle divider construction if (choice == 0) E[0] = screen; element[eCount] = new AngleDivider(P[0],P[1],P[2],(PlaneElement)E[0],N[0]); element[++eCount] = new LineElement(P[1],(PointElement)element[eCount-1]); return; case 3: // foot constructions if (choice == 0) element[eCount] = new Foot(P[0],P[1],P[2]); else element[eCount] = new PlaneFoot(P[0],(PlaneElement)E[0]); element[++eCount] = new LineElement(P[0], (PointElement)element[eCount-1]); return; case 4: // chord construction element[eCount] = new Chord(P[0],P[1],(CircleElement)E[0]); return; case 5: // bichord construction element[eCount] = new Bichord((CircleElement)E[0],(CircleElement)E[1]); return; case 6: // perpendicular constructions if (choice == 0) element[eCount] = new Perpendicular(P[0],P[1],screen,P[0],P[1]); else if (choice == 1) element[eCount] = new Perpendicular(P[0],P[1],(PlaneElement)E[0],P[0],P[1]); else if (choice == 2) element[eCount] = new Perpendicular(P[0],P[1],screen,P[2],P[3]); else if (choice == 3) element[eCount] = new Perpendicular(P[0],P[1],(PlaneElement)E[0],P[2],P[3]); else element[eCount] = new PlanePerpendicular(P[0],(PlaneElement)E[0],P[1],P[2]); return; case 7: // cutoff constructions element[eCount] = new Layoff(P[0],P[0],P[1],P[2],P[3]); element[++eCount] = new LineElement(P[0],(PointElement)element[eCount-1]); return; case 8: // extend constructions element[eCount] = new Layoff(P[1],P[0],P[1],P[2],P[3]); element[++eCount] = new LineElement(P[1],(PointElement)element[eCount-1]); return; case 9: // parallel constructions element[eCount] = new Layoff(P[0],P[1],P[2],P[1],P[2]); element[++eCount] = new LineElement(P[0],(PointElement)element[eCount-1]); return; case 10: // similar triangle (angle) constructions if (choice == 0) E[0] = E[1] = screen; element[eCount] = new Similar(P[0],P[1],(PlaneElement)E[0],P[2], P[3],P[4],(PlaneElement)E[1]); element[eCount+1] = new LineElement (P[0],(PointElement)element[eCount]); preexists[++eCount] = true; return; case 11: // proportion constructions element[eCount] = new Proportion(P[0],P[1],P[2],P[3],P[4],P[5],P[6],P[7]); element[++eCount] = new LineElement(P[6],(PointElement)element[eCount-1]); return; case 12: // meanProportional constructions element[eCount] = new MeanProportional(P[0],P[1],P[2],P[3],P[4],P[5]); element[++eCount] = new LineElement(P[4],(PointElement)element[eCount-1]); return; } case 2: // circle constructions switch (m) { case 0: // radius construction switch (choice) { case 0: element[eCount] = new CircleElement(P[0],P[1],screen); return; case 1: element[eCount] = new CircleElement(P[0],P[1],P[2],screen); return; case 2: element[eCount] = new CircleElement(P[0],P[1],(PlaneElement)E[0]); return; case 3: element[eCount] = new CircleElement(P[0],P[1],P[2],(PlaneElement)E[0]); return; } case 1: // circumcircle construction if (choice == 0) E[0] = screen; element[eCount] = new Circumcircle(P[0],P[1],P[2],(PlaneElement)E[0]); return; case 2: // invert in another circle element[eCount] = new InvertCircle((CircleElement)E[0],(CircleElement)E[1]); return; case 3: // intersection construction element[eCount] = new IntersectionSS((SphereElement)E[0],(SphereElement)E[1]); return; } case 3: // polygon constructions switch (m) { case 0: // square construction if (choice == 0) E[0] = screen; element[eCount] = new RegularPolygon(P[0],P[1],(PlaneElement)E[0],4); return; case 1: // triangle construction element[eCount] = new PolygonElement(P[0],P[1],P[2]); return; case 2: // quadrilateral construction element[eCount] = new PolygonElement(P[0],P[1],P[2],P[3]); return; case 3: // pentagon construction element[eCount] = new PolygonElement(P[0],P[1],P[2],P[3],P[4]); return; case 4: // hexagon construction element[eCount] = new PolygonElement(P[0],P[1],P[2],P[3],P[4],P[5]); return; case 5: // equilateral triangle constructions if (choice == 0) E[0] = screen; element[eCount] = new RegularPolygon(P[0],P[1],(PlaneElement)E[0],3); return; case 6: // parallelogram construction Layoff fourth; fourth = new Layoff(P[0],P[1],P[2],P[1],P[2]); element[eCount] = fourth; element[++eCount] = new PolygonElement(P[0],P[1],P[2],fourth); return; case 7: // regular polygon constructions if (choice == 0) E[0] = screen; element[eCount] = new RegularPolygon(P[0],P[1],(PlaneElement)E[0],N[0]); return; case 8: // star polygon constructions if (choice == 0) E[0] = screen; element[eCount] = new RegularPolygon(P[0],P[1],(PlaneElement)E[0],N[0],N[1]); return; case 9: // similar triangle constructions if (choice == 0) E[0] = E[1] = screen; element[eCount] = new Similar(P[0],P[1],(PlaneElement)E[0],P[2],P[3], P[4],(PlaneElement)E[1]); element[eCount+1] = new PolygonElement(P[0],P[1], (PointElement)element[eCount]); preexists[++eCount] = true; return; case 10: // application construction element[eCount] = new Application((PolygonElement)E[0],P[0],P[1],P[2]); return; case 11: // octagon construction element[eCount] = new PolygonElement(P[0],P[1],P[2],P[3],P[4],P[5],P[6],P[7]); return; case 12: // face of a polyhedron element[eCount] = ((PolyhedronElement)E[0]).P[N[0]-1]; preexists[eCount] = true; return; } case 4: // sector constructions switch (m) { case 0: // sector construction if (choice == 0) E[0] = screen; element[eCount] = new SectorElement(P[0],P[1],P[2],(PlaneElement)E[0]); return; case 1: // arc construction if (choice == 0) E[0] = screen; element[eCount] = new Arc(P[0],P[1],P[2],(PlaneElement)E[0]); return; } case 5: // plane constructions switch (m) { case 0: // 3points construction element[eCount] = new PlaneElement(P[0],P[1],P[2]); return; case 1: // plane perpendicular to line element[eCount] = new PerpendicularPL(P[0], P[1]); return; case 2: // parallel construction element[eCount] = new ParallelP((PlaneElement)E[0],P[0]); return; case 3: // ambient planes if (choice == 0) element[eCount] = P[0].AP; else element[eCount] = ((CircleElement)E[0]).AP; preexists[eCount] = true; return; } case 6: // sphere constructions switch (m) { case 0: // radius constructions if (choice == 0) element[eCount] = new SphereElement(P[0],P[0],P[1]); else element[eCount] = new SphereElement(P[0],P[1],P[2]); return; } case 7: // polyhedron constructions PolygonElement Pol; switch (m) { case 0: // tetrahedron construction Pol = new PolygonElement(P[0],P[1],P[2]); element[eCount++] = Pol; element[eCount] = new Pyramid(Pol,P[3]); return; case 1: // parallelepiped construction Layoff fourth = new Layoff(P[1],P[0],P[2],P[0],P[2]); element[eCount++] = fourth; Pol = new PolygonElement(P[1],P[0],P[2],fourth); element[eCount++] = Pol; element[eCount] = new Prism(Pol,P[0],P[3]); return; case 2: // prism construction element[eCount] = new Prism((PolygonElement)E[0],P[0],P[1]); return; case 3: // pyramid construction element[eCount] = new Pyramid((PolygonElement)E[0],P[0]); return; } } return; // should never reach here, but the compiler complains } Element constructElement (String name, String elementClass, String constructionMethod, String data, StringBuffer message) { if (lookupElement(name) != null) { message.append("An element with the name " + name + " has already been created."); return null; } int c = lookupElementClass (elementClass); if (c == -1) { message.append("Element class " + elementClass + " is not known."); return null; } int m = lookupConstructionMethod (c, constructionMethod); if (m == -1) { message.append("ConstructionMethod " + constructionMethod + " is not known for " + " element class " + elementClass + "."); return null; } PointElement P[] = new PointElement[8]; // just for points Element E[] = new Element[4]; // for any other kind of elements int N[] = new int[3]; // just for integers int choice = selectDataChoice (data, constructionDataType[c][m], P, E, N, message); if (choice == -1) { message.append("Construction method " + constructionMethod + " for " + " element class " + elementClass + " with data " + data + " requires different data."); return null; } if (element.length < eCount+2) extendArrays(); createElement (c, m, choice, P, E, N); element[eCount].name = name; return element[eCount++]; } void setPivot (String param) { StringTokenizer t = new StringTokenizer(param,","); String name = t.nextToken(); Element e = lookupElement(name); if (e == null || !e.inClass("PointElement")) return; if (!t.hasMoreTokens()) { ((PointElement)e).AP = screen; screen.pivot = (PointElement)e; return; } name = t.nextToken(); Element p = lookupElement(name); if (p == null || !p.inClass("PlaneElement")) return; ((PlaneElement)p).pivot = (PointElement)e; } void reset() { for (int i=0; i w) c = w; int h = size().height; if (d < 0) d = 0; else if (d > h) d = h; if (Math.abs(c-pick.x) + Math.abs(d-pick.y) < 1.0) return; // no motion // now actually change the slate if (pick.dragable) { // drag the point if (pick.drag(c,d)) updateCoordinates(picki); else return; } else if (pick.AP != null && pick.AP.pivot != null && pick.AP.pivot != pick) // rotate around the pivot rotateCoordinates(c,d); else { // translate all coordinates double dx = c - pick.x; double dy = d - pick.y; translateCoordinates(dx,dy); } repaint(); } public boolean keyDown(Event evt, int key) { if (key=='r' || key=='R' || key==' ') { reset(); // typing r or space resets the diagram repaint(); return true; } else return false; } public boolean mouseDown(Event evt, int c, int d) { // determine which ball is closest to location (c,d). pick = null; movePick (c,d); return true; } public boolean mouseDrag(Event evt, int c, int d) { movePick (c,d); return true; } public boolean mouseUp(Event evt, int c, int d) { if (pick == null) return true; movePick(c,d); pick = null; return true; } }