//VectorCanvas.java
// A Canvas for drawing of a basic 3D environment


import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.net.*;
import java.awt.event.*;
import java.util.*;

public final class VectorCanvas extends Canvas implements Runnable, MouseListener, MouseMotionListener {
  private static Projection projector;             
  public int xref;
  public int yref;
  
  public int latitude = 90;
  public int longitude = 36;
  public double dipolelength = 0.01;
  public double exponent = 1.0;
  public double tops = 1.0;
  public boolean IsPower = false;
  //public boolean IsPatchOn = true;
  public boolean IsPatchOn = false;
  public Color color_line = Color.gray;
  public Color color_line1 = Color.gray;
  public Color color_line2 = Color.gray;
  public Color color_line3 = Color.red;
  
  private Image im;
  private Graphics buf;
  
  // constants           
  private static final int TOP    = 0;
  private static final int CENTER = 1;
  
  
  //----------------------------------------------------------------------------

  VectorCanvas() {
    super();
        
    projector = new Projection();
    
    //--------------------------------------------------------------------------
    // This scales the viewing distance
    // Sets "new_distance" in Projection.java
    projector.setDistance(70);
    
    // This scales the picture with respect to the canvs
    // Sets "_2D_scale" in Projection_java
    projector.set2DScaling(13);
    
    // In Projection.java: factor = new_distance * _2D_scale
    
    //--------------------------------------------------------------------------
    //These set angles for initial condition of the x,y,z axes
    projector.setRotationAngle(45);//(45);
    projector.setAzimuthAngle(20);//polar angle, actually z axis is reference...
    
    //projector.setRotationAngle(0);
    //projector.setAzimuthAngle(0);//polar angle, actually z axis is reference...
    
    //--------------------------------------------------------------------------
    
    this.addMouseListener(this);
    this.addMouseMotionListener(this);
   
  }
  
  public void destroyImage() {
    
  }
  
  private boolean dragged;            // dragged flag
  public int     click_x, click_y;    // previous mouse cursor position
  
    public void mouseMoved(MouseEvent evt){;}
    public void mouseEntered(MouseEvent evt){;}
    public void mouseExited(MouseEvent evt){;}
    public void mousePressed(MouseEvent evt){
        int x, y;
	x=evt.getX();
	y=evt.getY();

        click_x = x;
        click_y = y;
        
    }
    
    public void mouseReleased(MouseEvent evt){;}
     
    public void mouseClicked(MouseEvent evt) {
        int x, y;
	x=evt.getX();
	y=evt.getY();

        click_x = x;
        click_y = y;
        
  }
  
  public void mouseDragged(MouseEvent evt) {
    int x, y, xref, yref;
    
    xref = getSize().width;
    yref = getSize().height;
    x=evt.getX();
    y=evt.getY();
    
    // Clamp x and y to size of Canvas
    if(x<0){x=0;} 
    if(y<0){y=0;} 
    if(x>xref){x=xref;} 
    if(y>yref){y=yref;} 
    
    float new_value = 0.0f;
    //new_value = projector.getRotationAngle() + (x - click_x);
    new_value = projector.getRotationAngle() + (x - click_x)*360/getSize().width;
    while (new_value > 360) new_value -= 360;
    while (new_value < 0) new_value += 360;
    projector.setRotationAngle(new_value);
    
    //System.out.println("Rotation = "+new_value);
    
    //new_value = projector.getAzimuthAngle() + (y - click_y);
    new_value = projector.getAzimuthAngle() + (y - click_y)*180/getSize().height;
    if (new_value > 180){new_value = 180;}
    else if (new_value < 0){new_value = 0;}
    projector.setAzimuthAngle(new_value);

    //System.out.println("Azimuth = "+new_value);
    
    repaint();
    click_x = x;
    click_y = y;
  }
  
  public void drawpanel(Graphics g){
        projector.setProjectionArea(new Rectangle(0,0,getSize().width, getSize().height));
        //g.setColor(Color.lightGray);
        //g.setColor(Color.white);
        g.setColor(new Color(250,250,255));
        g.fillRect(0,0,getSize().width,getSize().height); 
        
        drawStuff(g,true);
  }
  
  public void paint(Graphics g) {
        
        if(im == null){
		im = createImage(getSize().width,getSize().height);
		buf = im.getGraphics();
		drawpanel(buf);
        }
        else{
		drawpanel(buf);
        }
	
        repaint();
	g.drawImage(im,0,0,null);
  }

  public void update(Graphics g) {
        paint(g);
  }  

  public void run() {
                    
      Graphics g = getGraphics();
      paint(g);
      g.dispose();    
  }
  
/*----------------------------------------------------------------------------------------*
 *                            Private methods begin here                                  *
 *----------------------------------------------------------------------------------------*/

  
  private final void drawStuff(Graphics g, boolean draw_axes) {
        Graphics2D g2d = (Graphics2D)g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        Point    projection;   
        int      x[],y[],i,j;
        float    vpos[];
        float    vtip[];
        double   Array[][];
        float    x3D[][], y3D[][], z3D[][];
        double    Patchx1[][], Patchy1[][], Patchx2[][], Patchy2[][], 
                 Patchx3[][], Patchy3[][]; 
        float    xINT[][], yINT[][], zINT[][];
        double    zTest[];
        float    xRef, yRef, zRef;
        double   z3DAux[][];
        float    axisL = 17.0f;
        double   Scale = 15.0;
        Color    colore;
        int      thick1, thick2, thick3, thick4, thick5;
        int      rotx, roty;
        
        colore = Color.gray;
        if(!IsPower){
            color_line = color_line1;
        }
        else{
            color_line = color_line2;
        }
        
        thick1 = 1;
        thick2 = 2;
        thick3 = 3;
        thick4 = 4;
        thick5 = 5;

        x = new int[5]; y = new int[5]; vpos = new float[3]; vtip = new float[3];
        
        //Make radiation pattern 
        double vposx1, vposy1, vposx2, vposy2, vposx3, vposy3, vposx4, vposy4, MaxZ;
        Array = new double[(latitude*5)+2][longitude+1];
        
        //3D Values
        xINT = new float[latitude*5+2][longitude+1];
        yINT = new float[latitude*5+2][longitude+1];
        zINT = new float[latitude*5+2][longitude+1];
        
        x3D = new float[latitude*5+2][longitude+1];
        y3D = new float[latitude*5+2][longitude+1];
        z3D = new float[latitude*5+2][longitude+1];
        z3DAux = new double[latitude*5+2][longitude+1];
        
        zTest = new double[latitude*5+2];
        
        //Patches on 2D projection
        Patchx1 = new double[latitude*5+2][longitude+1];
        Patchy1 = new double[latitude*5+2][longitude+1];
        Patchx2 = new double[latitude*5+2][longitude+1];
        Patchy2 = new double[latitude*5+2][longitude+1];
        Patchx3 = new double[latitude*5+2][longitude+1];
        Patchy3 = new double[latitude*5+2][longitude+1];
        
        
        float theta, phi;
        
        roty = (int)projector.getRotationAngle();
        rotx = (int)projector.getAzimuthAngle();
        
        
        for(i=0;i<(latitude*5);i++){
		theta=(float)(Math.PI*i/(float)(latitude*5));
                for(j=0;j<longitude;j++){
                    phi=(float)(Math.PI*j/(float)(longitude/2));
                    //Array[i][j] = Scale*(Math.sin(theta));//*Math.sin(theta));
                    
                    if(theta!=0.0f && Math.abs(theta)!=(float)(Math.PI) ){
                        Array[i][j]=Math.pow( Scale*Math.abs(
                                  (-Math.cos(Math.PI*dipolelength*Math.cos(theta))
                                  +Math.cos(Math.PI*dipolelength))/Math.sin(theta)
                                   ), exponent);
                    }
                    else{
                        Array[i][j]=0.0;
                    }
                    
                    //xINT[(latitude*5)-1-i][longitude-1-j] = (float)(Array[i][j]*Math.sin(theta)*Math.cos(phi));
                    //yINT[(latitude*5)-1-i][longitude-1-j] = (float)(Array[i][j]*Math.sin(theta)*Math.sin(phi));
                    //zINT[(latitude*5)-1-i][longitude-1-j] = (float)(Array[i][j]*Math.cos(theta));
                    
                    xINT[i][j] = (float)(Array[i][j]*Math.sin(theta)*Math.cos(phi));
                    yINT[i][j] = (float)(Array[i][j]*Math.sin(theta)*Math.sin(phi));
                    zINT[i][j] = (float)(Array[i][j]*Math.cos(theta));
                }
        }
        
        //g.setColor(Color.black);
        //g.fillRect(0,0,getSize().width,getSize().height);
        
        for(i=0;i<(latitude*5);i++){
            for(j=0;j<longitude;j++){
                x3D[i][j] = 0.0f;
                y3D[i][j] = 0.0f;
                z3D[i][j] = 0.0f;
            }
        }
        
        //Same scale for all plots
        double massimo;
        massimo = Scale/MaestroA.getMax(Array,latitude*5,longitude);
        tops = MaestroA.getMax(Array,latitude*5,longitude);
        //System.out.println("massimo = "+massimo);
        
        for(i=0;i<(latitude*5);i++){
            for(j=0;j<longitude;j++){
                x3D[i][j] = xINT[i][j]*(float)massimo;
                y3D[i][j] = yINT[i][j]*(float)massimo;
                z3D[i][j] = zINT[i][j]*(float)massimo;
            }
        }  
        
         xRef = x3D[(latitude*5)/2][0];
         yRef = y3D[(latitude*5)/2][9];
         
         double Zmax = 0.0;
         for(i=1;i<(latitude*5)/2;i++){
            zTest[i] = Math.abs(z3D[i][0]);
         }
         
         Zmax = MaestroA.getMax(zTest);
          
        // Calculate Patches nodes
        
        for(i=0;i<(latitude*5);i++){
		for(j=0;j<longitude;j++){
                    
                    projection = projector.project(x3D[i][j],y3D[i][j],z3D[i][j]);
                    vposx1 = (double)projection.x;
                    vposy1 = (double)projection.y;
                    projection = projector.project(x3D[i+1][j],y3D[i+1][j],z3D[i+1][j]);
                    vposx2 = (double)projection.x;
                    vposy2 = (double)projection.y;
                    
                    if(j<(longitude-1)){
                        projection = projector.project(x3D[i][j+1],y3D[i][j+1],z3D[i][j+1]);
                        vposx3 = (double)projection.x;
                        vposy3 = (double)projection.y;
                    }
                    else{
                        projection = projector.project(x3D[i][0],y3D[i][0],z3D[i][0]);
                        vposx3 = (double)projection.x;
                        vposy3 = (double)projection.y;
                    }
                    
                    Patchx1[i][j] = vposx1;
                    Patchy1[i][j] = vposy1;
                    Patchx2[i][j] = vposx2;
                    Patchy2[i][j] = vposy2;
                    Patchx3[i][j] = vposx3;
                    Patchy3[i][j] = vposy3;
                }
        }
        
      //------------------------------------------------------------------------
      // draw axes labels
      //------------------------------------------------------------------------
        
        projection = projector.project(axisL,0,0);     
        x[0] = projection.x; y[0] = projection.y;
        if (projection.x < x[0]){//DRAW THE X LABEL
            outString(g,(int)(x[0]), (int)(1.02*y[0]),"x",Label.RIGHT,TOP, Color.black);
        }
        else{
            outString(g,(int)(x[0]), (int)(1.02*y[0]),"x",Label.LEFT,TOP, Color.black);
        }
        
        projection = projector.project(0,axisL,0);     
        x[0] = projection.x; y[0] = projection.y;
        if (projection.x < x[0]){//DRAW Y LABEL
            outString(g,(int)(x[0]), (int)(1.02*y[0]),"y",Label.RIGHT,TOP, Color.black);
        }
        else{
            outString(g,(int)(x[0]), (int)(1.02*y[0]),"y",Label.LEFT,TOP, Color.black);
        }
        
        projection = projector.project(0,0,axisL);     
        x[0] = projection.x; y[0] = projection.y;
       
        if(projector.getAzimuthAngle() < 90){//DRAW Z LABEL
            outString(g,(int)(1.05*x[0]), (int)(1.0*y[0]),"z",Label.CENTER,CENTER, Color.black);
        }
        else{
            outString(g,(int)(1.05*x[0]), (int)(0.98*y[0]),"z",Label.CENTER,CENTER, Color.black);
        }
        
      //------------------------------------------------------------------------      
      //draw axes - Length is 15.0
      //------------------------------------------------------------------------
      
      draw3DVector(g, axisL, 20, xRef, 0.0, 0.0, 18.0, 0.0, 0.0, thick2, Color.red); // x-axis
      draw3DVector(g, axisL, 20, 0.0, yRef, 0.0, 0.0, 18.0, 0.0, thick2, Color.red);  // y-axis
      
      //  make axis portion inside 3D shape semi-transparent
          int rule; 
          float alpha;
          rule = AlphaComposite.SRC_OVER;
          g2d.setComposite(AlphaComposite.getInstance(rule, 0.5f));
	  
      draw3DLine(g, axisL, 20, 0.0, 0.0, 0.0, xRef, 0.0, 0.0, thick2, Color.red); // x-axis              
      draw3DLine(g, axisL, 20, 0.0, 0.0, 0.0, 0.0, yRef, 0.0, thick2, Color.red);  // y-axis
      
        // draw obscured portion of Z axis
      draw3DLine(g, axisL, 0, 0.0, 0.0, (double)Zmax, 0.0, 0.0, 0.0, thick2, Color.red); // z-axis
       
      g2d.setComposite(AlphaComposite.getInstance(rule, 1.0f));
      
         
      //------------------------------------------------------------------------
      // draw wireframe
      //------------------------------------------------------------------------
        int endit;
        int size1 = 1;
        int size2 = 0;
        endit = longitude;
        
        if(!IsPatchOn){
           for(i=0;i<(latitude*5);i++){
             for(j=0;j<endit;j++){
             //for(j=0;j<3;j++){
                    drawLineThick(g, Patchx1[i][j], Patchy1[i][j], Patchx2[i][j], Patchy2[i][j], size1, color_line);
                    
                    if(j==(endit-1)){
                        drawLineThick(g, Patchx1[i][j+1], Patchy1[i][j+1], Patchx2[i][j+1], Patchy2[i][j+1], size1, color_line);
                    }
                    
                    if(dipolelength < 5.0){
                    
                        if(i==9 || i==19  || i==29 || i==39 || i==49 || i==59 ||
                           i==69 || i==79 || i==89 || i==99 || i==109 || i==119 || i==129 ||
                           i==139 || i==149 || i==159 || i==169 || i==179 || i==189 || 
                           i==199 || i==209 || i==219 || i==229 || i==239 || i==249 ||
                           i==259 || i==269 || i==279 || i==289 || i==299 || i==309 ||
                           i==319 || i==329 || i==339 || i==349 || i==359 || i==369 ||
                           i==379 || i==389 || i==399 || i==409 || i==419 || i==429 ||
                           i==439 || i==449)

                         {
                            drawLineThick(g, Patchx1[i][j], Patchy1[i][j], Patchx3[i][j], Patchy3[i][j], size1, color_line);
                            //diagonal of patch (forms the two triangles)
                            ////drawLineThick(g, Patchx2[i][j], Patchy2[i][j], Patchx3[i+10][j], Patchy3[i+10][j], 1, Color.lightGray);
                        }
                    }
                    else{
                         if(i==4 || i==14  || i==24 || i==34 || i==44 || i==54 ||
                           i==69 || i==74 || i==84 || i==94 || i==104 || i==114 || i==124 ||
                           i==134 || i==144 || i==154 || i==164 || i==174 || i==184 || 
                           i==194 || i==204 || i==214 || i==224 || i==234 || i==244 ||
                           i==254 || i==264 || i==274 || i==284 || i==294 || i==304 ||
                           i==314 || i==324 || i==334 || i==344 || i==354 || i==364 ||
                           i==374 || i==384 || i==394 || i==404 || i==414 || i==424 ||
                           i==434 || i==444 ||
                           i==9 || i==19  || i==29 || i==39 || i==49 || i==59 ||
                           i==69 || i==79 || i==89 || i==99 || i==109 || i==119 || i==129 ||
                           i==139 || i==149 || i==159 || i==169 || i==179 || i==189 || 
                           i==199 || i==209 || i==219 || i==229 || i==239 || i==249 ||
                           i==259 || i==269 || i==279 || i==289 || i==299 || i==309 ||
                           i==319 || i==329 || i==339 || i==349 || i==359 || i==369 ||
                           i==379 || i==389 || i==399 || i==409 || i==419 || i==429 ||
                           i==439 || i==449)

                         {
                            drawLineThick(g, Patchx1[i][j], Patchy1[i][j], Patchx3[i][j], Patchy3[i][j], size1, color_line);
                            //diagonal of patch (forms the two triangles)
                            ////drawLineThick(g, Patchx2[i][j], Patchy2[i][j], Patchx3[i+10][j], Patchy3[i+10][j], 1, Color.lightGray);
                        }   
                    }
                }        
            }
        }
      
      //------------------------------------------------------------------------
      // draw axes labels
      //------------------------------------------------------------------------
        
        
        projection = projector.project(axisL,0,0);     
        x[0] = projection.x; y[0] = projection.y;
        if (projection.x < x[0]){//DRAW THE X LABEL
            outString(g,(int)(x[0]), (int)(1.02*y[0]),"x",Label.RIGHT,TOP, Color.black);
        }
        else{
            outString(g,(int)(x[0]), (int)(1.02*y[0]),"x",Label.LEFT,TOP, Color.black);
        }
        
        projection = projector.project(0,axisL,0);     
        x[0] = projection.x; y[0] = projection.y;
        if (projection.x < x[0]){//DRAW Y LABEL
            outString(g,(int)(x[0]), (int)(1.02*y[0]),"y",Label.RIGHT,TOP, Color.black);
        }
        else{
            outString(g,(int)(x[0]), (int)(1.02*y[0]),"y",Label.LEFT,TOP, Color.black);
        }
        
      //------------------------------------------------------------------------      
      //draw axes - Length is 15.0
      //------------------------------------------------------------------------
      
        
      //draw3DLine(g, axisL, 20, 0.0, 0.0, 0.0, 15.0, 0.0, 0.0, thick1, Color.black); // x-axis              
      //draw3DVector(g, axisL, 20, xRef, 0.0, 0.0, 18.0, 0.0, 0.0, thick2, Color.red); // x-axis
      
      //draw3DLine(g, axisL, 20, 0.0, 0.0, 0.0, 0.0, 15.0, 0.0, thick1, Color.black);  // y-axis
      //draw3DVector(g, axisL, 20, 0.0, yRef, 0.0, 0.0, 18.0, 0.0, thick2, Color.red);  // y-axis
      
      //  draw unobstructed portion of Z axis
      draw3DVector(g, axisL, 20, 0.0, 0.0, (double)Zmax, 0.0, 0.0, 17.0, thick2, Color.red); // z-axis
      
      // transparency = 1.0 is totally opaque
      // transparency = 0.0 is fully transparent
      float transparency = 0.1f;
     
        
     //-------------------------------------------------------------------------
        
     if(IsPatchOn){
        //draw patches & wireframe - no hidden lines/patches algorithm here
            // bottom half
         
         for(i=(latitude*5)-1;i>(latitude*5)/2;i--){
            	//for(j=0;j<longitude;j++){
                for(j=longitude-1;j>-1;j--){
                   
                    projection = projector.project(x3D[i][j],y3D[i][j],z3D[i][j]);
                    vposx1 = (double)projection.x;
                    vposy1 = (double)projection.y;
                    projection = projector.project(x3D[i+1][j],y3D[i+1][j],z3D[i+1][j]);
                    vposx2 = (double)projection.x;
                    vposy2 = (double)projection.y;
                                
                    if(j<(longitude-1)){
                        projection = projector.project(x3D[i][j+1],y3D[i][j+1],z3D[i][j+1]);
                        vposx3 = (double)projection.x;
                        vposy3 = (double)projection.y;
                        projection = projector.project(x3D[i+1][j+1],y3D[i+1][j+1],z3D[i+1][j+1]);
                        vposx4 = (double)projection.x;
                        vposy4 = (double)projection.y;
                    }
                    else{
                        projection = projector.project(x3D[i][0],y3D[i][0],z3D[i][0]);
                        vposx3 = (double)projection.x;
                        vposy3 = (double)projection.y;
                        projection = projector.project(x3D[i+1][0],y3D[i+1][0],z3D[i+1][0]);
                        vposx4 = (double)projection.x;
                        vposy4 = (double)projection.y;
                    }
                    
                    double docolor = Math.abs(Array[i][j]/tops);                   
                    //if(docolor > 1.0){docolor = 1.0;} 
                    docolor = 1.0;
                    Color colorpatch = new Color(0,(int)(docolor*255),(int)(docolor*255));
                    
                    // vertical lines
                    drawLineThick(g, vposx1, vposy1, vposx2, vposy2, 1, color_line);
                    if(vposx1 > vposx3 && vposy1 > vposy2){
                        FillPatch(g, vposx1, vposy1, vposx2, vposy2, 
                                 vposx3, vposy3, vposx4, vposy4, 
                                 transparency, colorpatch);
                        drawLineThick(g, vposx1, vposy1, vposx2, vposy2, 1, color_line);
                    }
                    else{
                        FillPatch(g, vposx1, vposy1, vposx2, vposy2, 
                                 vposx3, vposy3, vposx4, vposy4, 
                                 transparency, colorpatch);
                        drawLineThick(g, vposx1, vposy1, vposx2, vposy2, 1, color_line);
                    }
                    
                    // horizontal lines
                    if(i==9 || i==19  || i==29 || i==39 || i==49 || i==59 ||
                       i==69 || i==79 || i==89 || i==99 || i==109 || i==119 || i==129 ||
                       i==139 || i==149 || i==159 || i==169 || i==179 || i==189 || 
                       i==199 || i==209 || i==219 || i==229 || i==239 || i==249 ||
                       i==259 || i==269 || i==279 || i==289 || i==299 || i==309 ||
                       i==319 || i==329 || i==339 || i==349 || i==359 || i==369 ||
                       i==379 || i==389 || i==399 || i==409 || i==419 || i==429 ||
                       i==439 || i==449)
                    {
                        if(vposx1 > vposx3 && vposy1 > vposy2)
                        {
                            drawLineThick(g, vposx1, vposy1, vposx3, vposy3, 1, color_line);
                        }
                        else
                        {
                            drawLineThick(g, vposx1, vposy1, vposx3, vposy3, 1, color_line);
                        }
                    }
                    
                }
        }  
          
      
      
            // top half
        
        for(i=(latitude*5)/2;i>-1;i--){
            	//for(j=0;j<longitude;j++){
                for(j=longitude-1;j>longitude/2-1;j--){
                    
                    projection = projector.project(x3D[i][j],y3D[i][j],z3D[i][j]);
                    vposx1 = (double)projection.x;
                    vposy1 = (double)projection.y;
                    projection = projector.project(x3D[i+1][j],y3D[i+1][j],z3D[i+1][j]);
                    vposx2 = (double)projection.x;
                    vposy2 = (double)projection.y;
                                
                    if(j<(longitude-1)){
                        projection = projector.project(x3D[i][j+1],y3D[i][j+1],z3D[i][j+1]);
                        vposx3 = (double)projection.x;
                        vposy3 = (double)projection.y;
                        projection = projector.project(x3D[i+1][j+1],y3D[i+1][j+1],z3D[i+1][j+1]);
                        vposx4 = (double)projection.x;
                        vposy4 = (double)projection.y;
                    }
                    else{
                        projection = projector.project(x3D[i][0],y3D[i][0],z3D[i][0]);
                        vposx3 = (double)projection.x;
                        vposy3 = (double)projection.y;
                        projection = projector.project(x3D[i+1][0],y3D[i+1][0],z3D[i+1][0]);
                        vposx4 = (double)projection.x;
                        vposy4 = (double)projection.y;
                    }
                    double docolor = Math.abs(Array[i][j]/tops);
                    //if(docolor > 1.0){docolor = 1.0;}
                    docolor = 1.0;
                    Color colorpatch = new Color(0,(int)(docolor*255),(int)(docolor*255));
                    
                    // vertical lines
                    drawLineThick(g, vposx1, vposy1, vposx2, vposy2, 1, color_line);
                    if(vposx1 > vposx3 && vposy1 > vposy2){
                        FillPatch(g, vposx1, vposy1, vposx2, vposy2, 
                                 vposx3, vposy3, vposx4, vposy4, 
                                 transparency, colorpatch);
                        drawLineThick(g, vposx1, vposy1, vposx2, vposy2, thick1, color_line);
                    }
                    else{
                        FillPatch(g, vposx1, vposy1, vposx2, vposy2, 
                                 vposx3, vposy3, vposx4, vposy4, 
                                 transparency, colorpatch);
                        drawLineThick(g, vposx1, vposy1, vposx2, vposy2, thick1, color_line);
                    }
                    
                    // horizontal lines
                    if(i==9 || i==19  || i==29 || i==39 || i==49 || i==59 ||
                       i==69 || i==79 || i==89 || i==99 || i==109 || i==119 || i==129 ||
                       i==139 || i==149 || i==159 || i==169 || i==179 || i==189 || 
                       i==199 || i==209 || i==219 || i==229 || i==239 || i==249 ||
                       i==259 || i==269 || i==279 || i==289 || i==299 || i==309 ||
                       i==319 || i==329 || i==339 || i==349 || i==359 || i==369 ||
                       i==379 || i==389 || i==399 || i==409 || i==419 || i==429 ||
                       i==439 || i==449)
                    {
                        if(vposx1 > vposx3 && vposy1 > vposy2)
                        {
                            drawLineThick(g, vposx1, vposy1, vposx3, vposy3, thick1, color_line);
                        }
                        else
                        {
                            drawLineThick(g, vposx1, vposy1, vposx3, vposy3, thick1, color_line);
                        }
                    }
                    
                }
        }
        
      
      
      
      for(i=0;i<(latitude*5)/2+1;i++){
            	//for(j=0;j<longitude/2;j++){
                for(j=longitude/2-1;j>-1;j--){
                    
                    projection = projector.project(x3D[i][j],y3D[i][j],z3D[i][j]);
                    vposx1 = (double)projection.x;
                    vposy1 = (double)projection.y;
                    projection = projector.project(x3D[i+1][j],y3D[i+1][j],z3D[i+1][j]);
                    vposx2 = (double)projection.x;
                    vposy2 = (double)projection.y;
                                
                    if(j<(longitude-1)){
                        projection = projector.project(x3D[i][j+1],y3D[i][j+1],z3D[i][j+1]);
                        vposx3 = (double)projection.x;
                        vposy3 = (double)projection.y;
                        projection = projector.project(x3D[i+1][j+1],y3D[i+1][j+1],z3D[i+1][j+1]);
                        vposx4 = (double)projection.x;
                        vposy4 = (double)projection.y;
                    }
                    else{
                        projection = projector.project(x3D[i][0],y3D[i][0],z3D[i][0]);
                        vposx3 = (double)projection.x;
                        vposy3 = (double)projection.y;
                        projection = projector.project(x3D[i+1][0],y3D[i+1][0],z3D[i+1][0]);
                        vposx4 = (double)projection.x;
                        vposy4 = (double)projection.y;
                    }
                    double docolor = Math.abs(Array[i][j]/tops);
                    //if(docolor > 1.0){docolor = 1.0;}
                    docolor = 1.0;
                    
                    Color colorpatch = new Color(0,(int)(docolor*255),(int)(docolor*255));
                    
                    // vertical lines
                    drawLineThick(g, vposx1, vposy1, vposx2, vposy2, thick1, color_line);
                    if(vposx1 > vposx3 && vposy1 > vposy2){
                        FillPatch(g, vposx1, vposy1, vposx2, vposy2, 
                                 vposx3, vposy3, vposx4, vposy4, 
                                 transparency, colorpatch);
                        drawLineThick(g, vposx1, vposy1, vposx2, vposy2, thick1, color_line);
                    }
                    else{
                        FillPatch(g, vposx1, vposy1, vposx2, vposy2, 
                                 vposx3, vposy3, vposx4, vposy4, 
                                 transparency, colorpatch);
                        drawLineThick(g, vposx1, vposy1, vposx2, vposy2, thick1, color_line);
                    }
                    
                    // horizontal lines
                    if(i==9 || i==19  || i==29 || i==39 || i==49 || i==59 ||
                       i==69 || i==79 || i==89 || i==99 || i==109 || i==119 || i==129 ||
                       i==139 || i==149 || i==159 || i==169 || i==179 || i==189 || 
                       i==199 || i==209 || i==219 || i==229 || i==239 || i==249 ||
                       i==259 || i==269 || i==279 || i==289 || i==299 || i==309 ||
                       i==319 || i==329 || i==339 || i==349 || i==359 || i==369 ||
                       i==379 || i==389 || i==399 || i==409 || i==419 || i==429 ||
                       i==439 || i==449)
                    {
                        if(vposx1 > vposx3 && vposy1 > vposy2)
                        {
                            drawLineThick(g, vposx1, vposy1, vposx3, vposy3, thick1, color_line);
                        }
                        else
                        {
                            drawLineThick(g, vposx1, vposy1, vposx3, vposy3, thick1, color_line);
                        }
                    }
                    
                }
        }
      
        /*    
        for(i=(latitude*5)/2;i<(latitude*5);i++){
                for(j=0;j<longitude;j++){
            //for(i=(latitude*5)-1;i>(latitude*5)/2-1;i--){
            //	for(j=0;j<longitude;j++){ 
                    projection = projector.project(x3D[i][j],y3D[i][j],z3D[i][j]);
                    vposx1 = (double)projection.x;
                    vposy1 = (double)projection.y;
                    projection = projector.project(x3D[i+1][j],y3D[i+1][j],z3D[i+1][j]);
                    vposx2 = (double)projection.x;
                    vposy2 = (double)projection.y;
                                
                    if(j<(longitude-1)){
                        projection = projector.project(x3D[i][j+1],y3D[i][j+1],z3D[i][j+1]);
                        vposx3 = (double)projection.x;
                        vposy3 = (double)projection.y;
                        projection = projector.project(x3D[i+1][j+1],y3D[i+1][j+1],z3D[i+1][j+1]);
                        vposx4 = (double)projection.x;
                        vposy4 = (double)projection.y;
                    }
                    else{
                        projection = projector.project(x3D[i][0],y3D[i][0],z3D[i][0]);
                        vposx3 = (double)projection.x;
                        vposy3 = (double)projection.y;
                        projection = projector.project(x3D[i+1][0],y3D[i+1][0],z3D[i+1][0]);
                        vposx4 = (double)projection.x;
                        vposy4 = (double)projection.y;
                    }
                    double docolor = Math.abs(Array[i][j]/tops);
                    if(docolor > 1.0){docolor = 1.0;}
                    Color colorpatch = new Color(0,(int)(docolor*255),(int)(docolor*255));
                    
                    // Vertical lines
                    //drawLineThick(g, vposx1, vposy1, vposx2, vposy2, 1, color_line);
                    if(vposx1 > vposx3 && vposy1 > vposy2){
                        FillPatch(g, vposx1, vposy1, vposx2, vposy2, 
                                 vposx3, vposy3, vposx4, vposy4, 
                                 transparency, colorpatch);
                        drawLineThick(g, vposx1, vposy1, vposx2, vposy2, 1, color_line);
                    }
                    else{
                        FillPatch(g, vposx1, vposy1, vposx2, vposy2, 
                                 vposx3, vposy3, vposx4, vposy4, 
                                 transparency, colorpatch);
                        drawLineThick(g, vposx1, vposy1, vposx2, vposy2, 1, Color.lightGray);
                    }
                
                    // Horizontal lines
                    if(i==9 || i==19  || i==29 || i==39 || i==49 || i==59 ||
                       i==69 || i==79 || i==89 || i==99 || i==109 || i==119 || i==129 ||
                       i==139 || i==149 || i==159 || i==169 || i==179 || i==189 || 
                       i==199 || i==209 || i==219 || i==229 || i==239 || i==249 ||
                       i==259 || i==269 || i==279 || i==289 || i==299 || i==309 ||
                       i==319 || i==329 || i==339 || i==349 || i==359 || i==369 ||
                       i==379 || i==389 || i==399 || i==409 || i==419 || i==429 ||
                       i==439 || i==449)
                    {
                        if(vposx1 > vposx3 && vposy1 > vposy2)
                        {
                            drawLineThick(g, vposx1, vposy1, vposx3, vposy3, 1, color_line);
                        }
                        else
                        {
                            drawLineThick(g, vposx1, vposy1, vposx3, vposy3, 1, Color.lightGray);
                        }
                    }
                    
                }
            }    
        */
     }
  }
  
  //----------------------------------------------------------------------------
  
  private final void outString(Graphics g, int x, int y, String s, int x_align, int y_align, Color colore) {
    g.setColor(colore);
    switch (y_align) {
      case TOP    : y += g.getFontMetrics(g.getFont()).getAscent(); break;
      case CENTER : y += g.getFontMetrics(g.getFont()).getAscent()/2; break;
    }
    switch (x_align) {
      case Label.LEFT  : g.drawString(s,x,y); 
                         break;
      case Label.RIGHT : g.drawString(s,x-g.getFontMetrics(
                                      g.getFont()).stringWidth(s),y); 
                         break;
      case Label.CENTER: g.drawString(s,x-g.getFontMetrics(
                                      g.getFont()).stringWidth(s)/2,y); 
                         break;
    }     
  }
  
  private void draw3DVector(Graphics g, float axisL, int tip_ratio, double vx1, double vy1, double vz1, double vx2, double vy2, double vz2, int thick, Color colore){
          
          Point projection;
          double vtipx, vtipy;
          double vposx, vposy;
          //length of arrow head lines
          double varrow = axisL/(float)tip_ratio;   
      
          Graphics2D g2d = (Graphics2D)g;
          g2d.setPaint(colore);
          g2d.setStroke(new BasicStroke(thick,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
          g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);

          //Get projection on 2D plane for origin of vector
          projection = projector.project((float)vx1,(float)vy1,(float)vz1);
          vposx = (double)projection.x;
          vposy = (double)projection.y;

          //Get projection on 2D plane for tip of vector
          projection = projector.project((float)vx2, (float)vy2, (float)vz2);
          vtipx = (double)projection.x;
          vtipy = (double)projection.y;

          //draw vector in 2D
          //g.drawLine(x[0],y[0],projection.x,projection.y); // OLD GRAPHICS
          
          // dash line
          drawLineThick(g, vposx, vposy, vtipx, vtipy, thick, colore); // JAVA 2D GRAPHICS - needs double values
          
            //-----------------------------------------------------------------------
            //drawing of arrow head at tip of vector

            double dvec, xsq, ysq, zsq, gamma_angle, Dz1, Dz2, Dx1, Dx2, Dy1, Dy2, 
                   theta, DL1, DL2, D1, D2, ref_angle, ref_angle2;
            double cox, coy, coz;

            theta = Math.PI/12.0;
            
            xsq = Math.pow(vx2-vx1,2);
            ysq = Math.pow(vy2-vy1,2);
            zsq = Math.pow(vz2-vz1,2);

            dvec = Math.sqrt(xsq + ysq + zsq);

            //direction cosines
            cox = (vx2 - vx1)/dvec;
            coy = (vy2 - vy1)/dvec;
            coz = (vz2 - vz1)/dvec;

            gamma_angle = Math.acos(coz);

            ref_angle = 0.5*Math.PI - gamma_angle - theta;
            ref_angle2 = gamma_angle - theta;

            Dz1 = vz2 - varrow * Math.sin(ref_angle);
            DL1 = varrow * Math.cos(ref_angle);
            //D1 = dvec * Math.sin(gamma_angle);

            Dz2 = vz2 - varrow * Math.cos(ref_angle2);
            DL2 = varrow * Math.sin(ref_angle2);
            //D2 = dvec * Math.sin(gamma_angle);
            if(gamma_angle > 0.0 && gamma_angle < Math.PI){
                Dx1 = vx2 - DL1 * cox/Math.sin(gamma_angle);
                Dy1 = vy2 - DL1 * coy/Math.sin(gamma_angle);
                Dx2 = vx2 - DL2 * cox/Math.sin(gamma_angle);
                Dy2 = vy2 - DL2 * coy/Math.sin(gamma_angle);
            }
            else{//When polar angle --> zero, ratios cox/Math.sin() gives NaN
                 //Set limit of ratio to one.
                Dx1 = vx2 + DL1;
                Dy1 = vy2 - DL1;
                Dx2 = vx2 + DL2;
                Dy2 = vy2 - DL2;
            }
            //Get projection on 2D plane for origin of vector
            projection = projector.project((float)vx2, (float)vy2, (float)vz2);
            vposx = (double)projection.x;
            vposy = (double)projection.y;

            //Get projection on 2D plane for tip of vector
            projection = projector.project((float)Dx1, (float)Dy1, (float)Dz1);
            vtipx = (double)projection.x;
            vtipy = (double)projection.y;

            //draw first line of arrow head 
            drawLineThick(g, vposx, vposy, vtipx, vtipy, thick+1, colore); // JAVA 2D GRAPHICS - needs double values

            //Get projection on 2D plane for origin of line
            projection = projector.project((float)vx2, (float)vy2, (float)vz2);
            vposx = (double)projection.x;
            vposy = (double)projection.y;

            //Get projection on 2D plane for tip of vector
            projection = projector.project((float)Dx2, (float)Dy2, (float)Dz2);
            vtipx = (double)projection.x;
            vtipy = (double)projection.y;

            //draw second line of arrow head 
            drawLineThick(g, vposx, vposy, vtipx, vtipy, thick+1, colore); // JAVA 2D GRAPHICS - needs double values

            //----------------------------------------------------------------------     
            //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
  }
  
  private void draw3DLine(Graphics g, float axisL, int tip_ratio, double vx1, double vy1, double vz1, double vx2, double vy2, double vz2, int thick, Color colore){
          
          Point projection;
          double vtipx, vtipy;
          double vposx, vposy;
          
          Graphics2D g2d = (Graphics2D)g;
          g2d.setPaint(colore);
          //g2d.setStroke(new BasicStroke(thick,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
          g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);

          //Get projection on 2D plane for origin of vector
          projection = projector.project((float)vx1,(float)vy1,(float)vz1);
          vposx = (double)projection.x;
          vposy = (double)projection.y;

          //Get projection on 2D plane for tip of vector
          projection = projector.project((float)vx2, (float)vy2, (float)vz2);
          vtipx = (double)projection.x;
          vtipy = (double)projection.y;

          //draw vector in 2D
          //g.drawLine(x[0],y[0],projection.x,projection.y); // OLD GRAPHICS
          
          drawDashLineThick(g, vposx, vposy, vtipx, vtipy, thick, 5, colore); // JAVA 2D GRAPHICS - needs double values
          
            //----------------------------------------------------------------------     
            //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
  }
  
   private void draw3DParallelepipedon(Graphics g, double vx1, double vy1, double vz1, 
                                                   double vx2, double vy2, double vz2, 
                                                   double vx3, double vy3, double vz3,
                                                   double vx4, double vy4, double vz4,
                                                   double vx5, double vy5, double vz5,
                                                   double vx6, double vy6, double vz6,
                                                   double vx7, double vy7, double vz7,
                                                   double vx8, double vy8, double vz8,
                                                   int thick, Color colore, 
                                                   Color colorbottom, 
                                                   Color colorside1, 
                                                   Color colorside2){
          
          //This routine contructs a 6 face parallelepipedon.
          //User must make sure that the points are coplanare in 
          //groups four to give a proper solid figure.
          //To obtain a cube, all faces should have identical areas
                                                       
          Point projection;
          double vposx1, vposy1, vposx2, vposy2, vposx3, vposy3, vposx4, vposy4;
          double vposx5, vposy5, vposx6, vposy6, vposx7, vposy7, vposx8, vposy8;
          
          Graphics2D g2d = (Graphics2D)g;
          g2d.setPaint(colore);
          g2d.setStroke(new BasicStroke(thick,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
          g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
          
          //Get projection on 2D plane for nodes
          projection = projector.project((float)vx1,(float)vy1,(float)vz1);
          vposx1 = (double)projection.x;
          vposy1 = (double)projection.y;
          
          projection = projector.project((float)vx2,(float)vy2,(float)vz2);
          vposx2 = (double)projection.x;
          vposy2 = (double)projection.y;
          
          projection = projector.project((float)vx3,(float)vy3,(float)vz3);
          vposx3 = (double)projection.x;
          vposy3 = (double)projection.y;
          
          projection = projector.project((float)vx4,(float)vy4,(float)vz4);
          vposx4 = (double)projection.x;
          vposy4 = (double)projection.y;
          
          projection = projector.project((float)vx5,(float)vy5,(float)vz5);
          vposx5 = (double)projection.x;
          vposy5 = (double)projection.y;
           
          projection = projector.project((float)vx6,(float)vy6,(float)vz6);
          vposx6 = (double)projection.x;
          vposy6 = (double)projection.y;
          
          projection = projector.project((float)vx7,(float)vy7,(float)vz7);
          vposx7 = (double)projection.x;
          vposy7 = (double)projection.y;
          
          // draw sides of cube - Could be done with polygns instead of lines
          projection = projector.project((float)vx8,(float)vy8,(float)vz8);
          vposx8 = (double)projection.x;
          vposy8 = (double)projection.y;
          
          drawLineThick(g, vposx1, vposy1, vposx2, vposy2, thick, colore); 
          drawLineThick(g, vposx1, vposy1, vposx3, vposy3, thick, colore); 
          drawLineThick(g, vposx2, vposy2, vposx4, vposy4, thick, colore);
          drawLineThick(g, vposx3, vposy3, vposx4, vposy4, thick, colore); 
          
          drawLineThick(g, vposx5, vposy5, vposx6, vposy6, thick, colore); 
          drawLineThick(g, vposx5, vposy5, vposx7, vposy7, thick, colore); 
          drawLineThick(g, vposx6, vposy6, vposx8, vposy8, thick, colore);
          drawLineThick(g, vposx7, vposy7, vposx8, vposy8, thick, colore); 
          
          drawLineThick(g, vposx1, vposy1, vposx5, vposy5, thick, colore); 
          drawLineThick(g, vposx3, vposy3, vposx7, vposy7, thick, colore); 
          drawLineThick(g, vposx2, vposy2, vposx6, vposy6, thick, colore);
          drawLineThick(g, vposx4, vposy4, vposx8, vposy8, thick, colore); 
          
          //Draw faces
          // transparency parameters
          int rule; 
          float alpha;
          rule = AlphaComposite.SRC_OVER;
            
          int xpoly[] = new int[4];
          int ypoly[] = new int[4];
          
          alpha = 0.3f;
          
          g2d.setComposite(AlphaComposite.getInstance(rule, alpha));
	  
          // Make faces with Polygons
          
          //bottom face
          xpoly[0] = (int)vposx3; xpoly[1] = (int)vposx4;
          xpoly[2] = (int)vposx8; xpoly[3] = (int)vposx7;
          ypoly[0] = (int)vposy3; ypoly[1] = (int)vposy4;
          ypoly[2] = (int)vposy8; ypoly[3] = (int)vposy7;
          
          //g.setColor(colorbottom);
          //g.fillPolygon(xpoly,ypoly,4); // regular Java Graphics
          
          g2d.setPaint(colorbottom);// Java 2D implementation
          GeneralPath s = new GeneralPath();
          s.moveTo((float)xpoly[0], (float)ypoly[0]);
          s.lineTo((float)xpoly[1], (float)ypoly[1]);
          s.lineTo((float)xpoly[2], (float)ypoly[2]);
          s.lineTo((float)xpoly[3], (float)ypoly[3]);
          s.closePath();
          g2d.fill(s);
          
          // outline of faces using polygons instead of lines
          // Note change in transparency
          //alpha = 0.3f;
          //g2d.setComposite(AlphaComposite.getInstance(rule, alpha));
          //g2d.setPaint(colore);
          //g2d.draw(s);
          //alpha = 0.1f;
          //g2d.setComposite(AlphaComposite.getInstance(rule, alpha));
	  
          // side face 1
          xpoly[0] = (int)vposx1; xpoly[1] = (int)vposx5;
          xpoly[2] = (int)vposx7; xpoly[3] = (int)vposx3;
          ypoly[0] = (int)vposy1; ypoly[1] = (int)vposy5;
          ypoly[2] = (int)vposy7; ypoly[3] = (int)vposy3;
          
          //g.setColor(colorside1);
          //g.fillPolygon(xpoly,ypoly,4); // regular Java Graphics
	  
          g2d.setPaint(colorside1);// Java 2D implementation
          GeneralPath s2 = new GeneralPath();
          s2.moveTo((float)xpoly[0], (float)ypoly[0]);
          s2.lineTo((float)xpoly[1], (float)ypoly[1]);
          s2.lineTo((float)xpoly[2], (float)ypoly[2]);
          s2.lineTo((float)xpoly[3], (float)ypoly[3]);
          s2.closePath();
          g2d.fill(s2);
          
          // side face 2
          xpoly[0] = (int)vposx5; xpoly[1] = (int)vposx6;
          xpoly[2] = (int)vposx8; xpoly[3] = (int)vposx7;
          ypoly[0] = (int)vposy5; ypoly[1] = (int)vposy6;
          ypoly[2] = (int)vposy8; ypoly[3] = (int)vposy7;
          
          //g.setColor(colorside2);
          //g.fillPolygon(xpoly,ypoly,4); // regular Java Graphics
          
          g2d.setPaint(colorside2);// Java 2D implementation
          GeneralPath s3 = new GeneralPath();
          s3.moveTo((float)xpoly[0], (float)ypoly[0]);
          s3.lineTo((float)xpoly[1], (float)ypoly[1]);
          s3.lineTo((float)xpoly[2], (float)ypoly[2]);
          s3.lineTo((float)xpoly[3], (float)ypoly[3]);
          s3.closePath();
          g2d.fill(s3);
          
          g2d.setComposite(AlphaComposite.getInstance(rule, 1.0f)); 
            //----------------------------------------------------------------------     
            //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
  }
   
  private void FillPatch(Graphics g, double vxpatch1, double vypatch1,
                                     double vxpatch2, double vypatch2,
                                     double vxpatch3, double vypatch3,
                                     double vxpatch4, double vypatch4,
                                     float transp, Color colore){
          
          //This routine fills a 4-point patch with two triangles.
                                                       
          Graphics2D g2d = (Graphics2D)g;
          g2d.setPaint(colore);
          g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
          
          //Draw faces
          // transparency parameters
          int rule; 
          float alpha;
          rule = AlphaComposite.SRC_OVER;
            
          int xpoly[] = new int[4];
          int ypoly[] = new int[4];
          
          alpha = transp; //0.3f;
          g2d.setComposite(AlphaComposite.getInstance(rule, alpha));
	  
          // Make patch with two triangles
          
          //lower triangle
          xpoly[0] = (int)vxpatch1; xpoly[1] = (int)vxpatch2;
          xpoly[2] = (int)vxpatch3; 
          ypoly[0] = (int)vypatch1; ypoly[1] = (int)vypatch2;
          ypoly[2] = (int)vypatch3; 
          
          GeneralPath s = new GeneralPath();
          s.moveTo((float)xpoly[0], (float)ypoly[0]);
          s.lineTo((float)xpoly[1], (float)ypoly[1]);
          s.lineTo((float)xpoly[2], (float)ypoly[2]);
          s.closePath();
          g2d.fill(s);
          
          xpoly[0] = (int)vxpatch2; xpoly[1] = (int)vxpatch3;
          xpoly[2] = (int)vxpatch4; 
          ypoly[0] = (int)vypatch2; ypoly[1] = (int)vypatch3;
          ypoly[2] = (int)vypatch4; 
          
          GeneralPath s2 = new GeneralPath();
          s2.moveTo((float)xpoly[0], (float)ypoly[0]);
          s2.lineTo((float)xpoly[1], (float)ypoly[1]);
          s2.lineTo((float)xpoly[2], (float)ypoly[2]);
          s2.closePath();
          g2d.fill(s2);
          
          
          g2d.setComposite(AlphaComposite.getInstance(rule, 1.0f)); 
            //----------------------------------------------------------------------     
            //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
  } 
   
  private void drawTriangle(Graphics g, double vx1, double vy1, double vz1, 
                                                   double vx2, double vy2, double vz2, 
                                                   double vx3, double vy3, double vz3,
                                                   int thick, Color colore){
          
          //This routine contructs a 6 face parallelepipedon.
          //User must make sure that the points are coplanare in 
          //groups four to give a proper solid figure.
          //To obtain a cube, all faces should have identical areas
                                                       
          Point projection;
          double vposx1, vposy1, vposx2, vposy2, vposx3, vposy3;
          
          Graphics2D g2d = (Graphics2D)g;
          g2d.setPaint(colore);
          g2d.setStroke(new BasicStroke(thick,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
          g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
          
          //Get projection on 2D plane for nodes
          projection = projector.project((float)vx1,(float)vy1,(float)vz1);
          vposx1 = (double)projection.x;
          vposy1 = (double)projection.y;
          
          projection = projector.project((float)vx2,(float)vy2,(float)vz2);
          vposx2 = (double)projection.x;
          vposy2 = (double)projection.y;
          
          projection = projector.project((float)vx3,(float)vy3,(float)vz3);
          vposx3 = (double)projection.x;
          vposy3 = (double)projection.y;
          
          
          drawLineThick(g, vposx1, vposy1, vposx2, vposy2, thick, colore); 
          drawLineThick(g, vposx1, vposy1, vposx3, vposy3, thick, colore); 
          drawLineThick(g, vposx2, vposy2, vposx3, vposy3, thick, colore);
          //----------------------------------------------------------------------     
          //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
  } 
  
  private void drawDashLineThick(Graphics g, double x1, double y1, double x2, double y2, int thick, int dash, Color color){
        Graphics2D g2d = (Graphics2D)g;
        g2d.setPaint(color);
        g2d.setStroke(new BasicStroke(thick,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
        float[] dashPattern = {dash,dash};
        g2d.setStroke(new BasicStroke(thick,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER,10.0F,dashPattern,0));  
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
        Line2D.Double line = new Line2D.Double(x1,y1,x2,y2);
        g2d.draw(line);
  
        g2d.setStroke(new BasicStroke(1));g2d.setStroke(new BasicStroke(thick,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
        
        //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
    }
  
  private void drawLineThick(Graphics g, double x1, double y1, double x2, double y2, int thick, Color color){
        Graphics2D g2d = (Graphics2D)g;
        g2d.setPaint(color);
        g2d.setStroke(new BasicStroke(thick,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
        
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
        Line2D.Double line = new Line2D.Double(x1,y1,x2,y2);
        g2d.draw(line);
  
        g2d.setStroke(new BasicStroke(1));
        //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
    }
  
  private void drawLineThick2(Graphics g, double x1, double y1, double x2, double y2, int thick, Color color){
        // Some routine as above, but no smoothing
        Graphics2D g2d = (Graphics2D)g;
        g2d.setPaint(color);
        g2d.setStroke(new BasicStroke(thick,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
        
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
        
        Line2D.Double line = new Line2D.Double(x1,y1,x2,y2);
        g2d.draw(line);
  
        g2d.setStroke(new BasicStroke(1));
        //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
    }
  
    private void drawCircleHorizontalThick(Graphics g, double xCenter, double yCenter, double zCenter, double Radius, int thick, Color color){	
          Point projection;
          double vposx, vposy, rado, centro;
          
          Graphics2D g2d = (Graphics2D)g;
          g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
          
          //Get projection on 2D plane for nodes
          projection = projector.project((float)xCenter,(float)yCenter,(float)zCenter);
          vposx = (double)projection.x;
          vposy = (double)projection.y;
          
          //Get length of radius
          rado = (double)projector.getLong(Radius);
          
        g2d.setPaint(color);
        g2d.setStroke(new BasicStroke(thick, BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL));
        
        //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
        Ellipse2D.Double circle = new Ellipse2D.Double(vposx-rado,vposy-rado*Math.sin(Math.PI/180.0*projector.getAzimuthAngle()),2*rado,(2*rado)*Math.sin(Math.PI/180.0*projector.getAzimuthAngle()));
        g2d.draw(circle);
        g2d.setStroke(new BasicStroke(1));
        //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
    }

    private void drawCircleThick(Graphics g, double xCenter, double yCenter, double Radius, int thick, Color color){	
        Graphics2D g2d = (Graphics2D)g;
        g2d.setPaint(color);
        g2d.setStroke(new BasicStroke(thick, BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL));
        
        //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
        Ellipse2D.Double circle = new Ellipse2D.Double(xCenter-Radius,yCenter-Radius,2*Radius,2*Radius);
        g2d.draw(circle);
        g2d.setStroke(new BasicStroke(1));
        //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
    }

    private void fillCircleThick(Graphics g, double xCenter, double yCenter, double Radius, int thick, Color color){	
        Graphics2D g2d = (Graphics2D)g;
        g2d.setPaint(color);
        g2d.setStroke(new BasicStroke(thick, BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL));
        
        //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
        Ellipse2D.Double circle = new Ellipse2D.Double(xCenter-Radius,yCenter-Radius,2*Radius,2*Radius);
        g2d.fill(circle);
        g2d.setStroke(new BasicStroke(1));
        //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
    }
    
    // WORK IN PROGRESS
    private void draw3DCircleThick(Graphics g, double xCenter, double yCenter, 
                                   double zCenter, double Radius, 
                                   double anglex, double angley, double anglez, 
                                   int thick, Color color){
        
        Point projection;
        Graphics2D g2d = (Graphics2D)g;
        g2d.setPaint(color);
        g2d.setStroke(new BasicStroke(thick, BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL));
        double xProjCenter, yProjCenter;
        
        projection = projector.project((float)xCenter,(float)yCenter,(float)zCenter);
        xProjCenter = (double)projection.x;
        yProjCenter = (double)projection.y;
          
        //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
        Ellipse2D.Double circle = new Ellipse2D.Double(xProjCenter-Radius,yProjCenter-Radius,2*Radius,2*Radius);
        g2d.draw(circle);
        g2d.setStroke(new BasicStroke(1));
        //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
    }
}