/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: JThreeDSideView.java
*
* Copyright (c) 2005 Sun Microsystems and Static Free Software
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.plugins.j3d.ui;
import com.sun.electric.tool.user.User;
import com.sun.electric.technology.Layer;
import com.sun.electric.database.geometry.GenMath;
import com.sun.electric.plugins.j3d.*;
import com.sun.electric.plugins.j3d.utils.J3DUtils;
import com.sun.electric.plugins.j3d.utils.J3DAppearance;
import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.universe.ViewingPlatform;
import com.sun.j3d.utils.universe.Viewer;
import com.sun.j3d.utils.universe.PlatformGeometry;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.picking.PickCanvas;
import com.sun.j3d.utils.picking.PickResult;
import javax.media.j3d.*;
import javax.vecmath.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;
import java.util.HashMap;
/**
* Support class for 3D viewing.
*/
public class JThreeDSideView extends JPanel
implements MouseMotionListener, MouseListener
{
private static Layer currentLayerSelected = null;
private HashMap<Layer,Shape3DTab> layerPolyhedra = null;
double lowHeight = Double.MAX_VALUE, highHeight = Double.MIN_VALUE;
private PickCanvas pickCanvas;
private JThreeDTab parentDialog;
// This class will store previous Z values assigned to layer
private static class Shape3DTab
{
Shape3D shape;
double origDist;
double origThick;
Shape3DTab(Shape3D s, double dist, double thick)
{
this.shape = s;
this.origDist = dist;
this.origThick = thick;
}
}
public JThreeDSideView(JThreeDTab dialog)
{
parentDialog = dialog;
GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
setLayout(new BorderLayout());
Canvas3D canvas = new Canvas3D(config);
add("Center", canvas);
canvas.addMouseListener(this);
// Set global highlight appearance before create the elements
J3DAppearance.setHighlightedAppearanceValues(this);
// Set global bounding box appearance before values are set
J3DAppearance.setCellAppearanceValues(this);
// Set global axes before values are set
J3DAppearance.setAxisAppearanceValues(this);
// Creating scene
BranchGroup scene = createSceneGraph(canvas, J3DUtils.infiniteBounds);
ViewingPlatform viewP = new ViewingPlatform(4);
viewP.setCapability(ViewingPlatform.ALLOW_CHILDREN_READ);
Viewer viewer = new Viewer(canvas);
SimpleUniverse u = new SimpleUniverse(viewP, viewer);
u.addBranchGraph(scene);
// lights on ViewPlatform geometry group
PlatformGeometry pg = new PlatformGeometry();
J3DUtils.createLights(pg);
viewP.setPlatformGeometry(pg) ;
JMouseRotate rotate = new JMouseRotate(MouseRotate.INVERT_INPUT);
rotate.setTransformGroup(u.getViewingPlatform().getMultiTransformGroup().getTransformGroup(0));
BranchGroup rotateBG = new BranchGroup();
rotateBG.addChild(rotate);
u.getViewingPlatform().addChild(rotateBG);
rotate.setSchedulingBounds(J3DUtils.infiniteBounds);
JMouseZoom zoom = new JMouseZoom(canvas, MouseZoom.INVERT_INPUT);
zoom.setTransformGroup(u.getViewingPlatform().getMultiTransformGroup().getTransformGroup(1));
zoom.setSchedulingBounds(J3DUtils.infiniteBounds);
zoom.setFactor(0.7); // default 0.4
BranchGroup zoomBG = new BranchGroup();
zoomBG.addChild(zoom);
u.getViewingPlatform().addChild(zoomBG);
JMouseTranslate translate = new JMouseTranslate(canvas, MouseTranslate.INVERT_INPUT);
translate.setTransformGroup(u.getViewingPlatform().getMultiTransformGroup().getTransformGroup(2));
translate.setSchedulingBounds(J3DUtils.infiniteBounds);
translate.setFactor(0.01 * (highHeight-lowHeight)); // default 0.02
BranchGroup translateBG = new BranchGroup();
translateBG.addChild(translate);
u.getViewingPlatform().addChild(translateBG);
// OrbitBehavior orbit = new OrbitBehavior(canvas, OrbitBehavior.REVERSE_ALL);
// orbit.setSchedulingBounds(infiniteBounds);
// Point3d center = new Point3d(-10, -10, (lowHeight+highHeight)/2);
//
// //orbit.setRotationCenter(center);
// orbit.setMinRadius(0);
// orbit.setZoomFactor(1);
// //orbit.setTransFactors(10, 10);
// orbit.setProportionalZoom(true);
// Transform3D home = new Transform3D();
// home.setTranslation(new Vector3d(center));
// //orbit.setHomeTransform(home);
// u.getViewingPlatform().setViewPlatformBehavior(orbit);
u.getViewingPlatform().setNominalViewingTransform();
//translate.setView(-10, -50);
J3DUtils.setViewPoint(u, canvas, scene, new Rectangle2D.Double(0, 0, 10, 20));
rotate.setRotation(-1.57, 0.5, 0);
zoom.setZoom(0.5);
}
private BranchGroup createSceneGraph(Canvas3D canvas, BoundingSphere infiniteBounds)
{
BranchGroup objRoot = new BranchGroup();
objRoot.setCapability(BranchGroup.ALLOW_BOUNDS_READ);
objRoot.setCapability(BranchGroup.ENABLE_PICK_REPORTING);
objRoot.setCapability(BranchGroup.ALLOW_BOUNDS_WRITE);
// Create a simple Shape3D node; add it to the scene graph.
Background bg = new Background(new Color3f(new Color(User.getColor(User.ColorPrefType.BACKGROUND))));
bg.setApplicationBounds(infiniteBounds);
objRoot.addChild(bg);
// Create the TransformGroup node and initialize it to the
// identity. Enable the TRANSFORM_WRITE capability so that
// our behavior code can modify it at run time. Add it to
// the root of the subgraph.
// Create a transform group node to scale and position the object.
Transform3D t = new Transform3D();
t.set(1, new Vector3d(0, -10, -40));
TransformGroup objTrans = new TransformGroup(t);
objRoot.addChild(objTrans);
TransformGroup nodesGroup = new TransformGroup();
nodesGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
nodesGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
nodesGroup.setCapability(TransformGroup.ENABLE_PICK_REPORTING);
objTrans.addChild(nodesGroup);
layerPolyhedra = new HashMap<Layer,Shape3DTab>(parentDialog.getTech().getNumLayers());
for(Iterator<Layer> it = parentDialog.getTech().getLayers(); it.hasNext(); )
{
Layer layer = (Layer)it.next();
if (layer.isPseudoLayer()) continue;
//if (!layer.isVisible()) continue;
double xyFactor = (layer.getFunctionExtras() == Layer.Function.CONMETAL) ? 0.8 : 1;
J3DAppearance ap = parentDialog.transparencyMap.get(layer);
GenMath.MutableDouble thickness = parentDialog.threeDThicknessMap.get(layer);
GenMath.MutableDouble distance = parentDialog.threeDDistanceMap.get(layer);
double dis = distance.doubleValue();
double thick = thickness.doubleValue();
Rectangle2D bounds = new Rectangle2D.Double(0, 0, 10*xyFactor, 20*xyFactor);
Shape3DTab shape = new Shape3DTab(J3DUtils.addPolyhedron(bounds, dis, thick, ap, nodesGroup), dis, thick);
layerPolyhedra.put(layer, shape);
if (dis < lowHeight)
lowHeight = dis;
double max = dis + thick;
if (max > highHeight)
highHeight = max;
}
// picking tool
pickCanvas = new PickCanvas(canvas, objRoot);
//pickCanvas.setMode(PickCanvas.BOUNDS);
pickCanvas.setMode(PickCanvas.GEOMETRY_INTERSECT_INFO);
pickCanvas.setTolerance(4.0f);
objRoot.compile();
return objRoot;
}
/**
* To highlight layer according to list on the left
* @param layer
*/
public void showLayer(Layer layer)
{
Shape3DTab shape;
if (currentLayerSelected != null)
{
// For this shape, its appareance has to be set back to normal
shape = layerPolyhedra.get(currentLayerSelected);
if (shape != null) // is null if previous shape belongs to another dialog (another tech)
shape.shape.setAppearance((J3DAppearance)parentDialog.transparencyMap.get(currentLayerSelected));
}
shape = layerPolyhedra.get(layer);
if (shape != null)
shape.shape.setAppearance(J3DAppearance.highlightApp);
else
System.out.println("Shape is null in JThreeDSideView.showLayer");
currentLayerSelected = layer;
}
public void updateZValues(Layer layer, double thickness, double distance)
{
Shape3DTab shape = layerPolyhedra.get(layer);
if (J3DUtils.updateZValues(shape.shape, (float)shape.origDist, (float)(shape.origDist+shape.origThick),
(float)distance, (float)(distance+thickness)))
{
// It has to remember temporary new values until they are committed into database
shape.origDist = distance;
shape.origThick = thickness;
}
}
// the MouseEvent events
public void mousePressed(MouseEvent evt)
{
}
public void mouseReleased(MouseEvent evt) {}
/**
* Method to handle picking tool in 3D
* @param evt
*/
public void mouseClicked(MouseEvent evt)
{
pickCanvas.setShapeLocation(evt);
PickResult result = pickCanvas.pickClosest();
if (result != null)
{
Shape3D s = (Shape3D)result.getNode(PickResult.SHAPE3D);
if (s != null)
{
J3DAppearance app = (J3DAppearance)s.getAppearance();
if (app != J3DAppearance.highlightApp)
{
Layer layer = app.getLayer();
parentDialog.threeDLayerList.setSelectedValue(layer.getName(), false);
parentDialog.processDataInFields(layer, false);
}
}
}
}
public void mouseEntered(MouseEvent evt) {}
public void mouseExited(MouseEvent evt) {}
// the MouseMotionListener events
public void mouseMoved(MouseEvent evt) {}
public void mouseDragged(MouseEvent evt) {}
}