
import java.awt.BorderLayout;

import javax.media.j3d.*;
import javax.swing.JFrame;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.behaviors.vp.OrbitBehavior;
import com.sun.j3d.utils.universe.PlatformGeometry;
import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.universe.ViewingPlatform;

/**
 *
 * @author  fherinean
 * @version $Revision: $
 */
public class HollowCilinder
{
   public static Geometry generate(double height, double outer_radius, double inner_radius, int steps)
   {
      double[] coords = new double[(2 * steps + 1) * 24];
      float[] normals = new float[(2 * steps + 1) * 24];

      double[] xi = new double[steps + 1];
      double[] xo = new double[steps + 1];
      double[] zi = new double[steps + 1];
      double[] zo = new double[steps + 1];

      xi[0] = inner_radius;
      xo[0] = outer_radius;
      xi[steps] = -inner_radius;
      xo[steps] = -outer_radius;

      double a = Math.PI / steps;
      double h = height / 2;

      for (int i = 1; i < steps; i++)
      {
         double x = Math.cos(a * i);
         double z = Math.sin(a * i);
         xi[i] = x * inner_radius;
         xo[i] = x * outer_radius;
         zi[i] = z * inner_radius;
         zo[i] = z * outer_radius;
      }

      int c = 0;
      int n = 0;

      // upper cap
      for (int i = 0; i < steps; i++)
      {
         coords[c++] = xo[i];
         coords[c++] = h;
         coords[c++] = zo[i];

         coords[c++] = xi[i];
         coords[c++] = h;
         coords[c++] = zi[i];

         coords[c++] = xi[i + 1];
         coords[c++] = h;
         coords[c++] = zi[i + 1];

         coords[c++] = xo[i + 1];
         coords[c++] = h;
         coords[c++] = zo[i + 1];

         for (int j = 0; j < 4; j++)
         {
            normals[n++] = 0;
            normals[n++] = 1;
            normals[n++] = 0;
         }
      }

      // lower cap
      for (int i = 0; i < steps; i++)
      {
         coords[c++] = xi[i];
         coords[c++] = -h;
         coords[c++] = zi[i];

         coords[c++] = xo[i];
         coords[c++] = -h;
         coords[c++] = zo[i];

         coords[c++] = xo[i + 1];
         coords[c++] = -h;
         coords[c++] = zo[i + 1];

         coords[c++] = xi[i + 1];
         coords[c++] = -h;
         coords[c++] = zi[i + 1];

         for (int j = 0; j < 4; j++)
         {
            normals[n++] = 0;
            normals[n++] = -1;
            normals[n++] = 0;
         }
      }

      // outer face
      for (int i = 0; i < steps; i++)
      {
         coords[c++] = xo[i];
         coords[c++] = -h;
         coords[c++] = zo[i];

         coords[c++] = xo[i];
         coords[c++] = h;
         coords[c++] = zo[i];

         coords[c++] = xo[i + 1];
         coords[c++] = h;
         coords[c++] = zo[i + 1];

         coords[c++] = xo[i + 1];
         coords[c++] = -h;
         coords[c++] = zo[i + 1];

         for (int k = 0; k < 2; k++)
         {
            double nx = Math.cos((i + k) * a);
            double nz = Math.sin((i + k) * a);
            for (int j = 0; j < 2; j++)
            {
               normals[n++] = (float) nx;
               normals[n++] = 0;
               normals[n++] = (float) nz;
            }
         }
      }

      // first transition
      coords[c++] = xo[steps];
      coords[c++] = -h;
      coords[c++] = zo[steps];

      coords[c++] = xo[steps];
      coords[c++] = h;
      coords[c++] = zo[steps];

      coords[c++] = xi[steps];
      coords[c++] = h;
      coords[c++] = zi[steps];

      coords[c++] = xi[steps];
      coords[c++] = -h;
      coords[c++] = zi[steps];

      for (int k = 0; k < 4; k++)
      {
         normals[n++] = 0;
         normals[n++] = 0;
         normals[n++] = -1;
      }

      // inner face
      for (int i = steps; i > 0; i--)
      {
         coords[c++] = xi[i];
         coords[c++] = -h;
         coords[c++] = zi[i];

         coords[c++] = xi[i];
         coords[c++] = h;
         coords[c++] = zi[i];

         coords[c++] = xi[i - 1];
         coords[c++] = h;
         coords[c++] = zi[i - 1];

         coords[c++] = xi[i - 1];
         coords[c++] = -h;
         coords[c++] = zi[i - 1];

         for (int k = 0; k < 2; k++)
         {
            double nx = -Math.cos((i - k) * a);
            double nz = -Math.sin((i - k) * a);
            for (int j = 0; j < 2; j++)
            {
               normals[n++] = (float) nx;
               normals[n++] = 0;
               normals[n++] = (float) nz;
            }
         }
      }

      // last transition
      coords[c++] = xi[0];
      coords[c++] = -h;
      coords[c++] = zi[0];

      coords[c++] = xi[0];
      coords[c++] = h;
      coords[c++] = zi[0];

      coords[c++] = xo[0];
      coords[c++] = h;
      coords[c++] = zo[0];

      coords[c++] = xo[0];
      coords[c++] = -h;
      coords[c++] = zo[0];

      for (int k = 0; k < 4; k++)
      {
         normals[n++] = 0;
         normals[n++] = 0;
         normals[n++] = -1;
      }

      GeometryArray result = new QuadArray(coords.length / 3, GeometryArray.COORDINATES | GeometryArray.NORMALS);
      result.setCoordinates(0, coords);
      result.setNormals(0, normals);
      return result;
   }

   public static void main(String[] args)
   {
      // super("Memory Usage Test");
      JFrame frame = new JFrame("Hollow Half Cylinder");

      // create canvas & universe
      Canvas3D c3d = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
      SimpleUniverse universe = new SimpleUniverse(c3d);
      ViewingPlatform platform = universe.getViewingPlatform();
      platform.setNominalViewingTransform();

      // create orbiter
      Bounds bounds = new BoundingSphere(new Point3d(), 10.0);
      OrbitBehavior orbit = new OrbitBehavior(c3d,
            OrbitBehavior.REVERSE_ALL |
            OrbitBehavior.DISABLE_TRANSLATE |
            OrbitBehavior.DISABLE_ZOOM);

      orbit.setSchedulingBounds(bounds);
      platform.setViewPlatformBehavior(orbit);

      // setup the lights
      Color3f ambientLightColor = new Color3f(0.30f, 0.30f, 0.30f);
      Color3f diffuseLightColor = new Color3f(0.75f, 0.75f, 0.75f);
      Vector3f diffuseLightDirection = new Vector3f(-1, -1, -1);
      PlatformGeometry pg = new PlatformGeometry();
      Light ambient = new AmbientLight(true, ambientLightColor);
      ambient.setInfluencingBounds(bounds);
      pg.addChild(ambient);
      Light directional = new DirectionalLight(true,
            diffuseLightColor,
            diffuseLightDirection);
      directional.setInfluencingBounds(bounds);
      pg.addChild(directional);
      platform.setPlatformGeometry(pg);

      BranchGroup root = new BranchGroup();
      Appearance appearance = new Appearance();
      Material material = new Material();
      appearance.setMaterial(material);
      Shape3D shape = new Shape3D(generate(1, 0.6, 0.4, 32), appearance);
      root.addChild(shape);
      root.compile();

      universe.getLocale().addBranchGraph(root);

      // show the window
      frame.getContentPane().add(c3d, BorderLayout.CENTER);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setSize(400, 400);
      frame.setLocation(300, 300);
      frame.setVisible(true);
   }
}
