/* * Project Info: http://jcae.sourceforge.net * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This program 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 Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * (C) Copyright 2008, by EADS France */ package org.jcae.vtk; import java.awt.Dimension; import java.awt.Graphics; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import vtk.vtkActorCollection; import vtk.vtkCanvas; import vtk.vtkInteractorStyleTrackballCamera; import vtk.vtkMapper; import vtk.vtkUnsignedCharArray; /** * This class is temporary. It permits to correct bugs on VTK. * See : * http://www.vtk.org/Bug/view.php?id=6268 * http://ij-plugins.svn.sourceforge.net/viewvc/ij-plugins/trunk/VTK-Examples/Wrapping/Java/vtk/util/VtkPanelUtil.java?view=markup * @author ibarz */ //TODO manage 3 vtkRenderer/layer: //1 - one for normal rendering //2 - one for picking rendering //3 - one for fast overlay rendering after picking //vtkRenderer 2 and 3 should be dynamically created when needed and not keeped in //the canvas. Beware to share vtkCamera. Beware of CameraClippingRange public class Canvas extends vtkCanvas { private vtkUnsignedCharArray buffer = new vtkUnsignedCharArray(); private int bufferWidth, bufferHeight = 0; private final static boolean OPT_2D=Boolean.getBoolean("org.jcae.vtk.2dopt"); private final static boolean REMOVE_NOTIFY = Boolean.parseBoolean( System.getProperty("org.jcae.vtk.removenotify", "true")); public Canvas() { addMouseWheelListener(new MouseWheelListener() { public void mouseWheelMoved(MouseWheelEvent e) { if(System.currentTimeMillis()-e.getWhen() < 500) { Lock(); if(e.getWheelRotation() > 0) iren.MouseWheelForwardEvent(); else iren.MouseWheelBackwardEvent(); UnLock(); } } }); setMinimumSize(new Dimension(0, 0)); setPreferredSize(new Dimension(0, 0)); vtkInteractorStyleTrackballCamera style = new vtkInteractorStyleTrackballCamera(); style.AutoAdjustCameraClippingRangeOn(); getIren().SetInteractorStyle(style); if(OPT_2D) rw.AddObserver("EndEvent", this, "endEvent"); } /** * Fix mouse wheel bug with VTK 6.3. * Starting with VTK 6.3 vtkCanvas implement mouse wheel support using this * method (see VTK commit 4fc0088). It does work alone but as we also * implement mouse wheel in this class in create a bug. So we override it * to do nothing. */ public void mouseWheelMoved(MouseWheelEvent e) {} /** * Save the current image to reuse it when no 3D rendering is necessary. * Called by VTK when vtkRendererWindow fire EndEvent. */ private void endEvent() { buffer.SetNumberOfValues(getWidth()*getHeight()); rw.GetPixelData(0, 0, getWidth()-1, getHeight()-1, 1, buffer); bufferWidth = getWidth(); bufferHeight = getHeight(); } /** * Correct a bug : update the reference of camera. * If we change the original camera the light does not follow the camera anymore. * @see http://www.vtk.org/Bug/view.php?id=6913 */ @Override public void UpdateLight() { if (LightFollowCamera == 0) return; cam = GetRenderer().GetActiveCamera(); super.UpdateLight(); } /** * Override to correct the bug of the UpdateLight (the light position is not updated * if the camera is moved by programming. * @see http://www.vtk.org/Bug/view.php?id=6913 */ public void RenderSecured() { if (!isWindowSet()) return; Utils.goToAWTThread(new Runnable() { @Override public void run() { Render(); } }); } /** * Override to correct the bug of the UpdateLight (the light position is not updated * if the camera is moved by programming. * @see http://www.vtk.org/Bug/view.php?id=6913 [^] */ @Override public void Render() { if (!rendering) { rendering = true; if (ren.VisibleActorCount() == 0) { rendering = false; return; } if (rw != null) { if (windowset == 0) { // set the window id and the active camera if (lightingset == 0) { ren.AddLight(lgt); lightingset = 1; } RenderCreate(rw); Lock(); rw.SetSize(getWidth(), getHeight()); UnLock(); windowset = 1; } UpdateLight(); Lock(); rw.Render(); UnLock(); rendering = false; } } } /** * Workaround a bug with JSplitterPane on Windows. * On Windows, JSplitterPane with no continous layout makes * the vtkPanel undrawable when split bar is moved. * As a workaround, do not call super.removeNotify() on * Windows. This method must be removed when vtk is fixed. * @see http://www.vtk.org/Bug/view.php?id=7107 */ @Override public void removeNotify() { if (REMOVE_NOTIFY) super.removeNotify(); } /** * Workaround for http://www.vtk.org/Bug/view.php?id=6268 * Pass through the case the rendering window is not linked to the canvas * because it's created (see vtkPanel constructor). * * @param width the new width of this component in pixels. * @param height the new height of this component in pixels */ @Override public void setSize(int x, int y) { super.setSize(x, y); Lock(); rw.SetSize(x, y); iren.SetSize(x, y); iren.ConfigureEvent(); UnLock(); } @Override public void lock() { if (isWindowSet()) super.lock(); } @Override public void unlock() { if (isWindowSet()) super.unlock(); } /** Disable keyboard event handling in VTK, use only Java*/ @Override public void keyPressed(KeyEvent e) { } @Override public void paint(Graphics g) { if(!OPT_2D || windowset == 0 || bufferWidth != getWidth() || bufferHeight != getHeight()) { Render(); } else { Lock(); rw.SetPixelData(0, 0, getWidth()-1, getHeight()-1, buffer, 1); UnLock(); } } /** * Set the ImmediadeRenderingMode on the current view * @param mode */ public void setImmediateRenderingMode(boolean mode) { vtkMapper mapper; vtkActorCollection listOfActors = GetRenderer().GetActors(); int nbActors = listOfActors.GetNumberOfItems(); listOfActors.InitTraversal(); for (int i = 0; i < nbActors; ++i) { //browsing the list of actors and getting their associated mappers mapper = listOfActors.GetNextActor().GetMapper(); mapper.SetImmediateModeRendering(Utils.booleanToInt(mode)); } } @Override public void mousePressed(MouseEvent e) { if (ren.VisibleActorCount() == 0) return; Lock(); rw.SetDesiredUpdateRate(5.0); lastX = e.getX(); lastY = e.getY(); ctrlPressed = (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0; shiftPressed = (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0; iren.SetEventInformationFlipY(e.getX(), e.getY(), ctrlPressed, shiftPressed, '0', 0, "0"); if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) iren.LeftButtonPressEvent(); else if ((e.getModifiers() & InputEvent.BUTTON2_MASK) == InputEvent.BUTTON2_MASK) iren.RightButtonPressEvent(); else if ((e.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) iren.MiddleButtonPressEvent(); UnLock(); VTKMemoryManager.GC.SetAutoGarbageCollection(false); } @Override public void mouseReleased(MouseEvent e) { rw.SetDesiredUpdateRate(0.01); ctrlPressed = (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0; shiftPressed = (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0; iren.SetEventInformationFlipY(e.getX(), e.getY(), ctrlPressed, shiftPressed, '0', 0, "0"); if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) { Lock(); iren.LeftButtonReleaseEvent(); UnLock(); } if ((e.getModifiers() & InputEvent.BUTTON2_MASK) == InputEvent.BUTTON2_MASK) { Lock(); iren.RightButtonReleaseEvent(); UnLock(); } if ((e.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) { Lock(); iren.MiddleButtonReleaseEvent(); UnLock(); } VTKMemoryManager.GC.SetAutoGarbageCollection(true); } }