
// AnimHistogram.java
// Andrew Davison, ad@coe.psu.ac.th, Feb. 2023

/* An animated set of NUM_BARS*NUM_BARS histogram bars
   which are redrawn every DELAY ms. 


   Using Jzy3d 2.2.0 (http://www.jzy3d.org/)

   Based on an example at:
   https://www.doc.jzy3d.org/guide/docs/getting-started-charts.html

   Usage:
    > compile AnimHistogram.java
    > run AnimHistogram
*/
import java.awt.BorderLayout;
import javax.swing.*;
import java.awt.event.*;
import java.util.Random;

import org.jzy3d.chart.*;
import org.jzy3d.chart.factories.*;
import org.jzy3d.chart.controllers.mouse.camera.*;
import org.jzy3d.chart.controllers.keyboard.camera.*;

import org.jzy3d.colors.*;
import org.jzy3d.colors.colormaps.*;

import org.jzy3d.plot3d.builder.*;
import org.jzy3d.plot3d.builder.concrete.*;

import org.jzy3d.plot3d.primitives.*;
import org.jzy3d.plot3d.primitives.axis.layout.*;
import org.jzy3d.plot3d.primitives.axis.layout.renderers.*;

import org.jzy3d.plot3d.rendering.scene.*;
import org.jzy3d.plot3d.rendering.canvas.*;
import org.jzy3d.plot3d.rendering.view.*;

import org.jzy3d.painters.*;

import org.jzy3d.maths.*;



public class AnimHistogram extends JPanel
{
  // dimensions of the panel
  private static final int P_WIDTH = 700;
  private static final int P_HEIGHT = 600;

  // display NUM_BARS x NUM_BARS bars 
  private static final int NUM_BARS = 4; 
  private static final int OFFSET = 50;  // for positioning the bars

  private static final int DELAY = 1000;  // ms; 1 sec


  private Chart chart;
  private HistogramBar[][] bars;
  private Random rand = new Random();

  // thread for updating the graph
  private Thread updateThread = null;
  private volatile boolean isRunning = true;


  public AnimHistogram()
  {
    setLayout( new BorderLayout());
    setPreferredSize(new java.awt.Dimension(P_WIDTH, P_HEIGHT));

    bars = new HistogramBar[NUM_BARS][NUM_BARS];  

    // create an empty chart
    Quality quality = Quality.Advanced();
    quality.setAnimated(true);   // so changes are drawn

    IChartFactory factory = new SwingChartFactory();
    chart = factory.newChart(quality);

    // modify the chart axes
    AxisLayout axl = chart.getAxisLayout();
    axl.setFont(Font.Helvetica_18);
    axl.setMainColor(Color.GRAY);

    FixedDecimalTickRenderer ren2dp = 
                   new FixedDecimalTickRenderer(2);  // 2 dp
    axl.setXTickRenderer(ren2dp);
    axl.setYTickRenderer(ren2dp);
    axl.setZTickRenderer(ren2dp);

    // add user viewing controls
    chart.addMouse();
    chart.addKeyboard();

    add((JPanel)chart.getCanvas(), BorderLayout.CENTER);

    startUpdater();
  } // end of AnimHistogram()



  public void startUpdater()
  // modify the bars every DELAY ms
  {
    updateThread = new Thread(){
      public void run() 
      {
        while(isRunning) {
          makeBars();
          pause(DELAY);
        }
      } /* run */
    };
    updateThread.start();
  } /* start */


  public void stopUpdater()
  {
    if (updateThread != null)
      isRunning = false;
  }


  public void makeBars()
  // generate a new set of bar heights
  {
    Scene scene = chart.getScene();

    for(int i=0; i < NUM_BARS; i++) {
      for(int j=0; j < NUM_BARS; j++) {
        if (bars[i][j] != null)
          scene.remove(bars[i][j]);
        bars[i][j] = makeBar(i*OFFSET, j*OFFSET, rand.nextInt(100));
        scene.add(bars[i][j]);
      }
    }
  } /* makeBars */


  private HistogramBar makeBar(double x, double y, float height)
  /* generate a bar at (x,y) of the specified height with
     a radius == 10, and a random color.
     Same code as in Histogram3DDemo.java
  */
  { Color color = new RandomGeom().color();
    color.a = 0.5f;  // semi-transparent
    
    HistogramBar bar = new HistogramBar();
    bar.setData(new Coord3d(x, y, 0), height, 10, color);
    bar.setWireframeDisplayed(false);  // necessary or image is corrupted

    return bar;
  }  // end of makeBar()



  private void pause(int ms)
  {
    try {
      Thread.sleep(ms);
    }
    catch(InterruptedException ex) { }
  }  // end of pause()



  // -------------------------------------------

  public static void main(String[] args)
  {
    AnimHistogram pane = new AnimHistogram();

    JFrame f = new JFrame("AnimHistogram");
    f.getContentPane().add(pane);

    f.addWindowListener( new WindowAdapter() {
        public void windowClosing(WindowEvent e) 
        { pane.stopUpdater();
          f.dispose();
          System.exit(0);
        }
      }
    );
    // f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    f.pack();
    f.setResizable(false);
    f.setVisible(true);
  } // end of main()


}  // end of AnimHistogram class