Java3Dで数値地図50mメッシュ(標高)を表示(その2)

 前回の続きで、GUI部分を実装する。
 実行時の画像は、以下のとおり。

 ■ソースコード
 JCanvas3Dを継承したDemCanvas3Dと、実行部分のDemAppクラスを実装する。
 せっかくなので、DemCanvas3Dには画面をスキャンするBehaviorを組み込む。

・DemCanvas3D.java(キャンバス部)

package test.dem50m;

import java.awt.GraphicsConfiguration;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Enumeration;

import javax.imageio.ImageIO;
import javax.media.j3d.AmbientLight;
import javax.media.j3d.Background;
import javax.media.j3d.Behavior;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.GraphicsContext3D;
import javax.media.j3d.Group;
import javax.media.j3d.ImageComponent;
import javax.media.j3d.ImageComponent2D;
import javax.media.j3d.Light;
import javax.media.j3d.Raster;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.View;
import javax.media.j3d.WakeupCriterion;
import javax.media.j3d.WakeupOnElapsedFrames;
import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.Vector3f;

import com.sun.j3d.utils.universe.PlatformGeometry;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class DemCanvas3D extends Canvas3D {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private SimpleUniverse universe;
	private PlatformGeometry platform;
	private TransformGroup world;
	private BoundingSphere boundingSphere;
	private BranchGroup root;
	private Background back;
	
	public DemCanvas3D(){
		super(SimpleUniverse.getPreferredConfiguration());
		initilize();
	}
	
	/**
	 * @param arg0
	 */
	public DemCanvas3D(GraphicsConfiguration arg0) {
		super(arg0);
		initilize();
	}

	/**
	 * @param arg0
	 * @param arg1
	 */
	public DemCanvas3D(GraphicsConfiguration arg0, boolean arg1) {
		super(arg0, arg1);
		initilize();
	}
	
	private void initilize(){
		universe=initUniverse();
		platform=initPlatformGeometry();
		universe.getViewingPlatform().setPlatformGeometry(platform);
		root=new BranchGroup();
		root.setName("root");
		world= new TransformGroup();
		world.setName("world");
		world.setCapability(Group.ALLOW_CHILDREN_READ);
		world.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
		world.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
		world.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		world.setCapability(Group.ALLOW_CHILDREN_EXTEND);
		root.addChild(world);
		boundingSphere=new BoundingSphere(new Point3d(),1000000);
		back=new Background(new Color3f(0.0f,0.0f,0.0f));
		back.setCapability(Background.ALLOW_COLOR_READ);
		back.setCapability(Background.ALLOW_COLOR_WRITE);
		back.setApplicationBounds(boundingSphere);
		root.addChild(back);
		initLightFog();
	}
	
	private void initLightFog(){
		Light l0=new DirectionalLight(new Color3f(1.0f,1.0f,1.0f),
	 	 	 new Vector3f(-0.5f,-0.866025f,0.0f));
		l0.setCapability(Light.ALLOW_COLOR_READ);
		l0.setCapability(Light.ALLOW_COLOR_WRITE);
		l0.setCapability(DirectionalLight.ALLOW_DIRECTION_READ);
		l0.setCapability(DirectionalLight.ALLOW_DIRECTION_WRITE);
		l0.setCapability(Light.ALLOW_STATE_READ);
		l0.setCapability(Light.ALLOW_STATE_WRITE);
		l0.setInfluencingBounds(boundingSphere);
		Light l1=new AmbientLight(new Color3f(0.9f,0.9f,0.9f));
		l1.setCapability(Light.ALLOW_COLOR_READ);
		l1.setCapability(Light.ALLOW_COLOR_WRITE);
		l1.setCapability(Light.ALLOW_STATE_READ);
		l1.setCapability(Light.ALLOW_STATE_WRITE);
		l1.setInfluencingBounds(boundingSphere);
		root.addChild(l0);
		root.addChild(l1);
	}
	
	public SimpleUniverse getUniverse() {
		return universe;
	}

	public BoundingSphere getBoundingSphere() {
		return boundingSphere;
	}
	
	public BranchGroup getRoot(){
		return root;
	}
	
	public TransformGroup getWorld(){
		return world;
	}
	
	public void addWorld(BranchGroup group){
		world.addChild(group);
	}
	
	public TransformGroup getViewPlatformTransform(){
		return universe.getViewingPlatform().getViewPlatformTransform();
	}

	public void start(){
		universe.addBranchGraph(root);
	}

	private SimpleUniverse initUniverse(){
		SimpleUniverse ret=new SimpleUniverse(this);
		ret.getViewingPlatform().setNominalViewingTransform();
		ret.getViewer().getView().setFrontClipPolicy(View.PHYSICAL_EYE);
		ret.getViewer().getView().setFrontClipDistance(0.1);
		ret.getViewer().getView().setBackClipPolicy(View.PHYSICAL_EYE);
		ret.getViewer().getView().setBackClipDistance(100000);
		return ret;
	}
	
	private PlatformGeometry initPlatformGeometry(){
		PlatformGeometry platformGeometry=new PlatformGeometry();
		platformGeometry.setCapability(PlatformGeometry.ALLOW_CHILDREN_READ);
		platformGeometry.setCapability(PlatformGeometry.ALLOW_CHILDREN_WRITE);
		platformGeometry.setCapability(PlatformGeometry.ALLOW_CHILDREN_EXTEND);
		return platformGeometry;
	}


	public void saveImage(final File f){
		BranchGroup bg=new BranchGroup();
		bg.setCapability(BranchGroup.ALLOW_DETACH);
		SaveBehavior sb=new SaveBehavior(bg,f);
		bg.addChild(sb);
		sb.setSchedulingBounds(boundingSphere);
		world.addChild(bg);
	}
	
	private class SaveBehavior extends Behavior{
		File file;
		BranchGroup bg;
		
		public SaveBehavior(BranchGroup b,File f){
			bg=b;
			file=f;
		}
		
		@Override
		public void initialize() {
			wakeupOn (new WakeupOnElapsedFrames(0));
		}
		
		@Override
		@SuppressWarnings("unchecked")
		public void processStimulus(Enumeration criteria) {
			WakeupCriterion wakeup;
			while (criteria.hasMoreElements()) {
				wakeup = (WakeupCriterion) criteria.nextElement();
				if (wakeup instanceof WakeupOnElapsedFrames) {
					saveImageProcess(file);
					world.removeChild(bg);
					return;
				}
			}
		}
	}
	
	private void saveImageProcess(File f){
		GraphicsContext3D  ctx = this.getGraphicsContext3D();
		int w = this.getWidth();
		int h = this.getHeight();
		BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
		ImageComponent2D im = new ImageComponent2D(ImageComponent.FORMAT_RGB, bi);
		Raster ras = new Raster(new Point3f( -1.0f, -1.0f, -1.0f ),
					 Raster.RASTER_COLOR, 0, 0, w, h, im, null );
		ctx.flush(true);
		ctx.readRaster( ras );
		BufferedImage out=ras.getImage().getImage();
		try{
			ImageIO.write(out,"png",f);
		}catch(IOException e){
			e.printStackTrace();
		}
	}

}

・DemApp.java(実行部)

package test.dem50m;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;

import javax.media.j3d.BranchGroup;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.WindowConstants;
import javax.swing.filechooser.FileFilter;

import com.sun.j3d.utils.behaviors.keyboard.KeyNavigatorBehavior;
import com.sun.j3d.utils.behaviors.vp.OrbitBehavior;

public class DemApp {
	private JFrame frame;
	private JFileChooser chooser;
	private ActionMap action;
	private DemCanvas3D canvas;
	private OrbitBehavior orbit;
	
	public DemApp(){
		frame=new JFrame();
		frame.setSize(640, 480);
		JPopupMenu.setDefaultLightWeightPopupEnabled(false);
		chooser=new JFileChooser();
		initGUI();
		initBehavior();
		initAction();
		frame.setJMenuBar(createJMenuBar());
	}

	private void initGUI(){
		frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		frame.getContentPane().setLayout(new BorderLayout());
		frame.addWindowListener(new WindowAdapter(){
			@Override
			public void windowClosing(WindowEvent e) {
				int id=JOptionPane.showConfirmDialog(frame, "Exit O.K.?", 
				"Info", JOptionPane.YES_NO_OPTION,JOptionPane.INFORMATION_MESSAGE);
				if(id==JOptionPane.YES_OPTION){
					frame.setVisible(false);
					System.exit(0);
				}
			}
		});
		canvas=new DemCanvas3D();
		frame.getContentPane().add(canvas,BorderLayout.CENTER);
	}
	
	private void initBehavior(){
		orbit=new OrbitBehavior(canvas,OrbitBehavior.REVERSE_ALL);
		orbit.setSchedulingBounds(canvas.getBoundingSphere());
		orbit.setZoomFactor(100d);
		orbit.setTransFactors(100d, 100d);
		orbit.setReverseRotate(true);
		canvas.getUniverse().getViewingPlatform().setViewPlatformBehavior(orbit);
		KeyNavigatorBehavior
			 kn=new KeyNavigatorBehavior(canvas.getViewPlatformTransform());
		kn.setSchedulingBounds(canvas.getBoundingSphere());
		canvas.getRoot().addChild(kn);
	}
	
	private void initAction(){
		action=new ActionMap();
		AbstractAction ac=new AbstractAction(){
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent arg0) {
				chooser.resetChoosableFileFilters();
				chooser.setFileFilter(new TmpFileFilter("mem"));
				int ret = chooser.showDialog(null, "Open");
				if (ret != JFileChooser.APPROVE_OPTION){return;}
				File file=chooser.getSelectedFile();
				DemLoader dl=new DemLoader();
				BranchGroup bg=dl.load(file);
				if(bg!=null)canvas.addWorld(bg);
			}
		};
		action.put("load.mem", ac);
				
		ac=new AbstractAction(){
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent arg0) {
				chooser.resetChoosableFileFilters();
				chooser.setFileFilter(new TmpFileFilter("png"));
				int ret = chooser.showDialog(null, "Save");
				if (ret != JFileChooser.APPROVE_OPTION){return;}
				File file=chooser.getSelectedFile();
				canvas.saveImage(file);
			}
		};
		action.put("export.png", ac);
		
		ac=new AbstractAction(){
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Transform3D t3d=new Transform3D();
				t3d.setIdentity();
				TransformGroup tg=
			 canvas.getUniverse().getViewingPlatform().getViewPlatformTransform();
				tg.setTransform(t3d);
			}
		};
		action.put("jump.home", ac);
	}
	
	private JMenuBar createJMenuBar(){
		JMenuBar ret=new JMenuBar();
		JMenu file=new JMenu("File");
		file.setMnemonic('F');
		ret.add(file);
		JMenuItem mem=new JMenuItem("Open(*.mem)");
		mem.addActionListener(action.get("load.mem"));
		file.add(mem);
		JMenuItem png=new JMenuItem("Scan(*.png)");
		file.add(png);
		png.addActionListener(action.get("export.png"));
		
		JMenuItem trs=new JMenuItem("Reset");
		file.add(trs);
		trs.addActionListener(action.get("jump.home"));
		return ret;
	}
		
	public void start(){
		frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
		canvas.start();
		frame.setVisible(true);
	}
	
	private class TmpFileFilter extends FileFilter{
		String ext;
		
		TmpFileFilter(String _ext){
			ext=_ext.toLowerCase();
		}
		
		@Override
		public boolean accept(File f) {
			String name=f.getName().toLowerCase();
			int id=name.lastIndexOf(".");
			if(id==-1||id==name.length()-1){
				return false;
			}else{
				String ex=name.substring(id+1, name.length());
				return ex.equals(ext);
			}
		}

		@Override
		public String getDescription() {
			return "*."+ext;
		}
	}
	
	public static void main(String[] args){
		DemApp app=new DemApp();
		app.start();
	}

}

 ■結果
 実行結果は、上記の画像のとおり。
 なお、右マウスドラッグで回転、左マウスドラッグで平行移動、ホイール回転で拡大・縮小する。
 ファイル読み込み後、画面が真っ暗な場合はホイールマウスを回転し縮小すれば画像が見えてくる。