X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.g3d.vtk%2Fsrc%2Forg%2Fsimantics%2Fg3d%2Fvtk%2Fswt%2FvtkCameraAndSelectorAction.java;h=e177834ed0ae624ba7a78abc2b100f03b62467a7;hb=6325452591b2a854f82ac913fe4f61e3df2f922d;hp=9c444b4f7eac40aff2e6d5fe9af0f8a92c4681c3;hpb=99366a416fcd1e18e0cf54c8efd255abfc8a01f4;p=simantics%2F3d.git diff --git a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/swt/vtkCameraAndSelectorAction.java b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/swt/vtkCameraAndSelectorAction.java index 9c444b4f..e177834e 100644 --- a/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/swt/vtkCameraAndSelectorAction.java +++ b/org.simantics.g3d.vtk/src/org/simantics/g3d/vtk/swt/vtkCameraAndSelectorAction.java @@ -18,6 +18,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import javax.vecmath.Vector3d; + import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; @@ -28,6 +30,7 @@ import org.simantics.g3d.tools.AdaptationUtils; import vtk.vtkCamera; import vtk.vtkProp; +import vtk.vtkProp3D; import vtk.vtkRenderWindow; import vtk.vtkRenderer; @@ -43,6 +46,7 @@ public class vtkCameraAndSelectorAction extends vtkSwtAction implements ISelecti protected double activeRate = 5.0; protected double passiveRate = 0.01; protected boolean doNotRotate = true; + private double[] upDirection = new double[] { 0, 1, 0 }; public vtkCameraAndSelectorAction(InteractiveVtkComposite panel) { super(panel); @@ -50,6 +54,10 @@ public class vtkCameraAndSelectorAction extends vtkSwtAction implements ISelecti this.rw = panel.getRenderWindow(); this.cam = ren.GetActiveCamera(); } + + public void setUpDirection(double[] upDirection) { + this.upDirection = upDirection; + } public void Lock() { panel.lock(); @@ -113,10 +121,10 @@ public class vtkCameraAndSelectorAction extends vtkSwtAction implements ISelecti int y = e.getY(); // rotate if (this.InteractionMode == 1) { - cam.Azimuth(lastX - x); - cam.Elevation(y - lastY); + cam.Elevation(clampElevationDelta(y - lastY)); if (doNotRotate) - cam.SetRoll(0); + cam.SetViewUp(upDirection); + cam.Azimuth(lastX - x); cam.OrthogonalizeViewUp(); resetCameraClippingRange(); // panel.UpdateLight(); @@ -125,9 +133,8 @@ public class vtkCameraAndSelectorAction extends vtkSwtAction implements ISelecti if (this.InteractionMode == 2) { double FPoint[]; double PPoint[]; - double APoint[] = new double[3]; + double APoint[]; double RPoint[]; - double focalDepth; // get the current focal point and position FPoint = cam.GetFocalPoint(); @@ -136,14 +143,15 @@ public class vtkCameraAndSelectorAction extends vtkSwtAction implements ISelecti // calculate the focal depth since we'll be using it a lot ren.SetWorldPoint(FPoint[0], FPoint[1], FPoint[2], 1.0); ren.WorldToDisplay(); - focalDepth = ren.GetDisplayPoint()[2]; - - APoint[0] = rw.GetSize()[0] / 2.0 + (x - lastX); - APoint[1] = rw.GetSize()[1] / 2.0 - (y - lastY); - APoint[2] = focalDepth; + APoint = ren.GetDisplayPoint(); + +// int[] size = rw.GetSize(); + APoint[0] -= x - lastX; + APoint[1] += y - lastY; ren.SetDisplayPoint(APoint); ren.DisplayToWorld(); RPoint = ren.GetWorldPoint(); + if (RPoint[3] != 0.0) { RPoint[0] = RPoint[0] / RPoint[3]; RPoint[1] = RPoint[1] / RPoint[3]; @@ -154,25 +162,21 @@ public class vtkCameraAndSelectorAction extends vtkSwtAction implements ISelecti * Compute a translation vector, moving everything 1/2 the distance to the * cursor. (Arbitrary scale factor) */ - cam.SetFocalPoint((FPoint[0] - RPoint[0]) / 2.0 + FPoint[0], (FPoint[1] - RPoint[1]) / 2.0 + FPoint[1], - (FPoint[2] - RPoint[2]) / 2.0 + FPoint[2]); - cam.SetPosition((FPoint[0] - RPoint[0]) / 2.0 + PPoint[0], (FPoint[1] - RPoint[1]) / 2.0 + PPoint[1], - (FPoint[2] - RPoint[2]) / 2.0 + PPoint[2]); + cam.SetFocalPoint(RPoint); + cam.SetPosition((RPoint[0] - FPoint[0]) + PPoint[0], (RPoint[1] - FPoint[1]) + PPoint[1], + (RPoint[2] - FPoint[2]) + PPoint[2]); resetCameraClippingRange(); } // zoom if (this.InteractionMode == 3) { double zoomFactor; - // double clippingRange[]; - zoomFactor = Math.pow(1.02, (y - lastY)); + cam.Dolly(zoomFactor); + if (cam.GetParallelProjection() == 1) { - cam.SetParallelScale(cam.GetParallelScale() / zoomFactor); - resetCameraClippingRange(); - } else { - cam.Dolly(zoomFactor); - resetCameraClippingRange(); + updateParallelScale(); } + resetCameraClippingRange(); } lastX = x; lastY = y; @@ -180,21 +184,45 @@ public class vtkCameraAndSelectorAction extends vtkSwtAction implements ISelecti return true; } + private static double dot(double[] a, double[] b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; + } + + /** Calculate change in elevation, clamped to vertical directions. */ + private double clampElevationDelta(double elevationDelta) { + if (!doNotRotate) + return elevationDelta; + + double[] direction = cam.GetDirectionOfProjection(); + double d = Math.min(1.0, Math.max(-1.0, dot(direction, upDirection))); + double elevation = Math.toDegrees(Math.acos(d)) + elevationDelta; + if (elevation < 0) + elevationDelta -= elevation - 1e-5; + else if (elevation > 180) + elevationDelta -= elevation - 180 + 1e-5; + return elevationDelta; + } + @Override public boolean mouseWheelMoved(MouseWheelEvent e) { double zoomFactor; // double clippingRange[]; zoomFactor = Math.pow(1.02, (e.getWheelRotation())); - if (cam.GetParallelProjection() == 1) { - cam.SetParallelScale(cam.GetParallelScale() / zoomFactor); - } else { - cam.Dolly(zoomFactor); - resetCameraClippingRange(); - } + cam.Dolly(zoomFactor); + updateParallelScale(); + resetCameraClippingRange(); panel.refresh(); return true; } + private void updateParallelScale() { + // Make height of parallel projection match the distance + double distance = cam.GetDistance(); + double angle = cam.GetViewAngle(); + double scale = Math.tan(Math.toRadians(angle / 2)) * distance; + cam.SetParallelScale(scale); + } + protected List selectActors = new ArrayList(); protected List hoverActor = new ArrayList(); @@ -378,12 +406,88 @@ public class vtkCameraAndSelectorAction extends vtkSwtAction implements ISelecti public void focus(double x, double y, double z) { Lock(); cam.SetFocalPoint(x, y, z); - if (doNotRotate) - cam.SetRoll(0); + if (doNotRotate) { + double[] proj = cam.GetDirectionOfProjection(); + if (Math.abs(proj[1] * upDirection[2] - proj[2] * upDirection[1]) < 1e-6 && + Math.abs(proj[2] * upDirection[0] - proj[0] * upDirection[2]) < 1e-6 && + Math.abs(proj[0] * upDirection[1] - proj[1] * upDirection[0]) < 1e-6) + cam.SetViewUp(upDirection[1], upDirection[2], upDirection[0]); + else + cam.SetViewUp(upDirection); + } cam.OrthogonalizeViewUp(); resetCameraClippingRange(); // panel.UpdateLight(); UnLock(); } + + public void fitToView(Collection props) { + if (props.isEmpty()) + return; + + double[] bounds = new double[] { Double.MAX_VALUE, -Double.MAX_VALUE, Double.MAX_VALUE, -Double.MAX_VALUE, Double.MAX_VALUE, -Double.MAX_VALUE }, b = new double[6]; + for (vtkProp3D prop : props) { + prop.GetBounds(b); + for (int i = 0; i < 6; i+=2) + bounds[i] = Math.min(bounds[i], b[i]); + for (int i = 1; i < 6; i+=2) + bounds[i] = Math.max(bounds[i], b[i]); + } + + fitToView(bounds); + } + + public void fitToView(double[] bounds) { + Vector3d center = new Vector3d((bounds[0] + bounds[1])/2, (bounds[2] + bounds[3])/2, (bounds[4] + bounds[5])/2); + Vector3d viewDir = new Vector3d(cam.GetDirectionOfProjection()); + Vector3d upDir = new Vector3d(cam.GetViewUp()); + viewDir.normalize(); + upDir.normalize(); + Vector3d sideDir = new Vector3d(); + sideDir.cross(viewDir, upDir); + sideDir.normalize(); + + double width = getBoxWidth(bounds, sideDir); + double height = getBoxWidth(bounds, upDir); + double depth = getBoxWidth(bounds, viewDir); + + int[] size = rw.GetActualSize(); + + double distance1 = height / 2 / Math.tan(Math.toRadians(cam.GetViewAngle()) / 2); + double distance2 = distance1 * (width / size[0] / (height / size[1])); + + double distance = Math.max(distance1, distance2) + depth / 2; + + viewDir.scale(-distance); + viewDir.add(center); + + cam.SetPosition(viewDir.x, viewDir.y, viewDir.z); + focus(center.x, center.y, center.z); + + if (cam.GetParallelProjection() == 1) { + cam.SetParallelScale(Math.max(height, width * size[1] / size[0]) / 2); + } + } + + private static double getBoxWidth(double[] bounds, Vector3d dir) { + double dx = bounds[1] - bounds[0]; + double dy = bounds[3] - bounds[2]; + double dz = bounds[5] - bounds[4]; + + return Math.abs(dx * dir.x) + Math.abs(dy * dir.y) + Math.abs(dz * dir.z); + } + + public void setViewDir(Vector3d direction) { + Vector3d focal = new Vector3d(cam.GetFocalPoint()); + Vector3d pos = new Vector3d(cam.GetPosition()); + Vector3d dir = new Vector3d(pos); + dir.sub(focal); + double distance = dir.length(); + dir.scaleAdd(distance, direction, focal); + cam.SetPosition(dir.x, dir.y, dir.z); + focus(focal.x, focal.y, focal.z); + //panel.UpdateLight(); + panel.refresh(); + } }