// // PoliSim.java-- emulate several candidates running in an election, // using a 2-D model of political positions. // // jsm-- could I speed up by making some methods "final"? // import java.applet.* ; import java.awt.* ; import java.awt.image.* ; public class PoliSim extends Applet implements Runnable { Candidate cand[] ; BorderSeg bordersegs[][] ; boolean isuptodate ; // panel components int fieldmax ; FieldCanvas mainfield ; BarGraphCanvas bargraph= new BarGraphCanvas(160, 260, true) ; Button animator= new Button("Run automatically") ; TextField numcandentry= new TextField(4) ; Button newcandstart= new Button("Go") ; Button upone= new Button("Add 1") ; Button downone= new Button("Remove 1") ; Button buffertoggle= new Button() ; int round= 0 ; boolean hasbeenmoved= false ; // hack to get right space allocation Label rounddisplay= new Label("Round "+round+(hasbeenmoved?"*":"")+" ") ; Button resetround= new Button("Reset rounds") ; // applet parameters int numtests ; double angles[] ; private double t ; static private int framespersecond= 20 ; Thread PoliSimThread ; Image doubleBuffer ; boolean autopilot= false ; public void init() { // get field size and create related components int fieldsize= getIntParameter("fieldsize", 400) ; fieldmax= fieldsize-1 ; mainfield= new FieldCanvas(fieldsize, fieldsize, true) ; // generate candidate list int numcands= getIntParameter("numcands", 4) ; cand= newcandlist(numcands) ; isuptodate= false ; // get any other applet parameters numtests= getIntParameter("numtests", 5) ; angles= getangles(numtests) ; // add components to main panel setLayout(new FlowLayout(FlowLayout.LEFT)) ; add(mainfield) ; Panel p= new Panel() ; p.setLayout(new BorderLayout()) ; p.add("North", bargraph) ; p.add("South", animator) ; Panel p2= new Panel() ; p2.add(resetround) ; p2.add(rounddisplay) ; p.add("West", p2) ; add(p) ; p= new Panel() ; p.add(new Label("Enter number of candidates:")) ; p.add(numcandentry) ; p.add(newcandstart) ; p.add(upone) ; p.add(downone) ; add(p) ; add(buffertoggle) ; // set various component fields if (mainfield.isbuffered) buffertoggle.setLabel("Increase Speed") ; else buffertoggle.setLabel("Reduce flicker") ; numcandentry.setText(Integer.toString(numcands)) ; } // generate new candidate list // ensure there's always at least one candidate public Candidate[] newcandlist(int numcands) { if (numcands<1) numcands= 1 ; Candidate newcand[]= new Candidate[numcands] ; float hue= (float)Math.random() ; for (int i=0; i1) hue-= 1 ; newcand[i]= new Candidate(Math.random()*(fieldmax+1), Math.random()*(fieldmax+1), Color.getHSBColor (hue, (float)1.0, (float)1.0) ) ; } return newcand ; } // calculate all new data, based on new candidate positions public void calculate() { // return immediately if allowed if (!isuptodate) { // otherwise, only allow one calculation at a time synchronized (this) { // if a thread waited, don't make it recalculate if (!isuptodate) { bordersegs= getbordersegs(cand) ; calcareas(cand,bordersegs) ; isuptodate= true ; } } } } // create list of perpendicular bisectors, plus framing lines // assumes no candidates are EXACTLY the same point. private BorderLine[] getborders(Candidate cand[]) { Point2D midpt ; Line2D connector ; BorderLine borders[]= new BorderLine[(cand.length*(cand.length-1))/2+4] ; int numborders= 0 ; for (int i=0; i0 && borders[i].c1!=null && borders[i].c2!=null) { Point2D startpoint= segs[i][0].p1 ; Point2D endpoint= segs[i][numsegs-1].p2 ; segs[i][0]= new BorderSeg(startpoint, endpoint, borders[i].c1,borders[i].c2) ; segs[i][0].isgood= true ; numsegs= 1 ; } // truncate the segment array BorderSeg seglist[]= new BorderSeg[numsegs] ; System.arraycopy(segs[i], 0, seglist, 0, numsegs) ; segs[i]= seglist ; // OK, line segments are now created /* BorderSeg newseg ; Point2D startpoint, endpoint ; for (int k=0; k bestarea ) { bestarea= newarea ; bestpt= newpt ; } // not strictly thread-safe, but safe enough for this app? PoliSimThread.yield() ; } newpos[i]= bestpt ; // save best location } // after testing all, set locations to new locations for (int i=0; i=x1 && Math.round(x)<=x2 && Math.round(y)>=y1 && Math.round(y)<=y2) ; } // make sure point is inside given rectangle public void constrain(double x1, double y1, double x2, double y2) { if (xx2) x= x2 ; if (yy2) y= y2 ; } // distance between two points public double distance(Point2D p) { double dx= p.x-this.x ; double dy= p.y-this.y ; return Math.sqrt(dx*dx+dy*dy) ; } // distance squared (faster, and often sufficient) public double distance2(Point2D p) { double dx= p.x-this.x ; double dy= p.y-this.y ; return dx*dx+dy*dy ; } // midpoint between two points public Point2D midpoint(Point2D p) { return new Point2D((this.x+p.x)/2, (this.y+p.y)/2) ; } // line connecting two points public Line2D connect(Point2D p) { return new Line2D(this,p) ; } ////////////////////////////////////////////////////////////////////// // hard-coded sort routine, until I get the general one working // binary sort an array; requires cmp() routine public static Point2D[] binsort(Point2D a[]) { return binsortpart(a, 0, a.length) ; } // binary sort part of an array (used by binsort()) public static Point2D[] binsortpart(Point2D a[], int start, int end) { // guard against bad input if (start>end) return null ; // first, if start=end, return that element if (start==end) { Point2D result[]= { a[start] } ; return result ; } // otherwise: sort two halves, and merge them int mid= (start+end)/2 ; Point2D[] a1= binsortpart(a, start, mid) ; Point2D[] a2= binsortpart(a, mid+1, end) ; return binmerge(a1,a2) ; } // merge two sorted lists (used by binsortpart()) public static Point2D[] binmerge(Point2D a1[], Point2D a2[]) { Point2D result[]= new Point2D[a1.length+a2.length] ; int sofar= 0 ; int i1=0, i2=0 ; while (sofarend) return null ; // first, if start=end, return that element if (start==end) { Point2D result[]= { a[start] } ; return result ; } // otherwise: sort two halves, and merge them int mid= (start+end)/2 ; Point2D[] a1= binsortpart(a, start, mid) ; Point2D[] a2= binsortpart(a, mid+1, end) ; return binmergeu(a1,a2) ; } // merge two sorted lists, removing duplicates (used by binsortpartu()) public static Point2D[] binmergeu(Point2D a1[], Point2D a2[]) { Point2D result[]= new Point2D[a1.length+a2.length] ; Point2D last ; int sofar= 0 ; int i1=0, i2=0 ; while (i1end) return null ; // first, if start=end, return that element if (start==end) { Sortable result[]= { o[start] } ; return result ; } // otherwise: sort two halves, and merge them int mid= (start+end)/2 ; Sortable[] a1= binsortpart(o, start, mid) ; Sortable[] a2= binsortpart(o, mid+1, end) ; return binmerge(a1,a2) ; } // merge two sorted lists (used by binsortpart()) public static Sortable[] binmerge(Sortable a1[], Sortable a2[]) { Sortable result[]= new Sortable[a1.length+a2.length] ; int sofar= 0 ; int i1=0, i2=0 ; while (sofar0 value }