import java.applet.Applet; import java.awt.*; import java.awt.event.*; public class Hyper extends Applet implements Runnable, MouseListener, MouseMotionListener { /* * Function void hypertryke() * * Physics engine for HyperTryke Trainer - uses the standard landyacht force algorithm: * - select a yacht heading and true wind speed * - calculate thrust and drag * - increase yacht speed * - calculate new thrust and drag * - loop until thrust equals drag, the top speed for that heading and true wind speed * * The hypertryke() function could be extended for use in a general purpose landyacht * performance calculation program * - has a built-in time and distance to top speed calc * - other good stuff * * Features: * - A 360° wing lift curve - sail in any direction * - Real-time acceleration, to simulate an actual sailing experience - yacht aerodynamic * forces act on the adjustable mass (weight) of the yacht * - Tire slip angle calculation uses tire rolling resistance data for tire drag calc, * slip angle value is also required to get correct wing attack angle for this fixed * wing yacht */ void hypertryke() { /* get apperant wind direction */ awind = Math.atan2(veloy+windy,velox+windx); /* CL curve */ double attack_ang = (awind - heading - slipangle_rad); if(attack_ang > Math.PI/2) attack_ang = -(Math.PI - attack_ang); else if(attack_ang < -(Math.PI/2)) attack_ang = -(- Math.PI - attack_ang); cl = (1.4 * Math.PI * ar * attack_ang) / (ar + 2.5); /* CD curve */ if(heading == -Math.PI) { cl = 0.0; cd = .1; } else cd = (Math.pow(cl,2) / (.55 * Math.PI * ar)) + .02; /* keep cd below 2.0 */ if(cd < -2.0)cd = -2.0; else if(cd > 2.0)cd = 2.0; /* stall slope */ if(cl>1.0) { cl = (Math.pow(clmax - cl, 2) * norm); } else if(cl<-1.0) { cl = -(Math.pow(clmax + cl, 2) * norm); } if(cl>1.0)cl=1.0; else if(cl<-1.0)cl=-1.0; /* apparent wind speed */ awindx = velox + windx; awindy = veloy + windy; awindv2 = (awindx * awindx) + (awindy * awindy); /* lift and drag */ lift = .001185 * awindv2 * wing_area * cl; drag = (.001185 * awindv2 * wing_area * cd) + (.001185 * awindv2 * front_area * .035); /* sideforce */ side += ((lift * Math.cos(awind - heading)) + (drag * Math.sin(awind - heading)) - side) * .1; /* slip angle */ slipangle_deg = side / vw / cc; slipangle_rad = slipangle_deg * (Math.PI / 180.0); /* break traction if sideforce is too great */ if(Math.abs(side / vw) > .75){ slipangle_rad = (awind - heading); heading += (side / vw) * .05; } /* tire drag due to slip angle */ slipdrag = Math.sin(slipangle_rad) * side; /* tire rolling resistance speed effect */ tiredrag = .015 * (1.0 + (velo / 146.666)); /* thrust */ thrust = (lift * Math.sin(awind - heading)) - ((drag * Math.cos(awind - heading)) + ((vw * tiredrag) + slipdrag)); /* acceleration */ thrusty = thrust * Math.sin(heading); thrustx = thrust * Math.cos(heading); /* realtime acceleration timer */ tic = System.currentTimeMillis(); double ticq = (tic - oldtic) * .001; velox += (32.2 * (thrustx/vw)) * ticq; veloy += (32.2 * (thrusty/vw)) * ticq; oldtic = tic; /* get total velocity */ velo = Math.sqrt(velox*velox+veloy*veloy); /* steer the yacht */ veloy = Math.sin(heading) * velo; velox = Math.cos(heading) * velo; } // end hypertryke() /* * End of yacht calculations * * Remaining code is the java interface */ private volatile Thread animateThread; Graphics wndG; Graphics memG; Graphics gageG; Image memIMG; Image gageIMG; Color myBlue; boolean hbdown; boolean wsbdown; boolean ccdown; boolean vwdown; int WIDTH; int HEIGHT; int TNUM; int t_index; long demotic; long tic; long oldtic; long flip; double awind; double heading; double steer_angle; double cd; double cl; double cl2; double cc; double vw; double ar; double wing_area; double front_area; double velox; double veloy; double velo; double windx; double windy; double awindx; double awindy; double awindv; double awindv2; double lift; double drag; double thrust; double thrustx; double thrusty; double side; double slipangle_rad; double slipangle_deg; double scurve; double tmpslip; double slipdrag; double tiredrag; double trailxy[][]; double clmax; double norm; public Hyper() { WIDTH = 370; HEIGHT = 210; heading = (90.0 / 180) * Math.PI; veloy = 40.0 * 1.4666; cc = 0.08; vw = 270.0; ar = 2.0; windx = 25.0 * 1.4666; wing_area = 30.0; front_area = 12.0; trailxy = new double[2][100]; clmax = (1.4 * Math.PI * (Math.PI/2.0) * ar) / (2.5 + ar); norm = 1.0 / Math.pow(clmax-1.0, 2); } public void init() { setBackground(Color.black); memIMG = createImage(580, 480); gageIMG = createImage(580, 480); wndG = getGraphics(); memG = memIMG.getGraphics(); memG.setFont(new Font("", 1, 18)); gageG = gageIMG.getGraphics(); oldtic = tic = System.currentTimeMillis(); addMouseListener(this); addMouseMotionListener(this); myBlue = new Color(30, 90, 255); } public void start() { drawgage(); hypertryke(); displaytryke(); animateThread = new Thread(this); animateThread.setPriority(Thread.MIN_PRIORITY); animateThread.start(); } public void stop() { animateThread = null; } public void run() { Thread thisThread = Thread.currentThread(); while (animateThread == thisThread) { try { thisThread.sleep(3); } catch(Exception ex){} hypertryke(); displaytryke(); } } public void mouseClicked(MouseEvent e){} public void mouseEntered(MouseEvent e){} public void mouseExited(MouseEvent e){} public void mouseMoved(MouseEvent e){} public void mousePressed(MouseEvent e) { double xpos = e.getX(); double ypos = e.getY(); if(ypos > 445) { if(xpos >= 13 && xpos <= 144) { vwdown = true; vw = (xpos +1 ) / .14; } else if(xpos >= 247 && xpos <= 490) { ccdown = true; cc = (xpos - 203) / 800; } } else { double xdif = xpos - 370; double ydif = ypos - 210; double tdif = (xdif * xdif) + (ydif * ydif); double tmp; if(tdif > 12000 && tdif < 44000) { tmp = Math.atan2(ypos - 210, xpos - 370); if(ypos > 210)heading = tmp - Math.PI; else if(ypos < 210)heading = tmp + Math.PI; else if(ypos == 210 && xpos < 370)heading = 0.0; else if(ypos == 210 && xpos > 370)heading = -Math.PI; hbdown = true; } tmp = mph(windx) * 0.026 + Math.PI; xdif = xpos - 78; ydif = ypos - 116; tdif = (xdif * xdif) + (ydif * ydif); if(tdif > 1200 && tdif < 5600) { tmp = Math.atan2(ypos - 116, xpos - 78) + Math.PI; windx = (tmp / 0.02618) * 1.46666; if(windx < 7.3333)windx = 7.3333; else if(windx > 88)windx = 88; wsbdown = true; } } } public void mouseReleased(MouseEvent e) { hbdown = wsbdown = vwdown = ccdown = false; } public void mouseDragged(MouseEvent e) { double xpos = e.getX(); double ypos = e.getY(); double tmp; if(hbdown) { double tmp_heading = heading; tmp = Math.atan2(ypos - 210, xpos - 370); if(ypos > 210)heading = tmp - Math.PI; else if(ypos < 210)heading = tmp + Math.PI; else if(ypos == 210 && xpos < 370)heading = 0.0; else if(ypos == 210 && xpos > 370)heading = -Math.PI; steer_angle = (tmp_heading - heading) * 10; } else if(wsbdown && ypos < 116) { tmp = Math.atan2(ypos - 116, xpos - 78) + Math.PI; windx = (tmp / 0.02618) * 1.46666; if(windx < 7.3333)windx = 7.3333; else if(windx > 88)windx = 88; } else if(vwdown && xpos >= 13 && xpos <= 144) { vw = (double)(xpos+1) / .14; } else if(ccdown && xpos >= 247 && xpos <= 490) { cc = (xpos - 203) / 800; } } void drawfoil( double angle, double heading, int size, double lox2, double loy2, boolean trails, boolean cline) { double X, Y, XR, YR, XB, YB, XO, YO, XD, X1, X2=0.0, Y1, Y2=0.0, XP, YP, R2, XA, YA, SA, CA, A, EX, EY=0.0, D2, XT=1.05, D=1.0, XC=-.2, SIZE=20.0; SA = Math.sin(angle); CA = Math.cos(angle); EX = (XT - D) * (XT - 1.0); A = XT - XC; double lox, loy; double x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2; lox = (Math.cos(heading+lox2) * loy2) + WIDTH; loy = (Math.sin(heading+lox2) * loy2) + HEIGHT; x1 = x2 = (Math.cos(angle) * size) + lox; y1 = y2 = (Math.sin(angle) * size) + loy; X = 1.0; Y = 0.0; XB = CA * X - SA * Y; YB = CA * Y + SA * X; XO = A * XB + XC; YO = A * YB; XD = XO - D; D2 = XD * XD + YO * YO; XP = XO - (EX * XD + EY * YO) / D2; YP = YO - (EY * XD + EX * YO) / D2; R2 = XP * XP + YP * YP; XA = XP + XP / R2; YA = YP - YP / R2; XR = SA * YA + CA * XA; YR = -SA * XA + CA * YA; X2 = size * XR + lox; Y2 = -size * YR + loy; for(double TH = 0.3;TH<6.41;TH+=.3) { X = Math.cos(TH); Y = Math.sin(TH); XB = CA * X - SA * Y; YB = CA * Y + SA * X; XO = A * XB + XC; YO = A * YB; XD = XO - D; D2 = XD * XD + YO * YO; XP = XO - (EX * XD + EY * YO) / D2; YP = YO - (EY * XD + EX * YO) / D2; R2 = XP * XP + YP * YP; XA = XP + XP / R2; YA = YP - YP / R2; XR = SA * YA + CA * XA; YR = -SA * XA + CA * YA; X1 = X2; Y1 = Y2; X2 = size * XR + lox; Y2 = -size * YR + loy; memG.drawLine((int)X1, (int)Y1, (int)X2, (int)Y2); } if(trails) { if(t_index<99)t_index++; else t_index=0; trailxy[0][t_index] = x2 + 2.0 - Math.random() * 4.0; trailxy[1][t_index] = y2 + 2.0 - Math.random() * 4.0; } } double deg(double rad) { return (rad/Math.PI)*180.0; } double mph(double fps) { return (fps/5280.0)*3600.0; } void drawgage() { int i, gx = 21, gy = 60, gwid = 115, vx = 370, vy = 210, tx = 600, ty = 10; String mess; gageG.setFont(new Font("", Font.PLAIN, 9)); gageG.setColor(Color.white); gageG.drawOval(vx-205,vy-205,410,410); gageG.drawOval(vx-181,vy-181,362,362); for(i=10;i<100;i+=10) { { gageG.drawString(String.valueOf(i), (int)(vx-5+Math.cos(((double)(i)/180.0)*Math.PI)*192), (int)(vy+5+Math.sin(((double)(i)/180.0)*Math.PI)*192)); gageG.drawString(String.valueOf(90-i), (int)(vx-5+Math.cos(((double)(i+90)/180.0)*Math.PI)*192), (int)(vy+5+Math.sin(((double)(i+90)/180.0)*Math.PI)*192)); gageG.drawString(String.valueOf(i), (int)(vx-5+Math.cos(((double)(i+180)/180.0)*Math.PI)*192), (int)(vy+5+Math.sin(((double)(i+180)/180.0)*Math.PI)*192)); if(90-i == 0) gageG.drawString(String.valueOf(90-i), (int)(vx-5+Math.cos(((double)(i+270)/180.0)*Math.PI)*197), (int)(vy+5+Math.sin(((double)(i+270)/180.0)*Math.PI)*197)); else gageG.drawString(String.valueOf(90-i), (int)(vx-5+Math.cos(((double)(i+270)/180.0)*Math.PI)*192), (int)(vy+5+Math.sin(((double)(i+270)/180.0)*Math.PI)*192)); } } gageG.drawArc(gx, gy, gwid, gwid, 0, 180); gageG.drawLine(gx, gy+(gwid/2), gx+gwid, gy+(gwid/2)); for(i=0;i<125;i+=10) { double rad = Math.PI+((double)i/120.0)*Math.PI; if(i==0) gageG.drawString(String.valueOf(i), (int)(gx-2+(gwid/2)+Math.cos(rad)*66.0), (int)(gy+2+(gwid/2)+Math.sin(rad)*66.0)); else if(i<100) gageG.drawString(String.valueOf(i), (int)(gx-2+(gwid/2)+Math.cos(rad)*68.0), (int)(gy+2+(gwid/2)+Math.sin(rad)*66.0)); else gageG.drawString(String.valueOf(i), (int)(gx-4+(gwid/2)+Math.cos(rad)*66.0), (int)(gy+2+(gwid/2)+Math.sin(rad)*66.0)); } gageG.drawString("VELOCITY (mph)", gx+22, gy+(gwid/2)+12); gy += 95; gageG.drawArc(gx, gy, gwid, gwid, 0, 180); gageG.drawLine(gx, gy+(gwid/2), gx+gwid, gy+(gwid/2)); gageG.setColor(Color.red); gageG.fillArc(gx+2, gy+1, gwid-4, gwid-4, 0, 20); gageG.setColor(Color.white); for(i=0;i<40;i+=5) { double rad = Math.PI+.007+((double)i/35.0)*Math.PI; gageG.drawString(String.valueOf(i), (int)(gx-2+(gwid/2)+Math.cos(rad)*66), (int)(gy+2+(gwid/2)+Math.sin(rad)*66)); } gageG.drawString("ANGLE OF ATTACK (deg)", gx+3, gy+(gwid/2)+12); gy += 95; gageG.drawArc(gx, gy, gwid, gwid, 0, 180); gageG.drawLine(gx, gy+(gwid/2), gx+gwid, gy+(gwid/2)); gageG.setColor(Color.red); gageG.fillArc(gx+2, gy+1, gwid-4, gwid-4, 0, 20); gageG.setColor(Color.white); for(i=0;i<85;i+=10) { double rad = Math.PI+.007+((double)i/80.2)*Math.PI; mess = new String(String.valueOf(i/10)); if(i==100) mess = new String("1"); if(i==0) mess = new String("0"); gageG.drawString(mess, (int)(gx-1+(gwid/2)+Math.cos(rad)*66), (int)(gy+2+(gwid/2)+Math.sin(rad)*66)); } gageG.drawString("SIDE FORCE (G's)", gx+18, gy+(gwid/2)+12); gy += 95; gageG.drawArc(gx, gy, gwid, gwid, 0, 180); gageG.drawLine(gx, gy+(gwid/2), gx+gwid, gy+(gwid/2)); gageG.drawLine(gx+(gwid/2), gy+(gwid/2), gx+(gwid/2), gy); for(i=-50;i<55;i+=10) { double rad = (Math.PI*1.5)+((double)i/100.5)*Math.PI; if(i==0) mess = new String(String.valueOf(i)); else mess = new String(String.valueOf(Math.abs(i/10))); gageG.drawString(mess, (int)(gx-1+(gwid/2)+Math.cos(rad)*66), (int)(gy+2+(gwid/2)+Math.sin(rad)*66)); } gageG.drawString("ACCELERATION (G's)", gx+10, gy+(gwid/2)+12); gageG.setFont(new Font("", Font.BOLD, 18)); gageG.drawString("- +", gx+(gwid/4), gy+(gwid/2)-16); gageG.setFont(new Font("", Font.PLAIN, 9)); gageG.drawString("VEHICLE WEIGHT (lbs X 100)", 18, 440); for(int lbi=1;lbi<11;lbi++) gageG.drawString(Integer.toString(lbi), (lbi*14)-1, 455); gageG.drawString("VEHICLE SLIP ANGLE RATIO (lbs / lbs / deg)", 273, 440); for(int sli=0;sli<25;sli+=2) if(sli+6<10) gageG.drawString(".0"+Integer.toString(sli+6), 182+((sli+6)*10), 455); else gageG.drawString("."+Integer.toString(sli+6), 182+((sli+6)*10), 455); int offset = gageG.getFontMetrics().stringWidth("APPARENT WIND"); int offset2 = offset; int xoff = gx+(gwid/2); gageG.setColor(myBlue); gageG.fillRect(xoff-(offset/2), 5, offset+4, 12); gageG.fillOval(xoff-(offset/2)-6, 5, 12, 12); gageG.fillOval(xoff+(offset/2)-4, 5, 12, 12); gageG.setColor(Color.white); gageG.drawString("APPARENT WIND", xoff+2-(offset/2), 15); offset = gageG.getFontMetrics().stringWidth("TRUE WIND"); gageG.setColor(Color.cyan); gageG.fillRect(xoff-(offset2/2), 20, offset2+4, 12); gageG.fillOval(xoff-(offset2/2)-6, 20, 12, 12); gageG.fillOval(xoff+(offset2/2)-4, 20, 12, 12); gageG.setColor(Color.black); gageG.drawString("TRUE WIND", xoff+2-(offset/2), 30); xoff = gx+(gwid/2)+95; offset = gageG.getFontMetrics().stringWidth("SLIP ANGLE"); gageG.setColor(Color.yellow); gageG.fillRect(xoff-(offset2/2), 5, offset2+5, 12); gageG.fillOval(xoff-(offset2/2)-6, 5, 12, 12); gageG.fillOval(xoff+(offset2/2)-3, 5, 12, 12); gageG.setColor(Color.black); gageG.drawString("SLIP ANGLE", xoff+2-(offset/2), 15); offset = gageG.getFontMetrics().stringWidth("TRUE COURSE"); gageG.setColor(Color.red); gageG.fillRect(xoff-(offset2/2), 20, offset2+5, 12); gageG.fillOval(xoff-(offset2/2)-6, 20, 12, 12); gageG.fillOval(xoff+(offset2/2)-3, 20, 12, 12); gageG.setColor(Color.white); gageG.drawString("TRUE COURSE", xoff+2-(offset/2), 29); } void displaytryke() { /* place gage background */ memG.drawImage(gageIMG, 0, 0, 580, 480, this); /* draw dust trails */ int i, gx = 78, gy = 116; double xx = velox * .1; double yy = veloy * .1; memG.setColor(Color.gray); double tx, ty, tx2, ty2; if(velo>.5) for(i=0;i<100;i++) { tx = tx2 = trailxy[0][i] += xx; ty = ty2 = trailxy[1][i] += yy; tx -= 370; ty -= 210; if((tx*tx+ty*ty)<32761) memG.fillRect((int)tx2, (int)ty2, 2, 2); } /* update gages */ awindv = Math.sqrt(awindv2); double gagenum; if(awindv < 176.0)gagenum = awindv; else gagenum = 176; gagenum = (double)mph(gagenum) * .026 + Math.PI; memG.setColor(myBlue); memG.drawLine( gx, gy, (int)(gx + Math.cos(gagenum) * 50), (int)(gy + Math.sin(gagenum) * 50)); memG.fillRect( (int)(gx + Math.cos(gagenum) * 50) - 1, (int)(gy + Math.sin(gagenum) * 50) - 1, 3, 3); if(velo < 176.0)gagenum = velo; else gagenum = 176; gagenum = (double)mph(gagenum) * .026 + Math.PI; memG.setColor(Color.red); memG.drawLine(gx, gy, (int)(gx + Math.cos(gagenum) * 50), (int)(gy + Math.sin(gagenum) * 50)); memG.fillRect( (int)(gx + Math.cos(gagenum) * 50) - 1, (int)(gy + Math.sin(gagenum) * 50) - 1, 3, 3); //(int)(((Math.PI - gagenum) / Math.PI) * 180) - 30, 60); if(windx < 176.0)gagenum = windx; else gagenum = 176; double tmpVal = (double)mph(gagenum) * .026 + Math.PI; double cosVal = Math.cos(tmpVal); double sinVal = Math.sin(tmpVal); memG.setColor(Color.cyan); memG.drawLine(gx, gy, (int)(gx + cosVal * 50), (int)(gy + sinVal * 50)); memG.fillArc( (int)(gx + cosVal * 55) - 18, (int)(gy + sinVal * 55) - 18, 36, 36, (int)(((Math.PI - tmpVal) / Math.PI) * 180) - 20, 40); memG.setColor(Color.white); memG.fillRect(gx-2, gy-1, 4, 4); gy += 95; gagenum = Math.abs(Math.abs(awind) - Math.abs(heading+slipangle_rad)); if(gagenum > 0.61085)gagenum = 0.61085; gagenum = (gagenum * 5.12) - Math.PI; memG.drawLine(gx, gy, (int)(gx + Math.cos(gagenum) * 50), (int)(gy + Math.sin(gagenum) * 50)); memG.fillRect( (int)(gx + Math.cos(gagenum) * 50) - 1, (int)(gy + Math.sin(gagenum) * 50) - 1, 3, 3); memG.fillRect(gx-2, gy-1, 4, 4); gy += 95; gagenum = Math.abs(side * ((270)/vw)); if(gagenum > 216)gagenum = 216; gagenum = (gagenum * .0145) - Math.PI; memG.drawLine(gx, gy, (int)(gx + Math.cos(gagenum) * 50), (int)(gy + Math.sin(gagenum) * 50)); memG.fillRect( (int)(gx + Math.cos(gagenum) * 50) - 1, (int)(gy + Math.sin(gagenum) * 50) - 1, 3, 3); memG.fillRect(gx-2, gy-1, 4, 4); gy += 95; gagenum = thrust/vw; if(gagenum < -.5)gagenum = -.5; else if(gagenum > .5)gagenum = .5; if(gagenum<0.0)memG.setColor(Color.red); else memG.setColor(Color.green); gagenum = (gagenum * Math.PI) - (Math.PI * .5); memG.drawLine(gx, gy, (int)(gx + Math.cos(gagenum)*50), (int)(gy + Math.sin(gagenum)*50)); memG.fillRect( (int)(gx + Math.cos(gagenum) * 50) - 1, (int)(gy + Math.sin(gagenum) * 50) - 1, 3, 3); memG.setColor(Color.white); memG.fillRect(gx-2, gy-1, 4, 4); gx = 168; gy = 210; memG.fillArc((int)((vw*.14)-18), 438, 36, 36, 250, 40); // weight memG.fillArc((int)(185+(cc*800)), 438, 36, 36, 250, 40); // slip /* draw vehicle */ memG.setColor(Color.gray); drawfoil(steer_angle+heading,heading+slipangle_rad,12,Math.PI,-120,true,true); steer_angle = 0; drawfoil(heading+slipangle_rad,heading+slipangle_rad,12,-2.15,85,true,true); drawfoil(heading+slipangle_rad,heading+slipangle_rad,12,2.15,85,true,true); drawfoil(heading+slipangle_rad,heading+slipangle_rad,35,Math.PI, 0,false,false); memG.setColor(Color.cyan); memG.drawLine( WIDTH-184, (int)(HEIGHT), WIDTH, (int)(HEIGHT)); memG.drawOval( WIDTH-192-8, (int)(HEIGHT)-8, 16,16); memG.setColor(myBlue); tmpVal = awind+Math.PI; cosVal = Math.cos(tmpVal); sinVal = Math.sin(tmpVal); memG.drawLine( (int)(WIDTH + cosVal * 184), (int)(HEIGHT + sinVal * 184), WIDTH, (int)HEIGHT); memG.drawOval( (int)(WIDTH + cosVal * 192) - 8, (int)(HEIGHT + sinVal * 192) - 8, 16,16); memG.setColor(Color.yellow); tmpVal = heading + slipangle_rad + Math.PI; cosVal = Math.cos(tmpVal); sinVal = Math.sin(tmpVal); memG.drawLine( (int)(WIDTH + cosVal * 184), (int)(HEIGHT + sinVal * 184), WIDTH, (int)HEIGHT); memG.drawOval( (int)(WIDTH + cosVal * 192) - 8, (int)(HEIGHT + sinVal * 192) - 8, 16, 16); memG.setColor(Color.red); tmpVal = heading + Math.PI; cosVal = Math.cos(tmpVal); sinVal = Math.sin(tmpVal); memG.drawLine( (int)(WIDTH + cosVal * 184), (int)(HEIGHT + sinVal * 184), WIDTH, (int)HEIGHT); memG.drawOval( (int)(WIDTH + cosVal * 192) - 8, (int)(HEIGHT + sinVal * 192) - 8, 16,16); memG.fillArc( (int)(WIDTH + cosVal * 182)-18, (int)(HEIGHT + sinVal * 182)-18, 36, 36, (int)(((Math.PI - tmpVal) / Math.PI) * 180) - 20, 40); memG.fillOval((int)WIDTH-10, (int)HEIGHT-10, 20, 20); memG.setColor(Color.white); memG.fillArc((int)WIDTH-10, (int)HEIGHT-10, 20, 20, 0, 90); memG.fillArc((int)WIDTH-10, (int)HEIGHT-10, 20, 20, 180, 90); if(Math.abs(Math.abs(awind)-Math.abs(heading+slipangle_rad))>0.575) { if(flip < System.currentTimeMillis()) flip = System.currentTimeMillis() + 250; if(flip > System.currentTimeMillis() + 125) { memG.drawString("STALL WARNING",WIDTH-80,90); memG.drawString("STALL WARNING",WIDTH-80,320); } } wndG.drawImage(memIMG, 0, 0, 580, 480, this); }// end displaytryke() }// end class hyper