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;
import vtk.vtkCamera;
import vtk.vtkProp;
+import vtk.vtkProp3D;
import vtk.vtkRenderWindow;
import vtk.vtkRenderer;
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);
this.rw = panel.getRenderWindow();
this.cam = ren.GetActiveCamera();
}
+
+ public void setUpDirection(double[] upDirection) {
+ this.upDirection = upDirection;
+ }
public void Lock() {
panel.lock();
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();
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();
// 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];
* 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);
- } else {
- cam.Dolly(zoomFactor);
- resetCameraClippingRange();
+ updateParallelScale();
}
+ resetCameraClippingRange();
}
lastX = x;
lastY = y;
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<vtkProp> selectActors = new ArrayList<vtkProp>();
protected List<vtkProp> hoverActor = new ArrayList<vtkProp>();
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<vtkProp3D> 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);
+ }
}