/* SectorCanvas is an extension to the PlotCanvas object that lets * users select a sector in the upper half plane. The number of points * contained in the sector can be counted. This code is still under revision. * September--October, 2003 * * December, 2003 revisions: * - Removed upper-half plane only restriction (user can still only select a * half-plane) * - Increased size of "grab" handles * - Added move cursor * */ import java.awt.*; import java.awt.event.*; import java.lang.*; import java.util.Vector; import java.util.Enumeration; class SectorCanvas extends PlotCanvas implements MouseListener, MouseMotionListener { Image gbuffer; // used to double-buffer the display /* Coordinates for adjustable pointers for the sector selection */ Handle r1,r2; /* Screen coordinates for the sector are stored in this polygon (triangle) */ Polygon sector; int xu,yu; /* unit position in pixels */ /* Utility variable that indicates user is clicking on a sector * control (and which one). */ int rs=0; /* Polynomial degree */ int degree=1; /* Selected sector angle (in degrees) */ double stheta = 90; double theta = Math.PI/2; double rho=0; public double discrepancy=0.3829; double old_dis=0; boolean mouseDown=false; /* Border */ int border=0; /* The Szego curve */ SerialData szego; /* A history plot of recent discrepancies */ PlotCanvas history; public Vector dh=new Vector(); /* We added the max_discrepancy_ variables to track the current max * discrepancy/degree/theta data in the history plot for display. */ double max_discrepancy = discrepancy; double max_discrepancy_theta = theta; int max_discrepancy_degree = degree; double min_discrepancy = discrepancy; double min_discrepancy_theta = theta; int min_discrepancy_degree = degree; boolean max_discrepancy_visible = false; /* Set to true to display */ SectorCanvas(PlotCanvas pc, SerialData gabor) { /* The constructor method for this object: most initialization * steps take place here. */ super(); history=pc; sector=new Polygon(); addMouseMotionListener(this); addMouseListener(this); points=new Vector(); MPoint p=new MPoint(0,0); p.setText("Zeros in sector: "); points.addElement(p); szego=gabor; /* Initialize the discrepancy history vector */ dh.addElement(new MPoint(0,-1000.0," ")); // 1st point is a label for (int j=1;j<101;j++) { dh.addElement(new MPoint(j,-1000.0)); } } public void clear() { points=new Vector(); MPoint p=new MPoint(0,0); p.setText("Zeros in sector: "); points.addElement(p); repaint(); } public void setDegree (int j) { degree=j; setAngle (r1.x); } public void setAngle (double x) { /* Compute the selected sector angle (in degrees) */ updateSector (); stheta = 180-(180/Math.PI)*Math.acos (x); stheta = ((double)Math.round(stheta*10))/10; theta = Math.acos (x); theta = (Math.PI/180)*(180-stheta); rho = newton(0.25,theta,0.000001); discrepancy = count() - degree*omega(theta,rho); if (old_dis!=discrepancy) { dh.addElement(new MPoint(0,discrepancy)); dh.removeElementAt(1); /* XXX Set the max/min discrepancy label */ if (max_discrepancy_visible) { MPoint mp=(MPoint)dh.elementAt(0); mp.y=28; mp.x=4; mp.setText("Max: "+roundoff(max_discrepancy,4)+"/"+max_discrepancy_degree+"/"+roundoff(max_discrepancy_theta,3) + " Min: "+roundoff(min_discrepancy,4)+"/"+min_discrepancy_degree+"/"+roundoff(min_discrepancy_theta,3)); mp.setColor(new Color(200,0,0)); dh.setElementAt(mp,0); } else { dh.setElementAt(new MPoint(0,-1000," "),0); } history.plot1D(dh); if(discrepancy>max_discrepancy) { max_discrepancy = discrepancy; max_discrepancy_theta = theta; max_discrepancy_degree = degree; } else if(discrepancy0) a=Math.PI/2; else if(p.x==0 && p.y<0) a=Math.PI+Math.PI/2; else if(p.x<0) a=Math.PI+Math.atan(p.y/p.x); else if(p.x>0 && p.y<0) a=2*Math.PI+Math.atan(p.y/p.x); else a=Math.atan(p.y/p.x); if(pc.getRed() ==1 && pc.getGreen() == 1 && pc.getBlue() == 255) { //System.out.println("("+roundoff(p.x,4)+","+roundoff(p.y,4)+")"+" angle "+roundoff(a,4)+" ["+roundoff(theta,4)+", "+roundoff(2*Math.PI-theta,4)+"]"); if (a>theta &&a<(2*Math.PI-theta)) c++; } /* if(sector.contains(x,y) && pc.getRed() ==1 && pc.getGreen() == 1 && pc.getBlue() == 255) { c++; } */ } return c; } public void update(Graphics g) { /* We override update and double buffer the plot * to avoid flicker */ try{ Graphics gr; Dimension dim=getSize(); if (gbuffer==null || (! (gbuffer.getWidth(this) == dim.width && gbuffer.getHeight(this) == dim.height))) { gbuffer = this.createImage(dim.width, dim.height); } gr = gbuffer.getGraphics(); gr.setColor(getBackground()); gr.fillRect(0,0,dim.width,dim.height); paint(gr); g.drawImage(gbuffer, 0, 0, this); } catch(Exception ex){} } public void paint(Graphics g) { /* The paint method is responsible for displaying the plot * on the screen. */ /* draw border, ticks, first * checking coordinate system bounds */ d = getSize(); d.width = d.width - 2*border; d.height = d.height - 2*border; /* Compute unit location */ xu = (int)(d.width/(xmax-xmin)); yu = (int)(d.height/(ymax-ymin)); if(autoScale){ xmax=0;xmin=0;ymax=0;ymin=0; for(Enumeration e=points.elements();e.hasMoreElements();){ MPoint p=(MPoint)e.nextElement(); if(p.style!=MPoint.STYLE_TEXT){ if(p.x > xmax) xmax=p.x; if(p.x < xmin) xmin=p.x; if(p.y > ymax) ymax=p.y; if(p.y < ymin) ymin=p.y; } } /* This is a little arbitrary... */ xmax=xmax+1; ymax=ymax+1; xmin=xmin-1; ymin=ymin-1; } if(xmax==0 && xmin==0) { xmax=1; xmin=-1; } if(ymax==0 && ymin==0) { ymax=1; ymin=-1; } if(squareAspectRatio){ // make square... double s; s=Math.max(xmax,ymax); s=Math.max(s,Math.abs(xmin)); s=Math.max(s,Math.abs(ymin)); xmax=s; xmin=-s; ymax=s; ymin=-s; } /* Set the count label */ MPoint p=(MPoint)points.elementAt(0); p.x=border+8; p.y=d.height+border; p.setText(" Degree: "+degree +" Sector angle: "+roundoff(((360.0-getAngle ())/2),1)+" Zeros in sector: "+count()+" Discrepancy: "+roundoff(discrepancy,4)); points.setElementAt(p,0); double x,y,xx,yy; int j,k; x=(double)d.width; y=(double)d.height; xcenter=border+(int)Math.abs(xmin*x/(xmax-xmin)); ycenter=border+(int)Math.abs(ymax*y/(ymin-ymax)); /* Clear the plot area */ g.setColor(Color.white); g.fillRect(border,border,d.width-1, d.height-1); /* Compute and draw the sector */ updateSector(); /* The interior of the sector */ // g.setColor(new Color(233,245,240)); g.setColor(new Color(238,246,242)); g.fillPolygon(sector); /* The boundary */ g.setColor(new Color(180,255,180)); g.drawPolygon(sector); /* Draw the plot border */ g.setColor(Color.black); g.draw3DRect(border,border, d.width-1, d.height-1, true); /* Draw the sector controls (continued...)*/ g.setColor(new Color(220,220,230)); g.drawOval(xcenter - xu, ycenter - yu, 2*xu, 2*yu); /* Draw the axes and tick marks */ plotAxes(g); Color cGreen = new Color (60,180,60); /* Draw the sector controls (...continued) */ switch(rs){ case 1: g.setColor(new Color(10,10,10)); g.fillRect(r1.jj,r1.kk,r1.size,r1.size); g.drawLine(xcenter, ycenter,r1.j,r1.k); g.setColor(cGreen); g.fillRect(r2.jj,r2.kk,r2.size,r2.size); break; case 2: g.setColor(cGreen); g.fillRect(r1.jj,r1.kk,r1.size,r1.size); g.setColor(new Color(10,10,10)); g.fillRect(r2.jj,r2.kk,r2.size,r2.size); g.drawLine(xcenter, ycenter,r2.j,r2.k); break; default: g.setColor(cGreen); g.fillRect(r1.jj,r1.kk,r1.size,r1.size); g.fillRect(r2.jj,r2.kk,r2.size,r2.size); break; } /* Draw the Szego curve */ displayData(g,szego.data,new Color(240,100,120)); /* Draw the plot points */ plotData(g); } public void updateSector () { int j,k; if( (r1==null) || (r2==null) ) { /* Not initialized yet! */ r1 = new Handle(xcenter, ycenter - yu, 7); r2 = new Handle(xcenter, ycenter + yu, 7); } sector=new Polygon(); sector.addPoint(xcenter,ycenter); /* XXX XXX XXX */ j=xcenter+(int)(3*(r1.j - xcenter)); k=ycenter+(int)(3*(r1.k - ycenter)); sector.addPoint(j,k); if(jd.height) { sector.addPoint(d.width,d.height); sector.addPoint(d.width,0); // sector.addPoint(border,d.height); // sector.addPoint(border,0); } j=xcenter+(int)(3*(r2.j - xcenter)); k=ycenter+(int)(3*(r2.k - ycenter)); if(j>border+d.width) sector.addPoint(border+d.width,0); if(k>d.height) { sector.addPoint(border,0); sector.addPoint(border,d.height); // sector.addPoint(d.width,0); // sector.addPoint(d.width,d.height); } sector.addPoint(j,k); } /* Mouse events */ public void mouseDragged(MouseEvent e) { e.consume(); int mx=e.getX(); int my=e.getY(); MPoint cp=cartesian(mx,my); java.awt.Point sp; double yy; int xlim = 1+(int)(0.7071067811865475*d.width/((double)(xmax-xmin))); // (pi/4) /* XXX */ if (mxxcenter+xlim) mx=xcenter+xlim; if(rs==1){ /* Move the r1 sector control around */ if(my<=ycenter) { /* Upper half-plane */ if(mx>xcenter-xlim && mx=ycenter) { /* lower half-plane */ if(mx>xcenter-xlim && mx0) retval=1.0; return retval; } void update(int m, int n) { /* Update the handle location using the given screen coordinates */ j=m; k=n; jj=j-3; kk=k-3; MPoint p=cartesian(j,k); x=p.x; y=p.y; if (Math.abs(Math.abs(x)-0.7071067811865475) < 0.01) { x=signum(x)*0.7071067811865475; y=signum(y)*0.7071067811865475; } } void update(double u, double v) { /* Update the handle location using the given coordinates */ x=u; y=v; java.awt.Point sp = screen(x,y); j=sp.x; k=sp.y; jj=j-3; kk=k-3; } } double fn(double t, double r) { return r*Math.exp(1-r*Math.cos(t))-1.0; } double dfn(double t, double r) { return Math.exp(1-r*Math.cos(t)) - r*Math.cos(t)*Math.exp(1-r*Math.cos(t)); } double newton (double r, double t, double tol){ double d=tol+1; int j=0; double ro=r; while ((j<100)&&(d>tol)) { r=ro - fn(t,ro)/dfn(t,ro); d=Math.abs(r-ro); //System.out.println("iteration "+j+" error "+d); ro=r; j++; } return r; } double phi(double t, double r){ return t - r*Math.sin(t); } double omega (double t, double r) { return (phi(2*Math.PI-t,r)-phi(t,r))/(2*Math.PI); } String roundoff(double x, int d){ double y=Math.round(Math.pow(10,d)*x)/Math.pow(10,d); String s=y+""; int j=s.indexOf("."); if (j<0) { s=s+"."; j=s.indexOf("."); } int k=s.substring(j).length()-1; while (k