
// Surface3DDemo.java
// Andrew Davison, ad@coe.psu.ac.th, Feb. 2023

/* Plot the equation z = x * Math.sin(x * y) as a 
   colored surface with a wireframe grid.

   The surface is displayed inside a JPanel in a JFrame.

   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 Surface3DDemo.java
   > run Surface3DDemo
*/

import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;

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.primitives.*;
import org.jzy3d.plot3d.primitives.axis.layout.*;
import org.jzy3d.plot3d.primitives.axis.layout.renderers.*;

import org.jzy3d.plot3d.rendering.canvas.*;
import org.jzy3d.plot3d.rendering.view.*;
import org.jzy3d.plot3d.rendering.legends.overlay.*;

import org.jzy3d.painters.*;

import org.jzy3d.maths.*;



public class Surface3DDemo extends JPanel
{
  // dimensions of the panel
  private static final int P_WIDTH = 700;
  private static final int P_HEIGHT = 600;


  public Surface3DDemo()
  {
    setLayout( new BorderLayout());
    setPreferredSize(new java.awt.Dimension(P_WIDTH, P_HEIGHT));

    // define the plotting function
    Func3D func = new Func3D((x, y) -> x * Math.sin(x * y));
    Range range = new Range(-1.5f, 1.5f);

    // build surface
    Shape surface = new SurfaceBuilder().orthonormal(func, range, 20);

    surface.setColorMapper( new ColorMapper(new ColorMapRainbow(),
              surface.getBounds().getZmin(),
              surface.getBounds().getZmax(),
              new Color(1, 1, 1, 0.5f))); // semi-transparent
    surface.setFaceDisplayed(true);
    surface.setWireframeDisplayed(true);
    surface.setWireframeColor(Color.BLACK);

    // create the chart
    IChartFactory factory = new SwingChartFactory();
    Chart chart = factory.newChart(Quality.Advanced());
    chart.getScene().getGraph().add(surface);

    // modify the chart axes
    AxisLayout axl = chart.getAxisLayout();
    axl.setFont(Font.Helvetica_18);  // bigger fontsize
    axl.setXAxisLabel("x-axis");
    axl.setYAxisLabel("y-axis");
    axl.setZAxisLabel("x.sin(xy)");
    axl.setMainColor(Color.GRAY);

    FixedDecimalTickRenderer ren2dp = 
                  new FixedDecimalTickRenderer(2);  // 2 dp 
    axl.setXTickRenderer(ren2dp);
    axl.setYTickRenderer(ren2dp);
    axl.setZTickRenderer(ren2dp);

    // add a title as an overlay
    ((AWTChart)chart).addRenderer(new OverlayLegendRenderer() {
      public void paint(Graphics g, int w, int h) 
      {
        Graphics2D g2d = (Graphics2D) g;
        g2d.setColor(java.awt.Color.BLACK);
        g2d.setFont( new java.awt.Font("Helvetica", 
                             java.awt.Font.BOLD, 18));
        g2d.drawString("Surface 3D Demo", 50, 50);
      }
    });

    // add user viewing controls
    chart.addMouse();
    chart.addKeyboard();

    // rotate the viewport up a little bit
    Coord3d vp = chart.getView().getViewPoint();
    Coord3d vpFar = vp.add(0, vp.y*0.1f, 0);
    chart.getView().setViewPoint(vpFar, true);

    add((JPanel)chart.getCanvas(), BorderLayout.CENTER);
  } // end of Surface3DDemo()


  // -------------------------------------------

  public static void main(String[] args)
  {
    JFrame f = new JFrame("Surface3DDemo");
    f.getContentPane().add( new Surface3DDemo());

    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.pack();
    f.setResizable(false);
    f.setVisible(true);
  } // end of main()


}  // end of Surface3DDemo class