package org.reprap.gui;
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.GraphicsConfigTemplate;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.io.File;
import java.net.URL;
import javax.media.j3d.Appearance;
import javax.media.j3d.AudioDevice;
import javax.media.j3d.Background;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.Bounds;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.GraphicsConfigTemplate3D;
import javax.media.j3d.Material;
import javax.media.j3d.PhysicalBody;
import javax.media.j3d.PhysicalEnvironment;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.View;
import javax.media.j3d.ViewPlatform;
import javax.media.j3d.VirtualUniverse;
import javax.swing.JPanel;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import org.reprap.Preferences;
import com.sun.j3d.audioengines.javasound.JavaSoundMixer;
import org.reprap.geometry.polyhedra.STLObject;
import org.reprap.utilities.Debug;
abstract public class Panel3D extends JPanel {
private static final long serialVersionUID = 1L;
//-------------------------------------------------------------
// What follows are defaults. These values should be overwritten from
// the reprap.properties file.
protected String wv_location = null;
// Translate and zoom scaling factors
protected double mouse_tf = 50;
protected double mouse_zf = 50;
protected double xwv = 300; // The RepRap machine...
protected double ywv = 300; // ...working volume in mm.
protected double zwv = 300;
// Factors for front and back clipping planes and so on
protected double RadiusFactor = 0.7;
protected double BackFactor = 2.0;
protected double FrontFactor = 0.001;
protected double BoundFactor = 3.0;
protected String worldName = "RepRap World";
protected Vector3d wv_offset = new Vector3d(-17.3, -24.85, -2);
// The background, and other colours
protected Color3f bgColour = new Color3f(0.9f, 0.9f, 0.9f);
protected Color3f selectedColour = new Color3f(0.6f, 0.2f, 0.2f);
protected Color3f machineColour = new Color3f(0.3f, 0.4f, 0.3f);
protected Color3f unselectedColour = new Color3f(0.3f, 0.3f, 0.3f);
// protected Color3f shellColour = new Color3f(0.1f, 0.6f, 0.1f);
// That's the end of the configuration file data
//--------------------------------------------------------------
protected static final Color3f black = new Color3f(0, 0, 0);
// protected Appearance default_app = null; // Colour for unselected parts
// protected Appearance shell_app = null; // Colour for the lower shell during print.
protected Appearance picked_app = null; // Colour for the selected part
protected Appearance wv_app = null; // Colour for the working volume
// protected Appearance extrusion_app = null; // Colour for extruded material
protected BranchGroup wv_and_stls = new BranchGroup(); // Where in the scene
// the
// working volume and STLs
// are joined on.
protected STLObject world = null; // Everything
protected STLObject workingVolume = null; // The RepRap machine itself.
// The world in the Applet
protected VirtualUniverse universe = null;
protected BranchGroup sceneBranchGroup = null;
protected Bounds applicationBounds = null;
// Set up the RepRap working volume
abstract protected BranchGroup createSceneBranchGroup() throws Exception;
// Set bg light grey
abstract protected Background createBackground();
abstract protected BranchGroup createViewBranchGroup(
TransformGroup[] tgArray, ViewPlatform vp);
public void refreshPreferences()
{
// -----------------------
// Set everything up from the properties file
// All this needs to go into Preferences.java
try
{
wv_location = Preferences.loadGlobalString("BuildBaseSTL(name)");
// Translate and zoom scaling factors
mouse_tf = 50; //Preferences.loadGlobalDouble("MouseTranslationFactor");
mouse_zf = 50; //Preferences.loadGlobalDouble("MouseZoomFactor");
RadiusFactor = 0.7; //Preferences.loadGlobalDouble("RadiusFactor");
BackFactor = 2.0; //Preferences.loadGlobalDouble("BackFactor");
FrontFactor = 0.001; //Preferences.loadGlobalDouble("FrontFactor");
BoundFactor = 3.0; //Preferences.loadGlobalDouble("BoundFactor");
xwv = Preferences.loadGlobalDouble("WorkingX(mm)"); // The RepRap machine...
ywv = Preferences.loadGlobalDouble("WorkingY(mm)"); // ...working volume in mm.
zwv = Preferences.loadGlobalDouble("WorkingZ(mm)");
// Factors for front and back clipping planes and so on
worldName = "RepRap-World"; //Preferences.loadGlobalString("WorldName");
wv_offset = new Vector3d(0, //Preferences.loadGlobalDouble("WorkingOffsetX(mm)"),
0, //Preferences.loadGlobalDouble("WorkingOffsetY(mm)"),
0); //Preferences.loadGlobalDouble("WorkingOffsetZ(mm)"));
// The background, and other colours
// bgColour = new Color3f((float)Preferences.loadGlobalDouble("BackColourR(0..1)"),
// (float)Preferences.loadGlobalDouble("BackColourG(0..1)"),
// (float)Preferences.loadGlobalDouble("BackColourB(0..1)"));
//
// selectedColour = new Color3f((float)Preferences.loadGlobalDouble("SelectedColourR(0..1)"),
// (float)Preferences.loadGlobalDouble("SelectedColourG(0..1)"),
// (float)Preferences.loadGlobalDouble("SelectedColourB(0..1)"));
//
// machineColour = new Color3f((float)Preferences.loadGlobalDouble("MachineColourR(0..1)"),
// (float)Preferences.loadGlobalDouble("MachineColourG(0..1)"),
// (float)Preferences.loadGlobalDouble("MachineColourB(0..1)"));
//
// unselectedColour = new Color3f((float)Preferences.loadGlobalDouble("UnselectedColourR(0..1)"),
// (float)Preferences.loadGlobalDouble("UnselectedColourG(0..1)"),
// (float)Preferences.loadGlobalDouble("UnselectedColourB(0..1)"));
bgColour = new Color3f((float)0.9, (float)0.9, (float)0.9);
selectedColour = new Color3f((float)0.6, (float)0.2, (float)0.2);
machineColour = new Color3f((float)0.3, (float)0.4, (float)0.3);
unselectedColour = new Color3f((float)0.3, (float)0.3, (float)0.3);
} catch (Exception ex)
{
Debug.e("Refresh Panel3D preferences: " + ex.toString());
}
// End of stuff from the preferences file
// ----------------------
}
protected void initialise() throws Exception {
refreshPreferences();
// default_app = new Appearance();
// default_app.setMaterial(new Material(unselectedColour, black, unselectedColour, black, 0f));
picked_app = new Appearance();
picked_app.setMaterial(new Material(selectedColour, black, selectedColour, black, 0f));
// extrusion_app = new Appearance();
// extrusion_app.setMaterial(new Material(unselectedColour, black, unselectedColour, black, 101f));
// shell_app = new Appearance();
// shell_app.setMaterial(new Material(shellColour, black, shellColour, black, 101f));
wv_app = new Appearance();
wv_app.setMaterial(new Material(machineColour, black, machineColour, black, 0f));
initJava3d();
}
// How far away is the back?
protected double getBackClipDistance() {
return BackFactor * getViewPlatformActivationRadius();
}
// How close is the front?
protected double getFrontClipDistance() {
return FrontFactor * getViewPlatformActivationRadius();
}
// Set up the size of the world
protected Bounds createApplicationBounds() {
applicationBounds = new BoundingSphere(new Point3d(xwv * 0.5,
ywv * 0.5, zwv * 0.5), BoundFactor
* getViewPlatformActivationRadius());
return applicationBounds;
}
// (About) how big is the world?
protected float getViewPlatformActivationRadius() {
return (float) (RadiusFactor * Math.sqrt(xwv * xwv + ywv * ywv + zwv * zwv));
}
public Color3f getObjectColour()
{
return unselectedColour;
}
// Where are we in the file system?
public static URL getWorkingDirectory() {
try {
File file = new File(System.getProperty("user.dir"));
return file.toURI().toURL();
} catch (Exception e) {
Debug.e("getWorkingDirectory( ): can't get user dir.");
}
//return getCodeBase( );
return null;
}
// Return handles on big things above where we are interested
public VirtualUniverse getVirtualUniverse() {
return universe;
}
protected View createView(ViewPlatform vp) {
View view = new View();
PhysicalBody pb = createPhysicalBody();
PhysicalEnvironment pe = createPhysicalEnvironment();
AudioDevice audioDevice = createAudioDevice(pe);
if (audioDevice != null) {
pe.setAudioDevice(audioDevice);
audioDevice.initialize();
}
view.setPhysicalEnvironment(pe);
view.setPhysicalBody(pb);
if (vp != null)
view.attachViewPlatform(vp);
view.setBackClipDistance(getBackClipDistance());
view.setFrontClipDistance(getFrontClipDistance());
Canvas3D c3d = createCanvas3D();
view.addCanvas3D(c3d);
addCanvas3D(c3d);
return view;
}
protected Canvas3D createCanvas3D() {
GraphicsConfigTemplate3D gc3D = new GraphicsConfigTemplate3D();
gc3D.setSceneAntialiasing(GraphicsConfigTemplate.PREFERRED);
GraphicsDevice gd[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
Canvas3D c3d = new Canvas3D(gd[0].getBestConfiguration(gc3D));
//c3d.setSize(getCanvas3dWidth(c3d), getCanvas3dHeight(c3d));
return c3d;
}
public javax.media.j3d.Locale getFirstLocale() {
java.util.Enumeration<?> en = universe.getAllLocales();
if (en.hasMoreElements() != false)
return (javax.media.j3d.Locale) en.nextElement();
return null;
}
// The size of the world
protected Bounds getApplicationBounds() {
if (applicationBounds == null)
applicationBounds = createApplicationBounds();
return applicationBounds;
}
// Fire up Java3D
public void initJava3d() throws Exception {
universe = createVirtualUniverse();
javax.media.j3d.Locale locale = createLocale(universe);
BranchGroup sceneBranchGroup = createSceneBranchGroup();
ViewPlatform vp = createViewPlatform();
BranchGroup viewBranchGroup = createViewBranchGroup(
getViewTransformGroupArray(), vp);
createView(vp);
Background background = createBackground();
if (background != null)
sceneBranchGroup.addChild(background);
locale.addBranchGraph(sceneBranchGroup);
addViewBranchGroup(locale, viewBranchGroup);
}
protected PhysicalBody createPhysicalBody() {
return new PhysicalBody();
}
protected AudioDevice createAudioDevice(PhysicalEnvironment pe) {
JavaSoundMixer javaSoundMixer = new JavaSoundMixer(pe);
if (javaSoundMixer == null)
Debug.e("create of audiodevice failed");
return javaSoundMixer;
}
protected PhysicalEnvironment createPhysicalEnvironment() {
return new PhysicalEnvironment();
}
protected ViewPlatform createViewPlatform() {
ViewPlatform vp = new ViewPlatform();
vp.setViewAttachPolicy(View.RELATIVE_TO_FIELD_OF_VIEW);
vp.setActivationRadius(getViewPlatformActivationRadius());
return vp;
}
// These two are probably wrong.
protected int getCanvas3dWidth(Canvas3D c3d) {
return getWidth();
}
protected int getCanvas3dHeight(Canvas3D c3d) {
return getHeight();
}
protected VirtualUniverse createVirtualUniverse() {
return new VirtualUniverse();
}
protected void addViewBranchGroup(javax.media.j3d.Locale locale,
BranchGroup bg) {
locale.addBranchGraph(bg);
}
protected javax.media.j3d.Locale createLocale(VirtualUniverse u) {
return new javax.media.j3d.Locale(u);
}
public TransformGroup[] getViewTransformGroupArray() {
TransformGroup[] tgArray = new TransformGroup[1];
tgArray[0] = new TransformGroup();
Transform3D viewTrans = new Transform3D();
Transform3D eyeTrans = new Transform3D();
BoundingSphere sceneBounds = (BoundingSphere) sceneBranchGroup
.getBounds();
// point the view at the center of the object
Point3d center = new Point3d();
sceneBounds.getCenter(center);
double radius = sceneBounds.getRadius();
Vector3d temp = new Vector3d(center);
viewTrans.set(temp);
// pull the eye back far enough to see the whole object
double eyeDist = radius / Math.tan(Math.toRadians(40) / 2.0);
temp.x = 0.0;
temp.y = 0.0;
temp.z = eyeDist;
eyeTrans.set(temp);
viewTrans.mul(eyeTrans);
// set the view transform
tgArray[0].setTransform(viewTrans);
return tgArray;
}
protected void addCanvas3D(Canvas3D c3d) {
setLayout(new BorderLayout());
add(c3d, BorderLayout.CENTER);
doLayout();
c3d.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
// protected void addBlock(BranchGroup root, Appearance appearance,
// double x1, double y1, double z1,
// double x2, double y2, double z2,
// float width, float height) {
// root.addChild(addRectangularSegment(appearance, x1, y1, z1, x2, y2, z2, width, height));
// }
//
// protected void addBlock(TransformGroup root, Appearance appearance,
// double x1, double y1, double z1,
// double x2, double y2, double z2,
// float width, float height) {
// root.addChild(addRectangularSegment(appearance, x1, y1, z1, x2, y2, z2, width, height));
// }
//
// protected TransformGroup addRectangularSegment(Appearance appearance,
// double x1, double y1, double z1,
// double x2, double y2, double z2,
// float width, float height) {
//
// z1 += width / 2.0;
// z2 += width / 2.0;
//
// Point3d p1 = new Point3d(x1, y1, z1);
// //Point3d p2 = new Point3d(x2, y2, z2);
//
// Vector3d unity = new Vector3d(0, 1, 0);
// Vector3d v = new Vector3d(x2 - x1, y2 - y1, z2 - z1);
//
// Primitive segment = new Box(width, (float)v.length() / 2.0f, height, appearance);
//
// Transform3D transform = new Transform3D();
//
// Vector3d translate = new Vector3d(p1);
// v.scale(0.5);
// translate.add(v);
// transform.setTranslation(translate);
//
// double angle = v.angle(unity);
// Vector3d axis = new Vector3d();
// axis.cross(unity, v);
// AxisAngle4d rotationAngle = new AxisAngle4d(axis.x, axis.y, axis.z, angle);
// transform.setRotation(rotationAngle);
//
// TransformGroup tg = new TransformGroup(transform);
// tg.addChild(segment);
// return tg;
// }
//
// protected TransformGroup addCylindricalSegment(Appearance appearance,
// double x1, double y1, double z1,
// double x2, double y2, double z2,
// float thickness) {
//
// Point3d p1 = new Point3d(x1, y1, z1);
// //Point3d p2 = new Point3d(x2, y2, z2);
//
// Vector3d unity = new Vector3d(0, 1, 0);
// Vector3d v = new Vector3d(x2 - x1, y2 - y1, z2 - z1 + thickness / 2.0);
//
// Primitive segment = new Cylinder(thickness, (float)v.length(), appearance);
//
// Transform3D transform = new Transform3D();
//
// Vector3d translate = new Vector3d(p1);
// v.scale(0.5);
// translate.add(v);
// transform.setTranslation(translate);
//
// double angle = v.angle(unity);
// Vector3d axis = new Vector3d();
// axis.cross(unity, v);
// AxisAngle4d rotationAngle = new AxisAngle4d(axis.x, axis.y, axis.z, angle);
// transform.setRotation(rotationAngle);
//
// TransformGroup tg = new TransformGroup(transform);
// tg.addChild(segment);
// return tg;
// }
protected double getScale() {
return 1.0;
}
// protected String getStlBackground() throws Exception {
// String path = getStlBackground("");
// if (path != null)
// return path;
// path = getStlBackground("lib/");
// if (path != null)
// return path;
// path = getStlBackground("../lib/");
// if (path != null)
// return path;
//
// // for eD's version of a NetBeans project - improvements welcome!
// path = getStlBackground("../host/lib/");
// if (path != null)
// return path;
//
// throw new Exception("Cannot locate background STL file");
// }
protected String getStlBackground() throws Exception {
URL u = ClassLoader.getSystemResource(wv_location);
if(u != null)
{
String name = u.toString();
//System.out.println("**- " + name);
return name;
}
throw new Exception("Cannot locate background STL file");
}
// protected String getStlBackground(String subdir) {
// URL codebase = null;
// String stlURL = null;
// String stlPath = null;
//
// try {
//// codebase = Panel3D.getWorkingDirectory();
//// stlPath = codebase.getPath() + subdir + wv_location;
//// stlURL = codebase.toExternalForm() + subdir + wv_location;
// URL u = ClassLoader.getSystemResource(wv_location);
// stlPath = u.getPath();
// stlURL = u.toExternalForm();//u.getFile();
//// System.out.println(stlPath + " : " + stlURL);
// } catch (Exception e) {
// Debug.e("createSceneBranchGroup(): Exception finding working directory: "
// + codebase.toExternalForm());
// e.printStackTrace();
// }
//
// File f = new File(stlPath);
// if (f.exists())
// return stlURL;
//
// return null;
//
// }
}