March 24, 2010

Few functions to draw lines, circles and ellipses in Java.

These days I'm working on few games which I'm writing in Java. I needed functions to draw lines and circles etc. Instead of using the Java libraries, I wrote my own functions. Thinking may be some day, some body else  use them too I'm putting the source code to these functions here, in my blog.

////////////////////////////////////////////////////////////////////////////
// NibblesFunctions.java                                                            //
// Written by, Sohail Qayum Malik                                              //
// Last modified on, Monday, 7th of March, 2010 @7:12AM           //
////////////////////////////////////////////////////////////////////////////

package Nibbles;

import java.lang.Math;
import java.awt.Graphics;

public class NibblesFunctions {

   //Bresenham circle
   //Read the following book at page 29...
   //http://books.google.com.pk/books?id=7gT1MhI1SbIC&pg=PP3&dq=+"Computer+Graphics++"SCHAUM's+outline+series"&cd=1#v=onepage&q= "Computer Graphics  "SCHAUM's outline series"&f=false
   // a and b is an origin ordinate pair(a,b)
   // r is the radius                                   
   public static void drawCircle(Graphics graphics, int a, int b, int r) {
 
      //We'll start at the right hand side of the circle
      //First point is always on the circle so error is zero and we know that x is r and y is 0
      //There are only two valid moves...
      //Up = x^2 + (y + 1)^2 - r^2 and Left = (x - 1)^2 + (y + 1)^2 - r^2
      //Our d = Up + Left     
      int x = r, y = 0, d = 3 - 2*r;
 
      // x is initially r, x will be same as y at 45(degree) angle
      while(y <= x) {
         
         // Eight way symmetry of circle
         graphics.drawString(".", x + b, y + a);
         graphics.drawString(".", y + b, x + a); 
         graphics.drawString(".", (-1)*y + b, x + a);
         graphics.drawString(".", (-1)*x + b, y + a);
         graphics.drawString(".", (-1)*x + b, (-1)*y + a);
         graphics.drawString(".", (-1)*y + b, (-1)*x + a);
         graphics.drawString(".", y + b, (-1)*x + a);
         graphics.drawString(".", x + b, (-1)*y + a);
       
         if(d < 0) // move Up = d + Up + 2  
            d = d + 4*y + 6;
         else { // move Left = d + Left + 2
            d = d - 4*(x - y) + 10;
           //Since we've started at the right hand side of the circle
            x = x - 1;
         }
         
         // Since we have started at top of the circle
         y = y + 1;                                
      }      
   }
   
/*
   //Bresenham circle
   //Read the following book at page 29...
   //http://books.google.com.pk/books?id=7gT1MhI1SbIC&pg=PP3&dq=+"Computer+Graphics++"SCHAUM's+outline+series"&cd=1#v=onepage&q= "Computer Graphics  "SCHAUM's outline series"&f=false 
   // a and b is an origin ordinate pair(a,b)
   // r is the radius                                   
   public static void drawCircle(Graphics graphics, int a, int b, int r) {
 
      //We'll start at the top of the circle
      //First point is always on the circle so error is zero and we know that x is zero and y is r         
      int x = 0, y = r, d = 3 - 2*r;
 
      // x is initially zero, x will be same as y at 45(degree) angle
      while(x <= y) {
         
         // Eight way symmetry of circle
         graphics.drawString(".", x + b, y + a);
         graphics.drawString(".", y + b, x + a); 
         graphics.drawString(".", (-1)*y + b, x + a);
         graphics.drawString(".", (-1)*x + b, y + a);
         graphics.drawString(".", (-1)*x + b, (-1)*y + a);
         graphics.drawString(".", (-1)*y + b, (-1)*x + a);
         graphics.drawString(".", y + b, (-1)*x + a);
         graphics.drawString(".", x + b, (-1)*y + a);
       
         if(d < 0) // move right
            d = d + 4*x + 6;
         else { // move down
            d = d + 4*(x - y) + 10;
           //Since we've started at the top of the circle
            y = y - 1;
         }
         
         // Since we have started at top of the circle
         x = x + 1;                                
      }      
   }
*/   
   
   //Bresenham line
   //Read chapter 3 at page 28 of the following book   
   //http://books.google.com.pk/books?id=7gT1MhI1SbIC&pg=PP3&dq=+"Computer+Graphics++"SCHAUM's+outline+series"&cd=1#v=onepage&q= "Computer Graphics  "SCHAUM's outline series"&f=false
   //I also went through following two documents
   //http://cs.fit.edu/~wds/classes/graphics/Rasterize/rasterize/rasterize.html
   //http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
   public static void drawLine(Graphics graphics, int x1, int y1, int x2, int y2)  {
      
       int x, y, dx, dy, d, ystep, tmp;

      //This algorithm only deals with lines having shallow slopes. When a line has steep slope then we take the advantage of the fact that steep line can be reflected across the line y = x
      boolean steep = Math.abs(y2 - y1) > Math.abs(x2 - x1);   

       //Yes line has steep slope make it shallow  
       if(steep) {
  
          //swap(x1, y1) 
          //Because Java for scalar types is pass by value
          tmp = y1;
          y1 = x1;
          x1 = tmp;
 
          //swap(x2, y2)
          //Because Java for scalar types is pass by value
          tmp = y2;
          y2 = x2;
          x2 = tmp;               
       }
  
       //We always move from left to right(that is x is always incremented)
       if(x1 > x2) {
  
          //swap(x1, x2);
          //Because Java for scalar types is pass by value
          tmp = x2;
          x2 = x1;
          x1 = tmp;

           //swap(y1, y2)
           //Because Java for scalar types is pass by value
           tmp = y2;
           y2 = y1;
           y1 = tmp;
       }
  
       dx = x2 - x1;  
       dy = Math.abs(y2 - y1);
       //Initial value, the first and the last points are always on the line, so error is zero(2e=2(0)=0)
       //e = dyX - dxY + c
       //eR = dy(X + 1) - dxY + c = e + dy
       //eD = dy(X + 1) - dx(Y + 1) + c = e + dy - dx
       //d = eR + eD
       d = 2*dy - dx;
  
       //Find out if we'll increment or decrement y
       if(y1 < y2) 
          ystep = 1;
       else
           ystep = -1;

       //Initial values(initial ordinate pair) 
       x = x1;
       y = y1;
  
       while(x <= x2) {
   
           //x is reflected as y(transitive)  
           if(steep)
              graphics.drawString(".", y, x);
           else
              graphics.drawString(".", x, y);   

           //We only allow two moves, move to the right, or move diagonally. when we move to the right we only increment x otherwise we increment both(sign of ystep)
           if(d < 0) 
              d = d + 2*dy;
           else {
    
               d = d + 2*dy - 2*dx;
               y = y + ystep;
           }

           x = x + 1;      
       }                  
   }

   // Trigonometric method
   // a = length of major axis, b = length of minor axis
   // h,k ordinate pair for the center of the ellipse
   // x = a * cos(0 to PI/2 radians) + h 
   // y = b * sin(0 to PI/2 radians) + k
   // Inorder to rotate on axis, make minor greater than major
   public static void drawEllipse(Graphics graphics, int h, int k, int a, int b) {      
   
        int x = 0, y = 0; 
  
        //i is the magnitude of increment to radian at each step, this should not be fixed as it is now
        double radian = 0, i = 0.01;

        while(radian <= Math.PI/2) {
             
            x = (int)(a*(Math.cos(radian)));
            y = (int)(b*(Math.sin(radian)));
 
            //Ellipses have 4 way symmetry
           graphics.drawString(".", x + h, y + k);  
           graphics.drawString(".", (-1)*x + h, y + k); 
           graphics.drawString(".", (-1)*x + h, (-1)*y + k); 
           graphics.drawString(".", x + h, (-1)*y + k); 

           radian = radian + i;  
        }             
   }   
     
   // It is easy, no special algorithm there, just draw four lines
   public static void drawRectangle(Graphics graphics, int x1, int y1, int width, int height) {
   
      drawLine(graphics, x1, y1, x1 + width, y1);
      drawLine(graphics, x1, y1 + height, x1 + width, y1 + height);
      drawLine(graphics, x1, y1, x1, y1 + height);
      drawLine(graphics, x1 + width, y1, x1 + width, y1 + height);      
   } 
   
   public static void fillRectangle(Graphics graphics, int x1, int y1, int width, int height) {
   
        int x, y;
  
        if(width < 2 || height < 2) {
  
           drawRectangle(graphics, x1, y1, width, height);
           return;
        }
  
        for(y = 0; y < height + 1; y++)
            for(x = 0; x < width + 1; x++)      
                graphics.drawString(".", x1 + x, y1 + y);             
   }

   public static void fillCircle(Graphics graphics, int a, int b, int r) {
   
        int r1;
  
        for(r1 = r; r1 > 0; r1--)  
            drawCircle(graphics, a, b, r1);     
   }          
};

 

Click Here!