*******************************************************************************/
package org.simantics.g3d.vtk.handlers;
-import javax.vecmath.Vector3d;
-
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.Command;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.handlers.HandlerUtil;
-import org.simantics.g3d.math.MathTools;
import org.simantics.g3d.vtk.common.VtkView;
import org.simantics.utils.threads.AWTThread;
import org.simantics.utils.threads.ThreadUtils;
vtkRenderer ren = panel.getRenderer();
vtkCamera cam = ren.GetActiveCamera();
if (activate){
-
- Vector3d focal = new Vector3d(panel.getRenderer().GetActiveCamera().GetFocalPoint());
- Vector3d pos = new Vector3d(panel.getRenderer().GetActiveCamera().GetPosition());
- double dist = MathTools.distance(pos, focal);
- cam.SetParallelScale(dist/4.0);
- // camera must be moved backwards, or graphics get clipped when parallel view is zoomed out
- // TODO : is there a better way to do this?
- Vector3d dir = new Vector3d(pos);
- dir.sub(focal);
- dir.normalize();
- dir.scale(100);
- dir.add(focal);
- cam.SetPosition(dir.x, dir.y, dir.z);
-
+ double distance = cam.GetDistance();
+ double angle = cam.GetViewAngle();
+ double scale = Math.tan(Math.toRadians(angle / 2)) * distance;
+ cam.SetParallelScale(scale);
cam.SetParallelProjection(1);
ren.ResetCameraClippingRange();
} else {
-
- double scale = cam.GetParallelScale();
cam.SetParallelProjection(0);
-
- Vector3d focal = new Vector3d(panel.getRenderer().GetActiveCamera().GetFocalPoint());
- Vector3d pos = new Vector3d(panel.getRenderer().GetActiveCamera().GetPosition());
- Vector3d dir = new Vector3d(pos);
- dir.sub(focal);
- dir.normalize();
- dir.scale(scale*4.0);
- dir.add(focal);
- cam.SetPosition(dir.x, dir.y, dir.z);
ren.ResetCameraClippingRange();
-
}
panel.refresh();
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;
// 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;
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>();
// 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);
+ }
}
type="push">
<parameter
name="org.simantics.g3d.viewDirection"
- value="-0.57735026918962576450914878050196,-0.57735026918962576450914878050196,0.57735026918962576450914878050196">
+ value="-0.57735026918962576450914878050196,0.57735026918962576450914878050196,-0.57735026918962576450914878050196">
</parameter>
</command>
<command
package org.simantics.plant3d.editor;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.simantics.g3d.scenegraph.NodeMap;
import org.simantics.g3d.scenegraph.RenderListener;
import org.simantics.g3d.scenegraph.base.INode;
+import org.simantics.g3d.scenegraph.base.ParentNode;
import org.simantics.g3d.toolbar.ToolComposite;
import org.simantics.g3d.vtk.action.RemoveAction;
import org.simantics.g3d.vtk.common.HoverHighlighter;
import org.simantics.g3d.vtk.common.NodeSelectionProvider2;
import org.simantics.g3d.vtk.common.SelectionHighlighter;
-import org.simantics.g3d.vtk.common.VTKSelectionItem;
import org.simantics.g3d.vtk.common.VtkView;
import org.simantics.g3d.vtk.shape.vtkShape;
import org.simantics.g3d.vtk.swt.ContextMenuListener;
import org.simantics.plant3d.scenegraph.EndComponent;
import org.simantics.plant3d.scenegraph.Equipment;
import org.simantics.plant3d.scenegraph.IP3DNode;
+import org.simantics.plant3d.scenegraph.IP3DVisualNode;
import org.simantics.plant3d.scenegraph.InlineComponent;
import org.simantics.plant3d.scenegraph.Nozzle;
import org.simantics.plant3d.scenegraph.P3DRootNode;
import vtk.vtkDefaultPass;
import vtk.vtkGaussianBlurPass;
import vtk.vtkLightsPass;
-import vtk.vtkProp;
+import vtk.vtkProp3D;
import vtk.vtkRenderPassCollection;
import vtk.vtkRenderer;
import vtk.vtkSSAAPass;
}
createActions();
-
}
public void setUpDirection(int upDirection) {
@Override
public void postRender() {
+ panel.removeListener(this);
+
try {
P3DUtil.finalizeDBLoad2(rootNode);
if (nodeMap.isRangeModified());
nodeMap.commit("Load sync");
} catch (Exception e) {
ExceptionUtils.logAndShowError("Failed to load model correctly", e);
- //throw new DatabaseException(e);
}
- panel.removeListener(this);
-
+
+ List<vtkProp3D> props = new ArrayList<vtkProp3D>();
+ collectProps(rootNode, props);
+ fitToWindow(props);
}
});
-
}
});
panel.getComponent().setFocus();
}
- private void createScene() {
+ protected void createScene() {
vtkRenderer ren1 = panel.getRenderer();
boolean multiPass = false;
AxesDisplay axesDisplay = new AxesDisplay(panel);
axesDisplay.show();
-
}
protected Menu contextMenu;
protected void createContextMenu(IMenuManager m) {
List<INode> selected = selectionProvider.getSelectedNodes();
- List<VTKSelectionItem<Resource>> selectedItems = selectionProvider.getSelectedItems();
- if (selectedItems.size() > 0) {
- List<vtkProp> props = new ArrayList<>();
- for (VTKSelectionItem<Resource> i : selectedItems) {
- vtkProp p = (vtkProp)i.getAdapter(vtkProp.class);
- if (p != null)
- props.add(p);
- }
- if (props.size() > 0) {
- focusAction.setProps(props);
- m.add(focusAction);
- }
- }
+
+ createFocusMenu(m, selected);
+
+ m.add(new Separator());
+
try {
if (selected.size() == 0) {
m.add(new AddEquipmentAction(rootNode, getLibraryUri()));
ExceptionUtils.logAndShowError(e);
}
}
+
+ protected void createFocusMenu(IMenuManager m, List<INode> selected) {
+ m.add(new Action("Fit to Window") {
+ @Override
+ public void run() {
+ List<vtkProp3D> props = new ArrayList<>();
+ final Collection<INode> collection = !selected.isEmpty() ? selected : getRootNode().getChild();
+ for (INode n : collection)
+ collectProps(n, props);
+
+ fitToWindow(props);
+ getPanel().refresh();
+ }
+ });
+
+ if (!selected.isEmpty()) {
+ List<vtkProp3D> actors = new ArrayList<>();
+ for (INode n : selected)
+ collectProps(n, actors);
+ if (actors.size() > 0) {
+ focusAction.setProps(new ArrayList<>(actors));
+ m.add(focusAction);
+ }
+ }
+ }
private IContentOutlinePage createOutline() {
if (rootNode == null || selectionProvider == null)
public P3DNodeMap getNodeMap() {
return nodeMap;
}
+
+ public void fitToWindow(Collection<vtkProp3D> props) {
+ cameraAction.fitToView(props);
+ }
+
+ protected static void collectProps(INode node, List<vtkProp3D> props) {
+ if (node instanceof IP3DVisualNode)
+ props.addAll(((IP3DVisualNode) node).getActors());
+
+ if (node instanceof ParentNode)
+ for (INode n : ((ParentNode<?>) node).getNodes()) {
+ collectProps(n, props);
+ }
+ }
}