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