1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 Association for Decentralized Information Management in
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.g3d.vtk.swt;
14 import java.awt.event.KeyEvent;
15 import java.awt.event.MouseEvent;
16 import java.awt.event.MouseWheelEvent;
17 import java.math.BigDecimal;
19 import javax.vecmath.AxisAngle4d;
20 import javax.vecmath.Point3d;
21 import javax.vecmath.Quat4d;
22 import javax.vecmath.Vector3d;
24 import org.eclipse.swt.SWT;
25 import org.eclipse.swt.events.SelectionAdapter;
26 import org.eclipse.swt.events.SelectionEvent;
27 import org.eclipse.swt.graphics.Cursor;
28 import org.eclipse.swt.widgets.Button;
29 import org.eclipse.swt.widgets.Combo;
30 import org.eclipse.swt.widgets.Display;
31 import org.eclipse.swt.widgets.Label;
32 import org.simantics.g3d.math.MathTools;
33 import org.simantics.g3d.math.Ray;
34 import org.simantics.g3d.scenegraph.IG3DNode;
35 import org.simantics.g3d.scenegraph.base.INode;
36 import org.simantics.g3d.scenegraph.structural.IStructuralNode;
37 import org.simantics.g3d.toolbar.ToolComposite;
38 import org.simantics.g3d.vtk.Activator;
39 import org.simantics.g3d.vtk.common.VTKNodeMap;
40 import org.simantics.g3d.vtk.gizmo.TranslateAxisGizmo;
41 import org.simantics.g3d.vtk.utils.vtkUtil;
42 import org.simantics.utils.threads.ThreadUtils;
46 public class TranslateAction extends vtkSwtAction {
48 public static final int X = 0;
49 public static final int Y = 1;
50 public static final int Z = 2;
51 public static final int XY = 3;
52 public static final int XZ = 4;
53 public static final int YZ = 5;
54 public static final int P = 6;
56 private VTKNodeMap<?, ? extends INode> nodeMap;
57 // private TranslateGizmo gizmo = new TranslateGizmo();
58 private TranslateAxisGizmo gizmo = new TranslateAxisGizmo();
59 protected IG3DNode node;
61 private Cursor activeCursor;// = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
62 private Cursor dragCursor;// = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
64 protected ToolComposite toolComposite;
65 protected Combo axisCombo;
67 public void setNode(IG3DNode node) {
69 if ((node instanceof IStructuralNode) && ((IStructuralNode) node).isPartOfInstantiatedModel()
70 && !((IStructuralNode) node).isInstantiatedModelRoot()) {
77 public IG3DNode getNode() {
81 public TranslateAction(InteractiveVtkComposite panel, VTKNodeMap<?, ? extends INode> nodeMap,
82 ToolComposite toolComposite) {
84 setImageDescriptor(Activator.imageDescriptorFromPlugin("com.famfamfam.silk", "icons/arrow_out.png"));
86 this.nodeMap = nodeMap;
88 activeCursor = Display.getCurrent().getSystemCursor(SWT.CURSOR_HAND);
89 dragCursor = Display.getCurrent().getSystemCursor(SWT.CURSOR_SIZEALL);
90 this.toolComposite = toolComposite;
93 protected void createTools(ToolComposite toolComposite) {
94 createMessage(toolComposite);
95 createAxisSelection(toolComposite);
96 createCloseButton(toolComposite);
98 toolComposite.relayout();
101 protected void createMessage(ToolComposite toolComposite) {
102 new Label(toolComposite, SWT.READ_ONLY).setText("Press ESC to close translation. ");
105 protected void createAxisSelection(ToolComposite toolComposite) {
106 Label label = new Label(toolComposite, SWT.READ_ONLY);
107 label.setText("Translate direction:");
108 axisCombo = new Combo(toolComposite, SWT.READ_ONLY);
115 axisCombo.add("Camera");
116 axisCombo.addSelectionListener(new SelectionAdapter() {
118 public void widgetSelected(SelectionEvent e) {
119 Combo c = (Combo) e.getSource();
120 index = c.getSelectionIndex();
122 panel.getComponent().setFocus();
125 axisCombo.select(index);
128 protected void createCloseButton(ToolComposite toolComposite) {
129 Button close = new Button(toolComposite, SWT.PUSH);
130 close.setText("Close");
131 close.addSelectionListener(new SelectionAdapter() {
132 public void widgetSelected(SelectionEvent e) {
133 panel.useDefaultAction();
138 public void attach() {
141 if (toolComposite != null) {
142 createTools(toolComposite);
146 ThreadUtils.asyncExec(panel.getThreadQueue(), new Runnable() {
154 public void deattach() {
155 if (toolComposite != null) {
156 toolComposite.clear();
161 nodeMap.commit("Translate");
167 private void attachUI() {
168 panel.getComponent().setCursor(activeCursor);
172 private void deattachUI() {
173 panel.getComponent().setCursor(Display.getCurrent().getSystemCursor(SWT.CURSOR_ARROW));
178 public boolean keyPressed(KeyEvent e) {
179 if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
180 panel.useDefaultAction();
183 if (e.getKeyCode() == KeyEvent.VK_X) {
189 if (e.getKeyCode() == KeyEvent.VK_Y) {
195 if (e.getKeyCode() == KeyEvent.VK_Z) {
201 if (e.getKeyCode() == KeyEvent.VK_G) {
202 worldCoord = !worldCoord;
211 private void updateLock() {
212 gizmo.setType(index);
213 if (axisCombo != null)
214 axisCombo.select(index);
219 public boolean mouseClicked(MouseEvent e) {
220 if (e.getClickCount() > 1) {
224 panel.useDefaultAction();
226 // if(!gizmo.isPartOf(actor))
227 // panel.useDefaultAction();
233 private boolean isOverNode(MouseEvent e) {
234 vtkProp picked[] = panel.pick(e.getX(), e.getY());
235 if (picked != null) {
236 for (int i = 0; i < picked.length; i++) {
237 if (node.equals(nodeMap.getNode(picked[i])))
245 protected boolean valid = false;
246 private boolean worldCoord = true;
247 private AxisAngle4d aa = null;
248 private Quat4d q = null;
250 public void setWorldCoord(boolean b) {
258 protected void update() {
262 gizmo.setRotation(new AxisAngle4d());
266 aa = new AxisAngle4d();
267 aa.set(((IG3DNode) node.getParent()).getWorldOrientation());
268 gizmo.setRotation(aa);
270 MathTools.getQuat(aa, q);
273 Vector3d nodePos = node.getWorldPosition();
274 // System.out.println(nodePos);
275 gizmo.setPosition(nodePos);
277 Point3d camPos = new Point3d(panel.getRenderer().GetActiveCamera().GetPosition());
278 Vector3d p = new Vector3d(nodePos);
282 Quat4d qi = new Quat4d(q);
284 MathTools.rotate(q, p, p);
286 if (panel.getRenderer().GetActiveCamera().GetParallelProjection() == 0) {
287 double distance = p.length();
289 double fov = panel.getRenderer().GetActiveCamera().GetViewAngle();
290 float s = (float) (Math.sin(fov) * distance * 0.1);
292 Vector3d scale = new Vector3d(1., 1., 1.);
301 gizmo.setScale(scale);
304 Vector3d scale = new Vector3d(1.f, 1.f, 1.f);
305 double s = panel.getRenderer().GetActiveCamera().GetParallelScale() / 5.;
313 gizmo.setScale(scale);
320 protected Vector3d prevTranslate = null;
323 public boolean mousePressed(MouseEvent e) {
324 if (e.getButton() == MouseEvent.BUTTON1) {
327 prevTranslate = getTranslate(e.getX(), e.getY());
329 panel.getComponent().setCursor(dragCursor);
332 getDefaultAction().mousePressed(e);
333 panel.getComponent().setCursor(activeCursor);
336 getDefaultAction().mousePressed(e);
339 // index = gizmo.getTranslateAxis(actor);
340 // if (index == -1) {
342 // panel.getDefaultAction().mousePressed(e);
346 // prevTranslate = getTranslate(e.getX(), e.getY());
347 // System.out.println("start translate " + prevTranslate);
351 public boolean mouseReleased(MouseEvent e) {
352 if (e.getButton() == MouseEvent.BUTTON1) {
354 prevTranslate = null;
355 panel.getComponent().setCursor(activeCursor);
357 getDefaultAction().mouseReleased(e);
363 public boolean mouseDragged(MouseEvent e) {
364 // if ((e.getModifiersEx() & MouseEvent.BUTTON1_DOWN_MASK) > 0 && valid) {
365 if (e.getButton() == MouseEvent.BUTTON1 && valid) {
367 Vector3d translate = getTranslate(e.getX(), e.getY(), prevTranslate);
368 // System.out.println("translate " + translate);
369 if (translate == null)
371 boolean step = ((e.getModifiers() & MouseEvent.CTRL_MASK) > 0);
373 Vector3d pos = new Vector3d(node.getWorldPosition());
375 pos = constaints(pos, step);
378 Vector3d pos = new Vector3d(node.getPosition());
380 pos = constaints(pos, step);
383 // mapping.rangeModified(node);
385 // nodeMap.modified(node);
388 getDefaultAction().mouseDragged(e);
395 public boolean mouseWheelMoved(MouseWheelEvent e) {
396 return getDefaultAction().mouseWheelMoved(e);
399 protected void setPos(Vector3d pos) {
400 node.setPosition(pos);
403 protected void setWorldPos(Vector3d pos) {
404 node.setWorldPosition(pos);
407 private double istep = 10.0;
408 private int decimals = 2;
410 protected Vector3d constaints(Vector3d p, boolean step) {
415 p.x = Math.round(istep * p.x) / istep;
416 BigDecimal bx = new BigDecimal(p.x);
417 bx.setScale(decimals, BigDecimal.ROUND_HALF_UP);
418 p.x = bx.doubleValue();
421 p.y = Math.round(istep * p.y) / istep;
422 BigDecimal by = new BigDecimal(p.y);
423 by.setScale(decimals, BigDecimal.ROUND_HALF_UP);
424 p.y = by.doubleValue();
428 p.z = Math.round(istep * p.z) / istep;
429 BigDecimal bz = new BigDecimal(p.z);
430 bz.setScale(decimals, BigDecimal.ROUND_HALF_UP);
431 p.z = bz.doubleValue();
438 public boolean mouseMoved(MouseEvent e) {
439 getDefaultAction().mouseMoved(e);
443 protected Vector3d getTranslate(double x, double y) {
444 return getTranslate(x, y, new Vector3d());
447 protected Vector3d getTranslate(double x, double y, Vector3d offset) {
448 Vector3d translate = new Vector3d();
450 Ray ray = vtkUtil.createMouseRay(panel.getRenderer(), x, y);
452 Vector3d p = node.getWorldPosition();
457 Vector3d normal = new Vector3d(panel.getRenderer().GetActiveCamera().GetDirectionOfProjection());
459 MathTools.rotate(q, normal, normal);
462 double s[] = new double[1];
463 Vector3d r = new Vector3d();
464 if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) {
473 dir = new Vector3d(1.0, 0.0, 0.0);
475 MathTools.rotate(q, dir, dir);
476 Vector3d i1 = new Vector3d();
477 Vector3d i2 = new Vector3d();
479 MathTools.intersectStraightStraight(p, dir, ray.pos, ray.dir, i2, i1, s);
484 dir = new Vector3d(0.0, 1.0, 0.0);
486 MathTools.rotate(q, dir, dir);
490 MathTools.intersectStraightStraight(p, dir, ray.pos, ray.dir, i2, i1, s);
494 dir = new Vector3d(0.0, 0.0, 1.0);
496 MathTools.rotate(q, dir, dir);
500 MathTools.intersectStraightStraight(p, dir, ray.pos, ray.dir, i2, i1, s);
504 normal = new Vector3d(0.0, 0.0, 1.0);
506 MathTools.rotate(q, normal, normal);
508 if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) {
515 normal = new Vector3d(0.0, 1.0, 0.0);
517 MathTools.rotate(q, normal, normal);
519 if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) {
526 normal = new Vector3d(1.0, 0.0, 0.0);
528 MathTools.rotate(q, normal, normal);
530 if (MathTools.intersectStraightPlane(ray.pos, ray.dir, p, normal, r)) {
540 translate.sub(offset);