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.csg.editor;
14 import java.awt.Component;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import java.util.HashSet;
18 import java.util.List;
21 import org.eclipse.jface.action.IMenuListener;
22 import org.eclipse.jface.action.IMenuManager;
23 import org.eclipse.jface.action.MenuManager;
24 import org.eclipse.jface.viewers.ISelectionChangedListener;
25 import org.eclipse.jface.viewers.SelectionChangedEvent;
26 import org.eclipse.swt.SWT;
27 import org.eclipse.swt.events.DisposeEvent;
28 import org.eclipse.swt.events.DisposeListener;
29 import org.eclipse.swt.layout.FillLayout;
30 import org.eclipse.swt.widgets.Composite;
31 import org.eclipse.swt.widgets.Display;
32 import org.eclipse.swt.widgets.Menu;
33 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
34 import org.simantics.db.ReadGraph;
35 import org.simantics.db.Resource;
36 import org.simantics.db.common.request.ReadRequest;
37 import org.simantics.db.exception.DatabaseException;
38 import org.simantics.g3d.csg.actions.AddBooleanOpAction2;
39 import org.simantics.g3d.csg.actions.AddPrimitiveAction2;
40 import org.simantics.g3d.csg.actions.SplitBooleanOpAction2;
41 import org.simantics.g3d.csg.scenegraph2.BarrelNode;
42 import org.simantics.g3d.csg.scenegraph2.BoxNode;
43 import org.simantics.g3d.csg.scenegraph2.CSGparentNode;
44 import org.simantics.g3d.csg.scenegraph2.CSGrootNode;
45 import org.simantics.g3d.csg.scenegraph2.ConeNode;
46 import org.simantics.g3d.csg.scenegraph2.CylinderNode;
47 import org.simantics.g3d.csg.scenegraph2.DifferenceNode;
48 import org.simantics.g3d.csg.scenegraph2.EllipticCylinderNode;
49 import org.simantics.g3d.csg.scenegraph2.ICSGnode;
50 import org.simantics.g3d.csg.scenegraph2.IntersectionNode;
51 import org.simantics.g3d.csg.scenegraph2.RectangularSolidNode;
52 import org.simantics.g3d.csg.scenegraph2.RegularPrismNode;
53 import org.simantics.g3d.csg.scenegraph2.SchemaBuilder;
54 import org.simantics.g3d.csg.scenegraph2.SphereNode;
55 import org.simantics.g3d.csg.scenegraph2.TorusNode;
56 import org.simantics.g3d.csg.scenegraph2.UnionNode;
57 import org.simantics.g3d.scenegraph.IG3DNode;
58 import org.simantics.g3d.scenegraph.NodeMap;
59 import org.simantics.g3d.scenegraph.base.INode;
60 import org.simantics.g3d.vtk.action.RemoveAction;
61 import org.simantics.g3d.vtk.awt.InteractiveVtkPanel;
62 import org.simantics.g3d.vtk.awt.RotateAction;
63 import org.simantics.g3d.vtk.awt.TranslateAction;
64 import org.simantics.g3d.vtk.awt.vtkCameraAndSelectorAction;
65 import org.simantics.g3d.vtk.common.HoverHighlighter;
66 import org.simantics.g3d.vtk.common.NodeSelectionProvider2;
67 import org.simantics.g3d.vtk.common.SelectionHighlighter;
68 import org.simantics.g3d.vtk.common.VTKContentOutlinePage;
69 import org.simantics.g3d.vtk.common.VtkView;
70 import org.simantics.g3d.vtk.shape.vtkShape;
71 import org.simantics.g3d.vtk.utils.vtkPanelUtil;
72 import org.simantics.objmap.graph.IMapping;
73 import org.simantics.objmap.graph.Mappings;
74 import org.simantics.objmap.graph.schema.IMappingSchema;
75 import org.simantics.selectionview.StandardPropertyPage;
76 import org.simantics.ui.workbench.IPropertyPage;
77 import org.simantics.ui.workbench.IResourceEditorInput;
78 import org.simantics.ui.workbench.ResourceEditorPart;
79 import org.simantics.utils.threads.AWTThread;
80 import org.simantics.utils.threads.ThreadUtils;
81 import org.simantics.utils.ui.ExceptionUtils;
82 import org.simantics.utils.ui.SWTAWTComponent;
85 import vtk.vtkCameraPass;
86 import vtk.vtkDefaultPass;
87 import vtk.vtkLightsPass;
88 import vtk.vtkRenderPassCollection;
89 import vtk.vtkRenderer;
90 import vtk.vtkSequencePass;
92 public class CSGEditor2 extends ResourceEditorPart {
93 private Composite parent;
94 private Resource input;
95 private InteractiveVtkPanel panel;
96 private SWTAWTComponent component;
98 private CSGrootNode rootNode;
99 private IMapping<Resource,Object> mapping;
101 private NodeSelectionProvider2<Resource,Object> selectionProvider;
103 private vtkCameraAndSelectorAction cameraAction;
104 private TranslateAction translateAction;
105 private RotateAction rotateAction;
106 private RemoveAction removeAction;
108 //private ScenegraphOutlinePage outlinePage;
110 private CSGNodeMap nodeMap;
115 public void createPartControl(Composite parent) {
116 this.parent = parent;
117 parent.setLayout (new FillLayout ());
118 component = new SWTAWTComponent(parent,SWT.NONE) {
121 protected Component createSwingComponent() {
123 panel = new InteractiveVtkPanel();
124 vtkPanelUtil.registerPanel(panel);
131 IResourceEditorInput rei = (IResourceEditorInput)getEditorInput();
132 input = rei.getResource();
135 //IActionBars actionBars = getEditorSite().getActionBars();
139 component.syncPopulate();
141 panel.addMouseListener(new java.awt.event.MouseAdapter() {
143 public void mouseClicked(final java.awt.event.MouseEvent e) {
144 if (e.getButton() == java.awt.event.MouseEvent.BUTTON3) {
145 Display.getDefault().asyncExec(new Runnable() {
147 contextMenu.setLocation(e.getXOnScreen(), e.getYOnScreen());
148 contextMenu.setVisible(true);
156 cameraAction = new vtkCameraAndSelectorAction(panel);
157 panel.setDefaultAction(cameraAction);
158 panel.useDefaultAction();
161 getSession().syncRequest(new ReadRequest() {
163 @SuppressWarnings({ "rawtypes", "unchecked" })
165 public void run(ReadGraph graph) throws DatabaseException {
166 IMappingSchema schema = SchemaBuilder.getSchema(graph);
167 mapping = Mappings.createWithListening(schema);
168 rootNode = (CSGrootNode)mapping.map(graph, input);
169 nodeMap = new CSGNodeMap(getSession(), mapping, panel,(CSGrootNode)rootNode);
173 if (rootNode == null)
174 throw new RuntimeException("Scenegraph loading failed.");
177 selectionProvider = new NodeSelectionProvider2<Resource,Object>(this,mapping,nodeMap);
179 cameraAction.addSelectionChangedListener(selectionProvider);
181 cameraAction.addHoverChangedListener(new HoverHighlighter(panel,nodeMap));
182 selectionProvider.addSelectionChangedListener(new SelectionHighlighter(panel,nodeMap));
184 getSite().setSelectionProvider(selectionProvider);
185 getSite().getPage().addPostSelectionListener(selectionProvider);
187 //outlinePage = new ScenegraphOutlinePage(rootNode);
190 parent.addDisposeListener(new DisposeListener() {
193 public void widgetDisposed(DisposeEvent e) {
194 getSite().getPage().removePostSelectionListener(selectionProvider);
195 ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {
200 vtkPanelUtil.unregisterPanel(panel);
210 } catch (DatabaseException e1) {
211 ExceptionUtils.logAndShowError("Cannot open CSG editor",e1);
215 translateAction = new TranslateAction(panel,nodeMap);
216 rotateAction = new RotateAction(panel,nodeMap);
217 removeAction = new RemoveAction(nodeMap) {
218 public void setNode(IG3DNode node) {
220 if (node.getParent() instanceof CSGparentNode)
232 public void populate() {
233 ThreadUtils.asyncExec(AWTThread.getThreadAccess(), new Runnable() {
246 public void setFocus() {
247 component.setFocus();
250 private void createScene() {
251 vtkRenderer ren1 = panel.GetRenderer();
253 boolean multiPass = false;
256 vtkLightsPass lightsPass = new vtkLightsPass();
257 vtkDefaultPass defaultPass = new vtkDefaultPass();
260 vtkRenderPassCollection passes = new vtkRenderPassCollection();
261 passes.AddItem(lightsPass);
262 passes.AddItem(defaultPass);
264 vtkSequencePass seq = new vtkSequencePass();
265 seq.SetPasses(passes);
269 vtkCameraPass cameraPass = new vtkCameraPass();
270 cameraPass.SetDelegatePass(seq);
272 ren1.SetPass(cameraPass);
275 // ren1.GetRenderWindow().LineSmoothingOn();
276 // ren1.GetRenderWindow().PointSmoothingOn();
277 // ren1.GetRenderWindow().PolygonSmoothingOn();
278 // ren1.GetRenderWindow().SetMultiSamples(2);
282 ren1.SetBackground2(1,1,1); // background color white
283 ren1.SetBackground(0.9,0.9,0.9);
284 ren1.SetGradientBackground(true);
286 // vtkActor grid = vtkShape.createGridActor(8,1.0,1|2|4);
287 vtkActor grid = vtkShape.createGridActor(8,1.0, 2 );
290 panel.addDeletable(grid);
296 protected Menu contextMenu;
298 protected void hookContextMenu() {
299 MenuManager menuMgr = new MenuManager("#PopupMenu");
300 menuMgr.setRemoveAllWhenShown(true);
301 menuMgr.addMenuListener(new IMenuListener() {
302 public void menuAboutToShow(IMenuManager manager) {
303 final IMenuManager m = manager;
304 List<IG3DNode> selected = selectionProvider.getSelectedNodes();
305 if (selected.size() == 0) {
306 m.add(new AddPrimitiveAction2(rootNode, BarrelNode.class));
307 m.add(new AddPrimitiveAction2(rootNode, BoxNode.class));
308 m.add(new AddPrimitiveAction2(rootNode, ConeNode.class));
309 m.add(new AddPrimitiveAction2(rootNode, CylinderNode.class));
310 m.add(new AddPrimitiveAction2(rootNode, EllipticCylinderNode.class));
311 m.add(new AddPrimitiveAction2(rootNode, RectangularSolidNode.class));
312 m.add(new AddPrimitiveAction2(rootNode, RegularPrismNode.class));
313 m.add(new AddPrimitiveAction2(rootNode, SphereNode.class));
314 m.add(new AddPrimitiveAction2(rootNode, TorusNode.class));
315 } else if (selected.size() == 1) {
316 m.add(translateAction);
319 ICSGnode node = (ICSGnode)selected.get(0);
320 translateAction.setNode(node);
321 rotateAction.setNode(node);
322 removeAction.setNode(node);
323 if (node instanceof CSGparentNode) {
324 m.add(new SplitBooleanOpAction2(rootNode,(CSGparentNode)node));
326 } else if (selected.size() == 2) {
327 if (selected.get(0).getParent().equals(rootNode) && selected.get(1).getParent().equals(rootNode)) {
328 Collection<ICSGnode> nodes = new ArrayList<ICSGnode>();
329 for (IG3DNode n : selected)
330 nodes.add((ICSGnode)n);
331 m.add(new AddBooleanOpAction2(rootNode, DifferenceNode.class, nodes));
332 m.add(new AddBooleanOpAction2(rootNode, IntersectionNode.class, nodes));
333 m.add(new AddBooleanOpAction2(rootNode, UnionNode.class, nodes));
337 // SimanticsUI.getSession().syncRequest(new ReadRequest() {
340 // public void run(ReadGraph graph) throws DatabaseException {
341 // Layer0 l0 = Layer0.getInstance(graph);
342 // CSG csg = CSG.getInstance(graph);
343 // Resource ontology = graph.getResource("http://www.simantics.org/CSG-0.1");
345 // if (selectionProvider.getSelectedResources().size() == 0) {
346 // List<NamedResource> primitives = new ArrayList<NamedResource>();
347 // for (Resource r : graph.getObjects(ontology, l0.ConsistsOf)) {
348 // if (graph.isInheritedFrom(r, csg.Primitive) && !r.equals(csg.Primitive)) {
349 // primitives.add(new NamedResource((String)graph.getRelatedValue(r, l0.HasName), r));
353 // Collections.sort(primitives);
354 // for (NamedResource n : primitives) {
355 // m.add(new AddPrimitiveAction(graph, n.getResource(),input));
358 // if (selectionProvider.getSelectedResources().size() == 2) {
359 // List<NamedResource> booleanOps = new ArrayList<NamedResource>();
360 // for (Resource r : graph.getObjects(ontology, l0.ConsistsOf)) {
361 // if (graph.isInheritedFrom(r, csg.BooleanOperation) && !r.equals(csg.BooleanOperation)) {
362 // booleanOps.add(new NamedResource((String)graph.getRelatedValue(r, l0.HasName), r));
366 // Collections.sort(booleanOps);
367 // for (NamedResource n : booleanOps) {
368 // m.add(new AddBooleanOpAction(graph, n.getResource(), input, selectionProvider.getSelectedResources()));
371 // if (selectionProvider.getSelectedResources().size() == 1) {
372 // m.add(translateAction);
373 // m.add(rotateAction);
374 // m.add(removeAction);
375 // Resource selected = selectionProvider.getSelectedResources().get(0);
376 // translateAction.setNode((IG3DNode2)mapping.get(selected));
377 // rotateAction.setNode((IG3DNode2)mapping.get(selected));
378 // removeAction.setNode((IG3DNode2)mapping.get(selected));
379 // if (graph.isInstanceOf(selected, csg.BooleanOperation)) {
380 // m.add(new SplitBooleanOpAction(input,selected));
388 // } catch (DatabaseException e) {
389 // // TODO Auto-generated catch block
390 // e.printStackTrace();
396 contextMenu = menuMgr.createContextMenu(parent);
399 private IContentOutlinePage createOutline() {
400 if (rootNode == null || selectionProvider == null)
402 IContentOutlinePage outlinePage = new VTKContentOutlinePage<Resource,Object>(rootNode, selectionProvider);
403 outlinePage.addSelectionChangedListener(new ISelectionChangedListener() {
406 public void selectionChanged(SelectionChangedEvent event) {
407 selectionProvider.selectionChanged(event);
413 @SuppressWarnings("rawtypes")
415 public Object getAdapter(Class adapter) {
416 if (IPropertyPage.class.equals(adapter))
417 return new StandardPropertyPage(getSite(),getPropertyContexts());
418 if (IContentOutlinePage.class.equals(adapter)) {
419 return createOutline();
421 if (NodeMap.class.equals(adapter)) {
424 if (INode.class.equals(adapter)) {
427 if (IMapping.class.equals(adapter)) {
430 if (InteractiveVtkPanel.class.equals(adapter)) {
433 if (VtkView.class.equals(adapter))
435 return super.getAdapter(adapter);
438 public Set<String> getPropertyContexts() {
439 Set<String> result = new HashSet<String>();
440 result.add("http://www.simantics.org/Project-1.0/ProjectBrowseContext");