Advertisement
jtvd78

Graphing

May 16th, 2012
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 30.19 KB | None | 0 0
  1. package com.justin.window;
  2.  
  3. import java.awt.Color;
  4. import java.awt.Font;
  5. import java.awt.Graphics;
  6. import java.awt.Point;
  7. import java.awt.Rectangle;
  8. import java.awt.event.ComponentEvent;
  9. import java.awt.event.ComponentListener;
  10. import java.awt.event.MouseEvent;
  11. import java.awt.event.MouseListener;
  12. import java.awt.event.MouseMotionListener;
  13. import java.awt.event.MouseWheelEvent;
  14. import java.awt.event.MouseWheelListener;
  15.  
  16. import javax.swing.JComponent;
  17.  
  18. import com.justin.function.FunctionController;
  19. import com.justin.function.LogFunction;
  20. import com.justin.function.QuadraticFunction;
  21. import com.justin.function.SpecialFunction;
  22.  
  23. public class GraphingComp extends JComponent{
  24.    
  25.     //--------SETTINGS--------//
  26.    
  27.         //False: No restriction on Current X
  28.         //True: The current X Slider will be restricted to integers
  29.             boolean lockCurrentX = false;
  30.        
  31.         //Size of circles (px) at current X location
  32.             int circleSize = 10;
  33.            
  34.         //Size (px) that the tick marks will be
  35.             int tickMarkSize = 20;
  36.        
  37.         //Font size
  38.             int fontSize = 12;
  39.            
  40.         //Weather to draw the background grid or not
  41.             boolean drawGrid = true;
  42.            
  43.         //Preferred Scale
  44.             int prefScale = fontSize*3;
  45.    
  46.     //---------END SETTINGS----------//
  47.        
  48.     //Amount in pixels that each unit on the graph is.
  49.     //This is used a lot in the program.
  50.     //These variables are essential to mouse input and drawing.
  51.     //Defaults to 'prefScale'
  52.         float xScl = prefScale;
  53.         float yScl = prefScale;
  54.        
  55.     //The amount that a single tick mark is.
  56.     //This variable is changed in the 'updateVariables()' method...
  57.     //so the graph does not become too cluttered
  58.         int xAmt = 1;
  59.         int yAmt = 1;
  60.    
  61.     //This object holds all of the functions that are drawn on the graph
  62.         FunctionController functionController;
  63.    
  64.     //Width and Height of the window. They are updated when the program repaints; 'UpdateVariables()'
  65.     //It is easier to use 'w' instead of 'getWidth()'
  66.         int w = -1;
  67.         int h = -1;
  68.    
  69.     //Position of origin (px) on screen.
  70.     //They are moved to the center of the screen when the program starts
  71.         float originX = -1;
  72.         float originY = -1;
  73.        
  74.     //Holds the location of the current X
  75.         float currentX = 0;
  76.     //If 'lockCurrentX' is true, this variable holds the true location of the currentX
  77.         float realCurrentX = currentX;
  78.    
  79.     //If the mouse is clicked on the currentX circle, This will be true
  80.     //This tells the program to move the current X if it being clicked on.
  81.         boolean allowCurrentXMovement = false;
  82.    
  83.     //Indicates weather the screen is being drawn for the first time.
  84.     //It is made false after the program is initialized
  85.         boolean firstTime = true;
  86.    
  87.     //Current quadrant of the mouse on the screen
  88.         int currentQuadrant = -1;
  89.    
  90.     //true if mouse is pressed
  91.     //includes all buttons
  92.         boolean pressed[] = new boolean[4];
  93.    
  94.     //position of mouse on window
  95.         int mouseX = -1;
  96.         int mouseY = -1;
  97.        
  98.     //Variables used for resizing the screen.
  99.     //They make sure that the origin is in the same relative...
  100.     //Spot when the screen is resized
  101.         int oldWidth = -1;
  102.         int oldHeight = -1;
  103.    
  104.        
  105.     //Constructor
  106.     public GraphingComp(FunctionController c){
  107.        
  108.         //Random functions added for testing
  109.         c.addFunction(new QuadraticFunction(new double[]{Math.PI,0,0},Color.red));
  110.         c.addFunction(new QuadraticFunction(new double[]{2*Math.PI,0,0},Color.green));
  111.     //  c.addFunction(new QuadraticFunction(new double[]{(-3d/25d),(6d/5d),0},Color.red));
  112.     //  c.addFunction(new QuadraticFunction(new double[]{(-4d/25d),(8d/5d),0},Color.red));
  113.     //  c.addFunction(new QuadraticFunction(new double[]{(-1d/9d),(8d/6d),0},Color.green));
  114.     //  c.addFunction(new QuadraticFunction(new double[]{(-3d/36d),(6d/6d),0},Color.green));
  115.     //  c.addFunction(new QuadraticFunction(new double[]{(-2d/36d),(4d/6d),0},Color.green));
  116.        
  117.     //  c.addFunction(new SpecialFunction(Color.blue));
  118.     //  c.addFunction(new LogFunction(2,Color.yellow));
  119.     //  c.addFunction(new Function(new int[]{4,4,-6,-5},Color.cyan));
  120.     //  c.addFunction(new Function(new int[]{4,4,-6,-6},Color.magenta));
  121.         this.functionController = c;
  122.        
  123.         //Listener is the subclass that implements all of the input interfaces
  124.         Listener l = new Listener();
  125.        
  126.         addMouseMotionListener(l);
  127.         addMouseListener(l);
  128.         addMouseWheelListener(l);
  129.        
  130.         //Adds resize listener(subclass) for window resize
  131.         addComponentListener(new ResizeListener());
  132.     }
  133.  
  134.     //This method is called whenever the program needs to paint the window
  135.     public void paintComponent(Graphics g){
  136.         updateVariables();
  137.        
  138.         //Stops the drawing if the window hasn't been properly initialized yet.
  139.         if(w == -1 || h == -1) return;
  140.        
  141.         //Called only when the program has been first started.
  142.         if(firstTime){
  143.             initFirstTime();
  144.             firstTime = false;
  145.         }
  146.        
  147.         g.setFont(new Font(null,Font.PLAIN,fontSize)); //Sets the font to the font size in the settings
  148.        
  149.         //----START GRAPH DRAWING----//
  150.         drawBackground(g);
  151.         drawAxis(g);
  152.        
  153.         //Draw currentX line
  154.         g.setColor(Color.white);
  155.         g.drawLine((int)(currentX*xScl)+(int)(originX),0,(int)(currentX*xScl)+(int)(originX),h);
  156.        
  157.         drawFunctions(g);
  158.         drawXOval(g);
  159.         //-----END GRAPH DRAWING--//
  160.     }
  161.    
  162.     //Does first-time initializing
  163.     public void initFirstTime(){
  164.         oldWidth = w;
  165.         oldHeight = h;
  166.        
  167.         originX = w/2;
  168.         originY = h/2;
  169.     }
  170.    
  171.     public void updateVariables(){
  172.         w = getWidth();
  173.         h = getHeight();
  174.        
  175.         xAmt = (int)((float)(prefScale)/xScl);
  176.         yAmt = (int)((float)(prefScale)/yScl);
  177.         if(xAmt == 0){
  178.             xAmt = 1;
  179.         }
  180.         if(yAmt == 0){
  181.             yAmt = 1;
  182.         }
  183.     }
  184.    
  185.     //Draws the background
  186.     public void drawBackground(Graphics g){
  187.         g.setColor(Color.black);
  188.         g.fillRect(0, 0, w,h);
  189.     }
  190.    
  191.     //Draws the axis
  192.     public void drawAxis(Graphics g){
  193.        
  194.         g.setColor(new Color(40,40,40)); //Gray
  195.        
  196.         //Edits where the loops should start at in order to have the tick marks in the right spot
  197.         int xc = (int)(originX/xScl) %xAmt - xAmt;
  198.         int yc = (int)(originY/yScl) %yAmt - yAmt;
  199.  
  200.         //Draws background grid
  201.         if(drawGrid){
  202.             for(int c = xc; c < Math.ceil(w/xScl)+1; c+=xAmt){
  203.                 g.drawLine((int)(xScl*c + originX % xScl), 0, (int)(xScl*c  + originX % xScl), h); //x
  204.             }
  205.            
  206.             for(int c = yc; c < Math.ceil(h/yScl)+1; c+=yAmt){
  207.                 g.drawLine(0,(int)(yScl*c + originY % yScl), w , (int)(yScl*c  + originY % yScl)); //y
  208.             }
  209.         }
  210.            
  211.         g.setColor(Color.white);
  212.        
  213.         //Draws tick marks and numbers for X axis
  214.         for(int c = xc; c < Math.ceil(w/xScl)+1; c+=xAmt){
  215.             g.drawLine((int)(xScl*c + (int)(originX) % xScl), (int)(originY)+(tickMarkSize/2), (int)(xScl*c + (int)(originX) % xScl), (int)(originY)-(tickMarkSize/2));
  216.             g.drawString(c-((int)((int)(originX)/xScl)) + "", (int)(xScl*c + (int)(originX) % xScl - fontSize/4), (int)(originY)+(tickMarkSize/2)+fontSize);
  217.         }
  218.            
  219.         //Draws tick marks and numbers for Y axis
  220.         for(int c = yc; c < Math.ceil(h/yScl)+1; c+=yAmt){
  221.             g.drawLine((int)(originX)+(tickMarkSize/2),(int)(yScl*c + originY % yScl), (int)(originX)-(tickMarkSize/2), (int)(yScl*c + originY % yScl));
  222.             g.drawString(-c+((int)(originY/yScl)) + "",(int)(originX)+(tickMarkSize/2)+fontSize/4,(int)(yScl*c + originY % yScl)+fontSize/2);
  223.         }
  224.        
  225.         //Draws X and Y axis lines
  226.         g.drawLine((int)(originX),0,(int)(originX),h); g.drawLine((int)(originX)-1,0,(int)(originX)-1,h); g.drawLine((int)(originX)+1,0,(int)(originX)+1,h);
  227.         g.drawLine(0, (int)(originY), w, (int)(originY)); g.drawLine(0, (int)(originY)-1, w, (int)(originY)-1); g.drawLine(0, (int)(originY)+1, w, (int)(originY)+1);
  228.     }
  229.    
  230.     //Draws the functions
  231.     public void drawFunctions(Graphics g){     
  232.        
  233.        
  234.         //X positions (px) that the graph should start and stop (edge of the screen)
  235.         int begin = -(int)(originX);
  236.         int end = w+begin;
  237.        
  238.         //Value of Y where the current X marker is.
  239.         float yy = -1;
  240.        
  241.         //Loops through every function in function controller
  242.         for(int c = 0; c < functionController.getFunctionCount(); c++){
  243.             g.setColor(functionController.getColor(c)); //Sets color to the graph's corresponding color
  244.            
  245.             //Previous x and y points.
  246.             //The functions are graphed when by finding a point, and then drawing a line...
  247.             //from that point to the previous point. So it is necessary to save the previous point.
  248.             //I defaulted them to -1000, so they would be off the screen
  249.             int xp = -1000;
  250.             int yp = -1000;
  251.            
  252.             //Loops from begin to end, and draws the corresponding points.  
  253.             for(int x = begin; x < end; x++){
  254.                 int y = (int) ((functionController.getY(x/xScl,c))*yScl);  
  255.                
  256.                 g.drawLine(xp, yp, x+(int)(originX),-y+(int)(originY));
  257.                
  258.                 xp = x+(int)(originX);
  259.                 yp =  -y+(int)(originY);
  260.             }
  261.            
  262.             yy = functionController.getY((currentX),c); //sets yy.
  263.            
  264.             //Draws a circle on the function where the current X is.
  265.             g.fillOval((int)(currentX*xScl)+(int)(originX)-(circleSize/2),((int)((-yy*yScl))+(int)(originY))-(circleSize/2),(circleSize),(circleSize));
  266.             g.drawString((float)(Math.round(yy*100))/100 + "",(int)(currentX*xScl)+(int)(originX) +20,((int)((-yy*yScl))+(int)(originY)));
  267.            
  268.             g.setColor(Color.black);
  269.             g.drawOval((int)(currentX*xScl)+(int)(originX)-(circleSize/2),((int)((-yy*yScl))+(int)(originY))-(circleSize/2),(circleSize),(circleSize));
  270.         }
  271.     }
  272.    
  273.     //Draws Oval for the current X marker
  274.     public void drawXOval(Graphics g){     
  275.         //oval
  276.         g.setColor(Color.white);
  277.         g.fillOval((int)(currentX*xScl)+(int)(originX)-(circleSize/2),(int)(originY)-(circleSize/2),(circleSize),(circleSize));
  278.        
  279.         //oval border
  280.         g.setColor(Color.black);
  281.         g.drawOval((int)(currentX*xScl)+(int)(originX)-(circleSize/2),(int)(originY)-(circleSize/2),(circleSize),(circleSize));
  282.         g.drawLine((int)(currentX*xScl)+(int)(originX),(int)(originY)-(circleSize/2),(int)(currentX*xScl)+(int)(originX),(int)(originY)+(circleSize/2));
  283.         g.drawLine((int)(currentX*xScl)+(int)(originX)-(circleSize/2),(int)(originY),(int)(currentX*xScl)+(int)(originX)+(circleSize/2),(int)(originY));
  284.     }
  285.    
  286.     //Gets the quadrant of a point on the screen
  287.     public int getQuadrant(int x, int y){
  288.         if(x > (int)(originX)){
  289.             if(y < originY){
  290.                 return 1;
  291.             }else if(y > originY){
  292.                 return 4;
  293.             }else{
  294.                 System.out.println("y"); //if mouse is on y axis
  295.             }
  296.         }else if(x < (int)(originX)){
  297.             if(y < originY){
  298.                 return 2;
  299.             }else if(y > originY){
  300.                 return 3;
  301.             }else{
  302.                 System.out.println("y2");
  303.             }
  304.         }else{
  305.             System.out.println("x"); //if mouse is on x axis
  306.         }
  307.         return -1;
  308.     }
  309.    
  310.     public void toggleXLock(){
  311.         if(lockCurrentX == false){
  312.             lockCurrentX = true;
  313.         }else{
  314.             lockCurrentX = false;
  315.         }
  316.     }
  317.    
  318.     //This class implements every interface used for input.
  319.     //It only contains inherited methods
  320.     class Listener implements MouseListener, MouseWheelListener,MouseMotionListener{
  321.  
  322.         //Zooms in and out when the mouse wheel is moved
  323.         @Override
  324.         public void mouseWheelMoved(MouseWheelEvent e) {
  325.             if(e.getWheelRotation() > 0){
  326.                 zoomOut();
  327.             }else{
  328.                 zoomIn();
  329.             }
  330.         }
  331.  
  332.         //Called when mouse button is pressed down.
  333.         @Override
  334.         public void mousePressed(MouseEvent e) {
  335.             pressed[e.getButton()] = true;
  336.            
  337.             //If the left mouse button is pressed, it checks to see if the mouse is in the current X circle.
  338.             //If it is, 'allowCurrentXMovement' is made true. Actual movement is dealt with in 'mouseMoved(Mouse Event e)'
  339.             if(pressed[1]){
  340.                 Rectangle r = new Rectangle((int)(currentX*xScl)+(int)(originX)-(circleSize/2),(int)(originY)-(circleSize/2),(circleSize),(circleSize));
  341.                 if(r.contains(new Point(mouseX,mouseY))){
  342.                     allowCurrentXMovement = true;
  343.                 }
  344.             }
  345.         }
  346.  
  347.         //called when mouse button is released
  348.         @Override
  349.         public void mouseReleased(MouseEvent e) {
  350.             allowCurrentXMovement = false;
  351.             pressed[e.getButton()] = false;
  352.             currentQuadrant = -1;
  353.         }
  354.  
  355.         //Called when mouse is pressed while it is being moved
  356.         //I just called MouseMoved(e), because I handle all of the mouse movement in that method.
  357.         @Override
  358.         public void mouseDragged(MouseEvent e) {
  359.             mouseMoved(e);
  360.         }
  361.  
  362.         @Override
  363.         public void mouseMoved(MouseEvent e) {
  364.             if(pressed[1]){
  365.                 //If mouse is on current X circle, move the current X location
  366.                 if(allowCurrentXMovement){
  367.                     realCurrentX =((e.getX()-originX)/xScl);
  368.                     if(lockCurrentX){
  369.                         currentX = Math.round(realCurrentX);
  370.                     }else{
  371.                         currentX = realCurrentX;
  372.                     }
  373.                 }else{
  374.                     //Allows the graph to be moved around when the scroll wheel is being held down.
  375.                     originX -= mouseX-e.getX();
  376.                     originY -= mouseY-e.getY();
  377.                 }
  378.                 repaint();
  379.             }else if(pressed[2]){
  380.                 //Middle Mouse Button
  381.                
  382.                
  383.            
  384.             }else if(pressed[3]){
  385.                
  386.                 float rat = (float)(xScl)/(float)(yScl);
  387.                
  388.                 //When the right mouse button is being held down, the user can adjust the x and y scale.
  389.                 //Lots of repeated code. This is what I am currently working on.
  390.                 if((currentQuadrant = getQuadrant(mouseX, mouseY)) != -1){
  391.                     if(!((e.getX()-originX) == 0 || (e.getY()-originY) == 0)){
  392.                         xScl -= (mouseX-e.getX())*(xScl/(e.getX()-originX));
  393.                         yScl -= (mouseY-e.getY())*(yScl/(e.getY()-originY));
  394.                     }
  395.                 }
  396.                
  397.                
  398.                 //makes sure that the screen is not resized to be too zoomed in.
  399.                 if(yScl > h/2){
  400.                     yScl = h/2;
  401.                 }
  402.                 if(xScl > w/2){
  403.                     xScl = w/2;
  404.                 }
  405.  
  406.                 //sets x and y scale to 1 if they have been set to lower than 1.
  407.                 if(xScl <= 1 || xScl == Float.NaN || xScl == Float.POSITIVE_INFINITY){
  408.                     xScl = 1;
  409.                 }
  410.                 if(yScl <= 1 || yScl == Float.NaN || yScl == Float.POSITIVE_INFINITY){
  411.                     yScl = 1;
  412.                 }
  413.                 repaint();
  414.             }
  415.            
  416.             //sets mouse coordinates
  417.             mouseX = e.getX();
  418.             mouseY = e.getY();
  419.         }
  420.        
  421.         //-----START UNUSED METHODS----//
  422.         @Override
  423.         public void mouseClicked(MouseEvent e) {}
  424.  
  425.         @Override
  426.         public void mouseEntered(MouseEvent e) {}
  427.  
  428.         @Override
  429.         public void mouseExited(MouseEvent e) {}
  430.         //------END UNUSED METHODS----//
  431.        
  432.     }
  433.    
  434.     //Makes sure that the origin is in the same location at resize
  435.     class ResizeListener implements ComponentListener{
  436.  
  437.         //Called when window is resized
  438.         @Override
  439.         public void componentResized(ComponentEvent e) {
  440.            
  441.             //Keeps the origin the same relative distance from the edge of the screen.         
  442.             originX *= ((float)(getWidth())/(float)(oldWidth));
  443.             originY *= ((float)(getHeight())/(float)(oldHeight));
  444.            
  445.             oldWidth = getWidth();
  446.             oldHeight = getHeight();
  447.            
  448.             repaint();
  449.         }
  450.  
  451.         //-----START UNUSED METHODS----//
  452.         @Override
  453.         public void componentMoved(ComponentEvent e) {}
  454.  
  455.         @Override
  456.         public void componentShown(ComponentEvent e) {}
  457.  
  458.         @Override
  459.         public void componentHidden(ComponentEvent e) {}
  460.         //-----END UNUSED METHODS----//
  461.     }
  462.    
  463.     //Zooms In
  464.     public void zoomIn(){
  465.        
  466.         float rat = (float)(xScl)/(float)(yScl);
  467.        
  468.         xScl*=1.25;
  469.         yScl*=1.25;
  470.        
  471.         if(xScl > w/2){
  472.             xScl = w/2;
  473.             yScl = xScl/rat;
  474.             repaint();
  475.             return;
  476.         }else if(yScl > h/2){
  477.             yScl = h/2;
  478.             xScl = rat*yScl;
  479.             repaint();
  480.             return;
  481.         }
  482.         repaint();
  483.     }
  484.    
  485.     //Zooms out
  486.     public void zoomOut(){
  487.        
  488.         float rat = (float)(xScl)/(float)(yScl);
  489.        
  490.         xScl*=0.8;
  491.         yScl*=0.8;
  492.        
  493.         if(xScl < 1){
  494.             xScl = 1;
  495.             yScl = xScl/rat;
  496.             repaint();
  497.             return;
  498.         }else if(yScl < 1){
  499.             yScl = 1;
  500.             xScl = rat*yScl;
  501.             repaint();
  502.             return;
  503.         }
  504.         repaint();
  505.     }
  506. }package com.justin.window;
  507.  
  508. import java.awt.Color;
  509. import java.awt.Font;
  510. import java.awt.Graphics;
  511. import java.awt.Point;
  512. import java.awt.Rectangle;
  513. import java.awt.event.ComponentEvent;
  514. import java.awt.event.ComponentListener;
  515. import java.awt.event.MouseEvent;
  516. import java.awt.event.MouseListener;
  517. import java.awt.event.MouseMotionListener;
  518. import java.awt.event.MouseWheelEvent;
  519. import java.awt.event.MouseWheelListener;
  520.  
  521. import javax.swing.JComponent;
  522.  
  523. import com.justin.function.FunctionController;
  524. import com.justin.function.LogFunction;
  525. import com.justin.function.QuadraticFunction;
  526. import com.justin.function.SpecialFunction;
  527.  
  528. public class GraphingComp extends JComponent{
  529.    
  530.     //--------SETTINGS--------//
  531.    
  532.         //False: No restriction on Current X
  533.         //True: The current X Slider will be restricted to integers
  534.             boolean lockCurrentX = false;
  535.        
  536.         //Size of circles (px) at current X location
  537.             int circleSize = 10;
  538.            
  539.         //Size (px) that the tick marks will be
  540.             int tickMarkSize = 20;
  541.        
  542.         //Font size
  543.             int fontSize = 12;
  544.            
  545.         //Weather to draw the background grid or not
  546.             boolean drawGrid = true;
  547.            
  548.         //Preferred Scale
  549.             int prefScale = fontSize*3;
  550.    
  551.     //---------END SETTINGS----------//
  552.        
  553.     //Amount in pixels that each unit on the graph is.
  554.     //This is used a lot in the program.
  555.     //These variables are essential to mouse input and drawing.
  556.     //Defaults to 'prefScale'
  557.         float xScl = prefScale;
  558.         float yScl = prefScale;
  559.        
  560.     //The amount that a single tick mark is.
  561.     //This variable is changed in the 'updateVariables()' method...
  562.     //so the graph does not become too cluttered
  563.         int xAmt = 1;
  564.         int yAmt = 1;
  565.    
  566.     //This object holds all of the functions that are drawn on the graph
  567.         FunctionController functionController;
  568.    
  569.     //Width and Height of the window. They are updated when the program repaints; 'UpdateVariables()'
  570.     //It is easier to use 'w' instead of 'getWidth()'
  571.         int w = -1;
  572.         int h = -1;
  573.    
  574.     //Position of origin (px) on screen.
  575.     //They are moved to the center of the screen when the program starts
  576.         float originX = -1;
  577.         float originY = -1;
  578.        
  579.     //Holds the location of the current X
  580.         float currentX = 0;
  581.     //If 'lockCurrentX' is true, this variable holds the true location of the currentX
  582.         float realCurrentX = currentX;
  583.    
  584.     //If the mouse is clicked on the currentX circle, This will be true
  585.     //This tells the program to move the current X if it being clicked on.
  586.         boolean allowCurrentXMovement = false;
  587.    
  588.     //Indicates weather the screen is being drawn for the first time.
  589.     //It is made false after the program is initialized
  590.         boolean firstTime = true;
  591.    
  592.     //Current quadrant of the mouse on the screen
  593.         int currentQuadrant = -1;
  594.    
  595.     //true if mouse is pressed
  596.     //includes all buttons
  597.         boolean pressed[] = new boolean[4];
  598.    
  599.     //position of mouse on window
  600.         int mouseX = -1;
  601.         int mouseY = -1;
  602.        
  603.     //Variables used for resizing the screen.
  604.     //They make sure that the origin is in the same relative...
  605.     //Spot when the screen is resized
  606.         int oldWidth = -1;
  607.         int oldHeight = -1;
  608.    
  609.        
  610.     //Constructor
  611.     public GraphingComp(FunctionController c){
  612.        
  613.         //Random functions added for testing
  614.         c.addFunction(new QuadraticFunction(new double[]{Math.PI,0,0},Color.red));
  615.         c.addFunction(new QuadraticFunction(new double[]{2*Math.PI,0,0},Color.green));
  616.     //  c.addFunction(new QuadraticFunction(new double[]{(-3d/25d),(6d/5d),0},Color.red));
  617.     //  c.addFunction(new QuadraticFunction(new double[]{(-4d/25d),(8d/5d),0},Color.red));
  618.     //  c.addFunction(new QuadraticFunction(new double[]{(-1d/9d),(8d/6d),0},Color.green));
  619.     //  c.addFunction(new QuadraticFunction(new double[]{(-3d/36d),(6d/6d),0},Color.green));
  620.     //  c.addFunction(new QuadraticFunction(new double[]{(-2d/36d),(4d/6d),0},Color.green));
  621.        
  622.     //  c.addFunction(new SpecialFunction(Color.blue));
  623.     //  c.addFunction(new LogFunction(2,Color.yellow));
  624.     //  c.addFunction(new Function(new int[]{4,4,-6,-5},Color.cyan));
  625.     //  c.addFunction(new Function(new int[]{4,4,-6,-6},Color.magenta));
  626.         this.functionController = c;
  627.        
  628.         //Listener is the subclass that implements all of the input interfaces
  629.         Listener l = new Listener();
  630.        
  631.         addMouseMotionListener(l);
  632.         addMouseListener(l);
  633.         addMouseWheelListener(l);
  634.        
  635.         //Adds resize listener(subclass) for window resize
  636.         addComponentListener(new ResizeListener());
  637.     }
  638.  
  639.     //This method is called whenever the program needs to paint the window
  640.     public void paintComponent(Graphics g){
  641.         updateVariables();
  642.        
  643.         //Stops the drawing if the window hasn't been properly initialized yet.
  644.         if(w == -1 || h == -1) return;
  645.        
  646.         //Called only when the program has been first started.
  647.         if(firstTime){
  648.             initFirstTime();
  649.             firstTime = false;
  650.         }
  651.        
  652.         g.setFont(new Font(null,Font.PLAIN,fontSize)); //Sets the font to the font size in the settings
  653.        
  654.         //----START GRAPH DRAWING----//
  655.         drawBackground(g);
  656.         drawAxis(g);
  657.        
  658.         //Draw currentX line
  659.         g.setColor(Color.white);
  660.         g.drawLine((int)(currentX*xScl)+(int)(originX),0,(int)(currentX*xScl)+(int)(originX),h);
  661.        
  662.         drawFunctions(g);
  663.         drawXOval(g);
  664.         //-----END GRAPH DRAWING--//
  665.     }
  666.    
  667.     //Does first-time initializing
  668.     public void initFirstTime(){
  669.         oldWidth = w;
  670.         oldHeight = h;
  671.        
  672.         originX = w/2;
  673.         originY = h/2;
  674.     }
  675.    
  676.     public void updateVariables(){
  677.         w = getWidth();
  678.         h = getHeight();
  679.        
  680.         xAmt = (int)((float)(prefScale)/xScl);
  681.         yAmt = (int)((float)(prefScale)/yScl);
  682.         if(xAmt == 0){
  683.             xAmt = 1;
  684.         }
  685.         if(yAmt == 0){
  686.             yAmt = 1;
  687.         }
  688.     }
  689.    
  690.     //Draws the background
  691.     public void drawBackground(Graphics g){
  692.         g.setColor(Color.black);
  693.         g.fillRect(0, 0, w,h);
  694.     }
  695.    
  696.     //Draws the axis
  697.     public void drawAxis(Graphics g){
  698.        
  699.         g.setColor(new Color(40,40,40)); //Gray
  700.        
  701.         //Edits where the loops should start at in order to have the tick marks in the right spot
  702.         int xc = (int)(originX/xScl) %xAmt - xAmt;
  703.         int yc = (int)(originY/yScl) %yAmt - yAmt;
  704.  
  705.         //Draws background grid
  706.         if(drawGrid){
  707.             for(int c = xc; c < Math.ceil(w/xScl)+1; c+=xAmt){
  708.                 g.drawLine((int)(xScl*c + originX % xScl), 0, (int)(xScl*c  + originX % xScl), h); //x
  709.             }
  710.            
  711.             for(int c = yc; c < Math.ceil(h/yScl)+1; c+=yAmt){
  712.                 g.drawLine(0,(int)(yScl*c + originY % yScl), w , (int)(yScl*c  + originY % yScl)); //y
  713.             }
  714.         }
  715.            
  716.         g.setColor(Color.white);
  717.        
  718.         //Draws tick marks and numbers for X axis
  719.         for(int c = xc; c < Math.ceil(w/xScl)+1; c+=xAmt){
  720.             g.drawLine((int)(xScl*c + (int)(originX) % xScl), (int)(originY)+(tickMarkSize/2), (int)(xScl*c + (int)(originX) % xScl), (int)(originY)-(tickMarkSize/2));
  721.             g.drawString(c-((int)((int)(originX)/xScl)) + "", (int)(xScl*c + (int)(originX) % xScl - fontSize/4), (int)(originY)+(tickMarkSize/2)+fontSize);
  722.         }
  723.            
  724.         //Draws tick marks and numbers for Y axis
  725.         for(int c = yc; c < Math.ceil(h/yScl)+1; c+=yAmt){
  726.             g.drawLine((int)(originX)+(tickMarkSize/2),(int)(yScl*c + originY % yScl), (int)(originX)-(tickMarkSize/2), (int)(yScl*c + originY % yScl));
  727.             g.drawString(-c+((int)(originY/yScl)) + "",(int)(originX)+(tickMarkSize/2)+fontSize/4,(int)(yScl*c + originY % yScl)+fontSize/2);
  728.         }
  729.        
  730.         //Draws X and Y axis lines
  731.         g.drawLine((int)(originX),0,(int)(originX),h); g.drawLine((int)(originX)-1,0,(int)(originX)-1,h); g.drawLine((int)(originX)+1,0,(int)(originX)+1,h);
  732.         g.drawLine(0, (int)(originY), w, (int)(originY)); g.drawLine(0, (int)(originY)-1, w, (int)(originY)-1); g.drawLine(0, (int)(originY)+1, w, (int)(originY)+1);
  733.     }
  734.    
  735.     //Draws the functions
  736.     public void drawFunctions(Graphics g){     
  737.        
  738.        
  739.         //X positions (px) that the graph should start and stop (edge of the screen)
  740.         int begin = -(int)(originX);
  741.         int end = w+begin;
  742.        
  743.         //Value of Y where the current X marker is.
  744.         float yy = -1;
  745.        
  746.         //Loops through every function in function controller
  747.         for(int c = 0; c < functionController.getFunctionCount(); c++){
  748.             g.setColor(functionController.getColor(c)); //Sets color to the graph's corresponding color
  749.            
  750.             //Previous x and y points.
  751.             //The functions are graphed when by finding a point, and then drawing a line...
  752.             //from that point to the previous point. So it is necessary to save the previous point.
  753.             //I defaulted them to -1000, so they would be off the screen
  754.             int xp = -1000;
  755.             int yp = -1000;
  756.            
  757.             //Loops from begin to end, and draws the corresponding points.  
  758.             for(int x = begin; x < end; x++){
  759.                 int y = (int) ((functionController.getY(x/xScl,c))*yScl);  
  760.                
  761.                 g.drawLine(xp, yp, x+(int)(originX),-y+(int)(originY));
  762.                
  763.                 xp = x+(int)(originX);
  764.                 yp =  -y+(int)(originY);
  765.             }
  766.            
  767.             yy = functionController.getY((currentX),c); //sets yy.
  768.            
  769.             //Draws a circle on the function where the current X is.
  770.             g.fillOval((int)(currentX*xScl)+(int)(originX)-(circleSize/2),((int)((-yy*yScl))+(int)(originY))-(circleSize/2),(circleSize),(circleSize));
  771.             g.drawString((float)(Math.round(yy*100))/100 + "",(int)(currentX*xScl)+(int)(originX) +20,((int)((-yy*yScl))+(int)(originY)));
  772.            
  773.             g.setColor(Color.black);
  774.             g.drawOval((int)(currentX*xScl)+(int)(originX)-(circleSize/2),((int)((-yy*yScl))+(int)(originY))-(circleSize/2),(circleSize),(circleSize));
  775.         }
  776.     }
  777.    
  778.     //Draws Oval for the current X marker
  779.     public void drawXOval(Graphics g){     
  780.         //oval
  781.         g.setColor(Color.white);
  782.         g.fillOval((int)(currentX*xScl)+(int)(originX)-(circleSize/2),(int)(originY)-(circleSize/2),(circleSize),(circleSize));
  783.        
  784.         //oval border
  785.         g.setColor(Color.black);
  786.         g.drawOval((int)(currentX*xScl)+(int)(originX)-(circleSize/2),(int)(originY)-(circleSize/2),(circleSize),(circleSize));
  787.         g.drawLine((int)(currentX*xScl)+(int)(originX),(int)(originY)-(circleSize/2),(int)(currentX*xScl)+(int)(originX),(int)(originY)+(circleSize/2));
  788.         g.drawLine((int)(currentX*xScl)+(int)(originX)-(circleSize/2),(int)(originY),(int)(currentX*xScl)+(int)(originX)+(circleSize/2),(int)(originY));
  789.     }
  790.    
  791.     //Gets the quadrant of a point on the screen
  792.     public int getQuadrant(int x, int y){
  793.         if(x > (int)(originX)){
  794.             if(y < originY){
  795.                 return 1;
  796.             }else if(y > originY){
  797.                 return 4;
  798.             }else{
  799.                 System.out.println("y"); //if mouse is on y axis
  800.             }
  801.         }else if(x < (int)(originX)){
  802.             if(y < originY){
  803.                 return 2;
  804.             }else if(y > originY){
  805.                 return 3;
  806.             }else{
  807.                 System.out.println("y2");
  808.             }
  809.         }else{
  810.             System.out.println("x"); //if mouse is on x axis
  811.         }
  812.         return -1;
  813.     }
  814.    
  815.     public void toggleXLock(){
  816.         if(lockCurrentX == false){
  817.             lockCurrentX = true;
  818.         }else{
  819.             lockCurrentX = false;
  820.         }
  821.     }
  822.    
  823.     //This class implements every interface used for input.
  824.     //It only contains inherited methods
  825.     class Listener implements MouseListener, MouseWheelListener,MouseMotionListener{
  826.  
  827.         //Zooms in and out when the mouse wheel is moved
  828.         @Override
  829.         public void mouseWheelMoved(MouseWheelEvent e) {
  830.             if(e.getWheelRotation() > 0){
  831.                 zoomOut();
  832.             }else{
  833.                 zoomIn();
  834.             }
  835.         }
  836.  
  837.         //Called when mouse button is pressed down.
  838.         @Override
  839.         public void mousePressed(MouseEvent e) {
  840.             pressed[e.getButton()] = true;
  841.            
  842.             //If the left mouse button is pressed, it checks to see if the mouse is in the current X circle.
  843.             //If it is, 'allowCurrentXMovement' is made true. Actual movement is dealt with in 'mouseMoved(Mouse Event e)'
  844.             if(pressed[1]){
  845.                 Rectangle r = new Rectangle((int)(currentX*xScl)+(int)(originX)-(circleSize/2),(int)(originY)-(circleSize/2),(circleSize),(circleSize));
  846.                 if(r.contains(new Point(mouseX,mouseY))){
  847.                     allowCurrentXMovement = true;
  848.                 }
  849.             }
  850.         }
  851.  
  852.         //called when mouse button is released
  853.         @Override
  854.         public void mouseReleased(MouseEvent e) {
  855.             allowCurrentXMovement = false;
  856.             pressed[e.getButton()] = false;
  857.             currentQuadrant = -1;
  858.         }
  859.  
  860.         //Called when mouse is pressed while it is being moved
  861.         //I just called MouseMoved(e), because I handle all of the mouse movement in that method.
  862.         @Override
  863.         public void mouseDragged(MouseEvent e) {
  864.             mouseMoved(e);
  865.         }
  866.  
  867.         @Override
  868.         public void mouseMoved(MouseEvent e) {
  869.             if(pressed[1]){
  870.                 //If mouse is on current X circle, move the current X location
  871.                 if(allowCurrentXMovement){
  872.                     realCurrentX =((e.getX()-originX)/xScl);
  873.                     if(lockCurrentX){
  874.                         currentX = Math.round(realCurrentX);
  875.                     }else{
  876.                         currentX = realCurrentX;
  877.                     }
  878.                 }else{
  879.                     //Allows the graph to be moved around when the scroll wheel is being held down.
  880.                     originX -= mouseX-e.getX();
  881.                     originY -= mouseY-e.getY();
  882.                 }
  883.                 repaint();
  884.             }else if(pressed[2]){
  885.                 //Middle Mouse Button
  886.                
  887.                
  888.            
  889.             }else if(pressed[3]){
  890.                
  891.                 float rat = (float)(xScl)/(float)(yScl);
  892.                
  893.                 //When the right mouse button is being held down, the user can adjust the x and y scale.
  894.                 //Lots of repeated code. This is what I am currently working on.
  895.                 if((currentQuadrant = getQuadrant(mouseX, mouseY)) != -1){
  896.                     if(!((e.getX()-originX) == 0 || (e.getY()-originY) == 0)){
  897.                         xScl -= (mouseX-e.getX())*(xScl/(e.getX()-originX));
  898.                         yScl -= (mouseY-e.getY())*(yScl/(e.getY()-originY));
  899.                     }
  900.                 }
  901.                
  902.                
  903.                 //makes sure that the screen is not resized to be too zoomed in.
  904.                 if(yScl > h/2){
  905.                     yScl = h/2;
  906.                 }
  907.                 if(xScl > w/2){
  908.                     xScl = w/2;
  909.                 }
  910.  
  911.                 //sets x and y scale to 1 if they have been set to lower than 1.
  912.                 if(xScl <= 1 || xScl == Float.NaN || xScl == Float.POSITIVE_INFINITY){
  913.                     xScl = 1;
  914.                 }
  915.                 if(yScl <= 1 || yScl == Float.NaN || yScl == Float.POSITIVE_INFINITY){
  916.                     yScl = 1;
  917.                 }
  918.                 repaint();
  919.             }
  920.            
  921.             //sets mouse coordinates
  922.             mouseX = e.getX();
  923.             mouseY = e.getY();
  924.         }
  925.        
  926.         //-----START UNUSED METHODS----//
  927.         @Override
  928.         public void mouseClicked(MouseEvent e) {}
  929.  
  930.         @Override
  931.         public void mouseEntered(MouseEvent e) {}
  932.  
  933.         @Override
  934.         public void mouseExited(MouseEvent e) {}
  935.         //------END UNUSED METHODS----//
  936.        
  937.     }
  938.    
  939.     //Makes sure that the origin is in the same location at resize
  940.     class ResizeListener implements ComponentListener{
  941.  
  942.         //Called when window is resized
  943.         @Override
  944.         public void componentResized(ComponentEvent e) {
  945.            
  946.             //Keeps the origin the same relative distance from the edge of the screen.         
  947.             originX *= ((float)(getWidth())/(float)(oldWidth));
  948.             originY *= ((float)(getHeight())/(float)(oldHeight));
  949.            
  950.             oldWidth = getWidth();
  951.             oldHeight = getHeight();
  952.            
  953.             repaint();
  954.         }
  955.  
  956.         //-----START UNUSED METHODS----//
  957.         @Override
  958.         public void componentMoved(ComponentEvent e) {}
  959.  
  960.         @Override
  961.         public void componentShown(ComponentEvent e) {}
  962.  
  963.         @Override
  964.         public void componentHidden(ComponentEvent e) {}
  965.         //-----END UNUSED METHODS----//
  966.     }
  967.    
  968.     //Zooms In
  969.     public void zoomIn(){
  970.        
  971.         float rat = (float)(xScl)/(float)(yScl);
  972.        
  973.         xScl*=1.25;
  974.         yScl*=1.25;
  975.        
  976.         if(xScl > w/2){
  977.             xScl = w/2;
  978.             yScl = xScl/rat;
  979.             repaint();
  980.             return;
  981.         }else if(yScl > h/2){
  982.             yScl = h/2;
  983.             xScl = rat*yScl;
  984.             repaint();
  985.             return;
  986.         }
  987.         repaint();
  988.     }
  989.    
  990.     //Zooms out
  991.     public void zoomOut(){
  992.        
  993.         float rat = (float)(xScl)/(float)(yScl);
  994.        
  995.         xScl*=0.8;
  996.         yScl*=0.8;
  997.        
  998.         if(xScl < 1){
  999.             xScl = 1;
  1000.             yScl = xScl/rat;
  1001.             repaint();
  1002.             return;
  1003.         }else if(yScl < 1){
  1004.             yScl = 1;
  1005.             xScl = rat*yScl;
  1006.             repaint();
  1007.             return;
  1008.         }
  1009.         repaint();
  1010.     }
  1011. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement